7-机器学习策略

机器学习策略

正则化

搭建机器学习系统的挑战之一是,可以尝试和改变的东西太多了,包括非常多的超参数,优化算法等等。

那么,我们需要非常明确:要调整什么来达到某个效果。

这个步骤称之为正则化。

简单理解为:在调整超参数等各种可以调整的内容时,需要尽可能保证在调整后,只对某一个效果有效,而不影响其他已经调节好的,打到了的效果。

例如:

要设计一个监督学习系统,需要确保四件事情:

  1. 在训练集上效果很好
  2. 在开发集上效果很好
  3. 在测试集上效果很好
  4. 在实际使用中效果很好

因此,如果算法在代价函数上不能很好拟合训练集,那么可以调整算法,例如选择更好的优化算法。

而如果算法对开发集的拟合很差,那么应该有另一套独立的调整方法。需要在满足第一个条件的基础上,调整系统让算法满足第二个条件。

而如果不符合第三个条件,那么同样,需要在满足前两个条件上进行调整。

正则化就是这个意思。

就像开车,油门和刹车控制速度,方向盘控制方向,调整油门并不影响汽车的方向;同样,调整方向盘也并不影响汽车速度。三者搭配起来,才能开好车。

单一数字评估指标

无论是调整超参数,还是尝试不同优化算法,都需要一个单实数的评估指标。

例如,给猫分类这个问题,有两个分类器A,B:

分类器PrecisionRecall
A95%90%
B98%85%

分别有查准率(Precision),查全率(Recall)。

查准率表示在分类器标记为猫的例子中,真的猫的比例是多少。

例如A的查准率为95%,表示A如果预测该图为猫时,有95%的概率真的是猫。

查全率表示在所有真猫的图片中,分类器正确识别出了多少,A的查全率是90%。例如,开发集全部是真猫图,那么对应所有图像,A准确分辨出了其中的90%。

这两个指标往往需要折中,两个指标都需要考虑。

那么就会有一个问题,A在查全率上表现更好,B在查准率上表现更好,如何进行选择呢。

因此需要找到一个新的单一数字评估指标,并能够结合查准率和查全率。

常用的标准方法是F1F_1分数。

定义是:

F1=21P+1RF_1 = \frac{2}{\frac{1}{P} + \frac{1}{R} }

其中P和R分别代表查准率和查全率。

在数学上,这个函数叫做查准率和查全率的调和平均数。

分类器PrecisionRecallF1 Score
A95%90%92.4%
B98%85%91.0%

计算出F1分数可以看出,A分类器更好。

满足和优化指标

还以猫图片分类为例子。

假设除了考虑分类器的准确率,还需要考虑运行时间。

分类器AccuracyRunning time
A90%80ms
B92%95ms
C95%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%。

因此可以同时查看这四个数据:

  1. 人类错误率(贝叶斯最优错误率):0%
  2. 训练误差:10%
  3. 训练-开发误差:12%
  4. 开发误差:12%

其中12之间存在的误差称为可避免偏差23之间存在的误差称为方差34之间存在的误差是数据不匹配问题

解决数据不匹配问题

目前数据不匹配问题没有一个系统性的解决方案,但是可以尝试一些方法。

  1. 进行错误分析,尝试了解训练集和开发集的具体差异
  2. 可以尝试把训练数据变得更像开发/测试集一点,或收集更多类似开发/测试集的数据。例如如果发现车辆背景噪声造成了数据不匹配,可以在训练集中加入模拟的车辆噪声

迁移学习(Transfer Learning)

深度学习中,最强大的理念之一是:有的时候神经网络可以从一个任务中学习知识,并将这些知识应用到另一个独立的任务中,这就是迁移学习。

例如,已经训练好了一个神经网络,可以识别猫图片,可以使用这些知识,或者部分知识,去构建一个识别x射线扫描图的神经网络。因为这两个任务的输入都是图片。

image-20220924172650112

对于已经训练好的神经网络,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不是一个标签,而是四个标签,是一个列向量。

image-20220924180024219

例如上图,检测到停车标志和车辆,但没有行人和交通灯,那么标签为y=[0,1,1,0]Ty = [0, 1, 1, 0]^T

可以训练一个神经网络来预测这些y值:

image-20220924180149564

输出层有四个节点,第一个节点预测有没有行人,第二个节点预测有没有车辆,以此类推。

现在定义神经网络的损失函数,对于y^\widehat{y},一个四维向量,整个训练集的平均损失为:

1mi=1mj=14L(y^j(i),yj(i))\frac{1}{m}\sum_{i=1}^{m} \sum_{j=1}^4L(\widehat{y}_j^{(i)}, y_j^{(i)})

其中j=14L(y^j(i),yj(i))\sum_{j=1}^4L(\widehat{y}_j^{(i)}, y_j^{(i)})是单个样本的损失,也就是对四个分量的求和。

L指的是logistic损失:

L(y^j(i),yj(i))=yj(i)logy^j(i)(1yj(i))log(1y^j(i))L(\widehat{y}_j^{(i)}, y_j^{(i)}) = -y_j^{(i)} \log{\widehat{y}_j^{(i)} } - (1- y_j^{(i)} ) \log{ (1- \widehat{y}^{(i)}_j ) }

整个训练集的平均损失之和,和之前分类猫的例子主要区别在于,现在要对输出y^\widehat{y}进行分量的求和。

与softmax回归的主要区别是,softmax将单个标签分配给单个样本,最终样本只有一个标签,即输出层概率最大的。

而这个例子中,一个样本有多个标签。


多任务学习的好处就在于:神经网络的一些早期特征,在识别不同物体时都会用到,因此训练一个神经网络同时做四件事情,要比训练四个独立的神经网络分别做四件事情效果更好。


另外,训练样本中,不一定每一张图片都有全部的标签,多任务学习也可以处理图像只有部分物体被标记的情况,例如一个训练样本,贴标签的人只标记了图里有一个行人,没有车,但是没有标记是否有停车标记和交通灯。

在求和时,只对有标签的值求和。


那么多任务学习什么情况下有意义,可以使用呢。

  1. 如果要训练的一组任务,可以共用低层次特征,例如上例中,识别交通灯,汽车、行人等,这些物体有相似的特征,能够帮助识别停车标志
  2. 通常来说(并不绝对),如果每个任务的数据量很接近,那么可以使用多任务学习
  3. 当训练一个足够大的神经网络时,可以使用多任务学习来同时做好所有任务,多任务学习会降低性能的唯一情况是:神经网络还不够大

端到端的深度学习

以前有一些数据处理系统或者学习系统,它们需要多个阶段的处理,而端到端深度学习就是指忽略掉所有这些不同的阶段,用单个神经网络代替。

以语音识别为例,输入一段音频,输出识别的文本y。

在之前,这一过程需要多个阶段,首先需要提取手工设计的音频特征,然后应用机器学习算法在音频片段中找到音位,再将音位串在一起构成独立的词,然后将词穿起来构成音频片段的听写文本。

所以和这种又很多阶段的流水线相比,端到端深度学习做的事情是:训练了一个巨大的神经网络,输入就是一段音频,输出直接是听写文本。忽略掉了所有上述的阶段。

简而言之就是,端到端学习从训练集中,直接学习到了x和y的函数映射。


端到端深度学习的挑战之一是:需要大量的数据才能让系统表现得较好。

如果数据量较小,传统的流水线方式效果也不错。


以人脸识别门禁系统为例。

一种方式是把门禁系统拍的照片直接作为输入,通过神经网络进行验证。

另一种阶段性的方式是首先识别出门禁系统拍的照片中的人脸,方法人脸,然后将人脸照片输入到神经网络中去,进行识别验证。

在这里第二种方法更好,原因是:

  1. 分阶段解决的两个问题实际上要简单的多
  2. 两个子任务的训练数据都很多

因此,对于人脸识别门禁系统,把它分成两个子问题,比纯粹的端到端深度学习方法,表现更好。

不过如果有足够多的数据来做端到端学习,也许端到端学习效果会更好。

是否使用端到端的深度学习

端到端深度学习的好处:

  • 让数据说话(Let the data speak):如果有足够多的数据,那么不管从x到y最适合的函数映射是什么,只要训练一个足够大的神经网络,那么这个神经网络能够自己搞清楚
  • 所需手工设计的组件更少,从而简化了设计工作流程

端到端深度学习的缺点:

  • 需要大量的数据
  • 排除了可能有用的手工设计组件,如果没有很多数据,那么学习算法就不能从很小的训练集数据中学习地很好,那么手工设计组件在这种情况,并不是一件坏事

7-机器学习策略
https://zhaoquaner.github.io/2022/09/24/DeepLearning/CourseNote/7-机器学习策略/
更新于
2022年9月24日
许可协议