machine-learning-yearning——读书笔记

书的链接

为什么需要策略?

       机器学习是很多应用的基础算法,但是为了提高算法的性能,我们能做的有很多:构建数据集(数量与多样性)、调整网络(规模、结构、正则化)等等。如何选择这些策略是十分重要的。

近年来驱动机器学习发展的要素是什么?

è¿éåå¾çæè¿°

       大规模网络、大规模数据。网络结构的设计也很重要,但是并没有前两者来的可靠。

什么是开发集和测试集?

       训练集是学习算法运行的地方;测试集用于评估算法性能而不能对学习算法和参数进行影响;开发集用于调整参数学习策略,可称为维持交叉验证集。测试集应该反映未来应用场景,而不是简单的从原训练集中挖出一部分(这是假定测试集、训练集分布相同)。

        而开发集和测试集的分布应该相同,我们专注于提高算法在开发集上的性能。如果开发的系统在开发集上工作的很好,但在测试集上并不如意。 既然开发集和测试集合来自相同的分布,那么会有一个非常明确的诊断哪里出错了:算法在开发集上过拟合(overfit)了。显而易见的方法是去获得更多的开发集数据。

         如果分布不同,那么出现同样的问题原因可能有三种:开机集过拟合、由于分布不同改进没有意义、已到达算法上限(就是不能在测试集上表现的好)。

          开发集越大,对算法的调整越精细,如果分类器A具有90.0%的准确度,分类器B具有90.1%的准确度,那么100个样本的开发集将不能检测出这0.1%的差异。

  • 当你拥有大量数据时,依据70%:30%的比例划分训练/测试集这一经验性的方法不太适用;开发/测试集可以占远小于30%的数据量。
  • 你的开发集应该足够大,以检测出算法准确性有意义的改变,但没必要更大。你的测试集应该足够大,大到能对你的系统整体性能有一个确信的评估。

为什么要建立一个单一数字的评估指标?

        如果你真的即关心查准率(Precision)又关心查全率(Recall),我推荐使用一种标准方法将它们组合成一个单一的数字。例如,可以取Precision和Recall的平均值,最终得到单个数字。或者,你可以计算“F1度量(F1 score)”,这是一种基于其平均值改善的方法,比简单地取平均值效果要好。

       如果你正在权衡N个不同的标准,例如模型的二进制文件大小(这对于移动app很重要,因为用户不想要下载很大的app)、运行时间和准确率,你可以考虑将其中N-1个标准设置为为“satisficing”指标。也就是说你只需要他们满足特定的值即可。然后将最后一个定义为“optimizing”指标。例如,将二进制文件大小和运行时间设定一个可接受的阈值,并尝试在这些约束条件下不断优化准确率。

如何用开发集和评估指标来加速迭代?

在构建机器学习系统时,我经常会:

  1. 首先有一些如何构建系统的想法(idea
  2. 用代码(code)来实现这些idea
  3. 进行实验(experiment),来告诉我的这个idea工作的如何。(通常我的前几个想法并不能work)基于这些学习,回去从而产生更多的idea,并不断迭代。

è¿éåå¾çæè¿°

        如果你没有特定的开发集和评估指标。那么每次团队开发出一个新的猫分类器时,你必须把它移植到你的app中,并体验几个小时来感受一下这个新的分类器性能是否有提升。这将非常慢!此外,如果你的团队将分类器的准确率从95.0%提升到95.1%,你可能无法通过体验app来感受到0.1%的提升。而通过不断积累这些许多个0.1%的改进,你的系统将取得很大的进步。有一个开发集和评估指标,可以使你很快地检测出哪些想法给你的系统带来了小(或大)的提升,因此你可以快速决定哪些想法可以继续改善,哪些可以舍弃。

何时更改开发/测试集和评估指标

       在不到一周之内(几乎不会更长)提供一个初始的开发/测试集和评估指标。提出一个不太完美的方案并迅速行动起来,比花过多时间去思考更好。如果你之后发现初始的开发/测试集或评估指标与目标有失偏颇,那么使用一切手段快速更改它们。

       [1]开发/测试集的数据分布并不能代表你需要做好的实际的数据分布。这种情况下,更新你的开发/测试集,使其更具代表性。二者需要同步修改(比如在错误分析中修正开发集中误标注的图片,也需要在测试集中干一样的事,以便开发集和测试集继续服从统一分布。只处理错误分类的误标注比较容易,不过记得正确分类的也有误标注的。)

       [2]在开发集上过拟合了。 在开发集上反复评估想法的过程导致算法逐渐对开发集“过拟合”。当完成开发后,你将在测试集上评估你的算法。如果你的算法在开发集上的表现远好于在测试集上的表现,这意味着你已经过拟合开发集。这种情况下,更新开发集。 如果你需要跟踪团队的进度,你也可以在测试集上定期评估你的系统——每月或每周一次。但不要使用测试集来对算法做任何决定,包括是否回滚到上一周的系统。如果这样做,你将开始过拟合测试集,并且不能再依靠它来完全无偏见的评估系统的性能。

      [3]评估指标衡量的并不是项目所需要优化的东西。该评估指标不能辨别出对产品而言算法B比算法A更好这一事实。所以,你不能再相信该指标能挑选出最佳算法。

错误分析

       查看开发集中错误分类的样例这一过程被称为错误分析(error analysis),了解错误的深层原因,判断idea的上限是多少,而不知直接投身其中。

      有以下几个想法来改进猫检测器:

  • 解决狗被错认为是猫的问题
  • 解决“大形猫科类动物(great cats)”(狮子,豹等)被错认为是家猫(宠物)的问题
  • 提高系统在模糊图像上的表现
  • ……

      查看100个分类错误的开发集样本并填写在表格上:

      思考人是 如何/是否 能正确地分类这些样例,这通常会启发你提出新的类别和解决办法。

è¿éåå¾çæè¿°

       根据消除误差的上限与工作量,分配工作。

       实际工作中开发集合往往很大,可以抽样调查一部分(Eyeball dev set:10%),然后在其他的没有未抽样的集合(Blackbox dev set:90%)自动评估分类器,也可以使用它来选择算法或调超参。一个连人都做不好的任务,那么检查 Eyeball 开发集的联系将不会有什么帮助,因为很难找出算法不能正确分类一个样本的原因。

       将开发集明确地分为 Eyeball 和 Blackbox 可以让你知道何时手动误差分析过程开始导致过拟合数据的 Eyeball 部分。如果你发现 Eyeball 开发集比 Blackbox 开发集性能提升的更快,你已经过拟合 Eyeball 开发集了。这种情况下,你可能需要丢弃它并找一个新的 Eyeball 开发集,可以通过将更多 Blackbox 开发集中的样本移到 Eyeball 开发集中

       Eyeball 开发集应该足够大,大到可以让你了解到算法的主要错误类别。如果你正在从事一项人类表现很好的任务(如识别图像中的猫),以下是一些粗略的指导方针:

  • 如果有约100个错误,你将会很清楚主要的错误来源。我见过有人手动分析更多的错误——有时候多达500个。只要你有足够多的数据,这将是无害的。假设你的分类器有5%的错误率。为了确保在 Eyeball 开发集中有约100个错误标记的样本,Eyeball 开发集应该有约2000个样本(因为 0.05*2000 = 100)。分类器的错误率越低,为了获得足够多的错误来分析,Eyeball 开发集需要越大。
  • 有数据的充足访问权限,那么 Eyeball 开发集的大小将主要取决于你有时间去手动分析样本的数量。例如,我很少看到有人手动分析超过1000个错误。

  • 对很多应用来说,含有1000-10000个样本的 Blackbox 开发集已足够。
  • 如果你的开发集不够大到可以按照这种方式进行拆分,那么就使用 Eyeball 开发集来用于手动错误分析、模型选择和调超参。

如何定位当前的问题?偏差和方差:错误的两大来源

       根据当前的问题,判断是否该增加训练集或者改变学习策略。如假设你希望构建一个5%错误的猫识别器。目前,你的训练集错误率为15%,并且你的开发集错误率为16%。在这种情况下,添加数据可能不会有太多帮助。你应该关注其他改变。实际上,在你的训练集上添加更多的样本只会让你的算法难以在训练集上做的更好。

       我们将这16%的错误分为两部分:

  • 算法在训练集上的错误率。在本例中,它是15%。我们非正式地将此认为是算法的偏差(bias)
  • 算法在开发(或测试)集上比训练集上差多少(泛化性能)。在本例中,开发集比训练集差1%。我们非正式地将此认为是算法的方差(variance)【1】。
  • 高方差低偏差的过拟合,高偏差低方差的欠拟合。

        对于最佳错误率远大于零的问题,这里有一个对算法错误更详细的分解。例如有噪音的语音识别的示例,可以将总的30%的开发集错误分解如下(类似的分析可以应用于测试集错误):

  • 最优错误率(“不可避免的偏差”):14%。假设我们决定,即使是世界上最好的语音系统,我们仍会遭受14%的错误。我们可以将其认为是学习算法的偏差“不可避免”的部分。
  • 可避免的偏差:1%。通过训练错误率和最优误差率之间的差值来计算【3】。
  • 方差:15%。开发错误和训练错误之间的差值。

诊断偏差和方差:学习曲线

       绘制完整的学习曲线给我们提供了更全面图片,绘制了算法在不同训练集大小上的表现。画出开发集错误如何随着训练集大小而变化的曲线,如果开发错误曲线趋于“稳定”(即变平),那么你可以立刻知道添加更多数据并不能达到你的目标。如果开发集很小,可能会更不确定,因为曲线可能很嘈杂。

2

       开发集(和测试集)错误应该随着训练集大小的增长而减少。但随着训练集大小的增加,训练集错误通常会增加。算法更难以完全适应巨大训练集,特别是有一些样本是模棱两可或错误标注的。因此,你的学习算法在该训练集上将做的更糟。

0

       举个例子——具有高可避免偏差的学习曲线

0

       我们的两个观察结果:

  • 随着我们添加更多的训练数据,训练错误只会变得更差。因此,蓝色的训练错误曲线只会保持不动或变得更高,所以它只会远离期望的性能水平(绿色的线)。
  • 红色的开发错误曲线通常要高于蓝色的训练错误曲线。因此,即使训练错误高于期望性能水平,通过添加更多数据来让红色开发错误曲线下降到期望性能水平之下也基本没有可能。

0

       蓝色的训练错误曲线相对低,红色开发错误曲线远高于蓝色训练错误。因此,偏差较小,但是方差较大。添加更多训练数据可能有助于缩小开发错误和训练错误之间的差距。

1

       训练错误较大,远高于期望性能水平。开发错误也比训练错误大很多。因此,具有显著的偏差和方差。你将不得不在算法中去寻找同时减少偏差和方差的方法。

处理误差

如果你的学习算法遭受高可避免偏差、方差,你可以尝试以下方法:

  • 增加模型大小(如神经元/层的数量):该方法可以减少偏差,因为它可以让你更好的适应训练集。如果你发现该方法增加了方差,那么使用正则化方法,它通常能够消除方差的增加。
  • 基于错误分析的洞察修改输入特征:假设错误分析启发你去创建额外的特征,以帮助算法消除特定类别的错误。(我们在下一章节进一步讨论)这些新特征可能有助于减少偏差和方差。理论上来说,增加更多的特征可能会增加方差,但如果你发现这种情况,那么使用正则化方法,它通常能够消除方差的增加。训练集也可以遵循类似于在 Eyeball 开发集上错误分析的规则。
  • 减少或消除正则化(L2正则化,L1正则化,dropout):这将减少可避免偏差,但会增加方差。
  • 修改模型架构(如神经网络架构)以便更适合你的问题:这种方法能够影响偏差和方差。
  • 增加更多训练数据:这种方法有助于解决方差问题,但是它通常对偏差没有显著的影响。

人类的标注能力

人类可以完成很好的任务,那么构建机器学习系统较为容易,有如下几个原因:

  1. 容易从人类标签获取数据。例如,由于人们可以很好的识别猫图,人们为学习算法提供高精度的标签较为容易。
  2. 错误分析可以利用人类的直觉。假设一个语音识别算法比人类识别更差。假设它错误的将一段音频剪辑转录为“This recipe calls for a pear of apples”,将“pair”错称为“pear”。你可以利用人类的直觉,并试图去理解一个人用什么信息去获取正确的转录,并用这些知识来获取学习算法。
  3. 使用人类级别的性能去评估最优错误率并设置“期望错误率”。假设你的算法在一项任务中取得了10%的错误率,但是人的错误率达到2%。然后我们知道最优错误率是2%甚至更低,可避免偏差至少8%。因此,你应该尝试减少偏差的方法。

如果能定位到问题的本质,那么机器是可以超越人类的。

       有很多重要的机器学习应用超越了人类的表现。例如,机器再预测电影评级、货车驾驶到某地需要耗时多久、是否批准贷款方面的表现更好。一旦人类很难识别算法明显出错的样例,只有一部分技术适用。因此,在机器已经超越人类表现的问题上,进展通常缓慢,而在机器仍在试图追赶人类水平的问题上进展较快。

面对大批量低质量数据和小批量高质量数据如何设计训练集开发集测试集?

       你的猫图app用户已经上传了1W张图片,手动标注过是否包含猫。你还有一个更大的数据集,包含20W从互联网下载下来的图片。你该如何定义训练/开发/测试集?由于两种数据具有较高一致性,20W可以包含在训练集中。

       将用户上传的5000张图片,而不是所有的1W张放入开发/测试集中。我们可以将剩余的5000张用户上传的样例放入训练集。这样,你的205000大小的训练集中包含一些来自开发/测试分布的数据,以及20W互联网图片。

       在最终的loss 上,增加1W张图片的权重可以减少建模的计算资源,但也会减少20w的数据集的意义。

       为了诊断不一致性的影响,我们可以定义四个数据子集:

  • 训练集:这是算法将从中学习的数据(例如互联网图片和移动图片)。这不必从我们真正关心数据的相同分布(开发/测试集分布)中获取。
  • 训练开发集:该数据和训练集来自相同的分布(即互联网图片和移动图片)。通常比训练集要小,它只需要足够大以评估和跟踪学习算法的进度就行。
  • 开发集:和测试集来自相同的分布,它反映我们最终关心并想要做好的数据的分布(即移动图片)。
  • 测试集:和开发集来自相同的分布(例如移动图片)。

      有以上四个独立的数据集,现在你可以评估:

  • 训练错误,通过对训练集进行评估。
  • 算法泛化到和训练数据来自相同分布的新数据的能力,通过对训练开发集进行评估。
  • 算法在你关心的任务上的表现,通过对开发、测试集进行评估。
  • 41

       开发集大小的指导方针同样适用于训练开发集。

       通过理解哪种类型的错误算法遭受的最多,你将更好的决定是否专注在减少偏差、减少方差还是减少数据不匹配。

        处理数据不匹配

         假设你开发了一个语音识别系统,在训练集和训练测试集上表现的非常好。然而,在开发集上表现糟糕:你有数据不匹配问题。你能怎么做?

        (i)试图去理解训练集分布和开发集分布之间数据的什么特性不同。

         (ii)试图寻找更多算法有问题的和开发集样例更匹配的训练数据【1】。

       有一些关于训练和测试在不同分布上的学术研究。包括“domain adaptation”,"tarnsfer learning"和"multitask learning"。但理论和实践还是存在很大的差距。如果你在数据集A上训练,并在其上测试分布大不相同的数据B,运气会对你的算法执行效率产生巨大的影响。(这里的“运气”包含研究者对特定任务手动设计的功能,以及其他我们尚不了解的因素)这使得对不同分布上训练和测试的学术研究系统的进行比较困难。

       还有一些关于“域适应”的研究——如何在一个分布上训练算法,并将其泛化到一个不同的分布。这些方法通常只适用于特殊类型的问题

       人工数据合成

       人工数据合成可以让你创造出一个合理匹配开发集的庞大数据集。有时候创建对人来说看起来很逼真的合成数据比创建对电脑来说看起来很逼真的数据要容易。

       有一小时的车噪声。如果你对原始1000小时训练数据的不同部分重复使用同样的这一小时的汽车噪声,你最终得到的合成数据集有着相同的汽车噪声,虽然听这种音频的人可能不能区分(对我们大多数人来说所有的汽车噪声都一样),但学习算法可能会“过拟合”这一个小时的汽车噪声。因此,对于汽车噪声听起来不同的新音频剪辑,算法可能泛化能力较差。这些问题很难被发现。

优化验证测试(44章)

       为了在实践中应用优化验证测试,你应该检测开发集中的错误。归因每个错误,具体是哪一个步骤(涉及具体算法,用控制变量的方法计算)的原因,然后安排优化方案。

何时应用端到端

       48-2

48-3

       它有三个组件:一个使用摄像机图像检车其他车辆;一个检测行人;然后最后一个组件为我们自己的汽车规划一条避免汽车和行人路线。

        并非每个流水线中的组件都需要学习。例如,“机器人运动规划”相关文献中有大量关于汽车最终路径规划步骤的算法。这些算法中很多并不涉及学习。

       相反,端到端的方法可能会试图接收传感器输入并直接输出转向方向

选择流水线组件:数据可用性

       拥有更多手工设计的组件通常可以让系统以更少的数据学习。当“两端”(输入端和输出端)都有很多标注数据时,端到端学习系统将表现良好。在该样例中,我们需要一个<音频,转录>对的大数据集。当该类型数据不可用时,请谨慎使用端到端学习方式处理。

        更为一般的说,如果有很多数据可用于训练一个流水线(例如汽车检测器或行人检测器)的“中间模块”,那么你可以考虑使用有多个阶段的流水线。这种架构可能更优,因为你可以使用所有可用的数据来训练中间模块。

选择流水线组件:任务简单

       应该尝试选择易于构建和学习的流水线组件。

      如果你能够执行复杂的任务,并将其分解成简单的子任务,那么通过明确地编写子任务的步骤,你正在为算法提供先验知识,以帮助其更有效的学习任务。

       直到更多端到端数据可用之前,我相信非端到端方法对自动驾驶更有希望:其架构更好匹配数据的可用性。

直接学习丰富的输出

      当你拥有正确的已标注(输入, 输出)对时,即使输出是比单个数字更丰富的句子、图片、音频或其他输出,你有时也可以学习端到端。

猜你喜欢

转载自blog.csdn.net/duyue3052/article/details/81076062