7-机器学习策略
机器学习策略
正则化
搭建机器学习系统的挑战之一是,可以尝试和改变的东西太多了,包括非常多的超参数,优化算法等等。
那么,我们需要非常明确:要调整什么来达到某个效果。
这个步骤称之为正则化。
简单理解为:在调整超参数等各种可以调整的内容时,需要尽可能保证在调整后,只对某一个效果有效,而不影响其他已经调节好的,打到了的效果。
例如:
要设计一个监督学习系统,需要确保四件事情:
- 在训练集上效果很好
- 在开发集上效果很好
- 在测试集上效果很好
- 在实际使用中效果很好
因此,如果算法在代价函数上不能很好拟合训练集,那么可以调整算法,例如选择更好的优化算法。
而如果算法对开发集的拟合很差,那么应该有另一套独立的调整方法。需要在满足第一个条件的基础上,调整系统让算法满足第二个条件。
而如果不符合第三个条件,那么同样,需要在满足前两个条件上进行调整。
正则化就是这个意思。
就像开车,油门和刹车控制速度,方向盘控制方向,调整油门并不影响汽车的方向;同样,调整方向盘也并不影响汽车速度。三者搭配起来,才能开好车。
单一数字评估指标
无论是调整超参数,还是尝试不同优化算法,都需要一个单实数的评估指标。
例如,给猫分类这个问题,有两个分类器A,B:
分类器 | Precision | Recall |
---|---|---|
A | 95% | 90% |
B | 98% | 85% |
分别有查准率(Precision),查全率(Recall)。
查准率表示在分类器标记为猫的例子中,真的猫的比例是多少。
例如A的查准率为95%,表示A如果预测该图为猫时,有95%的概率真的是猫。
查全率表示在所有真猫的图片中,分类器正确识别出了多少,A的查全率是90%。例如,开发集全部是真猫图,那么对应所有图像,A准确分辨出了其中的90%。
这两个指标往往需要折中,两个指标都需要考虑。
那么就会有一个问题,A在查全率上表现更好,B在查准率上表现更好,如何进行选择呢。
因此需要找到一个新的单一数字评估指标,并能够结合查准率和查全率。
常用的标准方法是分数。
定义是:
其中P和R分别代表查准率和查全率。
在数学上,这个函数叫做查准率和查全率的调和平均数。
分类器 | Precision | Recall | F1 Score |
---|---|---|---|
A | 95% | 90% | 92.4% |
B | 98% | 85% | 91.0% |
计算出F1分数可以看出,A分类器更好。
满足和优化指标
还以猫图片分类为例子。
假设除了考虑分类器的准确率,还需要考虑运行时间。
分类器 | Accuracy | Running time |
---|---|---|
A | 90% | 80ms |
B | 92% | 95ms |
C | 95% | 1500ms |
那么可以设定一个优化指标和满足指标。
在这个例子中,满足指标为运行时间,优化指标为准确度。
可以设定运行时间必须要满足小于等于100ms,否则无论准确度多高,都不实用。
因此分类器C被淘汰了。
而达到满足指标后,就无所谓了,可以根据优化指标来选择。
更一般来说,如果要考虑N个指标,可以把其中一个作为优化指标,剩下N-1个都是满足指标。
训练/开发/测试集划分
开发(dev)集有时也称为交叉验证集。
机器学习中的工作流程通常是:尝试很多思路,用训练集训练不同的模型,然后使用开发集来评估这些思路,最后选择一个最优模型,然后不断迭代去改善开发集的性能,最后得到一个最优模型,再使用测试集评估。
开发集和测试集划分的一个原则是:开发集和测试集来自同一分布。
举个例子,要开发一个猫分类器,有来自不同国家地区上传的猫图片,US,UK,India,China等等。
如果选择US,UK的数据作为开发集,India和China的图片作为测试集,那么开发集和数据集就不是来自同一分布。
相当于,打靶,训练了很久指定的靶心,结果实际测试中换了靶心,那么训练就没有意义。
因此,一个建议是:将所有的数据随机洗牌,放入开发集和测试集。
误差分析
如果希望让学习算法能够胜任人类能做的任务,但算法还没有达到人类的表现,那么可以人工检查算法犯的错误,来明确接下来应该如何修改,这个过程称为误差分析。
例如正在调试猫分类器,准确率为90%,在分类出错的例子中,将一些狗的图片分类成猫,证明算法可能较难区分猫和狗。
可以考虑设计针对狗的优化算法,但是可能优化后,算法的准确率并不会提升太多,因此如何判断这一方向是否值得优化呢。
首先可以查看在错误标记的开发集样本中,有多少错误样本是狗,即计算错误标记样本中,狗的样本占比是多少。
例如只有5%,那么即使优化了针对狗的算法,也只修正了错误样本中的5%,得不偿失。
但如果是50%,那么就很有必要去做针对狗的优化。
同样的,可能有多种错误类型,例如之前的把狗错误分类成猫,把老虎错误分类成猫,因为图片模糊分类错误等等。
可以把每种错误类型的样本统计一下,得出所占比例,就可以知道哪种错误类型占比最高,对准确率的影响最大,从而更好地指导下一步的优化。
清除标记错误的样本数据
在监督学习中,有时候输出标签是错误的,例如分类猫问题中,样本中狗图片的输出标签是1,被错误标注成了猫。
在这种情况下,讨论是否值得花时间修正这些标签。
首先考虑训练集,事实证明,深度学习算法对于训练集中的随机错误是相当健壮的。
随机错误是指,可能是做标记的人不小心标记错了,而非故意。
与随机错误对应的是系统性错误,例如将所有白色的狗都标记成了猫,这种情况下,分类器学习后,就会将所有白色狗都分类为猫,出现错误。
因此训练集中标记错误的样本是随机错误,在训练样本数量足够大的情况下,可以不修正这些错误标签。
现在考虑开发集,是否修正的建议是:如果这些错误标记严重影响了分类器在开发集上评估算法的能力,就应该修正。
可以通过观察三个数据来判断是否值得修正:
开发集整体错误率,由错误标记引起的错误率,其他原因导致的错误率。
例如,分类器在开发集上达到了90%的准确率,而6%的错误来自标记出错,即错误标记导致准确率下降了10% x 6% = 0.6%。
那么其他原因导致准确率下降了9.4%。
这种情况下,标记错误导致的错误占总体错误很小的一部分,因此可以不修正。
但是,如果整体错误率降到了2%,而总体错误中还是有6%是由标记错误导致的,就应该考虑修正错误标签。
如果要修正开发集中的错误标签,有一些原则:
- 同时修正开发集和测试集中的错误标签,确保开发集和测试集来自同一分布
- 同时检验算法判断正确和错误的样本
- 训练集可以与开发/测试集来自稍微不同的分布,因此修正开发集时,可以不修正训练集
使用来自不同分布的数据进行训练并测试
在划分训练、开发、测试集,经常会出现训练集和开发/测试集来自不同分布的情况。
有一些最佳做法来处理这种情况。
例如要开发一个手机应用,用户会上传他们的图片,想要识别用户上传的图片是不是猫。现在有两个数据来源,一个是真正关心的数据分布,也就是用户上传的图片,这些图片可能很业余,取景不好,比较模糊;另一个爬虫程序收集的网上图片,这些图片更专业,分辨率更好。
例如,只收集到了一万张用户上传的图片,网上收集了20万张图片,这种情况下,应该如何划分训练/开发/测试集。
一种选择是简单的将两组数据合在一起,然后随机分配到训练、开发、测试集中,例如训练集205000张,开发、测试各2500张。
这种选择的好处在于训练、开发、测试集都来自同一分布,而坏处也很大,观察开发集,可以发现大部分图片都来自网上下载,而不是真正关心的用户上传图片。
因此不建议使用这种选择。
建议这样划分:
网上收集的全部20万张图片作为训练集,同时从用户上传的一万张图片中拿出5000张作为训练集,剩下五千张,开发、测试集各2500张。
当然,这种情况下,训练集和开发/测试集的分布不一样,但是这种划分方法可以带来更好的性能。
数据分布不匹配时,偏差和方差的分析
继续以猫分类器为例,要进行错误率分析,通常需要看训练误差和开发误差。
例如,训练误差是1%,开发集误差是10%,如果开发集和训练集来自同一分布,那么可以确定,存在很大的方差问题,算法不能很好的从训练集出发泛化。
但是,如果训练集和开发集来自不同的分布,就不能轻易地下结论了。
也可能是上面所说的方差问题。
但也有可能是因为训练集都是高分辨率图像,因此算法在训练集上做的很好,但是开发集都是模糊图片,难以识别,所以算法没有方差问题,是因为数据的分布不匹配。
这里不能确定是哪种结论的原因是:第一,算法只见过训练集数据,没见过开发集数据;第二,开发集和训练集来自不同的分布。
因此为了分辨到底是方差问题还是数据不匹配问题,需要定义一组新的数据,称为训练-开发集,这是训练集的一个子集。
也就是说,训练-开发集和训练集来自同一分布,但是训练-开发集不用于训练神经网络。
在使用剩余的训练集训练好后,需要分别查看分类器在训练集、训练-开发集、开发集的误差。
例如:
- 训练误差:1%
- 训练-开发误差:9%
- 开发误差:10%
可以看出,当从训练数据变到训练-开发集数据时,错误率提升很多,而训练集数据和训练-开发数据的差异在于:算法只在训练集上训练,没有见过训练-开发集。
因此算法存在方差问题,因为训练集和训练-开发集来自同一分布。
再看一个例子:
- 训练误差:1%
- 训练-开发误差:1.5%
- 开发误差:10%
可以看出,当处理开发集时,错误率上升到10%,所以现在方差问题很小,因为从训练数据转到没有见过的训练-开发数据,错误率上升的很小。而转到开发集,错误率大大上升。
所以这时数据不匹配问题,即因为训练集和开发集来自不同分布。
人类可以在这个任务上能做到几乎不出差错,因此贝叶斯错误率(即能达到的最优错误率)是0%。
因此可以同时查看这四个数据:
- 人类错误率(贝叶斯最优错误率):0%
- 训练误差:10%
- 训练-开发误差:12%
- 开发误差:12%
其中1
和2
之间存在的误差称为可避免偏差,2
和3
之间存在的误差称为方差,3
和4
之间存在的误差是数据不匹配问题。
解决数据不匹配问题
目前数据不匹配问题没有一个系统性的解决方案,但是可以尝试一些方法。
- 进行错误分析,尝试了解训练集和开发集的具体差异
- 可以尝试把训练数据变得更像开发/测试集一点,或收集更多类似开发/测试集的数据。例如如果发现车辆背景噪声造成了数据不匹配,可以在训练集中加入模拟的车辆噪声
迁移学习(Transfer Learning)
深度学习中,最强大的理念之一是:有的时候神经网络可以从一个任务中学习知识,并将这些知识应用到另一个独立的任务中,这就是迁移学习。
例如,已经训练好了一个神经网络,可以识别猫图片,可以使用这些知识,或者部分知识,去构建一个识别x射线扫描图的神经网络。因为这两个任务的输入都是图片。
对于已经训练好的神经网络,x是图像,y是预测结果。
可以把这个神经网络拿过来,然后让它适应或者说迁移到识别X射线扫描图的任务中。
可以将神经网络的最后输出层删掉,同时把进入最后一层的权重也删掉,然后为最后一层重新赋予随机权重,使用放射诊断数据进行训练。
具体来说,在第一阶段,进行图像识别任务的训练时,可以训练神经网络中的所有常用参数,然后得到一个能够做图像识别预测的神经网络。要实现迁移学习,需要把数据集换成放射图像,然后初始化最后一层的权重,现在可以在这个新数据集上重新训练网络。
如果放射扫描图片数据量很小,那么可以只重新训练最后一层的权重,其他层权重保持不变,如果数据量很大,那么可以重新训练网络中的所有参数。
如果重新训练神经网络中的所有参数,那么在图像识别任务的训练阶段,称为预训练(pre-training),因为在这一阶段使用图像识别数预训练神经网络权重,然后在放射科数据上训练,这个过程叫做微调(fine tuning)。
在这个例子中,把图像识别中学到的知识应用或迁移到放射科诊断上来,为什么这样做有效果呢。
因为在图像识别阶段,有很多低层次的特征,例如边缘检测,曲线检测等,从大量的图像识别样本中学习到了,同样,也学到了很多结构信息,图像形状信息,这些知识或者部分知识也同样适用于放射科诊断学习,因此可以帮助放射科诊断神经网络学习的更好或者更快。
那么迁移学习什么时候是有意义的呢。
迁移学习适用的情况是:在迁移来源问题中,有很多样本数据,但在迁移目标问题中,没有那么多数据。
例如在上面例子中,图像识别任务有大量的数据,而放射科诊断任务重,数据量很小。
如果只用100张图训练图像识别系统,有100张甚至1000张图用于训练放射科诊断系统,那么使用迁移学习不会有太大的帮助。
直接用放射科诊断数据来训练,要比使用100张其他乱七八糟的训练数据效果更好。因为在放射科诊断任务中,一张X射线扫描图的价值要远大于一张图像识别中的数据图像。
那么总结一下,什么时候迁移学习有意义,或者说 什么情况下使用迁移学习更好。
如果想从任务A学习并迁移一些知识到任务B,那么当任务A和任务B有同样/同类型的输入x时,迁移学习是有意义的。
并且,当任务A的数据量要远大于任务B的数据量时,迁移学习的意义更大。
所有这些假设的前提是:希望能够提高任务B的性能。
因为任务B每个数据更有价值,所以任务A的数据量必须要比任务B的数据量大得多的情况下,迁移学习才有帮助。
多任务学习(Multi-Task Learning)
在迁移学习中,从一个任务到另一个任务,步骤是串行的。
而在多任务学习中,多个任务同时开始学习。
在单个神经网络中同时做多个任务,每个任务都可以帮到其他所有任务。
举一个例子,假设在开发无人驾驶车辆,需要检测汽车视线内各种各样的东西,例如检测行人、车辆、停车标志、交通灯等。
那么输入图像为x,输出标签为y,但这里的y不是一个标签,而是四个标签,是一个列向量。
例如上图,检测到停车标志和车辆,但没有行人和交通灯,那么标签为。
可以训练一个神经网络来预测这些y值:
输出层有四个节点,第一个节点预测有没有行人,第二个节点预测有没有车辆,以此类推。
现在定义神经网络的损失函数,对于,一个四维向量,整个训练集的平均损失为:
其中是单个样本的损失,也就是对四个分量的求和。
L指的是logistic损失:
整个训练集的平均损失之和,和之前分类猫的例子主要区别在于,现在要对输出进行分量的求和。
与softmax回归的主要区别是,softmax将单个标签分配给单个样本,最终样本只有一个标签,即输出层概率最大的。
而这个例子中,一个样本有多个标签。
多任务学习的好处就在于:神经网络的一些早期特征,在识别不同物体时都会用到,因此训练一个神经网络同时做四件事情,要比训练四个独立的神经网络分别做四件事情效果更好。
另外,训练样本中,不一定每一张图片都有全部的标签,多任务学习也可以处理图像只有部分物体被标记的情况,例如一个训练样本,贴标签的人只标记了图里有一个行人,没有车,但是没有标记是否有停车标记和交通灯。
在求和时,只对有标签的值求和。
那么多任务学习什么情况下有意义,可以使用呢。
- 如果要训练的一组任务,可以共用低层次特征,例如上例中,识别交通灯,汽车、行人等,这些物体有相似的特征,能够帮助识别停车标志
- 通常来说(并不绝对),如果每个任务的数据量很接近,那么可以使用多任务学习
- 当训练一个足够大的神经网络时,可以使用多任务学习来同时做好所有任务,多任务学习会降低性能的唯一情况是:神经网络还不够大
端到端的深度学习
以前有一些数据处理系统或者学习系统,它们需要多个阶段的处理,而端到端深度学习就是指忽略掉所有这些不同的阶段,用单个神经网络代替。
以语音识别为例,输入一段音频,输出识别的文本y。
在之前,这一过程需要多个阶段,首先需要提取手工设计的音频特征,然后应用机器学习算法在音频片段中找到音位,再将音位串在一起构成独立的词,然后将词穿起来构成音频片段的听写文本。
所以和这种又很多阶段的流水线相比,端到端深度学习做的事情是:训练了一个巨大的神经网络,输入就是一段音频,输出直接是听写文本。忽略掉了所有上述的阶段。
简而言之就是,端到端学习从训练集中,直接学习到了x和y的函数映射。
端到端深度学习的挑战之一是:需要大量的数据才能让系统表现得较好。
如果数据量较小,传统的流水线方式效果也不错。
以人脸识别门禁系统为例。
一种方式是把门禁系统拍的照片直接作为输入,通过神经网络进行验证。
另一种阶段性的方式是首先识别出门禁系统拍的照片中的人脸,方法人脸,然后将人脸照片输入到神经网络中去,进行识别验证。
在这里第二种方法更好,原因是:
- 分阶段解决的两个问题实际上要简单的多
- 两个子任务的训练数据都很多
因此,对于人脸识别门禁系统,把它分成两个子问题,比纯粹的端到端深度学习方法,表现更好。
不过如果有足够多的数据来做端到端学习,也许端到端学习效果会更好。
是否使用端到端的深度学习
端到端深度学习的好处:
- 让数据说话(Let the data speak):如果有足够多的数据,那么不管从x到y最适合的函数映射是什么,只要训练一个足够大的神经网络,那么这个神经网络能够自己搞清楚
- 所需手工设计的组件更少,从而简化了设计工作流程
端到端深度学习的缺点:
- 需要大量的数据
- 排除了可能有用的手工设计组件,如果没有很多数据,那么学习算法就不能从很小的训练集数据中学习地很好,那么手工设计组件在这种情况,并不是一件坏事