结构化你的机器学习工程改变了深度学习的错误
比如你分割数据的方法,分割成train,development(dev)或叫valid,test,所以最好的实践方法是什么?了解更多端对端的深度学习,进而了解到你是否需要使用它,这节课将分享了解到的所有热门领域的建立并改良很多深度学习问题
1 为什么是ML策略
如何构建你的机器学习项目也就是说机器学习的策略。我希望通过这门课程你们能够学到如何更快速高效地优化你的机器学习系统。那么,什么是机器学习策略呢
假设你正在调试你的猫分类器,经过一段时间的调整,你的系统达到了90%准确率,但对你的应用程序来说还不够好。
你可能有很多想法去改善你的系统,比如,你可能想我们去收集更多的训练数据吧。或者你会说,可能你的训练集的多样性还不够,你应该收集更多不同姿势的猫咪图片,或者更多样化的反例集。或者你想再用梯度下降训练算法,训练久一点。或者你想尝试用一个完全不同的优化算法,比如Adam优化算法。或者尝试使用规模更大或者更小的神经网络。或者你想试试dropout或者 L2正则化。或者你想修改网络的架构,比如修改激活函数,改变隐藏单元的数目之类的方法。
当你尝试优化一个深度学习系统时,你通常可以有很多想法可以去试,问题在于,如果你做出了错误的选择,你完全有可能白费6个月的时间,往错误的方向前进,在6个月之后才意识到这方法根本不管用。比如,我见过一些团队花了6个月时间收集更多数据,却在6个月之后发现,这些数据几乎没有改善他们系统的性能。所以,假设你的项目没有6个月的时间可以浪费,如果有快速有效的方法能够判断哪些想法是靠谱的,或者甚至提出新的想法,判断哪些是值得一试的想法,哪些是可以放心舍弃的。
我希望在这门课程中,可以教给你们一些策略,一些分析机器学习问题的方法,可以指引你们朝着最有希望的方向前进。这门课中,我会和你们分享我在搭建和部署大量深度学习产品时学到的经验和教训,我想这些内容是这门课程独有的。比如说,很多大学深度学习课程很少提到这些策略。事实上,机器学习策略在深度学习的时代也在变化,因为现在对于深度学习算法来说能够做到的事情,比上一代机器学习算法大不一样。我希望这些策略能帮助你们提高效率,让你们的深度学习系统更快投入实用。
2 正交化
搭建建立机器学习系统的挑战之一是,你可以尝试和改变的东西太多太多了。包括,比如说,有那么多的超参数可以调。我留意到,那些效率很高的机器学习专家有个特点,他们思维清晰,对于要调整什么来达到某个效果,非常清楚,这个步骤我们称之为正交化,让我告诉你是什么意思吧
这是一张老式电视图片,有很多旋钮可以用来调整图像的各种性质,所以对于这些旧式电视,可能有一个旋钮用来调图像垂直方向的高度,另外有一个旋钮用来调图像宽度,也许还有一个旋钮用来调梯形角度,还有一个旋钮用来调整图像左右偏移,还有一个旋钮用来调图像旋转角度之类的。电视设计师花了大量时间设计电路,那时通常都是模拟电路来确保每个旋钮都有相对独立的功能。
相比之下,想象一下,如果你有一个旋钮调的是0.1 x 表示图像高度 + 0.3 x 表示图像宽度 − 1.7 x 表示梯形角度 + 0.8 x 表示图像在水平轴上的坐标之类的。如果你调整这一个旋钮,那么图像的高度、宽度、梯形角度、平移位置全部都会同时改变,如果你有这样的旋钮,那几乎不可能把电视调好,让图像显示在区域正中。
另一个正交化例子,你想想学车的时候,一辆车有三个主要控制,第一是方向盘,方向盘决定你往左右偏多少,还有油门和刹车。就是这三个控制,其中一个控制方向,另外两个控制你的速度,这样就比较容易解读。知道不同控制的不同动作会对车子运动有什么影响
想象一下,如果有人这么造车,造了个游戏手柄,手柄的一个轴控制的是0.3× 转向角-0.8×速度,然后还有一个轴控制的是2× 转向角+0.9× 车速,理论上来说,通过调整这两个旋钮你是可以将车子调整到你希望得到的角度和速度,但这样比单独控制转向角度,分开独立的速度控制要难得多。
所以正交化的概念是指,你可以想出一个维度,这个维度你想做的是控制转向角,还有另一个维度来控制你的速度,那么你就需要一个旋钮尽量只控制转向角,另一个旋钮,在这个开车的例子里其实是油门和刹车控制了你的速度。但如果你有一个控制旋钮将两者混在一起,比如说这样一个控制装置同时影响你的转向角和速度,同时改变了两个性质,那么就很难令你的车子以想要的速度和角度前进。然而正交化之后,正交意味着互成90度。设计出正交化的控制装置,最理想的情况是和你实际想控制的性质一致,这样你调整参数时就容易得多。可以单独调整转向角,还有你的油门和刹车,令车子以你想要的方式运动。
那么这与机器学习有什么关系呢,要弄好一个监督学习系统,你通常需要调你的系统的旋钮
确保四件事情,首先,你通常必须确保至少系统在训练集上得到的结果不错,所以训练集上的表现必须通过某种评估,达到能接受的程度,对于某些应用,这可能意味着达到人类水平的表现,但这取决于你的应用。但是,在训练集上表现不错之后,你就希望系统也能在开发集上有好的表现,然后你希望系统在测试集上也有好的表现。在最后,你希望系统在测试集上系统的成本函数在实际使用中表现令人满意,比如说,你希望这些猫图片应用的用户满意。
我们回到电视调节的例子,如果你的电视图像太宽或太窄,你想要一个旋钮去调整,你可不想要仔细调节五个不同的旋钮,它们也会影响别的图像性质,你只需要一个旋钮去改变电视图像的宽度。
所以类似地,如果你的算法在成本函数上不能很好地拟合训练集,你想要一个旋钮让它很好地拟合训练集,所以你用来调试的旋钮是你可能可以训练更大的网络,或者可以切换到更好的优化算法,比如Adam优化算法,等等
如果你的算法在开发集上做的不好,它在训练集上做得很好,但开发集不行,然后你有一组正则化的旋钮可以调节,尝试让系统满足第二个条件。类比到电视,就是现在你调好了电视的宽度,如果图像的高度不太对,你就需要一个不同的旋钮来调节电视图像的高度,然后你希望这个旋钮尽量不会影响到电视的宽度。增大训练集可以是另一个可用的旋钮,它可以帮助你的学习算法更好地归纳开发集的规律
如果它不符合第三个标准呢?如果系统在开发集上做的很好,但测试集上做得不好呢?如果是这样,那么你需要调的旋钮,可能是更大的开发集。因为如果它在开发集上做的不错,但测试集不行这可能意味着你对开发集过拟合了,你需要往回退一步,使用更大的开发集。
最后,如果它在测试集上做得很好,但无法给你的猫图片应用用户提供良好的体验,这意味着你需要回去,改变开发集或成本函数。因为如果根据某个成本函数,系统在测试集上做的很好,但它无法反映你的算法在现实世界中的表现,这意味着要么你的开发集分布设置不正确,要么你的成本函数测量的指标不对。
所以如果现在你无法理解全部细节,别担心,但我希望你们对这种正交化过程有个概念。你要非常清楚,到底是四个问题中的哪一个,知道你可以调节哪些不同的东西尝试解决那个问题。
在机器学习中,如果你可以观察你的系统,然后说这一部分是错的,它在训练集上做的不好、在开发集上做的不好、它在测试集上做的不好,或者它在测试集上做的不错,但在现实世界中不好,这就很好。必须弄清楚到底是什么地方出问题了,然后我们刚好有对应的旋钮,或者一组对应的旋钮,刚好可以解决那个问题,那个限制了机器学习系统性能的问题。
这就是我们这周和下周要讲到的,如何诊断出系统性能瓶颈到底在哪。还有找到你可以用的一组特定的旋钮来调整你的系统,来改善它特定方面的性能,我们开始详细讲讲这个过程吧。
3 单一数字评估指标
无论你是调整超参数,或者是尝试不同的学习算法,或者在搭建机器学习系统时尝试不同手段,你会发现,如果你有一个单实数评估指标,你的进展会快得多,它可以快速告诉你,新尝试的手段比之前的手段好还是差。所以当团队开始进行机器学习项目时,我经常推荐他们为问题设置一个单实数评估指标。
应用机器学习是一个非常经验性的过程,我们通常有一个想法,编程序,跑实验,看看效果如何,然后使用这些实验结果来改善你的想法,然后继续走这个循环,不断改进你的算法。
比如说对于你的猫分类器,之前你搭建了某个分类器A ,通过改变超参数,还有改变训练集等手段,你现在训练出来了一个新的分类器B,所以评估你的分类器的一个合理方式是观察它的查准率(precision)和查全率(recall)。
简而言之,查准率的定义是在你的分类器标记为猫的例子中,有多少真的是猫。所以如果分类器 A A A 有95%的查准率,这意味着你的分类器说这图有猫的时候,有95%的机会真的是猫。查全率就是,对于所有真猫的图片,你的分类器正确识别出了多少百分比。实际为猫的图片中,有多少被系统识别出来?
如果分类器 A 在查全率上表现更好,分类器 B 在查准率上表现更好,你就无法判断哪个分类器更好。如果你尝试了很多不同想法,很多不同的超参数,你希望能够快速试验不仅仅是两个分类器,也许是十几个分类器,快速选出“最好的”那个,这样你可以从那里出发再迭代。如果有两个评估指标,就很难去快速地二中选一或者十中选一,所以我并不推荐使用两个评估指标,查准率和查全率来选择一个分类器。你只需要找到一个新的评估指标,能够结合查准率和查全率。
在机器学习文献中,结合查准率和查全率的标准方法是所谓的 F 1 F_1 F1分数, F 1 F_1 F1 分数的细节并不重要。但非正式的,你可以认为这是查准率P和查全率 R 的平均值。正式来看, F 1 F_1 F1 分数的定义是这个公式
在数学中,这个函数叫做查准率P 和查全率 R 的调和平均数。但非正式来说,你可以将它看成是某种查准率和查全率的平均值,只不过你算的不是直接的算术平均,而是用这个公式定义的调和平均。这个指标在权衡查准率和查全率时有一些优势。
但在这个例子中,你可以马上看出,分类器 A 的 F 1 F_1 F1 分数更高,你可以快速选出分类器 A ,淘汰分类器B 。
我发现很多机器学习团队就是这样,有一个定义明确的开发集用来测量查准率和查全率,再加上这样一个单一数值评估指标,有时我叫单实数评估指标,能让你快速判断分类器 A 或者分类器B 更好。所以有这样一个开发集,加上单实数评估指标,你的迭代速度肯定会很快,它可以加速改进您的机器学习算法的迭代过程。
另一个例子
假设你在开发一个猫应用来服务四个地理大区的爱猫人士,美国、中国、印度还有世界其他地区。我们假设你的两个分类器在来自四个地理大区的数据中得到了不同的错误率,比如算法 A 在美国用户上传的图片中达到了3%错误率,等等。
所以跟踪一下,你的分类器在不同市场和地理大区中的表现应该是有用的,但是通过跟踪四个数字,很难扫一眼这些数值就快速判断算法 A 或算法 B 哪个更好。如果你测试很多不同的分类器,那么看着那么多数字,然后快速选一个最优是很难的。所以在这个例子中,我建议,除了跟踪分类器在四个不同的地理大区的表现,也要算算平均值。假设平均表现是一个合理的单实数评估指标,通过计算平均值,你就可以快速判断
看起来算法 C的平均错误率最低,然后你可以继续用那个算法。你必须选择一个算法,然后不断迭代,所以你的机器学习的工作流程往往是你有一个想法,你尝试实现它,看看这个想法好不好
4 满足和优化指标
要把你顾及到的所有事情组合成单实数评估指标有时并不容易,在那些情况里,我发现有时候设立满足和优化指标是很重要的,让我告诉你是什么意思吧。
假设你已经决定你很看重猫分类器的分类准确度,但除了准确度之外,我们还需要考虑运行时间
你可以这么做,将准确度和运行时间组合成一个整体评估指标。所以成本,比如说,总体成本是 c o s t = a c c u r a c y − 0.5 ∗ r u n n i n g T i m e cost=accuracy-0.5*runningTime cost=accuracy−0.5∗runningTime ,这种组合方式可能太刻意,只用这样的公式来组合准确度和运行时间,两个数值的线性加权求和。
你还可以做其他事情,就是你可能选择一个分类器,能够最大限度提高准确度,但必须满足运行时间要求,就是对图像进行分类所需的时间必须小于等于100毫秒。所以在这种情况下,我们就说准确度是一个优化指标,因为你想要准确度最大化,你想做的尽可能准确,但是运行时间就是我们所说的满足指标,意思是它必须足够好,它只需要小于100毫秒,达到之后,你不在乎这指标有多好,或者至少你不会那么在乎。所以这是一个相当合理的权衡方式,或者说将准确度和运行时间结合起来的方式。实际情况可能是,只要运行时间少于100毫秒,你的用户就不会在乎运行时间是100毫秒还是50毫秒,甚至更快。
通过定义优化和满足指标,就可以给你提供一个明确的方式,去选择“最好的”分类器。在这种情况下分类器B最好,因为在所有的运行时间都小于100毫秒的分类器中,它的准确度最好。
所以更一般地说,如果你要考虑 N 个指标,有时候选择其中一个指标做为优化指标是合理的。所以你想尽量优化那个指标,然后剩下N−1 个指标都是满足指标,意味着只要它们达到一定阈值,例如运行时间快于100毫秒,但只要达到一定的阈值,你不在乎它超过那个门槛之后的表现,但它们必须达到这个门槛。
这里是另一个例子,假设你正在构建一个系统来检测唤醒语,也叫触发词,这指的是语音控制设备。对于苹果设备,你会说“Hey Siri”
所以你可能会在乎触发字检测系统的准确性,所以当有人说出其中一个触发词时,有多大概率可以唤醒你的设备。
你可能也需要顾及false positive(假阳性)的数量,就是没有人在说这个触发词时,它被随机唤醒的概率有多大?所以这种情况下,组合这两种评估指标的合理方式可能是最大化精确度。所以当某人说出唤醒词时,你的设备被唤醒的概率最大化,然后必须满足24小时内最多只能有1次假阳性,对吧?所以你的设备平均每天只会没有人真的在说话时随机唤醒一次。所以在这种情况下,准确度是优化指标,然后每24小时发生一次假阳性是满足指标,你只要每24小时最多有一次假阳性就满足了。
总结一下,如果你需要顾及多个指标,比如说,有一个优化指标,你想尽可能优化的,然后还有一个或多个满足指标,需要满足的,需要达到一定的门槛。
5 训练-开发-测试集的划分
开发集(dev)有时候也叫验证集(valid),机器学习中的工作流程是,你尝试很多思路,用训练集训练不同的模型,然后使用开发集来评估不同的思路,然后选择一个,然后不断迭代去改善开发集的性能,直到最后你可以得到一个令你满意的成本,然后你再用测试集去评估。
举个例子,你要开发一个猫分类器,然后你在这些区域里运营,美国、英国、其他欧洲国家,南美洲、印度、中国,其他亚洲国家和澳大利亚,那么你应该如何设立开发集和测试集呢?
其中一种做法是,你可以选择其中4个区域,我打算使用前四个,但也可以是随机选的区域,然后说,来自这四个区域的数据构成开发集。然后其他四个区域,我打算用后四个,也可以随机选择4个,这些数据构成测试集。
事实证明,这个想法非常糟糕,因为这个例子中,你的开发集和测试集来自不同的分布。我建议你们不要这样,而是让你的开发集和测试集来自同一分布。我的意思是这样,你们要记住,我想就是设立你的开发集加上一个单实数评估指标,这就是像是定下目标,然后告诉你的团队,那就是你要瞄准的靶心,因为你一旦建立了这样的开发集和指标,团队就可以快速迭代,尝试不同的想法,跑实验,可以很快地使用开发集和指标去评估不同分类器,然后尝试选出最好的那个。所以,机器学习团队一般都很擅长使用不同方法去逼近目标,然后不断迭代,不断逼近靶心。所以,针对开发集上的指标优化。
左侧设立开发集和测试集时存在一个问题,你的团队可能会花上几个月时间在开发集上迭代优化,结果发现,当你们最终在测试集上测试系统时,下面这四个地区的数据(测试集数据)和开发集里的数据可能差异很大,所以你可能会收获"意外惊喜",并发现,花了那么多个月的时间去针对开发集优化,在测试集上的表现却不佳。所以,如果你的开发集和测试集来自不同的分布,就像你设了一个目标,让你的团队花几个月尝试逼近靶心,结果在几个月工作之后发现,你说“等等”,测试的时候,“我要把目标移到这里”,然后团队可能会说"好吧,为什么你让我们花那么多个月的时间去逼近那个靶心,然后突然间你可以把靶心移到不同的位置?"。
所以,为了避免这种情况,我建议的是你将所有数据随机洗牌,放入开发集和测试集,所以开发集和测试集都有来自八个地区的数据,并且开发集和测试集都来自同一分布,这分布就是你的所有数据混在一起。
这里有另一个例子,这是个真实的故事,但有一些细节变了。所以我知道有一个机器学习团队,花了好几个月在开发集上优化,开发集里面有中等收入邮政编码的贷款审批数据。那么具体的机器学习问题是,输入 x 为贷款申请,你是否可以预测输出 y , y 是他们有没有还贷能力?所以这系统能帮助银行判断是否批准贷款。所以开发集来自贷款申请,这些贷款申请来自中等收入邮政编码,zip code就是美国的邮政编码。但是在这上面训练了几个月之后,团队突然决定要在,低收入邮政编码数据上测试一下。当然了,这个分布数据里面中等收入和低收入邮政编码数据是很不一样的,而且他们花了大量时间针对前面那组数据优化分类器,导致系统在后面那组数据中效果很差。所以这个特定团队实际上浪费了3个月的时间,不得不退回去重新做很多工作。
这里实际发生的是事情是这个团队画三个月瞄准一个目标,三个月后经理突然问“你们试试瞄准那个目标如何”,这新目标位置完全不同,所以这件事对于这个团队来说非常崩溃,所以我建议你们在设置开发集和测试集时,
要选择这样的开发集和测试集,能够反应你未来会得到的数据,认为很重要的数据,必须得到好的结果的数据
特别是开发集和测试集可能来自同一个分布,所以不管你未来得到什么样的数据一旦你的算法效果不错,要尝试收集类似的数据而且不管那些数据是什么,都要随机分配到开发集和测试集上,因为这样你才能瞄准想要的目标,让你的团队高效迭代来逼近同一个目标。
我们还没提如何设立训练集,我们会在之后谈谈如何设立训练集,但这节的重点在于设立开发集以及评估指标,它定义了你要瞄准的目标。我们希望通过在同一分布中设立开发集和测试集,你就可以瞄准你所希望的机器学习团队瞄准的目标。而设立训练集的方式则会影响你逼近那个目标有多快,但我们可以在另一个讲座里提到。我知道有一些机器学习团队,他们如果能遵循这个方针,就可以省下几个月的工作,所以我希望这些方针也能帮到你们。
6 训练集开发集测试集的大小
在上一节中你们知道了你的开发集和测试集为什么必须来自同一分布,但它们规模应该多大?在深度学习时代,设立开发集和测试集的方针也在变化,我们来看看一些最佳做法。
在以前的机器学习任务中我们的数据集不是特别大,采用下面这种划分方式是可行的(7:3 或6:2:2)
但在现代机器学习中,我们更习惯操作规模大得多的数据集,比如说你有1百万个训练样本,下面这种划分显得更为合适(98:1:1)
因为深度学习算法对数据的胃口很大,我们可以看到那些有海量数据集的问题,有更高比例的数据划分到训练集里,那么测试集呢?
要记住,测试集的目的是完成系统开发之后,测试集可以帮你评估投产系统的性能。方针就是,令你的测试集足够大,能够以高置信度评估系统整体性能。所以除非你需要对最终投产系统有一个很精确的指标,一般来说测试集不需要上百万个例子。对于你的应用程序,也许你想,有10,000个例子就能给你足够的置信度来给出性能指标了,也许100,000个之类的可能就够了,这数目可能远远小于比如说整体数据集的30%,取决于你有多少数据。
对于某些应用,你也许不需要对系统性能有置信度很高的评估,也许你只需要训练集和开发集。我认为,不单独分出一个测试集也是可以的。事实上,有时在实践中有些人会只分成训练集和测试集,他们实际上在测试集上迭代,所以这里没有测试集,他们有的是训练集和开发集,但没有测试集。如果你真的在调试这个集,这个开发集或这个测试集,这最好称为开发集。
你只要有数据去训练,有数据去调试就够了。你打算不管测试集,直接部署最终系统,所以不用太担心它的实际表现,我觉得这也是很好的,就将它们称为训练集、开发集就好。然后说清楚你没有测试集,这是不是有点不正常?我绝对不建议在搭建系统时省略测试集,因为有个单独的测试集比较令我安心。因为你可以使用这组不带偏差的数据来测量系统的性能。但如果你的开发集非常大,这样你就不会对开发集过拟合得太厉害,这种情况,只有训练集和测试集也不是完全不合理的。不过我一般不建议这么做。
总结一下,在大数据时代旧的经验规则,这个70/30不再适用了。现在流行的是把大量数据分到训练集,然后少量数据分到开发集和测试集,特别是当你有一个非常大的数据集时。以前的经验法则其实是为了确保开发集足够大,能够达到它的目的,就是帮你评估不同的想法,然后选出 A 还是 B 更好。测试集的目的是评估你最终的成本偏差,你只需要设立足够大的测试集,可以用来这么评估就行了,可能只需要远远小于总体数据量的30%。
所以我希望本节能给你们一点指导和建议,让你们知道如何在深度学习时代设立开发和测试集。接下来,有时候在研究机器学习的问题途中,你可能需要更改评估指标,或者改动你的开发集和测试集,我们会讲什么时候需要这样做。
7 什么时候改变开发和测试集和指标
你已经学过如何设置开发集和评估指标,就像是把目标定在某个位置,让你的团队瞄准。但有时候在项目进行途中,你可能意识到,目标的位置放错了。这种情况下,你应该移动你的目标。
算法 A 由于某些原因,把很多色情图像分类成猫了。如果你部署算法 A ,那么用户就会看到更多猫图,因为它识别猫的错误率只有3%,但它同时也会给用户推送一些色情图像,这是你的公司完全不能接受的,你的用户也完全不能接受。相比之下,算法 B 有5%的错误率,这样分类器就得到较少的图像,但它不会推送色情图像。所以从你们公司的角度来看,以及从用户接受的角度来看,算法 B 实际上是一个更好的算法,因为它不让任何色情图像通过。
那么在这个例子中,发生的事情就是,算法A在评估指标上做得更好,它的错误率达到3%,但实际上是个更糟糕的算法。在这种情况下,评估指标加上开发集它们都倾向于选择算法 A ,因为它们会说,看算法A的错误率较低,这是你们自己定下来的指标评估出来的。但你和你的用户更倾向于使用算法 B ,因为它不会将色情图像分类为猫。所以当这种情况发生时,当你的评估指标无法正确衡量算法之间的优劣排序时,在这种情况下,原来的指标错误地预测算法A是更好的算法这就发出了信号,你应该改变评估指标了,或者要改变开发集或测试集。在这种情况下,你用的分类错误率指标可以写成这样:
这个评估指标的问题在于,它对色情图片和非色情图片一视同仁,但你其实真的希望你的分类器不会错误标记色情图像。比如说把一张色情图片分类为猫,然后推送给不知情的用户,他们看到色情图片会非常不满。
其中一种解决方法就是加一个权重 w ( i ) w^{(i)} w(i)
其中如果图片 x ( i ) x^{(i)} x(i)不是色情图片,则 w ( i ) = 1 w^{(i)}=1 w(i)=1 。如果 x ( i ) x^{(i)} x(i)是色情图片, w ( i ) w^{(i)} w(i)可能就是10甚至100,这样你赋予了色情图片更大的权重,让算法将色情图分类为猫图时,错误率这个项快速变大。这个例子里,你把色情图片分类成猫这一错误的惩罚权重加大10倍。
如果你希望得到归一化常数,在技术上,就是 w ( i ) w^{(i)} w(i) 对所有 i 求和,这样错误率仍然在0和1之间,即:
加权的细节并不重要,实际上要使用这种加权,你必须自己过一遍开发集和测试集,在开发集和测试集里,自己把色情图片标记出来,这样你才能使用这个加权函数。
但粗略的结论是,如果你的评估指标无法正确评估好算法的排名,那么就需要花时间定义一个新的评估指标。上面是定义评估指标的其中一种可能方式。评估指标的意义在于,准确告诉你已知两个分类器,哪一个更适合你的应用。就节的内容而言,我们不需要太注重新错误率指标是怎么定义的,关键在于,如果你对旧的错误率指标不满意,那就不要一直沿用你不满意的错误率指标,而应该尝试定义一个新的指标,能够更加符合你的偏好,定义出实际更适合的算法。
处理机器学习问题时,应该把它切分成独立的步骤。一步是弄清楚如何定义一个指标来衡量你想做的事情的表现,然后我们可以分开考虑如何改善系统在这个指标上的表现
关键在于正交化的思路。
这是另一个指标和开发集测试集出问题的例子
假设你的两个猫分类器 A 和 B ,分别有用开发集评估得到3%的错误率和5%的错误率。或者甚至用在网上下载的图片构成的测试集上,这些是高质量,取景框很专业的图像。但也许你在部署算法产品时,你发现算法 B 看起来表现更好,即使它在开发集上表现不错,你发现你一直在用从网上下载的高质量图片训练,但当你部署到手机应用时,算法作用到用户上传的图片时,那些图片取景不专业,没有把猫完整拍下来,或者猫的表情很古怪,也许图像很模糊,当你实际测试算法时,你发现算法 B 表现其实更好。
问题在于,你做评估用的是很漂亮的高分辨率的开发集和测试集,图片取景很专业。但你的用户真正关心的是,他们上传的图片能不能被正确识别。那些图片可能是没那么专业的照片,有点模糊,取景很业余。
所以方针是,如果你在指标上表现很好,在当前开发集或者开发集和测试集分布中表现很好,但你的实际应用程序,你真正关注的地方表现不好,那么就需要修改指标或者你的开发测试集。换句话说,如果你发现你的开发测试集都是这些高质量图像,但在开发测试集上做的评估无法预测你的应用实际的表现。因为你的应用处理的是低质量图像,那么就应该改变你的开发测试集,让你的数据更能反映你实际需要处理好的数据。
但总体方针就是,如果你当前的指标和当前用来评估的数据和你真正关心必须做好的事情关系不大,那就应该更改你的指标或者你的开发测试集,让它们能更够好地反映你的算法需要处理好的数据。
有一个评估指标和开发集让你可以更快做出决策,判断算法 A 还是算法B 更优,这真的可以加速你和你的团队迭代的速度。所以我的建议是,即使你无法定义出一个很完美的评估指标和开发集,你直接快速设立出来,然后使用它们来驱动你们团队的迭代速度。如果在这之后,你发现选的不好,你有更好的想法,那么完全可以马上改。
8 为什么是人的表现
在过去的几年里,更多的机器学习团队一直在讨论如何比较机器学习系统和人类的表现,为什么呢?
我认为有两个主要原因,首先是因为深度学习系统的进步,机器学习算法突然变得更好了。在许多机器学习的应用领域已经开始见到算法已经可以威胁到人类的表现了。其次,事实证明,当你试图让机器做人类能做的事情时,可以精心设计机器学习系统的工作流程,让工作流程效率更高,所以在这些场合,比较人类和机器是很自然的,或者你要让机器模仿人类的行为。我们来看几个这样的例子
我看到很多机器学习任务中,当你在一个问题上付出了很多时间之后,所以x 轴是时间,这可能是很多个月甚至是很多年。在这些时间里,一些团队或一些研究小组正在研究一个问题,当你开始往人类水平努力时,进展是很快的。但是过了一段时间,当这个算法表现比人类更好时,那么进展和精确度的提升就变得更慢了。也许它还会越来越好,但是在超越人类水平之后,它还可以变得更好,但性能增速,准确度上升的速度这个斜率,会变得越来越平缓,我们都希望能达到理论最佳性能水平。随着时间的推移,当您继续训练算法时,可能模型越来越大,数据越来越多,但是性能无法超过某个理论上限,这就是所谓的贝叶斯最优错误率(Bayes optimal error)。所以贝叶斯最优错误率一般认为是理论上可能达到的最优错误率,就是说没有任何办法设计出一个 x 到 y 的函数,让它能够超过一定的准确度。
例如,对于语音识别来说,如果x 是音频片段,有些音频就是这么嘈杂,基本不可能知道说的是什么,所以完美的准确率可能不是100%。或者对于猫图识别来说,也许一些图像非常模糊,不管是人类还是机器,都无法判断该图片中是否有猫。所以,完美的准确度可能不是100%。
Bayes optimal error 或Bayesian optimal error,Bayes error就是从x 到 y 映射的理论最优函数,永远不会被超越。所以你们应该不会感到意外,这紫色线,无论你在一个问题上工作多少年,你永远不会超越贝叶斯错误率,贝叶斯最佳错误率。
事实证明,机器学习的进展往往相当快,直到你超越人类的表现之前一直很快,当你超越人类的表现时,有时进展会变慢。我认为有两个原因,为什么当你超越人类的表现时,进展会慢下来。一个原因是人类水平在很多任务中离贝叶斯最优错误率已经不远了,人们非常擅长看图像,分辨里面有没有猫或者听写音频。所以,当你超越人类的表现之后也许没有太多的空间继续改善了。但第二个原因是,只要你的表现比人类的表现更差,那么实际上可以使用某些工具来提高性能。一旦你超越了人类的表现,这些工具就没那么好用了。
对于人类相当擅长的任务,包括看图识别事物,听写音频,或阅读语言,人类一般很擅长处理这些自然数据。对于人类擅长的任务,只要你的机器学习算法比人类差,你就可以从让人帮你标记数据,你可以让人帮忙或者花钱请人帮你标记例子,这样你就有更多的数据可以喂给学习算法。下周我们会讨论,人工错误率分析,但只要人类的表现比任何其他算法都要好,你就可以让人类看看你算法处理的例子,知道错误出在哪里,并尝试了解为什么人能做对,算法做错。下周我们会看到,这样做有助于提高算法的性能。你也可以更好地分析偏差和方差,我们稍后会谈一谈。但是只要你的算法仍然比人类糟糕,你就有这些重要策略可以改善算法。而一旦你的算法做得比人类好,这三种策略就很难利用了。所以这可能是另一个和人类表现比较的好处,特别是在人类做得很好的任务上。
为什么机器学习算法往往很擅长模仿人类能做的事情,然后赶上甚至超越人类的表现。特别是,即使你知道偏差是多少,方差是多少。知道人类在特定任务上能做多好可以帮助你更好地了解你应该重点尝试减少偏差,还是减少方差,我想在下一节中给你一个例子。
9 可避免偏差
我们经常使用猫分类器来做例子,比如人类具有近乎完美的准确度,所以人类水平的错误是1%。在这种情况下,如果您的学习算法达到8%的训练错误率和10%的开发错误率,那么你也许想在训练集上得到更好的结果。所以事实上,你的算法在训练集上的表现和人类水平的表现有很大差距的话,说明你的算法对训练集的拟合并不好。所以从减少偏差和方差的工具这个角度看,在这种情况下,我会把重点放在减少偏差上。你需要做的是,比如说训练更大的神经网络,或者跑久一点梯度下降,就试试能不能在训练集上做得更好。
但现在我们看看同样的训练错误率和开发错误率,假设人类的表现不是1%,我们就把它抄写过来。但你知道,在不同的应用或者说用在不同的数据集上,假设人类水平错误实际上是7.5%,也许你的数据集中的图像非常模糊,即使人类都无法判断这张照片中有没有猫。这个例子可能稍微更复杂一些,因为人类其实很擅长看照片,分辨出照片里有没有猫。但就为了举这个例子,比如说你的数据集中的图像非常模糊,分辨率很低,即使人类错误率也达到7.5%。在这种情况下,即使你的训练错误率和开发错误率和其他例子里一样,你就知道,也许你的系统在训练集上的表现还好,它只是比人类的表现差一点点。在第二个例子中,你可能希望专注减少这个分量,减少学习算法的方差,也许你可以试试正则化,让你的开发错误率更接近你的训练错误率。
所以在之前的课程关于偏差和方差的讨论中,我们主要假设有一些任务的贝叶斯错误率几乎为0。所以要解释这里发生的事情,看看这个猫分类器,用人类水平的错误率估计或代替贝叶斯错误率或贝叶斯最优错误率,对于计算机视觉任务而言,这样替代相当合理,因为人类实际上是非常擅长计算机视觉任务的,所以人类能做到的水平和贝叶斯错误率相差不远。根据定义,人类水平错误率比贝叶斯错误率高一点,因为贝叶斯错误率是理论上限,但人类水平错误率离贝叶斯错误率不会太远。所以这里比较意外的是取决于人类水平错误率有多少,或者这真的就很接近贝叶斯错误率,所以我们假设它就是,但取决于我们认为什么样的水平是可以实现的。
这两种情况下,具有同样的训练错误率和开发错误率,我们决定专注于减少偏差的策略或者减少方差的策略。那么左边的例子发生了什么? 8%的训练错误率真的很高,你认为你可以把它降到1%,那么减少偏差的手段可能有效。而在右边的例子中,如果你认为贝叶斯错误率是7.5%,这里我们使用人类水平错误率来替代贝叶斯错误率,但是你认为贝叶斯错误率接近7.5%,你就知道没有太多改善的空间了,不能继续减少你的训练错误率了,你也不会希望它比7.5%好得多,因为这种目标只能通过可能需要提供更进一步的训练。而这边train error和dev error有更多的改进空间,可以将这个2%的差距缩小一点,使用减少方差的手段应该可行,比如正则化,或者收集更多的训练数据。
所以要给这些概念命名一下,这不是广泛使用的术语,但我觉得这么说思考起来比较流畅。就是把这个差值,贝叶斯错误率或者对贝叶斯错误率的估计和训练错误率之间的差值称为可避免偏差,你可能希望一直提高训练集表现,直到你接近贝叶斯错误率,但实际上你也不希望做到比贝叶斯错误率更好,这理论上是不可能超过贝叶斯错误率的,除非过拟合。而这个训练错误率和开发错误率之前的差值,就大概说明你的算法在方差问题上还有多少改善空间。
可避免偏差这个词说明了有一些别的偏差,或者错误率有个无法超越的最低水平,那就是说如果贝叶斯错误率是7.5%。你实际上并不想得到低于该级别的错误率,所以你不会说你的训练错误率是8%,然后8%就衡量了例子中的偏差大小。你应该说,可避免偏差可能在0.5%左右,或者0.5%是可避免偏差的指标。而这个2%是方差的指标,所以要减少这个2%比减少这个0.5%空间要大得多。而在左边的例子中,这7%衡量了可避免偏差大小,而2%衡量了方差大小。所以在左边这个例子里,专注减少可避免偏差可能潜力更大。
所以在这个例子中,当你理解人类水平错误率,理解你对贝叶斯错误率的估计,你就可以在不同的场景中专注于不同的策略,使用避免偏差策略还是避免方差策略。在训练时如何考虑人类水平表现来决定工作着力点,具体怎么做还有更多微妙的细节,所以在下节中,我们会深入了解人类水平表现的真正意义。
10 理解人的表现
人类水平表现这个词在论文里经常随意使用,但我现在告诉你这个词更准确的定义,特别是使用人类水平表现这个词的定义,可以帮助你们推动机器学习项目的进展。还记得上个视频中,我们用人类水平错误率用来估计贝叶斯误差,那就是理论最低的错误率,任何函数不管是现在还是将来,能够到达的最低值。我们先记住这点,然后看看医学图像分类例子。
假设你要观察这样的放射科图像,然后作出分类诊断,假设一个普通的人类,未经训练的人类,在此任务上达到3%的错误率。普通的医生,也许是普通的放射科医生,能达到1%的错误率。经验丰富的医生做得更好,错误率为0.7%。还有一队经验丰富的医生,就是说如果你有一个经验丰富的医生团队,让他们都看看这个图像,然后讨论并辩论,他们达成共识的意见达到0.5%的错误率。所以我想问你的问题是,你应该如何界定人类水平错误率?人类水平错误率3%,1%, 0.7%还是0.5%?
就是如果你想要替代或估计贝叶斯错误率,那么一队经验丰富的医生讨论和辩论之后,可以达到0.5%的错误率。我们知道贝叶斯错误率小于等于0.5%,因为有些系统,这些医生团队可以达到0.5%的错误率。所以根据定义,最优错误率必须在0.5%以下。我们不知道多少更好,也许有一个更大的团队,更有经验的医生能做得更好,所以也许比0.5%好一点。但是我们知道最优错误率不能高于0.5%,那么在这个背景下,我就可以用0.5%估计贝叶斯错误率。所以我将人类水平定义为0.5%
现在,为了发表研究论文或者部署系统,也许人类水平错误率的定义可以不一样,你可以使用1%,只要你超越了一个普通医生的表现,如果能达到这种水平,那系统已经达到实用了。也许超过一名放射科医生,一名医生的表现,意味着系统在一些情况下可以有部署价值了。
本节的要点是,在定义人类水平错误率时,要弄清楚你的目标所在,如果要表明你可以超越单个人类,那么就有理由在某些场合部署你的系统,也许这个定义是合适的(1%)。但是如果您的目标是替代贝叶斯错误率,那么这个定义(human=0.5%)才合适
下面看第一个例子
在这个第一个例子中,无论你做出哪些选择,可避免偏差大概是4%,如果你取1%就是4%,如果你取0.5%就是4.5%,而这个差距(训练误差与开发误差之间的差值)是1%。所以在这个例子中,我得说,不管你怎么定义人类水平错误率,使用单个普通医生的错误率定义,还是单个经验丰富医生的错误率定义或经验丰富的医生团队的错误率定义,这是4%还是4.5%,这明显比都比方差问题更大。所以在这种情况下,你应该专注于减少偏差的技术,例如培训更大的网络。
来看看第二个例子(右侧)
比如说你的训练错误率是1%,开发错误率是5%,这其实也不怎么重要,这种问题更像学术界讨论的,人类水平表现是1%或0.7%还是0.5%。因为不管你使用哪一个定义,你测量可避免偏差的方法是,如果用那个值,就是0%到0.5%之前,对吧?那就是人类水平和训练错误率之前的差距,而这个差距(train和dev)是4%,所以这个4%差距比任何一种定义的可避免偏差都大。所以他们就建议,你应该主要使用减少方差的工具,比如正则化或者去获取更大的训练集。
比如你的训练错误率是0.7%,所以你现在已经做得很好了,你的开发错误率是0.8%。在这种情况下,你用0.5%来估计贝叶斯错误率关系就很大。因为在这种情况下,你测量到的可避免偏差是0.2%,这是你测量到的方差问题0.1%的两倍,这表明也许偏差和方差都存在问题。但是,可避免偏差问题更严重。在这个例子中,我们在上一张幻灯片中讨论的是0.5%,就是对贝叶斯错误率的最佳估计,因为一群人类医生可以实现这一目标。如果你用0.7代替贝叶斯错误率,你测得的可避免偏差基本上是0%,那你就可能忽略可避免偏差了。实际上你应该试试能不能在训练集上做得更好。
我希望讲这个能让你们有点概念,知道为什么机器学习问题上取得进展会越来越难,当你接近人类水平时进展会越来越难。
在这个例子中,一旦你接近0.7%错误率,除非你非常小心估计贝叶斯错误率,你可能无法知道离贝叶斯错误率有多远,所以你应该尽量减少可避免偏差。事实上,如果你只知道单个普通医生能达到1%错误率,这可能很难知道是不是应该继续去拟合训练集,这种问题只会出现在你的算法已经做得很好的时候,只有你已经做到0.7%, 0.8%, 接近人类水平时会出现。
今天讲的和之前课程中见到的重大区别是,以前你们比较的是训练错误率和0%,直接用这个值估计偏差。相比之下,在这节中,我们有一个更微妙的分析,其中并没有假设你应该得到0%错误率,因为有时贝叶斯错误率是非零的,有时基本不可能做到比某个错误率阈值更低。所以在之前的课程中,我们测量的是训练错误率,然后观察的是训练错误率比0%高多少,就用这个差值来估计偏差有多大。而事实证明,对于贝叶斯错误率几乎是0%的问题这样就行了,例如识别猫,人类表现接近完美,所以贝叶斯错误率也接近完美。所以当贝叶斯错误率几乎为零时,可以那么做。但数据噪点很多时,比如背景声音很嘈杂的语言识别,有时几乎不可能听清楚说的是什么,并正确记录下来。对于这样的问题,更好的估计贝叶斯错误率很有必要,可以帮助你更好地估计可避免偏差和方差,这样你就能更好的做出决策,选择减少偏差的策略,还是减少方差的策略。
回顾一下,对人类水平有大概的估计可以让你做出对贝叶斯错误率的估计,这样可以让你更快地作出决定是否应该专注于减少算法的偏差,或者减少算法的方差。这个决策技巧通常很有效,直到你的系统性能开始超越人类,那么你对贝叶斯错误率的估计就不再准确了,但这些技巧还是可以帮你做出明确的决定。
现在,深度学习的令人兴奋的发展之一就是对于越来越多的任务,我们的系统实际上可以超越人类了。在下一节中,让我们继续谈谈超越人类水平的过程。
11 超过人的表现
很多团队会因为机器在特定的识别分类任务中超越了人类水平而激动不已,我们谈谈这些情况,看看你们自己能不能达到。
我们讨论过机器学习进展,会在接近或者超越人类水平的时候变得越来越慢。我们举例谈谈为什么会这样。
左侧避免偏差的估计是0.1%,然后方差是0.2%。和减少可避免偏差比较起来,减少方差可能空间更大。而右侧这个可能比较难
现在,可避免偏差是什么呢?现在其实很难回答,事实上你的训练错误率是0.3%,这是否意味着你过拟合了0.2%,或者说贝叶斯错误率其实是0.1%呢?或者也许贝叶斯错误率是0.2%?或者贝叶斯错误率是0.3%呢?你真的不知道。但是基于本例中给出的信息,你实际上没有足够的信息来判断优化你的算法时应该专注减少偏差还是减少方差,这样你取得进展的效率就会降低。
还有比如说,如果你的错误率已经比一群充分讨论辩论后的人类专家更低,那么依靠人类直觉去判断你的算法还能往什么方向优化就很难了。所以在这个例子中,一旦你超过这个0.5%的门槛,要进一步优化你的机器学习问题就没有明确的选项和前进的方向了。这并不意味着你不能取得进展,你仍然可以取得重大进展。但现有的一些工具帮助你指明方向的工具就没那么好用了。
现在,机器学习有很多问题已经可以大大超越人类水平了。例如,我想网络广告,估计某个用户点击广告的可能性,可能学习算法做到的水平已经超越任何人类了。还有提出产品建议,向你推荐电影或书籍之类的任务。我想今天的网站做到的水平已经超越你最亲近的朋友了。还有物流预测,从 A 到 B 开车需要多久,或者预测快递车从 A 开到 B 需要多少时间。或者预测某人会不会偿还贷款,这样你就能判断是否批准这人的贷款。我想这些问题都是今天的机器学习远远超过了单个人类的表现。
请注意这四个例子,所有这四个例子都是从结构化数据中学习得来的,这里你可能有个数据库记录用户点击的历史,你的购物历史数据库,或者从A到B需要多长时间的数据库,以前的贷款申请及结果的数据库,这些并不是自然感知问题,这些不是计算机视觉问题,或语音识别,或自然语言处理任务。人类在自然感知任务中往往表现非常好,所以有可能对计算机来说在自然感知任务的表现要超越人类要更难一些。
最后,这些问题中,机器学习团队都可以访问大量数据,所以比如说,那四个应用中,最好的系统看到的数据量可能比任何人类能看到的都多,所以这样就相对容易得到超越人类水平的系统。现在计算机可以检索那么多数据,它可以比人类更敏锐地识别出数据中的统计规律。
除了这些问题,今天已经有语音识别系统超越人类水平了,还有一些计算机视觉任务,一些图像识别任务,计算机已经超越了人类水平。但是由于人类对这种自然感知任务非常擅长,我想计算机达到那种水平要难得多。还有一些医疗方面的任务,比如阅读ECG或诊断皮肤癌,或者某些特定领域的放射科读图任务,这些任务计算机做得非常好了,也许超越了单个人类的水平。
因为人类一般很擅长这种自然感知任务,所以要达到超越人类的表现往往不容易,但如果有足够多的数据,已经有很多深度学习系统,在单一监督学习问题上已经超越了人类的水平,所以这对你在开发的应用是有意义的。我希望有一天你也能够搭建出超越人类水平的深度学习系统
12 改善你的模型的表现
你们学过正交化,如何设立开发集和测试集,用人类水平错误率来估计贝叶斯错误率以及如何估计可避免偏差和方差。我们现在把它们全部组合起来写成一套指导方针,如何提高学习算法性能的指导方针。
所以我想要让一个监督学习算法达到实用,基本上希望或者假设你可以完成两件事情。首先,你的算法对训练集的拟合很好,这可以看成是你能做到可避免偏差很低。还有第二件事你可以做好的是,在训练集中做得很好,然后推广到开发集和测试集也很好,这就是说方差不是太大。
总结前面几节的内容
如果你想提升机器学习系统的性能,我建议你们看看训练错误率和贝叶斯错误率估计值之间的距离,让你知道可避免偏差有多大。换句话说,就是你觉得还能做多好,你对训练集的优化还有多少空间。然后看看你的开发错误率和训练错误率之间的距离,就知道你的方差问题有多大。换句话说,你应该做多少努力让你的算法表现能够从训练集推广到开发集,算法是没有在开发集上训练的。
如果你想用尽一切办法减少可避免偏差,我建议试试这样的策略:比如使用规模更大的模型,这样算法在训练集上的表现会更好,或者训练更久。使用更好的优化算法,比如说加入momentum或者RMSprop,或者使用更好的算法,比如Adam。你还可以试试寻找更好的新神经网络架构,或者说更好的超参数。这些手段包罗万有,你可以改变激活函数,改变层数或者隐藏单位数,虽然你这么做可能会让模型规模变大。或者试用其他模型,其他架构,如循环神经网络和卷积神经网络。在之后的课程里我们会详细介绍的,新的神经网络架构能否更好地拟合你的训练集,有时也很难预先判断,但有时换架构可能会得到好得多的结果。
另外当你发现方差是个问题时,你可以试用很多技巧,包括以下这些:你可以收集更多数据,因为收集更多数据去训练可以帮你更好地推广到系统看不到的开发集数据。你可以尝试正则化,包括 L2正则化,dropout正则化或者我们在之前课程中提到的数据增强。同时你也可以试用不同的神经网络架构,超参数搜索,看看能不能帮助你,找到一个更适合你的问题的神经网络架构。
我想这些偏差、可避免偏差和方差的概念是容易上手,难以精通的。如果你能系统全面地应用本周课程里的概念,你实际上会比很多现有的机器学习团队更有效率、更系统、更有策略地系统提高机器学习系统的性能。
2.1 进行误差分析
如果你希望让学习算法能够胜任人类能做的任务,但你的学习算法还没有达到人类的表现,那么人工检查一下你的算法犯的错误也许可以让你了解接下来应该做什么。这个过程称为错误分析,我们从一个例子开始讲吧。
假设你正在调试猫分类器,然后你取得了90%准确率,相当于10%错误,在你的开发集上做到这样,这离你希望的目标还有很远。也许你的队员看了一下算法分类出错的例子,注意到算法将一些狗分类为猫,你看看这两只狗,它们看起来是有点像猫,至少乍一看是。所以也许你的队友给你一个建议,如何针对狗的图片优化算法。试想一下,你可以针对狗,收集更多的狗图,或者设计一些只处理狗的算法功能之类的,为了让你的猫分类器在狗图上做的更好,让算法不再将狗分类成猫。所以问题在于,你是不是应该去开始做一个项目专门处理狗?
这项目可能需要花费几个月的时间才能让算法在狗图片上犯更少的错误,这样做值得吗?或者与其花几个月做这个项目,有可能最后发现这样一点用都没有。这里有个错误分析流程,可以让你很快知道这个方向是否值得努力。
首先,收集一下,比如说100个错误标记的开发集样本,然后手动检查,一次只看一个,看看你的开发集里有多少错误标记的样本是狗。现在,假设事实上,你的100个错误标记样本中只有5%是狗,就是说在100个错误标记的开发集样本中,有5个是狗。这意味着100个样本,在典型的100个出错样本中,即使你完全解决了狗的问题,你也只能修正这100个错误中的5个。或者换句话说,如果只有5%的错误是狗图片,那么如果你在狗的问题上花了很多时间,那么你最多只能希望你的错误率从10%下降到9.5%。你就可以确定这样花时间不好,或者也许应该花时间,但至少这个分析给出了一个上限。如果你继续处理狗的问题,能够改善算法性能的上限,对吧?在机器学习中,有时我们称之为性能上限,就意味着,最好能到哪里,完全解决狗的问题可以对你有多少帮助。
但现在,假设发生了另一件事,假设我们观察一下这100个错误标记的开发集样本,你发现实际有50张图都是狗,所以有50%都是狗的照片,现在花时间去解决狗的问题可能效果就很好。这种情况下,如果你真的解决了狗的问题,那么你的错误率可能就从10%下降到5%了。然后你可能觉得让错误率减半的方向值得一试,可以集中精力减少错误标记的狗图的问题。
我知道在机器学习中,有时候我们很鄙视手工操作,或者使用了太多人为数值。但如果你要搭建应用系统,那这个简单的人工统计步骤,错误分析,可以节省大量时间,可以迅速决定什么是最重要的,或者最有希望的方向。
实际上,如果你观察100个错误标记的开发集样本,也许只需要5到10分钟的时间,亲自看看这100个样本,并亲自统计一下有多少是狗。根据结果,看看有没有占到5%、50%或者其他东西。这个在5到10分钟之内就能给你估计这个方向有多少价值,并且可以帮助你做出更好的决定,是不是把未来几个月的时间投入到解决错误标记的狗图这个问题。
以上是我们要描述一下如何使用错误分析来评估某个想法,这个样本里狗的问题是否值得解决。有时你在做错误分析时,也可以同时并行评估几个想法
比如,你有几个改善猫检测器的想法,也许你可以改善针对狗图的性能,或者有时候要注意,那些猫科动物,如狮子,豹,猎豹等等,它们经常被分类成小猫或者家猫,所以你也许可以想办法解决这个错误。或者也许你发现有些图像是模糊的,如果你能设计出一些系统,能够更好地处理模糊图像。也许你有些想法,知道大概怎么处理这些问题,要进行错误分析来评估这三个想法。
我会做的是建立这样一个表格,我通常用电子表格来做,但普通文本文件也可以
在最左边,人工过一遍你想分析的图像集,所以图像可能是从1到100,如果你观察100张图的话。电子表格的一列就对应你要评估的想法,所以狗的问题,猫科动物(great cat)的问题,模糊图像的问题,我通常也在电子表格中留下空位来写评论。所以记住,在错误分析过程中,你就看看算法识别错误的开发集样本,如果你发现第一张识别错误的图片是狗图,那么我就在那里打个勾,为了帮我自己记住这些图片,有时我会在评论里注释,也许这是一张比特犬的图。如果第二张照片很模糊,也记一下。如果第三张是在下雨天动物园里的狮子,被识别成猫了,这是大型猫科动物,还有图片模糊,在评论部分写动物园下雨天,是雨天让图像模糊的之类的。最后,这组图像过了一遍之后,我可以统计这些算法错误的百分比,或者这里每个错误类型的百分比,有多少是狗,大猫或模糊这些错误类型。所以也许你检查的图像中8%是狗,可能43%属于great cat,61%属于模糊。这意味着扫过每一列,并统计那一列有多少百分比图像打了勾
在这个步骤做到一半时,有时你可能会发现其他错误类型,比如说你可能发现有Instagram滤镜,那些花哨的图像滤镜,干扰了你的分类器。在这种情况下,实际上可以在错误分析途中,增加这样一列,
比如多色滤镜 Instagram滤镜和Snapchat滤镜,然后再过一遍,也统计一下那些问题,并确定这个新的错误类型占了多少百分比,这个分析步骤的结果可以给出一个估计,是否值得去处理每个不同的错误类型。
例如,在这个样本中,有很多错误来自模糊图片,也有很多错误类型是大猫图片。所以这个分析的结果不是说你一定要处理模糊图片,这个分析没有给你一个严格的数学公式,告诉你应该做什么,但它能让你对应该选择那些手段有个概念。它也告诉你,比如说不管你对狗图片或者Instagram图片处理得有多好,在这些例子中,你最多只能取得8%或者12%的性能提升。而在大猫图片这一类型,你可以做得更好。或者模糊图像,这些类型有改进的潜力。这些类型里,性能提高的上限空间要大得多。所以取决于你有多少改善性能的想法,比如改善大猫图片或者模糊图片的表现。也许你可以选择其中两个,或者你的团队成员足够多,也许你把团队可以分成两个团队,其中一个想办法改善大猫的识别,另一个团队想办法改善模糊图片的识别。但这个快速统计的步骤,你可以经常做,最多需要几小时,就可以真正帮你选出高优先级任务,并了解每种手段对性能有多大提升空间。
所以总结一下,进行错误分析,你应该找一组错误样本,可能在你的开发集里或者测试集里,观察错误标记的样本,看看假阳性(false positives)和假阴性(false negatives),统计属于不同错误类型的错误数量。在这个过程中,你可能会得到启发,归纳出新的错误类型,就像我们看到的那样。如果你过了一遍错误样本,然后说,天,有这么多Instagram滤镜或Snapchat滤镜,这些滤镜干扰了我的分类器,你就可以在途中新建一个错误类型。总之,通过统计不同错误标记类型占总数的百分比,可以帮你发现哪些问题需要优先解决,或者给你构思新优化方向的灵感。在做错误分析的时候,有时你会注意到开发集里有些样本被错误标记了,这时应该怎么做呢
2.2 清除标记错误的数据
你的监督学习问题的数据由输入 x 和输出标签 y 构成,如果你观察一下你的数据,并发现有些输出标签 是错的。你的数据有些标签是错的,是否值得花时间去修正这些标签呢?
比如猫咪分类的数据里发现了一个标记错误的例子,人类给这部分数据加的标签,实际上是错的,这实际上是一只狗,所以y 其实应该是0,也许做标记的那人疏忽了
首先,我们来考虑训练集,事实证明,深度学习算法对于训练集中的随机错误是相当健壮的。只要你的标记出错的样本,只要这些错误样本离随机错误不太远,有时可能做标记的人没有注意或者不小心,按错键了,如果错误足够随机,那么放着这些错误不管可能也没问题,而不要花太多时间修复它们。
当然你浏览一下训练集,检查一下这些标签,并修正它们也没什么害处。有时候修正这些错误是有价值的,有时候放着不管也可以,只要总数据集总足够大,实际错误率可能不会太高。我见过一大批机器学习算法训练的时候,明知训练集里有 x个错误标签,但最后训练出来也没问题。
我这里先警告一下,深度学习算法对随机误差很健壮,但对系统性的错误就没那么健壮了。所以比如说,如果做标记的人一直把白色的狗标记成猫,那就成问题了。因为你的分类器学习之后,会把所有白色的狗都分类为猫。但随机错误或近似随机错误,对于大多数深度学习算法来说不成问题
之前的讨论集中在训练集中的标记出错的样本,那么如果是开发集和测试集中有这些标记出错的样本呢?如果你担心开发集或测试集上标记出错的样本带来的影响,他们一般建议你在错误分析时,添加一个额外的列,这样你也可以统计标签 Y错误的例子数
也许你统计一下对100个标记出错的样本的影响,所以你会找到100个样本,其中你的分类器的输出和开发集的标签不一致,有时对于其中的少数样本,你的分类器输出和标签不同,是因为标签错了,而不是你的分类器出错。所以也许在这个样本中(image98),你发现标记的人漏了背景里的一只猫,所以那里打个勾,来表示样本98标签出错了。也许这张图(image100)实际上是猫的画,而不是一只真正的猫,也许你希望标记数据的人将它标记为 y=0 ,而不是y=1 ,然后再在那里打个勾。
所以现在问题是,是否值得修正这6%标记出错的样本
我的建议是,如果这些标记错误严重影响了你在开发集上评估算法的能力,那么就应该去花时间修正错误的标签。但是,如果它们没有严重影响到你用开发集评估成本偏差的能力,那么可能就不应该花宝贵的时间去处理。
下面看一个例子
标签错误的数据占6%,10%的%6就是0.6% ,剩下的占9.4%,是其他原因导致的,比如把狗误认为猫,大猫图片。所以在这种情况下,我说有9.4%错误率需要集中精力修正,而标记出错导致的错误是总体错误的一小部分而已,所以如果你一定要这么做,你也可以手工修正各种错误标签,但也许这不是当下最重要的任务。
另一个例子
总体错误率降到2%的情况下,错误率0.6%就比较多了
如果你还记得设立开发集的目标的话,开发集的主要目的是,你希望用它来从两个分类器 A 和 B 中选择一个。所以当你测试两个分类器 A 和 B时,在开发集上一个有2.1%错误率,另一个有1.9%错误率,但是你不能再信任开发集了,因为它无法告诉你这个分类器是否比这个好,因为0.6%的错误率是标记出错导致的。那么现在你就有很好的理由去修正开发集里的错误标签,因为在右边这个样本中,标记出错对算法错误的整体评估标准有严重的影响。而左边的样本中,标记出错对你算法影响的百分比还是相对较小的。
我鼓励你不管用什么修正手段,都要同时作用到开发集和测试集上,我们之前讨论过为什么,开发和测试集必须来自相同的分布。
其次,我强烈建议你要考虑同时检验算法判断正确和判断错误的样本,要检查算法出错的样本很容易,只需要看看那些样本是否需要修正,但还有可能有些样本算法判断正确,那些也需要修正。如果你只修正算法出错的样本,你对算法的偏差估计可能会变大,这会让你的算法有一点不公平的优势,我们就需要再次检查出错的样本,但也需要再次检查做对的样本,因为算法有可能因为运气好把某个东西判断对了。在那个特例里,修正那些标签可能会让算法从判断对变成判断错。这第二点不是很容易做,所以通常不会这么做。通常不会这么做的原因是,如果你的分类器很准确,那么判断错的次数比判断正确的次数要少得多。那么就有2%出错,98%都是对的,所以更容易检查2%数据上的标签,然而检查98%数据上的标签要花的时间长得多,所以通常不这么做,但也是要考虑到的。
最后,如果你进入到一个开发集和测试集去修正这里的部分标签,你可能会,也可能不会去对训练集做同样的事情,还记得我们在其他视频里讲过,修正训练集中的标签其实相对没那么重要,你可能决定只修正开发集和测试集中的标签,因为它们通常比训练集小得多,你可能不想把所有额外的精力投入到修正大得多的训练集中的标签,所以这样其实是可以的。我们将在本周晚些时候讨论一些步骤,用于处理你的训练数据分布和开发与测试数据不同的情况,对于这种情况学习算法其实相当健壮,你的开发集和测试集来自同一分布非常重要。但如果你的训练集来自稍微不同的分布,通常这是一件很合理的事情,我会在本周晚些时候谈谈如何处理这个问题。
首先,深度学习研究人员有时会喜欢这样说:“我只是把数据提供给算法,我训练过了,效果拔群”。这话说出了很多深度学习错误的真相,更多时候,我们把数据喂给算法,然后训练它,并减少人工干预,减少使用人类的见解。但我认为,在构造实际系统时,通常需要更多的人工错误分析,更多的人类见解来架构这些系统,尽管深度学习的研究人员不愿意承认这点。
其次,不知道为什么,我看一些工程师和研究人员不愿意亲自去看这些样本,也许做这些事情很无聊,坐下来看100或几百个样本来统计错误数量,但我经常亲自这么做。当我带领一个机器学习团队时,我想知道它所犯的错误,我会亲自去看看这些数据,尝试和一部分错误作斗争。我想就因为花了这几分钟,或者几个小时去亲自统计数据,真的可以帮你找到需要优先处理的任务,我发现花时间亲自检查数据非常值得,所以我强烈建议你们这样做,如果你在搭建你的机器学习系统的话,然后你想确定应该优先尝试哪些想法,或者哪些方向。
这就是错误分析过程,在下一节,我想分享一下错误分析是如何在启动新的机器学习项目中发挥作用的。
2.3 快速搭建你的第一个系统并进行迭代
如果你正在开发全新的机器学习应用,我通常会给你这样的建议,你应该尽快建立你的第一个系统原型,然后快速迭代。
让我告诉你我的意思,我在语音识别领域研究了很多年,如果你正在考虑建立一个新的语音识别系统,其实你可以走很多方向,可以优先考虑很多事情。
比如,有一些特定的技术,可以让语音识别系统对嘈杂的背景更加健壮,嘈杂的背景可能是说咖啡店的噪音,背景里有很多人在聊天,或者车辆的噪音,高速上汽车的噪音或者其他类型的噪音。有一些方法可以让语音识别系统在处理带口音时更健壮,还有特定的问题和麦克风与说话人距离很远有关,就是所谓的远场语音识别。儿童的语音识别带来特殊的挑战,挑战来自单词发音方面,还有他们选择的词汇,他们倾向于使用的词汇。还有比如说,说话人口吃,或者说了很多无意义的短语,比如“哦”,“啊”之类的。你可以选择很多不同的技术,让你听写下来的文本可读性更强,所以你可以做很多事情来改进语音识别系统。
一般来说,对于几乎所有的机器学习程序可能会有50个不同的方向可以前进,并且每个方向都是相对合理的可以改善你的系统。但挑战在于,你如何选择一个方向集中精力处理。即使我已经在语音识别领域工作多年了,如果我要为一个新应用程序域构建新系统,我还是觉得很难不花时间去思考这个问题就直接选择方向。
所以我建议你们,如果你想搭建全新的机器学习程序,就是快速搭好你的第一个系统,然后开始迭代。我的意思是我建议你快速设立开发集和测试集还有指标,这样就决定了你的目标所在,如果你的目标定错了,之后改也是可以的。但一定要设立某个目标,然后我建议你马上搭好一个机器学习系统原型,然后找到训练集,训练一下,看看效果,开始理解你的算法表现如何,在开发集测试集,你的评估指标上表现如何。当你建立第一个系统后,你就可以马上用到之前说的偏差方差分析,还有之前最后几节讨论的错误分析,来确定下一步优先做什么。特别是如果错误分析让你了解到大部分的错误的来源是说话人远离麦克风,这对语音识别构成特殊挑战,那么你就有很好的理由去集中精力研究这些技术,所谓远场语音识别的技术,这基本上就是处理说话人离麦克风很远的情况。
建立这个初始系统的所有意义在于,它可以是一个快速和粗糙的实现,你知道的,别想太多。初始系统的全部意义在于,有一个学习过的系统,有一个训练过的系统,让你确定偏差方差的范围,就可以知道下一步应该优先做什么,让你能够进行错误分析,可以观察一些错误,然后想出所有能走的方向,哪些是实际上最有希望的方向。
所以回顾一下,我建议你们快速建立你的第一个系统,然后迭代。不过如果你在这个应用程序领域有很多经验,这个建议适用程度要低一些。还有一种情况适应程度更低,当这个领域有很多可以借鉴的学术文献,处理的问题和你要解决的几乎完全相同,所以,比如说,人脸识别就有很多学术文献,如果你尝试搭建一个人脸识别设备,那么可以从现有大量学术文献为基础出发,一开始就搭建比较复杂的系统。但如果你第一次处理某个新问题,那我真的不鼓励你想太多,或者把第一个系统弄得太复杂。我建议你们构建一些快速而粗糙的实现,然后用来帮你找到改善系统要优先处理的方向。我见过很多机器学习项目,我觉得有些团队的解决方案想太多了,他们造出了过于复杂的系统。我也见过有限团队想的不够,然后造出过于简单的系统。平均来说,我见到更多的团队想太多,构建太复杂的系统。
所以我希望这些策略有帮助,如果你将机器学习算法应用到新的应用程序里,你的主要目标是弄出能用的系统,你的主要目标并不是发明全新的机器学习算法,这是完全不同的目标,那时你的目标应该是想出某种效果非常好的算法。所以我鼓励你们搭建快速而粗糙的实现,然后用它做偏差/方差分析,用它做错误分析,然后用分析结果确定下一步优先要做的方向。
2.4 在不同的划分上进行训练并测试
深度学习算法对训练数据的胃口很大,当你收集到足够多带标签的数据构成训练集时,算法效果最好,这导致很多团队用尽一切办法收集数据,然后把它们堆到训练集里,让训练的数据量更大,即使有些数据,甚至是大部分数据都来自和开发集、测试集不同的分布。在深度学习时代,越来越多的团队都用来自和开发集、测试集分布不同的数据来训练,这里有一些微妙的地方,一些最佳做法来处理训练集和测试集存在差异的情况,我们来看看。
假设你在开发一个手机应用,用户会上传他们用手机拍摄的照片,你想识别用户从应用中上传的图片是不是猫。现在你有两个数据来源,一个是你真正关心的数据分布,来自应用上传的数据,比如右边的应用,这些照片一般更业余,取景不太好,有些甚至很模糊,因为它们都是业余用户拍的。另一个数据来源就是你可以用爬虫程序挖掘网页直接下载,就这个样本而言,可以下载很多取景专业、高分辨率、拍摄专业的猫图片。如果你的应用用户数还不多,也许你只收集到10,000张用户上传的照片,但通过爬虫挖掘网页,你可以下载到海量猫图,也许你从互联网上下载了超过20万张猫图。而你真正关心的算法表现是你的最终系统处理来自应用程序的这个图片分布时效果好不好,因为最后你的用户会上传类似右边这些图片,你的分类器必须在这个任务中表现良好。现在你就陷入困境了,因为你有一个相对小的数据集,只有10,000个样本来自那个分布,而你还有一个大得多的数据集来自另一个分布,图片的外观和你真正想要处理的并不一样。但你又不想直接用这10,000张图片,因为这样你的训练集就太小了,使用这20万张图片似乎有帮助。但是,困境在于,这20万张图片并不完全来自你想要的分布,那么你可以怎么做呢?
这里有一种选择,你可以做的一件事是将两组数据合并在一起,这样你就有21万张照片,你可以把这21万张照片随机分配到训练、开发和测试集中。为了说明观点,我们假设你已经确定开发集和测试集各包含2500个样本,所以你的训练集有205000个样本。现在这么设立你的数据集有一些好处,也有坏处。好处在于,你的训练集、开发集和测试集都来自同一分布,这样更好管理。但坏处在于,这坏处还不小,就是如果你观察开发集,看看这2500个样本其中很多图片都来自网页下载的图片,那并不是你真正关心的数据分布,你真正要处理的是来自手机的图片。
所以对于这2500个样本,有2381张图来自网页下载,只有119张图来自手机上传。要记住,设立开发集的目的是告诉你的团队去瞄准的目标,而你瞄准目标的方式,你的大部分精力都用在优化来自网页下载的图片,这其实不是你想要的。所以我真的不建议使用第一个选项,因为这样设立开发集就是告诉你的团队,针对不同于你实际关心的数据分布去优化,所以不要这么做。
我建议你走另外一条路,就是这样,训练集,比如说还是205,000张图片,我们的训练集是来自网页下载的200,000张图片,然后如果需要的话,再加上5000张来自手机上传的图片。然后对于开发集和测试集,你的开发集和测试集都是手机图。而训练集包含了来自网页的20万张图片,还有5000张来自应用的图片,开发集就是2500张来自应用的图片,测试集也是2500张来自应用的图片。这样将数据分成训练集、开发集和测试集的好处在于,现在你瞄准的目标就是你想要处理的目标,你告诉你的团队,我的开发集包含的数据全部来自手机上传,这是你真正关心的图片分布。我们试试搭建一个学习系统,让系统在处理手机上传图片分布时效果良好。缺点在于,当然了,现在你的训练集分布和你的开发集、测试集分布并不一样。但事实证明,这样把数据分成训练、开发和测试集,在长期能给你带来更好的系统性能。我们以后会讨论一些特殊的技巧,可以处理 训练集的分布和开发集和测试集分布不一样的情况。
再看另一个例子
假设你正在开发一个全新的产品,一个语音激活汽车后视镜,现在你就可以和后视镜对话了,然后只需要说:“亲爱的后视镜,请帮我找找到最近的加油站的导航方向”,然后后视镜就会处理这个请求。所以这实际上是一个真正的产品,假设现在你要为你自己的国家研制这个产品,那么你怎么收集数据去训练这个产品语言识别模块呢?
嗯,也许你已经在语音识别领域上工作了很久,所以你有很多来自其他语音识别应用的数据,它们并不是来自语音激活后视镜的数据。现在我讲讲如何分配训练集、开发集和测试集。对于你的训练集,你可以将你拥有的所有语音数据,从其他语音识别问题收集来的数据,比如这些年你从各种语音识别数据供应商买来的数据,今天你可以直接买到成 x,y 对的数据,其中 x是音频剪辑, y 是听写记录。或者也许你研究过智能音箱,语音激活音箱,所以你有一些数据,也许你做过语音激活键盘的开发之类的。
举例来说,也许你从这些来源收集了500,000段录音。而你的开发集和测试集,也许数据集小得多(20000),比如实际上来自语音激活后视镜的数据。因为用户要查询导航信息或试图找到通往各个地方的路线,这个数据集可能会有很多街道地址,对吧?“请帮我导航到这个街道地址”,或者说:“请帮助我导航到这个加油站”,所以这个数据的分布和左边大不一样,但这真的是你关心的数据,因为这些数据是你的产品必须处理好的,所以你就应该把它设成你的开发和测试集。
在这个样本中,你应该这样设立你的训练集,左边有500,000段语音,然后你的开发集和测试集,我把它简写成 D 和 T ,可能每个集包含10,000段语音,是从实际的语音激活后视镜收集的。或者换种方式,如果你觉得不需要将20,000段来自语音激活后视镜的录音全部放进开发和测试集,也许你可以拿一半,把它放在训练集里,那么训练集可能是51万段语音,包括来自那里的50万段语音,还有来自后视镜的1万段语音,然后开发集和测试集也许各自有5000段语音。所以有2万段语音,也许1万段语音放入了训练集,5000放入开发集,5000放入测试集。所以这是另一种将你的数据分成训练、开发和测试的方式。这样你的训练集大得多,大概有50万段语音,比只用语音激活后视镜数据作为训练集要大得多。
所以在这节中,你们见到几组样本,让你的训练集数据来自和开发集、测试集不同的分布,这样你就可以有更多的训练数据。在这些样本中,这将改善你的学习算法。
现在你可能会问,是不是应该把收集到的数据都用掉?答案很微妙,不一定都是肯定的答案,我们在下节看看一个反例。
2.5 不匹配数据划分的偏差和方差
估计学习算法的偏差和方差真的可以帮你确定接下来应该优先做的方向,但是,当你的训练集来自和开发集、测试集不同分布时,分析偏差和方差的方式可能不一样,我们来看为什么。
我们继续用猫分类器为例,我们说人类在这个任务上能做到几乎完美,所以贝叶斯错误率或者说贝叶斯最优错误率,我们知道这个问题里几乎是0%。所以要进行错误率分析,你通常需要看训练误差,也要看看开发集的误差。比如说,在这个样本中,你的训练集误差是1%,你的开发集误差是10%,如果你的开发集来自和训练集一样的分布,你可能会说,这里存在很大的方差问题,你的算法不能很好的从训练集出发泛化,它处理训练集很好,但处理开发集就突然间效果很差了。
但如果你的训练数据和开发数据来自不同的分布,你就不能再放心下这个结论了。
特别是,也许算法在开发集上做得不错,可能因为训练集很容易识别,因为训练集都是高分辨率图片,很清晰的图像,但开发集要难以识别得多。所以也许没有方差问题,这只不过反映了开发集包含更难准确分类的图片。所以这个分析的问题在于,当你看训练误差,再看开发误差,有两件事变了。首先算法只见过训练集数据,没见过开发集数据。第二,开发集数据来自不同的分布。而且因为你同时改变了两件事情,很难确认这增加的9%误差率有多少是因为算法没看到开发集中的数据导致的,这是问题方差的部分,有多少是因为开发集数据就是不一样。
为了弄清楚哪个因素影响更大,如果你完全不懂这两种影响到底是什么,别担心我们马上会再讲一遍。但为了分辨清楚两个因素的影响,定义一组新的数据是有意义的,我们称之为训练-开发集,所以这是一个新的数据子集。我们应该从训练集的分布里挖出来,但你不会用来训练你的网络。
我的意思是我们已经设立过这样的训练集、开发集和测试集了,并且开发集和测试集来自相同的分布,但训练集来自不同的分布。我们要做的是随机打散训练集,然后分出一部分训练集作为训练-开发集(training-dev),就像开发集和测试集来自同一分布,训练集、训练-开发集也来自同一分布。
但不同的地方是,现在你只在训练集训练你的神经网络,你不会让神经网络在训练-开发集上跑后向传播。为了进行误差分析,你应该做的是看看分类器在训练集上的误差,训练-开发集上的误差,还有开发集上的误差。
比如说这个样本中,训练误差是1%,我们说训练-开发集上的误差是9%,然后开发集误差是10%,和以前一样。你就可以从这里得到结论,当你从训练数据变到训练-开发集数据时,错误率真的上升了很多。而训练数据和训练-开发数据的差异在于,你的神经网络能看到第一部分数据并直接在上面做了训练,但没有在训练-开发集上直接训练,这就告诉你,算法存在方差问题,因为训练-开发集的错误率是在和训练集来自同一分布的数据中测得的。所以你知道,尽管你的神经网络在训练集中表现良好,但无法泛化到来自相同分布的训练-开发集里,它无法很好地泛化推广到来自同一分布,但以前没见过的数据中,所以在这个样本中我们确实有一个方差问题。
来看另一个例子
假设训练误差为1%,训练-开发误差为1.5%,但当你开始处理开发集时,错误率上升到10%。现在你的方差问题就很小了,因为当你从见过的训练数据转到训练-开发集数据,神经网络还没有看到的数据,错误率只上升了一点点。但当你转到开发集时,错误率就大大上升了,所以这是数据不匹配的问题。因为你的学习算法没有直接在训练-开发集或者开发集训练过,但是这两个数据集来自不同的分布。但不管算法在学习什么,它在训练-开发集上做的很好,但开发集上做的不好,所以总之你的算法擅长处理和你关心的数据不同的分布,我们称之为数据不匹配的问题。
左边有高偏差,右边的例子除了偏差还存在数据不匹配问题
Human level和train error 之间是可避免误差,train error和train-dev之间是方差,train-dev和Dev error之间是数据不匹配问题,Dev和Test之间就是过拟合程度了
要记住,你的开发集和测试集来自同一分布,所以这里存在很大差距的话。如果算法在开发集上做的很好,比测试集好得多,那么你就可能对开发集过拟合了。如果是这种情况,那么你可能要往回退一步,然后收集更多开发集数据。
还有一种情况,你的任务在Dev上做的很好
很意外,算法在开发集上做的更好。你见到这种现象,比如说在处理语音识别任务时发现这样,其中训练数据其实比你的开发集和测试集难识别得多。所以这两个(7%,10%)是从训练集分布评估的,而这两个(6%,6%)是从开发测试集分布评估的。所以有时候如果你的开发测试集分布比你应用实际处理的数据要容易得多,那么这些错误率可能真的会下降。
最后,我们以前讲过很多处理偏差的手段,讲过处理方差的手段,但怎么处理数据不匹配呢?特别是开发集、测试集和你的训练集数据来自不同分布时,这样可以用更多训练数据,真正帮你提高学习算法性能。但是,如果问题不仅来自偏差和方差,你现在又有了这个潜在的新问题,数据不匹配,有什么好办法可以处理数据不匹配的呢?实话说,并没有很通用,或者至少说是系统解决数据不匹配问题的方法,但你可以做一些尝试,可能会有帮助,我们在下一节里看看这些尝试。
所以我们讲了如何使用来自和开发集、测试集不同分布的训练数据,这可以给你提供更多训练数据,因此有助于提高你的学习算法的性能,但是,潜在问题就不只是偏差和方差问题,这样做会引入第三个潜在问题,数据不匹配。如果你做了错误分析,并发现数据不匹配是大量错误的来源,那么你怎么解决这个问题呢?但结果很不幸,并没有特别系统的方法去解决数据不匹配问题,但你可以做一些尝试,可能会有帮助,
2.6 解决数据不匹配
如果您的训练集来自和开发测试集不同的分布,如果错误分析显示你有一个数据不匹配的问题该怎么办?这个问题没有完全系统的解决方案,但我们可以看看一些可以尝试的事情。
如果我发现有严重的数据不匹配问题,我通常会亲自做错误分析,尝试了解训练集和开发测试集的具体差异。技术上,为了避免对测试集过拟合,要做错误分析,你应该人工去看开发集而不是测试集。
但作为一个具体的例子,如果你正在开发一个语音激活的后视镜应用,你可能要看看……我想如果是语音的话,你可能要听一下来自开发集的样本,尝试弄清楚开发集和训练集到底有什么不同。所以,比如说你可能会发现很多开发集样本噪音很多,有很多汽车噪音,这是你的开发集和训练集差异之一。也许你还会发现其他错误,比如在你的车子里的语言激活后视镜,你发现它可能经常识别错误街道号码,因为那里有很多导航请求都有街道地址,所以得到正确的街道号码真的很重要。当你了解开发集误差的性质时,你就知道,开发集有可能跟训练集不同或者更难识别,那么你可以尝试把训练数据变得更像开发集一点,或者,你也可以收集更多类似你的开发集和测试集的数据。所以,比如说,如果你发现车辆背景噪音是主要的错误来源,那么你可以模拟车辆噪声数据,我会在后面详细讨论这个问题。或者你发现很难识别街道号码,也许你可以有意识地收集更多人们说数字的音频数据,加到你的训练集里。
现在我知道上面只给出了粗略的指南,列出一些你可以做的尝试,这不是一个系统化的过程,我想,这不能保证你一定能取得进展。但我发现这种人工见解,我们可以一起尝试收集更多和真正重要的场合相似的数据,这通常有助于解决很多问题。所以,如果你的目标是让训练数据更接近你的开发集,那么你可以怎么做呢?
你可以利用的其中一种技术是人工合成数据(artificial data synthesis)我们讨论一下。在解决汽车噪音问题的场合
所以要建立语音识别系统。也许实际上你没那么多实际在汽车背景噪音下录得的音频,或者在高速公路背景噪音下录得的音频。但我们发现,你可以合成。所以假设你录制了大量清晰的音频,不带车辆背景噪音的音频,“The quick brown fox jumps over the lazy dog”,所以,这可能是你的训练集里的一段音频,顺便说一下,这个句子在AI测试中经常使用,因为这个短句包含了从a到z所有字母,所以你会经常见到这个句子。但是,有了这个“the quick brown fox jumps over the lazy dog”这段录音之后,你也可以收集一段这样的汽车噪音,这就是汽车内部的背景噪音,如果你一言不发开车的话,就是这种声音。如果你把两个音频片段放到一起,你就可以合成出"the quick brown fox jumps over the lazy dog",在汽车背景噪音中的效果,听起来像这样,所以这是一个相对简单的音频合成例子。在实践中,你可能会合成其他音频效果,比如混响,就是声音从汽车内壁上反弹叠加的效果。
但是通过人工数据合成,你可以快速制造更多的训练数据,就像真的在车里录的那样,那就不需要花时间实际出去收集数据,比如说在实际行驶中的车子,录下上万小时的音频。所以,如果错误分析显示你应该尝试让你的数据听起来更像在车里录的,那么人工合成那种音频,然后喂给你的机器学习算法,这样做是合理的。
现在我们要提醒一下,人工数据合成有一个潜在问题,比如说,你在安静的背景里录得10,000小时音频数据,然后,比如说,你只录了一小时车辆背景噪音,那么,你可以这么做,将这1小时汽车噪音回放10,000次,并叠加到在安静的背景下录得的10,000小时数据。如果你这么做了,人听起来这个音频没什么问题。但是有一个风险,有可能你的学习算法对这1小时汽车噪音过拟合。
特别是,如果这组汽车里录的音频可能是你可以想象的所有汽车噪音背景的集合,如果你只录了一小时汽车噪音,那你可能只模拟了全部数据空间的一小部分,你可能只从汽车噪音的很小的子集来合成数据。
而对于人耳来说,这些音频听起来没什么问题,因为一小时的车辆噪音对人耳来说,听起来和其他任意一小时车辆噪音是一样的。但你有可能从这整个空间很小的一个子集出发合成数据,神经网络最后可能对你这一小时汽车噪音过拟合。我不知道以较低成本收集10,000小时的汽车噪音是否可行,这样你就不用一遍又一遍地回放那1小时汽车噪音,你就有10,000个小时永不重复的汽车噪音来叠加到10,000小时安静背景下录得的永不重复的语音录音。这是可以做的,但不保证能做。但是使用10,000小时永不重复的汽车噪音,而不是1小时重复学习,算法有可能取得更好的性能。人工数据合成的挑战在于,人耳的话,人耳是无法分辨这10,000个小时听起来和那1小时没什么区别,所以你最后可能会制造出这个原始数据很少的,在一个小得多的空间子集合成的训练数据,但你自己没意识到。
这里有人工合成数据的另一个例子,假设你在研发无人驾驶汽车,你可能希望检测出这样的车,然后用这样的框包住它。很多人都讨论过的一个思路是,为什么不用计算机合成图像来模拟成千上万的车辆呢?这里有几张车辆照片,
其实是用计算机合成的,我想这个合成是相当逼真的,我想通过这样合成图片,你可以训练出一个相当不错的计算机视觉系统来检测车子。
不幸的是,前面介绍的情况也会在这里出现,
比如这是所有车的集合,如果你只合成这些车中很小的子集,对于人眼来说也许这样合成图像没什么问题,但你的学习算法可能会对合成的这一个小子集过拟合。
特别是很多人都独立提出了一个想法,一旦你找到一个电脑游戏,里面车辆渲染的画面很逼真,那么就可以截图,得到数量巨大的汽车图片数据集。事实证明,如果你仔细观察一个视频游戏,如果这个游戏只有20辆独立的车,那么这游戏看起来还行。因为你是在游戏里开车,你只看到这20辆车,这个模拟看起来相当逼真。但现实世界里车辆的设计可不只20种,如果你用着20量独特的车合成的照片去训练系统,那么你的神经网络很可能对这20辆车过拟合,但人类很难分辨出来。即使这些图像看起来很逼真,你可能真的只用了所有可能出现的车辆的很小的子集。
所以,总而言之,如果你认为存在数据不匹配问题,我建议你做错误分析,或者看看训练集,或者看看开发集,试图找出,试图了解这两个数据分布到底有什么不同,然后看看是否有办法收集更多看起来像开发集的数据作训练。
我们谈到其中一种办法是人工数据合成,人工数据合成确实有效。在语音识别中。我已经看到人工数据合成显著提升了已经非常好的语音识别系统的表现,所以这是可行的。但当你使用人工数据合成时,一定要谨慎,要记住你有可能从所有可能性的空间只选了很小一部分去模拟数据。
所以这就是如何处理数据不匹配问题,接下来,我想和你分享一些想法就是如何从多种类型的数据同时学习。
2.7 迁移学习
深度学习中,最强大的理念之一就是,有的时候神经网络可以从一个任务中习得知识,并将这些知识应用到另一个独立的任务中。所以例如,也许你已经训练好一个神经网络,能够识别像猫这样的对象,然后使用那些知识,或者部分习得的知识去帮助您更好地阅读x射线扫描图,这就是所谓的迁移学习。
我们来看看,假设你已经训练好一个图像识别神经网络,所以你首先用一个神经网络,并在 (x,y) 对上训练,其中 x 是图像, y 是某些对象,图像是猫、狗、鸟或其他东西。如果你把这个神经网络拿来,然后让它适应或者说迁移,在不同任务中学到的知识,比如放射科诊断,就是说阅读 X 射线扫描图。你可以做的是把神经网络最后的输出层拿走,就把它删掉,还有进入到最后一层的权重删掉,然后为最后一层重新赋予随机权重,然后让它在放射诊断数据上训练。
具体来说,在第一阶段训练过程中,当你进行图像识别任务训练时,你可以训练神经网络的所有常用参数,所有的权重,所有的层,然后你就得到了一个能够做图像识别预测的网络。在训练了这个神经网络后,要实现迁移学习,你现在要做的是,把数据集换成新的(x,y) 对,x变成放射科图像,而y 是你想要预测的诊断,你要做的是初始化最后一层的权重,让我们称之为 w [ L ] w^{[L]} w[L] 和 b [ L ] b^{[L]} b[L]随机初始化。现在,我们在这个新数据集上重新训练网络,在新的放射科数据集上训练网络。要用放射科数据集重新训练神经网络有几种做法。
如果你的放射科数据集很小,你可能只需要重新训练最后一层的权重,就是 w [ L ] w^{[L]} w[L]和 b [ L ] b^{[L]} b[L]并保持其他参数不变。如果你有足够多的数据,你可以重新训练神经网络中剩下的所有层。经验规则是,如果你有一个小数据集,就只训练输出层前的最后一层,或者也许是最后一两层。但是如果你有很多数据,那么也许你可以重新训练网络中的所有参数。如果你重新训练神经网络中的所有参数,那么这个在图像识别数据的初期训练阶段,有时称为预训练(pre-training),因为你在用图像识别数据去预先初始化,或者预训练神经网络的权重。然后,如果你以后更新所有权重,然后在放射科数据上训练,有时这个过程叫微调(fine tuning)。如果你在深度学习文献中看到预训练和微调,你就知道它们说的是这个意思,预训练和微调的权重来源于迁移学习。
在这个例子中你做的是,把图像识别中学到的知识应用或迁移到放射科诊断上来,为什么这样做有效果呢?有很多低层次特征,比如说边缘检测、曲线检测、阳性对象检测(positive objects),从非常大的图像识别数据库中习得这些能力可能有助于你的学习算法在放射科诊断中做得更好,算法学到了很多结构信息,图像形状的信息,其中一些知识可能会很有用,所以学会了图像识别,它就可能学到足够多的信息,可以了解不同图像的组成部分是怎样的,学到线条、点、曲线这些知识,也许对象的一小部分,这些知识有可能帮助你的放射科诊断网络学习更快一些,或者需要更少的学习数据。
另一个例子
假设你已经训练出一个语音识别系统,现在 x是音频或音频片段输入,而 y 是听写文本,所以你已经训练了语音识别系统,让它输出听写文本。现在我们说你想搭建一个“唤醒词”或“触发词”检测系统,所谓唤醒词或触发词就是我们说的一句话,可以唤醒家里的语音控制设备,比如你说“Alexa”可以唤醒一个亚马逊Echo设备,或用“OK Google”来唤醒Google设备,用"Hey Siri"来唤醒苹果设备,用"你好百度"唤醒一个百度设备。要做到这点,你可能需要去掉神经网络的最后一层,然后加入新的输出节点,但有时你可以不只加入一个新节点,或者甚至往你的神经网络加入几个新层,然后把唤醒词检测问题的标签 y 喂进去训练。再次,这取决于你有多少数据,你可能只需要重新训练网络的新层,也许你需要重新训练神经网络中更多的层。
那么迁移学习什么时候是有意义的呢?迁移学习起作用的场合是,在迁移来源问题中你有很多数据,但迁移目标问题你没有那么多数据。
例如,假设图像识别任务中你有1百万个样本,所以这里数据相当多。可以学习低层次特征,可以在神经网络的前面几层学到如何识别很多有用的特征。但是对于放射科任务,也许你只有一百个样本,所以你的放射学诊断问题数据很少,也许只有100次 X 射线扫描,所以你从图像识别训练中学到的很多知识可以迁移,并且真正帮你加强放射科识别任务的性能,即使你的放射科数据很少。
对于语音识别,也许你已经用10,000小时数据训练过你的语言识别系统,所以你从这10,000小时数据学到了很多人类声音的特征,这数据量其实很多了。但对于触发字检测,也许你只有1小时数据,所以这数据太小,不能用来拟合很多参数。所以在这种情况下,预先学到很多人类声音的特征人类语言的组成部分等等知识,可以帮你建立一个很好的唤醒字检测器,即使你的数据集相对较小。对于唤醒词任务来说,至少数据集要小得多。
所以在这两种情况下,你从数据量很多的问题迁移到数据量相对小的问题
然后反过来的话,迁移学习可能就没有意义了。比如,你用100张图训练图像识别系统,然后有100甚至1000张图用于训练放射科诊断系统,人们可能会想,为了提升放射科诊断的性能,假设你真的希望这个放射科诊断系统做得好,那么用放射科图像训练可能比使用猫和狗的图像更有价值,所以100甚至1000张图用于训练放射科诊断系统的每个样本价值比100张图训练图像识别系统要大得多,至少就建立性能良好的放射科系统而言是这样。所以,如果你的放射科数据更多,那么你这100张猫猫狗狗或者随机物体的图片肯定不会有太大帮助,因为来自猫狗识别任务中,每一张图的价值肯定不如一张 X 射线扫描图有价值,对于建立良好的放射科诊断系统而言是这样。
所以,这是其中一个例子,说明迁移学习可能不会有害,但也别指望这么做可以带来有意义的增益。同样,如果你用10小时数据训练出一个语音识别系统。然后你实际上有10个小时甚至更多,比如说50个小时唤醒字检测的数据,你知道迁移学习有可能会有帮助,也可能不会,也许把这10小时数据迁移学习不会有太大坏处,但是你也别指望会得到有意义的增益
所以总结一下,什么时候迁移学习是有意义的?
如果你想从任务 A 学习并迁移一些知识到任务 B ,那么当任务A 和任务B 都有同样的输入 x 时,迁移学习是有意义的。在第一个例子中, A 和 B 的输入都是图像,在第二个例子中,两者输入都是音频。当任务 A 的数据比任务 B 多得多时,迁移学习意义更大。所有这些假设的前提都是,你希望提高任务 B 的性能,因为任务 B 每个数据更有价值,对任务B 来说通常任务A 的数据量必须大得多,才有帮助,因为任务 A 里单个样本的价值没有比任务 B 单个样本价值大。然后如果你觉得任务 A 的低层次特征,可以帮助任务B 的学习,那迁移学习更有意义一些。
而在这两个前面的例子中,也许学习图像识别教给系统足够多图像相关的知识,让它可以进行放射科诊断,也许学习语音识别教给系统足够多人类语言信息,能帮助你开发触发字或唤醒字检测器。
所以总结一下,迁移学习最有用的场合是,如果你尝试优化任务B的性能,通常这个任务数据相对较少,例如,在放射科中你知道很难收集很多 X 射线扫描图来搭建一个性能良好的放射科诊断系统,所以在这种情况下,你可能会找一个相关但不同的任务,如图像识别,其中你可能用1百万张图片训练过了,并从中学到很多低层次特征,所以那也许能帮助网络在任务 B 在放射科任务上做得更好,尽管任务 B 没有这么多数据。迁移学习什么时候是有意义的?它确实可以显著提高你的学习任务的性能,但我有时候也见过有些场合使用迁移学习时,任务 A 实际上数据量比任务 B 要少,这种情况下增益可能不多。
好,这就是迁移学习,你从一个任务中学习,然后尝试迁移到另一个不同任务中。从多个任务中学习还有另外一个版本,就是所谓的多任务学习,当你尝试从多个任务中并行学习,而不是串行学习,在训练了一个任务之后试图迁移到另一个任务,所以在下一节,让我们来讨论多任务学习。
2.8 多任务学习
在迁移学习中,你的步骤是串行的,你从任务 A 里学习只是然后迁移到任务 B 。在多任务学习中,你是同时开始学习的,试图让单个神经网络同时做几件事情,然后希望这里每个任务都能帮到其他所有任务。
我们来看一个例子,假设你在研发无人驾驶车辆,那么你的无人驾驶车可能需要同时检测不同的物体,比如检测行人、车辆、停车标志,还有交通灯各种其他东西。比如在这个例子中,图像里有个停车标志,然后图像中有辆车,但没有行人,也没有交通灯。
那么这里不再是一个标签 y ( i ) y^{(i)} y(i),而是有4个标签,也许 y ( i ) y^{(i)} y(i) 的维数会更高,现在我们就先用4个吧.将训练集的标签水平堆叠起来,所以这个矩阵Y 现在变成 4 x m 矩阵.
那么你现在可以做的是训练一个神经网络,来预测这些 y 值
你就得到这样的神经网络,输入 x ,现在输出是一个四维向量 y 。请注意,这里输出我画了四个节点,所以第一个节点就是我们想预测图中有没有行人,然后第二个输出节点预测的是有没有车,第三个输出节点预测有没有停车标志,第四个输出节点预测有没有交通灯,所以这里 y ^ \hat{y} y^ 是四维的。
要训练这个神经网络,你现在需要定义神经网络的损失函数,对于一个输出
y
^
\hat{y}
y^ ,是个4维向量,对于整个训练集的平均损失:
整个训练集的平均损失和之前分类猫的例子主要区别在于,现在你要对 j=1到 4 求和,这与softmax回归的主要区别在于,与softmax回归不同,softmax将单个标签分配给单个样本。而这张图可以有很多不同的标签,所以不是说每张图都只是一张行人图片,汽车图片、停车标志图片或者交通灯图片。你要知道每张照片是否有行人、或汽车、停车标志或交通灯,多个物体可能同时出现在一张图里。
所以你不是只给图片一个标签,而是需要遍历不同类型,然后看看每个类型,那类物体有没有出现在图中。所以我就说在这个场合,一张图可以有多个标签。如果你训练了一个神经网络,试图最小化这个成本函数,你做的就是多任务学习。因为你现在做的是建立单个神经网络,观察每张图,然后解决四个问题,系统试图告诉你,每张图里面有没有这四个物体。另外你也可以训练四个不同的神经网络,而不是训练一个网络做四件事情。但神经网络一些早期特征,在识别不同物体时都会用到,然后你发现,训练一个神经网络做四件事情会比训练四个完全独立的神经网络分别做四件事性能要更好,这就是多任务学习的力量。
另一个细节,到目前为止,我是这么描述算法的,好像每张图都有全部标签。事实证明,多任务学习也可以处理图像只有部分物体被标记的情况。所以第一个训练样本,我们说有人,给数据贴标签的人告诉你里面有一个行人,没有车,但他们没有标记是否有停车标志,或者是否有交通灯。也许第二个例子中,有行人,有车。但是,当标记人看着那张图片时,他们没有加标签,没有标记是否有停车标志,是否有交通灯等等。也许有些样本都有标记,但也许有些样本他们只标记了有没有车,然后还有一些是问号。
即使是这样的数据集,你也可以在上面训练算法,同时做四个任务,即使一些图像只有一小部分标签,其他是问号或者不管是什么。然后你训练算法的方式,即使这里有些标签是问号,或者没有标记,这就是对 j 从1到4求和,你就只对带0和1标签的 j 值求和,所以当有问号的时候,你就在求和时忽略那个项,这样只对有标签的值求和,于是你就能利用这样的数据集。
那么多任务学习什么时候有意义呢?当三件事为真时,它就是有意义的。
第一,如果你训练的一组任务,可以共用低层次特征。对于无人驾驶的例子,同时识别交通灯、汽车和行人是有道理的,这些物体有相似的特征,也许能帮你识别停车标志,因为这些都是道路上的特征。
第二,这个准则没有那么绝对,所以不一定是对的。但我从很多成功的多任务学习案例中看到,如果每个任务的数据量很接近,你还记得迁移学习时,你从 A 任务学到知识然后迁移到B 任务,所以如果任务A 有1百万个样本,任务 B 只有1000个样本,那么你从这1百万个样本学到的知识,真的可以帮你增强对更小数据集任务 B 的训练。那么多任务学习又怎么样呢?在多任务学习中,你通常有更多任务而不仅仅是两个,所以也许你有,以前我们有4个任务,但比如说你要完成100个任务,而你要做多任务学习,尝试同时识别100种不同类型的物体。你可能会发现,每个任务大概有1000个样本。所以如果你专注加强单个任务的性能,比如我们专注加强第100个任务的表现,我们用A100 表示,如果你试图单独去做这个最后的任务,你只有1000个样本去训练这个任务,这是100项任务之一,而通过在其他99项任务的训练,这些加起来可以一共有99000个样本,这可能大幅提升算法性能,可以提供很多知识来增强这个任务的性能。不然对于任务 A100 ,只有1000个样本的训练集,效果可能会很差。如果有对称性,这其他99个任务,也许能提供一些数据或提供一些知识来帮到这100个任务中的每一个任务。所以第二点不是绝对正确的准则,但我通常会看的是如果你专注于单项任务,如果想要从多任务学习得到很大性能提升,那么其他任务加起来必须要有比单个任务大得多的数据量。要满足这个条件,其中一种方法是,比如右边这个例子这样,或者如果每个任务中的数据量很相近,但关键在于,如果对于单个任务你已经有1000个样本了,那么对于所有其他任务,你最好有超过1000个样本,这样其他任务的知识才能帮你改善这个任务的性能。
最后多任务学习往往在以下场合更有意义
当你可以训练一个足够大的神经网络,同时做好所有的工作,所以多任务学习的替代方法是为每个任务训练一个单独的神经网络。所以不是训练单个神经网络同时处理行人、汽车、停车标志和交通灯检测。你可以训练一个用于行人检测的神经网络,一个用于汽车检测的神经网络,一个用于停车标志检测的神经网络和一个用于交通信号灯检测的神经网络。那么研究员Rich Carona几年前发现的是什么呢?多任务学习会降低性能的唯一情况,和训练单个神经网络相比性能更低的情况就是你的神经网络还不够大。但如果你可以训练一个足够大的神经网络,那么多任务学习肯定不会或者很少会降低性能,我们都希望它可以提升性能,比单独训练神经网络来单独完成各个任务性能要更好。
所以这就是多任务学习,在实践中,多任务学习的使用频率要低于迁移学习。我看到很多迁移学习的应用,你需要解决一个问题,但你的训练数据很少,所以你需要找一个数据很多的相关问题来预先学习,并将知识迁移到这个新问题上。但多任务学习比较少见,就是你需要同时处理很多任务,都要做好,你可以同时训练所有这些任务,也许计算机视觉是一个例子。在物体检测中,我们看到更多使用多任务学习的应用,其中一个神经网络尝试检测一大堆物体,比分别训练不同的神经网络检测物体更好。但我说,平均来说,目前迁移学习使用频率更高,比多任务学习频率要高,但两者都可以成为你的强力工具。
所以总结一下,多任务学习能让你训练一个神经网络来执行许多任务,这可以给你更高的性能,比单独完成各个任务更高的性能。但要注意,实际上迁移学习比多任务学习使用频率更高。我看到很多任务都是,如果你想解决一个机器学习问题,但你的数据集相对较小,那么迁移学习真的能帮到你,就是如果你找到一个相关问题,其中数据量要大得多,你就能以它为基础训练你的神经网络,然后迁移到这个数据量很少的任务上来。
今天我们学到了很多和迁移学习有关的问题,还有一些迁移学习和多任务学习的应用。但多任务学习,我觉得使用频率比迁移学习要少得多,也许其中一个例外是计算机视觉,物体检测。在那些任务中,人们经常训练一个神经网络同时检测很多不同物体,这比训练单独的神经网络来检测视觉物体要更好。但平均而言,我认为即使迁移学习和多任务学习工作方式类似。实际上,我看到用迁移学习比多任务学习要更多,我觉得这是因为你很难找到那么多相似且数据量对等的任务可以用单一神经网络训练。再次,在计算机视觉领域,物体检测这个例子是最显著的例外情况。
所以这就是多任务学习,多任务学习和迁移学习都是你的工具包中的重要工具。最后,我想继续讨论端到端深度学习,所以我们来看下一节来讨论端到端学习。
2.9 什么是端到端的深度学习
深度学习中最令人振奋的最新动态之一就是端到端深度学习的兴起,那么端到端学习到底是什么呢?简而言之,以前有一些数据处理系统或者学习系统,它们需要多个阶段的处理。那么端到端深度学习就是忽略所有这些不同的阶段,用单个神经网络代替它。
我们来看一些例子
以语音识别为例,你的目标是输入 x ,比如说一段音频,然后把它映射到一个输出 y ,就是这段音频的听写文本。所以传统上,语音识别需要很多阶段的处理。首先你会提取一些特征,一些手工设计的音频特征,也许你听过MFCC,这种算法是用来从音频中提取一组特定的人工设计的特征。在提取出一些低层次特征之后,你可以应用机器学习算法在音频片段中找到音位,所以音位是声音的基本单位,比如说“Cat”这个词是三个音节构成的,Cu-、Ah-和Tu-,算法就把这三个音位提取出来,然后你将音位串在一起构成独立的词,然后你将词串起来构成音频片段的听写文本。
所以和这种有很多阶段的流水线相比,端到端深度学习做的是,你训练一个巨大的神经网络,输入就是一段音频,输出直接是听写文本。
AI的其中一个有趣的社会学效应是,随着端到端深度学习系统表现开始更好,有一些花了大量时间或者整个事业生涯设计出流水线各个步骤的研究员,还有其他领域的研究员,不只是语言识别领域的,也许是计算机视觉,还有其他领域,他们花了大量的时间,写了很多论文,有些甚至整个职业生涯的一大部分都投入到开发这个流水线的功能或者其他构件上去了。而端到端深度学习就只需要把训练集拿过来,直接学到了 x 和 y 之间的函数映射,直接绕过了其中很多步骤。对一些学科里的人来说,这点相当难以接受,他们无法接受这样构建AI系统,因为有些情况,端到端方法完全取代了旧系统,某些投入了多年研究的中间组件也许已经过时了。
事实证明,端到端深度学习的挑战之一是,你可能需要大量数据才能让系统表现良好,比如,你只有3000小时数据去训练你的语音识别系统,那么传统的流水线效果真的很好。但当你拥有非常大的数据集时,比如10,000小时数据或者100,000小时数据,这样端到端方法突然开始很厉害了。所以当你的数据集较小的时候,传统流水线方法其实效果也不错,通常做得更好。你需要大数据集才能让端到端方法真正发出耀眼光芒。如果你的数据量适中,那么也可以用中间件方法,你可能输入还是音频,然后绕过特征提取,直接尝试从神经网络输出音位,然后也可以在其他阶段用,所以这是往端到端学习迈出的一小步,但还没有到那里。
这张图上是一个研究员做的人脸识别门禁,是百度的林元庆研究员做的。这是一个相机,它会拍下接近门禁的人,如果它认出了那个人,门禁系统就自动打开,让他通过,所以你不需要刷一个RFID工卡就能进入这个设施。系统部署在越来越多的中国办公室,希望在其他国家也可以部署更多,你可以接近门禁,如果它认出你的脸,它就直接让你通过,你不需要带RFID工卡。
那么,怎么搭建这样的系统呢?你可以做的第一件事是,看看相机拍到的照片,对吧?我想我画的不太好,但也许这是相机照片,你知道,有人接近门禁了,所以这可能是相机拍到的图像 x 。有件事你可以做,就是尝试直接学习图像 x 到人物 y 身份的函数映射,事实证明这不是最好的方法。其中一个问题是,人可以从很多不同的角度接近门禁,他们可能在绿色位置,可能在蓝色位置。有时他们更靠近相机,所以他们看起来更大,有时候他们非常接近相机,那照片中脸就很大了。在实际研制这些门禁系统时,他不是直接将原始照片喂到一个神经网络,试图找出一个人的身份。相反,迄今为止最好的方法似乎是一个多步方法,首先,你运行一个软件来检测人脸,所以第一个检测器找的是人脸位置,检测到人脸,然后放大图像的那部分,并裁剪图像,使人脸居中显示,然后就是这里红线框起来的照片,再喂到神经网络里,让网络去学习,或估计那人的身份。
研究人员发现,比起一步到位,一步学习,把这个问题分解成两个更简单的步骤。首先,是弄清楚脸在哪里。第二步是看着脸,弄清楚这是谁。这第二种方法让学习算法,或者说两个学习算法分别解决两个更简单的任务,并在整体上得到更好的表现。
顺便说一句,如果你想知道第二步实际是怎么工作的,我这里其实省略了很多。训练第二步的方式,训练网络的方式就是输入两张图片,然后你的网络做的就是将输入的两张图比较一下,判断是否是同一个人。比如你记录了10,000个员工ID,你可以把红色框起来的图像快速比较……也许是全部10,000个员工记录在案的ID,看看这张红线内的照片,是不是那10000个员工之一,来判断是否应该允许其进入这个设施或者进入这个办公楼。这是一个门禁系统,允许员工进入工作场所的门禁。
为什么两步法更好呢?实际上有两个原因。一是,你解决的两个问题,每个问题实际上要简单得多。但第二,两个子任务的训练数据都很多。
具体来说,有很多数据可以用于人脸识别训练,对于这里的任务1来说,任务就是观察一张图,找出人脸所在的位置,把人脸图像框出来,所以有很多数据,有很多标签数据(x,y),其中 x 是图片,y 是表示人脸的位置,你可以建立一个神经网络,可以很好地处理任务1。然后任务2,也有很多数据可用,今天,业界领先的公司拥有,比如说数百万张人脸照片,所以输入一张裁剪得很紧凑的照片,比如这张红色照片,下面这个,今天业界领先的人脸识别团队有至少数亿的图像,他们可以用来观察两张图片,并试图判断照片里人的身份,确定是否同一个人,所以任务2还有很多数据。相比之下,如果你想一步到位,这样 ( x , y )的数据对就少得多,其中 x 是门禁系统拍摄的图像,y 是那人的身份,因为你没有足够多的数据去解决这个端到端学习问题,但你却有足够多的数据来解决子问题1和子问题2。实际上,把这个分成两个子问题,比纯粹的端到端深度学习方法,达到更好的表现。不过如果你有足够多的数据来做端到端学习,也许端到端方法效果更好。但在今天的实践中,并不是最好的方法。
我们再来看几个例子,比如机器翻译
传统上,机器翻译系统也有一个很复杂的流水线,比如英语机翻得到文本,然后做文本分析,基本上要从文本中提取一些特征之类的,经过很多步骤,你最后会将英文文本翻译成法文。因为对于机器翻译来说的确有很多的数据对,端到端深度学习在机器翻译领域非常好用,那是因为在今天可以收集 x − y 对的大数据集,就是英文句子和对应的法语翻译。所以在这个例子中,端到端深度学习效果很好。
最后一个例子
比如说你希望观察一个孩子手部的X光照片,并估计一个孩子的年龄。这是儿科医生用来判断一个孩子的发育是否正常。处理这个例子的一个非端到端方法,就是照一张图,然后分割出每一块骨头,所以就是分辨出那段骨头应该在哪里,那段骨头在哪里,那段骨头在哪里,等等。然后,知道不同骨骼的长度,你可以去查表,查到儿童手中骨头的平均长度,然后用它来估计孩子的年龄,所以这种方法实际上很好。
相比之下,如果你直接从图像去判断孩子的年龄,那么你需要大量的数据去直接训练。据我所知,这种做法今天还是不行的,因为没有足够的数据来用端到端的方式来训练这个任务。
你可以想象一下如何将这个问题分解成两个步骤,第一步是一个比较简单的问题,也许你不需要那么多数据,也许你不需要许多X射线图像来切分骨骼。而任务二,收集儿童手部的骨头长度的统计数据,你不需要太多数据也能做出相当准确的估计,所以这个多步方法看起来很有希望,也许比端对端方法更有希望,至少直到你能获得更多端到端学习的数据之前
所以端到端深度学习系统是可行的,它表现可以很好,也可以简化系统架构,让你不需要搭建那么多手工设计的单独组件,但它也不是灵丹妙药,并不是每次都能成功。在下一节中,我想与你分享一个更系统的描述,什么时候你应该使用或者不应该使用端到端的深度学习,以及如何组装这些复杂的机器学习系统。
2.10 是否要使用端到端的深度学习
假设你正在搭建一个机器学习系统,你要决定是否使用端对端方法,我们来看看端到端深度学习的一些优缺点,这样你就可以根据一些准则,判断你的应用程序是否有希望使用端到端方法。
首先端到端学习真的只是让数据说话。所以如果你有足够多的 ( x , y )数据,那么不管从 x 到 y 最适合的函数映射是什么,如果你训练一个足够大的神经网络,希望这个神经网络能自己搞清楚,而使用纯机器学习方法,直接从 x 到 y 输入去训练的神经网络,可能更能够捕获数据中的任何统计信息,而不是被迫引入人类的成见。例如,在语音识别领域,早期的识别系统有这个音位概念,就是基本的声音单元,如cat单词的“cat”的C、A和T,我觉得这个音位是人类语言学家生造出来的,我实际上认为音位其实是语音学家的幻想,用音位描述语言也还算合理。但是不要强迫你的学习算法以音位为单位思考,这点有时没那么明显。如果你让你的学习算法学习它想学习的任意表示方式,而不是强迫你的学习算法使用音位作为表示方式,那么其整体表现可能会更好。
端到端深度学习的第二个好处就是这样,所需手工设计的组件更少,所以这也许能够简化你的设计工作流程,你不需要花太多时间去手工设计功能,手工设计这些中间表示方式。
那么缺点呢?这里有一些缺点,首先,它可能需要大量的数据。要直接学到这个 x 到 y 的映射,你可能需要大量 ( x , y )数据。我们在以前的视频里看过一个例子,其中你可以收集大量子任务数据,比如人脸识别,我们可以收集很多数据用来分辨图像中的人脸,当你找到一张脸后,也可以找得到很多人脸识别数据。但是对于整个端到端任务,可能只有更少的数据可用。所以 x 这是端到端学习的输入端,y 是输出端,所以你需要很多这样的 ( x , y ) 数据,在输入端和输出端都有数据,这样可以训练这些系统。这就是为什么我们称之为端到端学习,因为你直接学习出从系统的一端到系统的另一端
另一个缺点是,它排除了可能有用的手工设计组件。机器学习研究人员一般都很鄙视手工设计的东西,但如果你没有很多数据,你的学习算法就没办法从很小的训练集数据中获得洞察力。所以手工设计组件在这种情况,可能是把人类知识直接注入算法的途径,这总不是一件坏事。我觉得学习算法有两个主要的知识来源,一个是数据,另一个是你手工设计的任何东西,可能是组件,功能,或者其他东西。所以当你有大量数据时,手工设计的东西就不太重要了,但是当你没有太多的数据时,构造一个精心设计的系统,实际上可以将人类对这个问题的很多认识直接注入到问题里,进入算法里应该挺有帮助的。所以端到端深度学习的弊端之一是它把可能有用的人工设计的组件排除在外了,精心设计的人工组件可能非常有用,但它们也有可能真的伤害到你的算法表现。例如,强制你的算法以音位为单位思考,也许让算法自己找到更好的表示方法更好。所以这是一把双刃剑,可能有坏处,可能有好处,但往往好处更多,手工设计的组件往往在训练集更小的时候帮助更大。
如果你在构建一个新的机器学习系统,而你在尝试决定是否使用端到端深度学习,我认为关键的问题是,你有足够的数据能够直接学到从 x 映射到 y 足够复杂的函数吗?我还没有正式定义过这个词“必要复杂度(complexity needed)”。但直觉上,如果你想从 x 到 y 的数据学习出一个函数,
就是看着这样的图像识别出图像中所有骨头的位置,那么也许这像是识别图中骨头这样相对简单的问题,也许系统不需要那么多数据来学会处理这个任务。或给出一张人物照片,也许在图中把人脸找出来不是什么难事,所以你也许不需要太多数据去找到人脸,或者至少你可以找到足够数据去解决这个问题。相对来说,把手的X射线照片直接映射到孩子的年龄,直接去找这种函数,直觉上似乎是更为复杂的问题。如果你用纯端到端方法,需要很多数据去学习。
最后我讲一个更复杂的例子,你可能知道我一直在花时间帮忙主攻无人驾驶技术的公司drive.ai,无人驾驶技术的发展其实让我相当激动,你怎么造出一辆自己能行驶的车呢?好,这里你可以做一件事,这不是端到端的深度学习方法,你可以把你车前方的雷达、激光雷达或者其他传感器的读数看成是输入图像。但是为了说明起来简单,我们就说拍一张车前方或者周围的照片,然后驾驶要安全的话,你必须能检测到附近的车,你也需要检测到行人,你需要检测其他的东西,当然,我们这里提供的是高度简化的例子。弄清楚其他车和形如的位置之后,你就需要计划你自己的路线。所以换句话说,当你看到其他车子在哪,行人在哪里,你需要决定如何摆方向盘在接下来的几秒钟内引导车子的路径。如果你决定了要走特定的路径,也许这是道路的俯视图
这是你的车,也许你决定了要走那条路线,这是一条路线,那么你就需要摆动你的方向盘到合适的角度,还要发出合适的加速和制动指令。所以从传感器或图像输入到检测行人和车辆,深度学习可以做得很好,但一旦知道其他车辆和行人的位置或者动向,选择一条车要走的路,这通常用的不是深度学习,而是用所谓的运动规划软件完成的。如果你学过机器人课程,你一定知道运动规划,然后决定了你的车子要走的路径之后。还会有一些其他算法,我们说这是一个控制算法,可以产生精确的决策确定方向盘应该精确地转多少度,油门或刹车上应该用多少力。
所以这个例子就表明了,如果你想使用机器学习或者深度学习来学习某些单独的组件,那么当你应用监督学习时,你应该仔细选择要学习的 x 到 y 映射类型,这取决于那些任务你可以收集数据。相比之下,谈论纯端到端深度学习方法是很激动人心的,你输入图像,直接得出方向盘转角,但是就目前能收集到的数据而言,还有我们今天能够用神经网络学习的数据类型而言,这实际上不是最有希望的方法,或者说这个方法并不是团队想出的最好用的方法。而我认为这种纯粹的端到端深度学习方法,其实前景不如这样更复杂的多步方法。因为目前能收集到的数据,还有我们现在训练神经网络的能力是有局限的。
这就是端到端的深度学习,有时候效果拔群。但你也要注意应该在什么时候使用端到端深度学习。最后,谢谢你,恭喜你坚持到现在,如果你学完了本章所有内容,那么我认为你已经变得更聪明,更具战略性,并能够做出更好的优先分配任务的决策,更好地推动你的机器学习项目,也许比很多机器学习工程师,还有和我在硅谷看到的研究人员都强。所以恭喜你学到这里,我希望你能看看本周的作业,应该能再给你一个机会去实践这些理念,并确保你掌握它们。