1. 深度学习的优化策略
1.2 正交化 (Orthogonalization)
我留意到,那些效率很高的机器学习专家有个特点,他们思维清晰,对于要调整什么来达到某个效果,非常清楚,这个步骤我们称之为正交化。
举例来说,一辆车有三个主要控制,方向盘、油门和刹车,一个控制方向,另外两个控制你的速度,这样就比较容易解读,知道不同控制的不同动作会对车子运动有什么影响。
想象一下,如果有人这么造车,造了个手柄,手柄的一个轴控制的是转向角-速度,然后还有一个轴控制的是
转向角
车速,理论上来说,通过调整这两个旋钮你是可以将车子调整到你希望得到的角度和速度,但这样比单独控制转向角度、分开独立的速度控制要难得多。
所以正交化的概念是指,你需要2个维度,一个维度是控制转向角,另一个维度来控制你的速度,那么你就需要一个旋钮尽量只控制转向角,另一个旋钮,在这个开车的例子里其实是油门和刹车控制了你的速度。但如果你有一个控制旋钮将两者混在一起,比如说这样一个控制装置同时影响你的转向角和速度,同时改变了两个性质,那么就很难令你的车子以想要的速度和角度前进。
正交化之后,正交意味着互成90度。设计出正交化的控制装置,最理想的情况是和你实际想控制的性质一致,这样你调整参数时就容易得多。可以单独调整转向角,还有你的油门和刹车,令车子以你想要的方式运动。
当我训练神经网络时,我一般不用early stopping,这个技巧也还不错,很多人都这么干。但个人而言,我觉得用early stopping有点难以分析,因为这个旋钮会同时影响你对训练集的拟合,因为如果你早期停止,那么对训练集的拟合就不太好,但它同时也用来改善开发集的表现,所以这个旋钮没那么正交化。因为它同时影响两件事情,就像一个旋钮同时影响电视图像的宽度和高度。不是说这样就不要用,如果你想用也是可以的。但如果你有更多的正交化控制,比如我这里写出的其他手段,用这些手段调网络会简单不少。
When a supervised learning system is design, these are the 4 assumptions that needs to be true and orthogonal.
- Fit training set well in cost function
If it doesn’t fit well, the use of a bigger neural network or switching to a better optimization algorithm might help. - Fit development set well on cost function
If it doesn’t fit well, regularization or using bigger training set might help. - Fit test set well on cost function
If it doesn’t fit well, the use of a bigger development set might help. - Performs well in real world
If it doesn’t perform well, the development test set is not set correctly or the cost function is not evaluating the right thing.
1.3 单一数字评估指标
应用机器学习是一个非常经验性的过程,我们通常有一个想法,编程序,跑实验,看看效果如何,然后使用这些实验结果来改善你的想法,然后继续走这个循环,不断改进你的算法。
比如说对于你的猫分类器,之前你搭建了某个分类器,通过改变超参数,还有改变训练集等手段,你现在训练出来了一个新的分类器B,所以评估你的分类器的一个合理方式是观察它的查准率(precision)和查全率(recall)。
查准率和查全率的确切细节对于这个例子来说不太重要。简而言之,查准率的定义是在你的分类器标记为猫的例子中,有多少真的是猫。所以如果分类器有95%的查准率,这意味着你的分类器说这图有猫的时候,有95%的机会真的是猫。
查全率就是,对于所有真猫的图片,你的分类器正确识别出了多少百分比。实际为猫的图片中,有多少被系统识别出来?如果分类器查全率是90%,这意味着对于所有的图像,比如说你的开发集都是真的猫图,分类器
准确地分辨出了其中的90%。
查准率和查全率之间往往需要折衷,两个指标都要顾及到。你希望得到的效果是,当你的分类器说某个东西是猫的时候,有很大的机会它真的是一只猫,但对于所有是猫的图片,你也希望系统能够将大部分分类为猫,所以用查准率和查全率来评估分类器是比较合理的。
但使用查准率和查全率作为评估指标的时候,有个问题,如果分类器在查全率上表现更好,分类器
在查准率上表现更好,你就无法判断哪个分类器更好。如果有两个评估指标,就很难去快速地二中选一或者十中选一,所以我并不推荐使用两个评估指标。你只需要找到一个新的评估指标,能够结合查准率和查全率。
在机器学习文献中,结合查准率和查全率的标准方法是所谓的分数,
分数的细节并不重要。但非正式的,你可以认为这是查准率
和查全率
的平均值。正式来看,
分数的定义是这个公式:
。在数学中,这个函数叫做查准率
和查全率
的调和平均数。
所以本节介绍的是,有一个单实数评估指标真的可以提高你的效率,或者提高你的团队做出这些决策的效率。现在我们还没有完整讨论如何有效地建立评估指标。在下一个视频中,我会教你们如何设置优化以及满足指标。
1.4 满足和优化指标
假设你已经决定你很看重猫分类器的分类准确度,这可以是分数或者用其他衡量准确度的指标。但除了准确度之外,我们还需要考虑运行时间,就是需要多长时间来分类一张图。
你可以将准确度和运行时间组合成一个整体评估指标。所以成本,比如说,总体成本是,两个数值的线性加权求和。
你还可以选择一个分类器,能够最大限度提高准确度,但必须满足运行时间要求,比如对图像进行分类所需的时间必须小于等于100毫秒。在这种情况下,我们就说准确度是一个优化指标,因为你想要准确度最大化,你想做的尽可能准确,但是运行时间就是我们所说的满足指标,意思是它只需要满足即可,而不在乎它满足条件后有多好。所以这是一个相当合理的权衡方式,或者说将准确度和运行时间结合起来的方式。
所以更一般地说,如果你要考虑个指标,有时候选择其中一个指标做为优化指标是合理的。所以你想尽量优化那个指标,然后剩下
个指标都是满足指标,意味着只要它们达到一定阈值,你不在乎它超过那个门槛之后的表现,但它们必须达到这个门槛。
1.5 训练/开发/测试集
同分布
设立开发集以及评估指标,真的就定义了你要瞄准的目标。我们希望在同一分布中建立开发集和测试集,因为设立你的开发集加上一个单实数评估指标,这就是像是定下靶心,然后使用不同方法去逼近目标,然后不断迭代,不断逼近靶心。如果开发集和测试集来自不同的分布,就像你设了一个目标,让你的团队花几个月尝试逼近靶心,结果在几个月工作之后测试的时候,你说“等等,我要把目标移到这里”。
所以,为了避免这种情况,我建议的是你将所有数据随机洗牌,放入开发集和测试集,所以开发集和测试集都有来自八个地区的数据,并且开发集和测试集都来自同一分布,这分布就是你的所有数据混在一起。
划分比例
Guidelines
- Set up the size of the test set to give a high confidence in the overall performance of the system.
- Test set helps evaluate the performance of the final classifier which could be less 30% of the whole data set.
- The development set has to be big enough to evaluate different ideas.
你可能听说过一条经验法则,在机器学习中,把你取得的全部数据用70/30比例分成训练集和测试集。或者如果你必须设立训练集、开发集和测试集,你会这么分60%训练集,20%开发集,20%测试集。在机器学习的早期,这样分是相当合理的,因为以前的数据集大小要小得多。如果你总共有100个样本,这样70/30或者60/20/20分的经验法则是合理的。如果你有几千个样本或者有一万个样本,这些做法也是合理的。
但在现代机器学习中,我们更习惯操作规模大得多的数据集,比如说你有1百万个训练样本,这样分可能更合理,98%作为训练集,1%开发集,1%测试集,我们用和
缩写来表示开发集和测试集。因为如果你有1百万个样本,那么1%就是10,000个样本,这对于开发集和测试集来说可能已经够了。
要记住,测试集的目的是完成系统开发之后,测试集可以帮你评估投产系统的性能。方针就是,令你的测试集足够大,能够以高置信度评估系统整体性能。所以除非你需要对最终投产系统有一个很精确的指标,一般来说测试集不需要上百万个例子。对于你的应用程序,也许你想,有10,000个例子就能给你足够的置信度来给出性能指标了,也许100,000个之类的可能就够了,这数目可能远远小于比如说整体数据集的30%,取决于你有多少数据。
对于某些应用,你也许不需要对系统性能有置信度很高的评估,也许你只需要训练集和开发集dev set,我认为,不单独分出一个测试集也是可以的。事实上,有时在实践中有些人会只分成训练集和测试集,他们实际上在测试集上迭代,所以这里没有测试集,他们有的是训练集和开发集,但没有测试集。不过在机器学习的历史里,不是每个人都把术语定义分得很清的,有时人们说的开发集,其实应该看作测试集。但如果你只要有数据去训练,有数据去调试就够了。
什么时候该改变开发/测试集和指标?
前面讲了如何设置开发集和评估指标,就像是把目标定在某个位置,让你的团队瞄准。但有时候在项目进行途中,你可能意识到,目标的位置放错了。这种情况下,你应该移动你的目标。
Guideline
- Define correctly an evaluation metric that helps better rank order classifiers
- Optimize the evaluation metric
举例
算法由于某些原因,把很多色情图像分类成猫了。如果你部署算法
,那么用户就会看到更多猫图,因为它识别猫的错误率只有3%,但它同时也会给用户推送一些色情图像。相比之下,算法
有5%的错误率,这样分类器就得到较少的图像,但它不会推送色情图像。所以从你们公司的角度来看,以及从用户接受的角度来看,算法
实际上是一个更好的算法,因为它不让任何色情图像通过。那么在这个例子中,算法A在评估指标上做得更好,但实际上是个更糟糕的算法。
当你的评估指标无法正确衡量算法之间的优劣排序时,原来的指标错误地预测算法A是更好的算法这就发出了信号,你应该改变评估指标了,或者要改变开发集或测试集。在这种情况下,你用的分类错误率指标可以写成这样:
%7D%20%5Cneq%20y%5E%7B(i)%7D%5C%7D%7D#card=math&code=Error%20%3D%20%5Cfrac%7B1%7D%7Bm%7B%7Bdev%7D%7D%7D%5Csum%7Bi%20%3D%201%7D%5E%7Bm%7B%7Bdev%7D%7D%7D%7BI%5C%7B%20y%7B%7Bpred%7D%7D%5E%7B%28i%29%7D%20%5Cneq%20y%5E%7B%28i%29%7D%5C%7D%7D&id=yG6ae)
是你的开发集例子数,用
%7D#card=math&code=y_%7B%7Bpred%7D%7D%5E%7B%28i%29%7D&id=CLH5y)表示预测值,其值为0或1,
这符号表示一个函数,统计出里面这个表达式为真的样本数,所以这个公式统计了分类错误的样本。
这个评估指标的问题在于,它对色情图片和非色情图片一视同仁,但你其实真的希望你的分类器不会错误标记色情图像。其中一个修改评估指标的方法是,这里(与
%7D%20%5Cneq%20y%5E%7B(i)%7D%5C%7D%7D#card=math&code=%5Csum%7Bi%20%3D1%7D%5E%7Bm%7B%7Bdev%7D%7D%7D%7BI%5C%7B%20y_%7B%7Bpred%7D%7D%5E%7B%28i%29%7D%20%5Cneq%20y%5E%7B%28i%29%7D%5C%7D%7D&id=ScNXB)之间)加个权重项,即:
%7DI%5C%7B%20y%7B%7Bpred%7D%7D%5E%7B(i)%7D%20%5Cneq%20y%5E%7B(i)%7D%5C%7D%7D#card=math&code=Error%20%3D%20%5Cfrac%7B1%7D%7Bm%7B%7Bdev%7D%7D%7D%5Csum%7Bi%20%3D%201%7D%5E%7Bm%7B%7Bdev%7D%7D%7D%7Bw%5E%7B%28i%29%7DI%5C%7B%20y_%7B%7Bpred%7D%7D%5E%7B%28i%29%7D%20%5Cneq%20y%5E%7B%28i%29%7D%5C%7D%7D&id=DVO0U)
我们将这个称为%7D#card=math&code=w%5E%7B%5Cleft%28%20i%20%5Cright%29%7D&id=QLeWQ),其中如果图片
%7D#card=math&code=x%5E%7B%28i%29%7D&id=jro7N)不是色情图片,则
%7D%20%3D%201#card=math&code=w%5E%7B%5Cleft%28%20i%20%5Cright%29%7D%20%3D%201&id=CoCqt)。如果
%7D#card=math&code=x%5E%7B%28i%29%7D&id=TYPI5)是色情图片,
%7D#card=math&code=w%5E%7B%28i%29%7D&id=LQQS6)可能就是10甚至100,这样你赋予了色情图片更大的权重,让算法将色情图分类为猫图时,错误率这个项快速变大。这个例子里,你把色情图片分类成猫这一错误的惩罚权重加大10倍。如果你希望得到归一化常数,在技术上,就是
%7D#card=math&code=w%5E%7B%28i%29%7D&id=pQuWb)对所有
求和,这样错误率仍然在0和1之间,即:
%7D%7D%5Csum%7Bi%20%3D%201%7D%5E%7Bm%7B%7Bdev%7D%7D%7D%7Bw%5E%7B(i)%7DI%5C%7B%20y%7B%7Bpred%7D%7D%5E%7B(i)%7D%20%5Cneq%20y%5E%7B(i)%7D%5C%7D%7D#card=math&code=Error%20%3D%20%5Cfrac%7B1%7D%7B%5Csum%7B%7D%5E%7B%7Dw%5E%7B%28i%29%7D%7D%5Csum%7Bi%20%3D%201%7D%5E%7Bm%7B%7Bdev%7D%7D%7D%7Bw%5E%7B%28i%29%7DI%5C%7B%20y_%7B%7Bpred%7D%7D%5E%7B%28i%29%7D%20%5Cneq%20y%5E%7B%28i%29%7D%5C%7D%7D&id=XQVAl)
加权的细节并不重要。实际上要使用这种加权,你必须自己过一遍开发集和测试集,在开发集和测试集里,自己把色情图片标记出来,这样你才能使用这个加权函数。
但粗略的结论是,如果你的评估指标无法正确评估好算法的排名,那么就需要花时间定义一个新的评估指标。这是定义评估指标的其中一种可能方式(上述加权法)。评估指标的意义在于,准确告诉你已知两个分类器,哪一个更适合你的应用。
就本节内容而言,我们不需要太注重新错误率指标是怎么定义的,关键在于,如果你对旧的错误率指标不满意,那就不要一直沿用你不满意的错误率指标,而应该尝试定义一个新的指标,能够更加符合你的偏好,定义出实际更适合的算法。
你可能注意到了,到目前为止我们只讨论了如何定义一个指标去评估分类器,也就是说,我们定义了一个评估指标帮助我们更好的把分类器排序,能够区分出它们在识别色情图片的不同水平,这实际上是一个正交化的例子。
我想你处理机器学习问题时,应该把它切分成2个独立的步骤。
- 定义评价指标,也就是设定目标。
- 考虑怎么逼近这个目标。比如最小化训练集上的损失。
这里关键在于正交化的思路,把设立目标定为第一步,然后瞄准和射击目标是独立的第二步。换种说法,我鼓励你们将定义指标看成一步,然后在定义了指标之后,你才能想如何优化系统来提高这个指标评分。
再讲一个例子。假设你的两个猫分类器和
,做评估用的是很漂亮的高分辨率的开发集和测试集,
和
分别得到3%的错误率和5%的错误率。但也许你发现当你部署到手机应用时,算法作用到用户上传的图片时,那些图片取景不专业,出现猫不完整、表情古怪、图像模糊等情况,这时你发现算法
表现其实更好。
这种情况下就需要修改指标或者你的开发测试集。
总体方针就是,如果你当前的指标和当前用来评估的数据和你真正关心必须做好的事情关系不大,那就应该更改你的指标或者你的开发测试集,让它们能更够好地反映你的算法需要处理好的数据。
有一个评估指标和开发集让你可以更快做出决策,判断算法还是算法
更优,这真的可以加速你和你的团队迭代的速度。所以我的建议是,即使你无法定义出一个很完美的评估指标和开发集,你直接快速设立出来,然后使用它们来驱动你们团队的迭代速度。如果在这之后,你发现选的不好,你有更好的想法,那么完全可以马上改。
2. 改善模型表现
2.1 误差分析
我会建立一个表格,在最左边,人工过一遍你想分析的错误图像集,每列对应你要评估的想法,比如错误的样本是狗、是猫科动物,或者是模糊的问题,我通常也在电子表格中留下一列来写评论。在错误分析过程中,你就看看算法识别错误的开发集样本,如果你发现第一张识别错误的图片是狗图,那么我就在那里打个勾,为了帮我自己记住这些图片,有时我会在评论里注释,也许这是一张比特犬的图。如果第二张照片很模糊,也记一下。如果第三张是在下雨天动物园里的狮子,被识别成猫了,这是大型猫科动物,还有图片模糊,在评论部分写动物园下雨天,是雨天让图像模糊的之类的。
最后,这组图像过了一遍之后,我可以统计这些算法(错误)的百分比,或者这里每个错误类型的百分比,有多少是狗,大猫或模糊这些错误类型。所以也许你检查的图像中8%是狗,可能43%属于大猫,61%属于模糊。
总结以下,错误分析就是通过统计不同错误标记类型占总数的百分比,可以帮你发现哪些问题需要优先解决,或者给你构思新优化方向的灵感。
2.2 样本标记错误
如果你发现你的数据有一些标记错误的样本,你该怎么办?首先,我们来考虑训练集,事实证明,深度学习算法对于训练集中的随机错误是相当健壮的(robust)。标记错误的原因可能是做标记的人没有注意或者不小心按错键了,如果是这样随机的错误,那么放着这些错误不管可能也没问题,只要总数据集总足够大,实际错误率可能不会太高。
深度学习算法对随机误差很健壮,但对系统性的错误就没那么健壮了。所以比如说,如果做标记的人一直把白色的狗标记成猫,那就成问题了。因为你的分类器学习之后,会把所有白色的狗都分类为猫。
所以现在问题是,是否值得修正标记出错的样本。我的建议是,如果这些标记错误严重影响了你在开发集上评估算法的能力,那么就应该去花时间修正错误的标签。但是,如果它们没有严重影响到你用开发集评估成本偏差的能力,那么可能就不应该花宝贵的时间去处理。同样的,你需要通过误差分析来做决定。
如果你的开发集上有10%错误,其中0.6%是因为标记出错,剩下的占9.4%,是其他原因导致的,比如把狗误认为猫,大猫图片。所以在这种情况下,我说有9.4%错误率需要集中精力修正,而标记出错导致的错误是总体错误的一小部分而已,所以如果你一定要这么做,你也可以手工修正各种错误标签,但也许这不是当下最重要的任务。
我们再看另一个样本,假设你在学习问题上取得了很大进展,错误率降到了2%,但总体错误中的0.6%还是标记出错导致的,标记错误占错误结果的30%。所以现在,似乎修正开发集里的错误标签似乎更有价值。
现在如果你决定要去修正开发集数据,手动重新检查标签,并尝试修正一些标签,你最好对开发集和测试集做同样的修正以确保它们继续来自相同的分布。
其次,我强烈建议你要考虑同时检验算法判断正确和判断错误的样本,要检查算法出错的样本很容易,只需要看看那些样本是否需要修正,但还有可能有些样本算法判断正确,也需要修正。因为算法有可能因为运气好把某个东西判断对了,在那个特例里,修正那些标签可能会让算法从判断对变成判断错。这第二点不算很容易做,因为如果你的分类器很准确,那么判断错的次数比判断正确的次数要少得多。那么就有2%出错,98%都是对的,所以更容易检查2%数据上的标签,然而检查98%数据上的标签要花的时间长得多,所以通常不这么做。但也是要考虑到的。
最后,修正训练集中的标签其实相对没那么重要,你可能决定只修正开发集和测试集中的标签,因为它们通常比训练集小得多,你可能不想把所有额外的精力投入到修正大得多的训练集中的标签,所以这样其实是可以的。你的开发集和测试集来自同一分布非常重要。但如果你的训练集来自稍微不同的分布,通常这是一件很合理的事情,我会在本周晚些时候谈谈如何处理这个问题。
2.4 来自不同分布的数据划分
现在你有两个数据来源,一个是你真正关心的数据分布,来自用户上传的数据,另一个数据来源是你在网络上爬虫获得的高质量图片。
假设你的应用用户数还不多,目前收集到1万张用户上传的照片,而你从互联网上下载了超过20万张猫图。你真正关心的算法表现是处理来自应用程序的这个图片分布时效果好不好,困境在于,这20万张图片并不完全来自你想要的分布,那么你可以怎么做呢?
这里有一种选择,你可以做的一件事是将两组数据合并在一起,这样你就有21万张照片,你可以把这21万张照片随机分配到训练、开发和测试集中。我们假设你已经确定开发集和测试集各包含2500个样本,训练集有205000个样本。现在这么设立你的数据集有一些好处,也有坏处。好处在于,你的训练集、开发集和测试集都来自同一分布,这样更好管理。但坏处在于,这坏处还不小,你的开发集并不是你真正关心的数据分布,你真正要处理的是来自手机用户的图片,它在开发集中按比例计算,大概只有张。
要记住,设立开发集的目的是告诉你的团队去瞄准的目标,而你瞄准目标的方式,你的大部分精力都用在优化来自网页下载的图片,这其实不是你想要的。所以我真的不建议使用这种方法,因为这样设立的开发集是针对不同于你实际关心的数据分布去优化,所以不要这么做。
我建议的划分方法是,训练集,比如说还是205,000张图片,来自网页下载的200,000张图片加上5000张来自手机上传的图片。然后对于开发集和测试集各是2500张来自应用的图片。这样开发集包含的数据全部来自手机上传,这是你真正关心的图片分布。缺点在于现在你的训练集分布和你的开发集、测试集分布并不一样。但事实证明,这样把数据分成训练、开发和测试集,在长期能给你带来更好的系统性能。我们以后会讨论一些特殊的技巧,可以处理训练集的分布和开发集和测试集分布不一样的情况。
2.5 数据分布不同时误差分析
估计学习算法的偏差和方差真的可以帮你确定接下来应该优先做的方向,但是,当你的训练集来自和开发集、测试集不同分布时,分析偏差和方差的方式可能不一样。
我们继续用猫分类器为例,我们说人类在这个任务上能做到几乎完美,所以贝叶斯错误率或者说贝叶斯最优错误率几乎是0%。所以要进行错误率分析,你通常需要看训练误差,也要看看开发集的误差。假设在这个样本中,你的训练集误差是1%,开发集误差是10%,如果你的开发集来自和训练集一样的分布,那么这里可能存在很大的方差问题。
但如果你的训练数据和开发数据来自不同的分布,你就不能再放心下这个结论了。很难确认这增加的9%误差率有多少是因为算法没看到开发集中的数据导致的,这是问题方差的部分,有多少是因为开发集数据分布不一样。
为了弄清楚哪个因素影响更大,定义一组新的数据是有意义的,我们称之为训练-开发集,所以这是一个新的数据子集。它是从训练集的分布里随机分出的一部分数据,但你不会用它来训练你的网络。进行误差分析,你应该做的是看看分类器在训练集上的误差,训练-开发集上的误差,还有开发集上的误差。
- 如果在训练-开发集上的错误率比训练集的错误率上升了很多,我们就能确定这里确实存在方差问题。尽管你的神经网络在训练集中表现良好,但无法泛化到来自相同分布的训练-开发集里,它无法很好地泛化推广到来自同一分布,但以前没见过的数据中。
- 假设训练误差为1%,训练-开发误差为1.5%,但当你开始处理开发集时,错误率上升到10%。现在你的方差问题就很小了,所以这是数据不匹配的问题。
- 假设训练误差是10%,训练-开发误差是11%,开发误差为12%,要记住,人类水平对贝叶斯错误率的估计大概是0%,如果你得到了这种等级的表现,那就真的存在偏差问题了。存在可避免偏差问题,因为算法做的比人类水平差很多,所以这里的偏差真的很高。
- 最后一个例子,如果你的训练集错误率是10%,你的训练-开发错误率是11%,开发错误率是20%,那么这其实有两个问题。第一,可避免偏差相当高,因为你在训练集上都没有做得很好,而人类能做到接近0%错误率,但你的算法在训练集上错误率为10%。这里方差似乎很小,但数据不匹配问题很大。所以对于这个样本,我说,如果你有很大的偏差或者可避免偏差问题,还有数据不匹配问题。
总的来说,我们要看的关键数据是人类水平错误率,训练集错误率,训练-开发集错误率,开发/训练集错误率。根据这些错误率之间差距有多大,你可以大概知道,可避免偏差、方差数据不匹配问题各自有多大。
- 你希望算法至少要在训练集上的表现接近人类,这大概表明了方差大小。
- 从训练集泛化推广到训练-开发集时效果如何?而这告诉你数据不匹配的问题大概有多大。
- 测试集错误率的差距就说明你对开发集过拟合的程度,所以如果开发集表现和测试集表现有很大差距,那么你可能对开发集过拟合了,所以也许你需要一个更大的开发集,对吧?要记住,你的开发集和测试集来自同一分布,所以这里存在很大差距的话。如果算法在开发集上做的很好,比测试集好得多,那么你就可能对开发集过拟合了。如果是这种情况,那么你可能要往回退一步,然后收集更多开发集数据。
- 这里还有个例子,算法在开发集上做的更好。有时候如果你的开发测试集分布比你应用实际处理的数据要容易得多,那么这些错误率可能真的会下降。
2.6 处理数据不匹配问题
这个问题没有完全系统的解决方案,但我们可以看看一些可以尝试的事情。
首先尝试弄清楚开发集和训练集到底有什么不同。比如你正在开发一个语音激活的后视镜应用,你可能会发现很多开发集样本有汽车噪音,也许你还会发现其他错误,比如它经常识别错误街道号码,因为很多导航请求都有街道地址,得到正确的街道号码很重要。
你可以尝试把训练数据变得更像开发集一点,或者,你也可以收集更多类似你的开发集和测试集的数据。所以,对于上面的汽车噪音和识别错误街道号码,你可以模拟车辆噪声数据,以及有意识地收集更多人们说数字的音频数据,加到你的训练集里。
你可以利用的一种技术是人工合成数据(artificial data synthesis)。在解决汽车噪音问题时,你可以收集一段汽车噪音,把它与清晰的音频合成,是一个相对简单的音频合成例子。在实践中,你可能会合成其他音频效果,比如混响,就是声音从汽车内壁上反弹叠加的效果。这样就不需要花时间实际出去收集数据,录上万小时的音频。
人工数据合成有一个潜在问题,比如说,你只录了一小时车辆背景噪音,你的学习算法可能会对这1小时汽车噪音过拟合。而对于人耳来说,这些音频听起来没什么问题,因为一小时的车辆噪音对人耳来说,听起来和其他任意一小时车辆噪音是一样的。所以这组汽车里录的音频可能是你可以想象的所有汽车噪音背景的集合,但实际上可能你只模拟了全部数据空间的一小部分,你只是从汽车噪音的很小的子集来合成数据,但你自己没意识到。
2.7 迁移学习
有的时候神经网络可以从一个任务中习得知识,并将这些知识应用到另一个独立的任务中。所以例如,也许你已经训练好一个神经网络,能够识别像猫这样的对象,然后使用那些知识,或者部分习得的知识去帮助您更好地阅读x射线扫描图,这就是所谓的迁移学习。
你可以做的是把神经网络最后的输出层删掉,还有进入到最后一层的权重删掉,然后为最后一层重新赋予随机权重,然后让它在放射诊断数据上训练。如果你有足够多的数据,你可以重新训练神经网络中的所有层。
如果你重新训练神经网络中的所有参数,那么这个图像识别数据的训练阶段,有时称为预训练(pre-training),因为你在用图像识别数据去预先初始化,或者预训练神经网络的权重。然后你在放射科数据上训练,有时这个过程叫微调(fine tuning)。预训练和微调的权重来源于迁移学习。
在这个例子中,我们把图像识别中学到的知识应用或迁移到放射科诊断上来,为什么这样做有效果呢?有很多低层次特征,比如说边缘检测、曲线检测、阳性对象检测(positive objects),从非常大的图像识别数据库中习得这些能力可能有助于你的学习算法在放射科诊断中做得更好,算法学到了很多结构信息,图像形状的信息,其中一些知识可能会很有用,所以学会了图像识别,它就可能学到足够多的信息,可以了解不同图像的组成部分是怎样的,学到线条、点、曲线这些知识,也许对象的一小部分,这些知识有可能帮助你的放射科诊断网络学习更快一些,或者需要更少的学习数据。
再举另一个例子,假设你已经训练出一个语音识别系统,让它输出听写文本。现在我们说你想搭建一个“唤醒词”或“触发词”检测系统,可以唤醒家里的语音控制设备。要做到这点,你可能需要去掉神经网络的最后一层,然后加入新的输出节点,但有时你可以不只加入一个新节点,或者甚至往你的神经网络加入几个新层,然后把唤醒词检测问题的标签喂进去训练。再次,这取决于你有多少数据,你可能只需要重新训练网络的新层,也许你需要重新训练神经网络中更多的层。
那么迁移学习什么时候是有意义的呢?迁移学习起作用的场合是,在迁移来源问题中你有很多数据,但迁移目标问题你没有那么多数据。对于语音识别,也许你已经用10,000小时数据训练过你的语言识别系统,所以你从这10,000小时数据学到了很多人类声音的特征,这数据量其实很多了。但对于触发字检测,也许你只有1小时数据,所以这数据太小,不能用来拟合很多参数。所以在这种情况下,预先学到很多人类声音的特征人类语言的组成部分等等知识,可以帮你建立一个很好的唤醒字检测器,即使你的数据集相对较小。
但是反过来,如果你的目标问题的训练数据比迁移来源问题中的数据大,迁移学习可能就没有意义了。比如现在有一个用100张图训练的猫狗识别系统,然后你用100甚至1000张图用于训练放射科诊断系统,那么你这100张猫猫狗狗或者随机物体的图片肯定不会有太大帮助,因为来自猫狗识别任务中,每一张图的价值肯定不如一张射线扫描图有价值。同样,如果你用10小时数据训练出一个语音识别系统。然后你实际上有10个小时甚至更多,比如说50个小时唤醒字检测的数据,你知道迁移学习有可能会有帮助,也可能不会,也许把这10小时数据迁移学习不会有太大坏处,但是你也别指望会得到有意义的增益。
什么时候迁移学习是有意义的?
- 如果你想从任务
学习并迁移一些知识到任务
,那么当任务
和任务
都有同样的输入
时,迁移学习是有意义的。在第一个例子中,
和
的输入都是图像,在第二个例子中,两者输入都是音频。当任务
的数据比任务
多得多时,迁移学习意义更大。
- 所有这些假设的前提都是,你希望提高任务
的性能,因为任务
每个数据更有价值,对任务
来说通常任务
的数据量必须大得多,才有帮助,因为任务
里单个样本的价值没有比任务
单个样本价值大。
- 如果你觉得任务
的低层次特征,可以帮助任务
的学习,那迁移学习更有意义一些。
所以总结一下,迁移学习最有用的场合是,如果你尝试优化任务B的性能,通常这个任务数据相对较少。在这种情况下,你可能会找一个相关但不同的任务,如图像识别,其中你可能用1百万张图片训练过了,并从中学到很多低层次特征,所以那也许能帮助网络在任务在放射科任务上做得更好,尽管任务
没有这么多数据。
2.8 多任务学习
在迁移学习中,你的步骤是串行的,你从任务里学习只是然后迁移到任务
。在多任务学习中,你是同时开始学习的,试图让单个神经网络同时做几件事情,然后希望这里每个任务都能帮到其他所有任务。
我们来看一个例子,假设你在研发无人驾驶车辆,你的无人驾驶车可能需要同时检测不同的物体,比如检测行人、车辆、停车标志,还有交通灯,那么这里不再是一个标签 %7D#card=math&code=y%5E%7B%28i%29%7D&id=Zu4Yt),而是有4个标签。如果你从整体来看这个训练集标签和以前类似,我们将训练集的标签水平堆叠起来,像这样
%7D#card=math&code=y%5E%7B%281%29%7D&id=BOy9p)一直到
%7D#card=math&code=y%5E%7B%28m%29%7D&id=DcX3o):
%7D%20%26%20y%5E%7B(2)%7D%20%26%20y%5E%7B(3)%7D%20%26%20%5Cldots%20%26%20y%5E%7B(m)%7D%20%5C%5C%0A%7C%20%26%20%7C%20%26%20%7C%20%26%20%5Cldots%20%26%20%7C%20%5C%5C%0A%5Cend%7Bbmatrix%7D%0A#card=math&code=Y%20%3D%20%5Cbegin%7Bbmatrix%7D%0A%7C%20%26%20%7C%20%26%20%7C%20%26%20%5Cldots%20%26%20%7C%20%5C%5C%0Ay%5E%7B%281%29%7D%20%26%20y%5E%7B%282%29%7D%20%26%20y%5E%7B%283%29%7D%20%26%20%5Cldots%20%26%20y%5E%7B%28m%29%7D%20%5C%5C%0A%7C%20%26%20%7C%20%26%20%7C%20%26%20%5Cldots%20%26%20%7C%20%5C%5C%0A%5Cend%7Bbmatrix%7D%0A&id=r0OmY)
不过现在%7D#card=math&code=y%5E%7B%28i%29%7D&id=Bqwrb)是4×1向量,所以这些都是竖向的列向量,所以这个矩阵
现在变成
矩阵。而之前,当
是单实数时,这就是
矩阵。
那么你现在可以做的是训练一个神经网络,来预测这些值。这里输出我画了四个节点,所以第一个节点就是我们想预测图中有没有行人,然后第二个输出节点预测的是有没有车,这里预测有没有停车标志,这里预测有没有交通灯,所以
是四维的。
要训练这个神经网络,你现在需要定义神经网络的损失函数,对于一个输出,是个4维向量,对于整个训练集的平均损失:
%7D%2Cy%7Bj%7D%5E%7B(i)%7D)%7D%7D#card=math&code=%5Cfrac%7B1%7D%7Bm%7D%5Csum%7Bi%20%3D%201%7D%5E%7Bm%7D%7B%5Csum%7Bj%20%3D%201%7D%5E%7B4%7D%7BL%28%5Chat%20y%7Bj%7D%5E%7B%28i%29%7D%2Cy_%7Bj%7D%5E%7B%28i%29%7D%29%7D%7D&id=Gawd4)
%7D%2Cy%7Bj%7D%5E%7B(i)%7D)%7D#card=math&code=%5Csum%7Bj%20%3D%201%7D%5E%7B4%7D%7BL%28%5Chat%20y%7Bj%7D%5E%7B%28i%29%7D%2Cy%7Bj%7D%5E%7B%28i%29%7D%29%7D&id=bXIVi)是单个预测的损失,是对四个分量的求和,行人、车、停车标志、交通灯,L指的是logistic损失,我们就这么写:
%7D%2Cy%7Bj%7D%5E%7B(i)%7D)%20%3D%20-%20y%7Bj%7D%5E%7B(i)%7D%5Clog%5Chat%20y%7Bj%7D%5E%7B(i)%7D%20-%20(1%20-%20y%7Bj%7D%5E%7B(i)%7D)log(1%20-%20%5Chat%20y%7Bj%7D%5E%7B(i)%7D)#card=math&code=L%28%5Chat%20y%7Bj%7D%5E%7B%28i%29%7D%2Cy%7Bj%7D%5E%7B%28i%29%7D%29%20%3D%20-%20y%7Bj%7D%5E%7B%28i%29%7D%5Clog%5Chat%20y%7Bj%7D%5E%7B%28i%29%7D%20-%20%281%20-%20y%7Bj%7D%5E%7B%28i%29%7D%29log%281%20-%20%5Chat%20y_%7Bj%7D%5E%7B%28i%29%7D%29&id=uC3Kd)
整个训练集的平均损失和之前分类猫的例子主要区别在于,现在你要对到4求和,这与softmax回归的主要区别在于,与softmax回归不同,softmax将单个标签分配给单个样本。
在上一张幻灯片中,那张图同时有车和停车标志,但没有行人和交通灯,所以你不是只给图片一个标签,而是需要遍历不同类型,然后看看那类物体有没有出现在图中。因为你现在做的是建立单个神经网络,观察每张图,然后解决四个问题,也就是系统试图告诉你每张图里面有没有这四个物体,这就是多任务学习。
另一个细节,多任务学习也可以处理图像只有部分物体被标记的情况。比如第一个训练样本,给数据贴标签的人告诉你,这里面有一个行人、没有车,但他们没有标记是否有停车标志,也没有标记是否有交通灯。也许第二个例子中,有行人,有车,但是没有标记是否有停车标志,是否有交通灯等等。也许有些样本都有标记,但也许有些样本他们只标记了有没有车,然后还有一些是问号。
即使是这样的数据集,你也可以在上面训练算法,同时做四个任务。你训练算法的方式,即使这里有些标签是问号,或者没有标记,还是对从1到4求和,你就只对带0和1标签的
值求和,忽略问号那个项。这样只对有标签的值求和,于是你就能利用这样的数据集。
那么多任务学习什么时候有意义呢?当三件事为真时,它就是有意义的。
第一,如果你训练的一组任务,可以共用低层次特征。对于无人驾驶的例子,同时识别交通灯、汽车和行人是有道理的,这些物体有相似的特征,也许能帮你识别停车标志,因为这些都是道路上的特征。
第二,这个准则没有那么绝对,所以不一定是对的。想想前面讲的迁移学习,你从任务学到知识然后迁移到
任务,所以如果任务
的样本数远大于任务
的样本数,那么你从A学到的知识真的可以帮你增强对任务
的训练。在多任务学习中,如果想要从多任务学习得到很大性能提升,那么其他任务加起来必须要有比单个任务大得多的数据量。要满足这个条件,其中一种方法是,比如右边这个例子这样,或者如果每个任务中的数据量很相近,但关键在于,如果对于单个任务你已经有1000个样本了,那么对于所有其他任务,你最好有超过1000个样本,这样其他任务的知识才能帮你改善这个任务的性能。
最后,当你可以训练一个足够大的神经网络,同时做好所有的工作时,多任务学习才有意义。多任务学习的替代方法是为每个任务训练一个单独的神经网络。多任务学习会降低性能的唯一情况(和训练单个神经网络相比性能更低的情况)就是你的神经网络还不够大。但如果你可以训练一个足够大的神经网络,那么多任务学习肯定不会或者很少会降低性能。
所以总结一下,多任务学习能让你训练一个神经网络来执行许多任务,这可以给你更高的性能,比单独完成各个任务更高的性能。
实际上迁移学习比多任务学习使用频率更高。如果你想解决一个机器学习问题,但你的数据集相对较小,那么迁移学习真的能帮到你,就是如果你找到一个相关问题,其中数据量要大得多,你就能以它为基础训练你的神经网络,然后迁移到这个数据量很少的任务上来。
也许其中一个例外是计算机视觉,物体检测。在这些任务中,人们经常训练一个神经网络同时检测很多不同物体,这比训练单独的神经网络来检测视觉物体要更好。但因为你很难找到那么多相似且数据量对等的任务可以用单一神经网络训练,所以多任务学习的使用率没有迁移学习高。但多任务学习和迁移学习都是你的工具包中的重要工具。
2.9 端到端的深度学习
端到端学习是什么呢?简而言之,以前有一些数据处理系统或者学习系统,它们需要多个阶段的处理。那么端到端深度学习就是忽略所有这些不同的阶段,用单个神经网络代替它。
举例 1
以语音识别为例,传统上,语音识别需要很多阶段的处理,首先你要提取一些手工设计的音频特征,也许你听过MFCC,这种算法是用来从音频中提取一组特定的人工设计的特征。在提取出一些低层次特征之后,你可以应用机器学习算法在音频片段中找到音位,音位是声音的基本单位,比如说“Cat”这个词是三个音节构成的,Cu-、Ah-和Tu-,然后你将音位串在一起构成独立的词,然后你将词串起来构成音频片段的听写文本。
端到端深度学习只需要把训练集拿过来,直接学到了和
之间的函数映射,直接绕过了其中很多步骤。对一些学科里的人来说,这点相当难以接受,某些投入了多年研究的中间组件也许已经过时了。
端到端深度学习的挑战之一是,你可能需要大量数据才能让系统表现良好,比如,你只有3000小时数据去训练你的语音识别系统,那么传统的流水线效果真的很好。但当你拥有非常大的数据集时,比如10,000小时数据或者100,000小时数据,这样端到端方法突然开始很厉害了。
举例 2
这是一个人脸识别门禁,怎么搭建这样的系统呢?你可以尝试直接学习图像到人物
身份的函数映射,但事实证明这不是最好的方法。我们来看看相机拍到的照片,人可能从不同的方位走近门禁,那么照片中人物的位置就不同,且与相机的距离越近照片中的脸越大。所以在实际研制这些门禁系统时,他不是直接将原始照片喂到一个神经网络,试图找出一个人的身份。
迄今为止最好的方法似乎是一个多步方法,首先检测人脸,找到人脸位置,然后放大并裁剪图像,使人脸居中显示,然后就是这里红线框起来的照片,再喂到神经网络里,让网络去学习或估计那人的身份。所以,第一步是弄清楚脸在哪里。第二步是看着脸,弄清楚这是谁。两个学习算法分别解决两个更简单的任务,并在整体上得到更好的表现。
为什么两步法更好呢?有两个原因。一是,你解决的两个问题,每个问题要简单得多。第二,两个子任务的训练数据都很多。相比之下,如果你想一步到位,这样#card=math&code=%28x%2Cy%29&id=eESW7)的数据对就少得多,其中
是门禁系统拍摄的图像,
是那人的身份,因为你没有足够多的数据去解决这个端到端学习问题,但你却有足够多的数据来解决子问题1和子问题2。
不过如果你有足够多的数据来做端到端学习,也许端到端方法效果更好。但在今天的实践中,并不是最好的方法。
举例 3
传统上,机器翻译系统也有一个很复杂的流水线,比如英语机翻得到文本,然后做文本分析,基本上要从文本中提取一些特征之类的,经过很多步骤,你最后会将英文文本翻译成法文。因为对于机器翻译来说的确有很多(英文,法文)的数据对,端到端深度学习在机器翻译领域非常好用,那是因为在今天可以收集对的大数据集,就是英文句子和对应的法语翻译。所以在这个例子中,端到端深度学习效果很好。
举例 4
你希望观察一个孩子手部的X光照片,并估计一个孩子的年龄。这是儿科医生用来判断一个孩子的发育是否正常。
处理这个例子的一个非端到端方法,就是照一张图,然后分割出每一块骨头,所以就是分辨出那段骨头应该在哪里,那段骨头在哪里,那段骨头在哪里,等等。然后,知道不同骨骼的长度,你可以去查表,查到儿童手中骨头的平均长度,然后用它来估计孩子的年龄,所以这种方法实际上很好。
相比之下,如果你直接从图像去判断孩子的年龄,那么你需要大量的数据去直接训练。据我所知,这种做法今天还是不行的,因为没有足够的数据来用端到端的方式来训练这个任务。
总结:端到端深度学习系统是可行的,它表现可以很好,也可以简化系统架构,让你不需要搭建那么多手工设计的单独组件,但它也不是灵丹妙药,并不是每次都能成功。
是否要使用端到端的深度学习
我们来看看端到端深度学习的一些优缺点,这样你就可以根据一些准则,判断你的应用程序是否有希望使用端到端方法。
优点
- 只让数据说话,而不是引入人类的成见(比如音位概念)。
- 手工设计的组件更少,不需要手工设计中间表示方式,简化工作流程。
缺点
- 需要大量数据。
- 排除了可能有用的手工设计组件。
所以当你有大量数据时,手工设计的东西就不太重要了,但是当你没有太多的数据时,构造一个精心设计的系统,实际上可以将人类对这个问题的很多认识直接注入到问题里,进入算法里应该挺有帮助的。
如果你考虑在尝试决定是否使用端到端深度学习,我认为关键的问题是,你有足够的数据能够直接学到从映射到
足够复杂的函数吗?像是识别图中骨头这样相对简单的问题,也许系统不需要那么多数据来学会处理这个任务。给出一张人物照片,在图中把人脸找出来不是什么难事,所以你也许不需要太多数据去找到人脸,或者至少你可以找到足够数据去解决这个问题。相对来说,把手的X射线照片直接映射到孩子的年龄,直接去找这种函数,直觉上似乎是更为复杂的问题。如果你用纯端到端方法,需要很多数据去学习。
我认为这种纯粹的端到端深度学习方法,其实前景不如这样更复杂的多步方法。因为目前能收集到的数据,还有我们现在训练神经网络的能力是有局限的。