本周的内容主要包括误差分析、训练集与dev/test set的不匹配(主要指数据分布不同)、迁移学习和端到端学习。
error analysis
如果我们希望学习算法能够胜任人类能做的任务,但在学习算法还没有达到人类水平之前,我们要不断地分析算法的错误或问题出现在哪里,这个过程就称为误差分析。
2.1 carry out error analysis
假设我们在调试一个识别猫的模型,准确率为90%,也就是说dev set上的误差是10%,这离我们的目标还有距离。这时候,团队的另一个人发现算法很容易将一些狗的图片识别为猫,至少它们乍一眼看上去很像,也许我们需要针对狗的图片优化算法(如,收集更多的狗图,或设计一些只处理狗的算法),那么,我们是否就应该开始做一个项目专门处理狗呢?这项工作可能要花费数个月才能得到较好的性能,这样值得吗?这里有个误差分析流程,可以让我们快速知道这个方向是否值得努力。
1、收集比如100个错误识别的dev set样本(假正例),然后一个一个的人工检查,看下错误识别的样本中,有多少实际上是狗图像。假设100个假正例中,只有5%是狗,那么,即便我们在狗的问题上花了很多时间,对误差的改善却非常有限(10%改善到9.5%),就可以确定花时间去做这件事不值得。假设100个假正例中,有50个是狗,这时候花时间去解决狗问题可能效果就很好(10%改善到5%)。
有时在做误差分析时,还可以并行评估几个想法。比如,我们有几个改善猫检测器的想法:1、针对狗图提升性能;2、针对猫科类动物提升性能;3、提升模糊图像性能。所以进行误差分析来评估这三个想法。注意:误差分析是针对dev set中识别错误的例子(假正例、假负例)做的。根据这三种想法,做下图这样的表格,逐个记录每个错误识别图像的情况,并分别进行统计,得到这些错误的百分比。也许在统计的过程中又发现了其他的错误,那就给表格增加一列。这个分析步骤的结果可以给出一个估计:是否值得去处理每个不同的错误类型。误差分析让你对应该选择哪些手段、以及性能的提升上限有个概念。
总结一下:进行误差分析,我们要从dev set中找出一组识别错误的例子(假正例、假负例),统计不同误差类型的数量,在这个过程中,可能会归纳出新的误差类型,那么就新建一个错误类型,通过统计每个错误类型所占的比例,可以给出我们提升算法性能的方向以及性能提升上限。
若dev set中的样本被错误标记了又该怎么办呢?
2.2 cleaning up incorrectly labeled data
监督学习算法的数据包括输入X和输出标记Y。如果你查看数据,发现有些标记是错误的,是否值得花时间去修正这些标签呢?——取决于它们是否是造成算法误差的主要因素。
首先统一下说法,“incorrectly labeled examples”指的是被错误标记的样本,是做标记的人标记错误了,“mislabel example”指的是学习算法输出了错误的Y值。如果我们发现数据集中有标记错误的例子,应该怎么办呢?
首先,考虑下训练集。事实表明,DL算法对训练集中的随机误差是非常鲁棒的,只要这些标记错误离随机误差不太远,即只要这些标记错误足够随机,那么我们无需去理会这些标记误差,只要数据集足够大。但是对系统性误差就没有那么鲁棒了,比如标记人员总是认为白色的狗是猫的话,这样学习算法就会将白色的狗当成是猫。
那么,incorrectly labeled examples对dev set和test set又有什么影响呢?如下图所示,在误差分析时,增加额外的一列,这样就可以统计Y被标记错误的例子数。如图中左边所示,如果算法整体的误差为10%,标记错误引起的误差只占0.6%,还有9.4%的误差是由其他原因引起的,这时候我们可以更多的关注其他原因引起的误差,因为标记错误引起的误差不是最主要的。但是,若如右边所示,算法整体的误差为2%,标记误差为0.6%,那么就要考虑下标记错误引起的误差了,因为它所占的比例比较重了。
另外,如果我有两个学习算法,误差分别是2.1%和1.9%,而且我已知数据集中有标记错误,那么,这时候就无法判断到底是哪个学习算法性能更好了。这时候,这些标记错误影响了我们用dev set去评估算法的能力,那么就有必要去修正。反之,则没必要花费时间。
手动检查修正dev set中标记错误的样本,需要注意的方针和原则:
1、无论采用什么修正方法,务必使这个方法同时作用于dev set和test set。原因之前已经讲过,在处理学习算法时,要保证dev set和test set服从相同的分布。否则就会造成学习算法验证时瞄准的一个靶心,而测试时靶心却改变了的尴尬局面。。。
2、强烈建议同时检查学习算法判断正确和判断错误的例子。要检查算法判断错的例子很容易,只需要看这些例子是否需要修正。但也有可能,对于一些样本,算法判断正确,仍需要修正。如果只修正算法出错的例子,那么对算法误差的估计就会有较大偏差。(这一点很难做,所以通常不这么做。因为,如果算法很准确,那么判对的机会就比判错的机会大很多,这样再去检查判对的样本,工作量就很大了。)
3、如果对dev set和test set中的数据修正了,那么,对training set中的数据可修正也可不修正。因为修正训练集中的标签其实相对没那么重要,而且验证集和测试集要比训练集小的多,因此可行性也高许多。
下节课将讲误差分析是如何在学习算法启动时起作用的。
2.3 build your first system quickly, then iterate
当开始一个全新学习算法时,Ng通常会建议大家:先尽快建立一个系统原型,然后快速迭代。
广泛来说,对于任何一个机器学习算法,大约有50种不同的方向可以前进,而且每个方向都是合理的,可以使你的系统性能更好。因此,尽快建立一个系统原型,设置好dev set、test set以及评价指标(这些决定了你的目标所在,即便错误,后面改也是可以的,但一定要设立一个目标),然后快速搭好一个原型系统,找到训练集,训练模型,在dev/test set和评价指标上看看表现的怎么样。然后就可以用bias/variance分析以及之前提到的误差分析来考虑该接下来应该优先使用什么方法来提升算法性能。特别的,如果误差分析让你了解到大部分误差的来源,比如说是某一方面原因造成的,那么,你就可以集中精力去研究这些技术。
训练数据与验证/测试数据不匹配
2.4 training and testing on different distributions
深度学习对训练数据需求很大,这往往会使得我们训练的数据和我们期望检测的数据来自不同的分布。比如我们要检测猫,在开始阶段,我们真正能从移动端获取的数据是非常少的,少到远不足以满足算法训练的需求,这时候我们不得不从其他地方获得更多的数据,如网络上爬取。假设我们从网络上获取了200k的图片,从真实场景的移动端获取了10k的图片。怎么样来划分training/dev/test set呢?
1、将所有的210k图片混在一起,然后取205k作为training set,2.5k作为dev set,2.5k作为test set。这样的话,虽然training、dev、test来自相同的分布,但dev/test set中,来自真实场景的图片所占比例太少,不能反映出我们学习算法的学习目标,使得学习目标和想要的目标有偏差,因此,这种划分方法不推荐。
2、training set =200k来自网络的图像+5k来自移动端的图像,dev set = 2.5k来自移动端的图像,test set = 2.5k来自移动端的图像。这样划分训练、验证、测试集的好处在于现在我们瞄准的目标就是我们想要处理的目标。缺点就是,我们的训练集与验证/测试集的分布不同。但事实证明,这种划分方法能给学习算法长期带来好处。
2.5 bias and variance with mismatched data distributions
估计学习算法的bias和variance可以帮助我们确定接下来应该优先做的方向。但是,当training set与dev/testset来自不同的分布时,分析bias和variance的方法也就改变了。为什么呢?
继续以猫分类器为例,我们假设人类在这个问题上的表现近乎完美。要进行误差分析,我们通常需要查看training error、dev error。比如training error=1%,dev error=10%,且training set和dev set来自同一分布,那么这可能存在很大的方差问题,算法泛化能力差。但是,如果training set和dev set来自不同的分布,我们就不能轻易下这样的结论了。特别的,也许算法在dev set上表现不错,可能因为training set中的图片太好识别了(分辨率高,清晰),dev set中的图片太模糊了。这样,当training set和dev set来自不同的分布时,从training error到dev error,就同时改变了两件事:1、算法只见过training set,没见过dev set(泛化问题、variance);2、training set 和 dev set来自不同分布(data mismatch)。因此,我们无法判断从training error到dev error增加的这9%的误差到底是哪一件事引起的,是因为模型的泛化性能差还是因为training set和dev set来自不同的分布?为了弄清楚这两个因素的影响,就引出了一个新的数据集——training-dev set:same distribution as training set, but not used for training.
目前我们就有四个数据集:training、training-dev、dev、test。其中,dev和test具有相同的分布,training和training-dev具有相同的分布。我们只在training set上训练算法。为了进行误差分析,我们需要比较算法在training set、training-dev和dev set上的error。如下表序号为1的行所示,training error、training-dev error、dev error分别1%、9%、10%,从training error到training-dev error误差上升了8%,而这个过程中只存在数据的泛化性问题(variance problem)。再比如像序号为2的行所示,training error、training-dev error、dev error分别1%、1.5%、10%,这时,算法的variance问题就很小了,但是从training-dev error 到 dev error误差上升的比较多,这就是data mismatch问题了,也就是数据属于不同分布造成的问题。第3、第4行分析方法同上。
No. | human-level | training error | training-dev error | dev error | test error | conclusion |
---|---|---|---|---|---|---|
1 | – | 1% | 9% | 10% | – | variance problem |
2 | – | 1% | 1.5% | 10% | – | data mismatch problem |
3 | 0% | 10% | 11% | 12% | – | avoidable bias |
4 | 0% | 10% | 11% | 20% | – | avoidable bias; data mismatch |
一般原则:我们关注的关键指标是human-level error、training set error、training-dev set error、dev set error,通过比较这些误差之间的差异大小,我们大概可以知道avoidable bias、variance、data mismatch问题各自有多大。其中
training set error与human-level error之间的差异表示了avoidable bias的大小;
training-dev set error与training set error之间的差异表示了variance的大小;
dev set error与training-dev set error之间的差异表示了data mismatch的大小;
test set error与dev set error之间的差异表示了对dev set overfitting的程度。这时我们需要退回去一步,在一个更大的dev set上评估dev set error。
从上图左边看到,似乎从human-level到test error,误差是逐渐变大的。而右边就给出了error不会逐渐变大的例子,这表明,dev/test中的例子要比training中的数据容易识别的多。当我们遇到这类有趣的现象时,可能需要一个更普适的分析方法。如下图所示,水平轴表示不同的datasets,纵轴表示对数据不同的处理方法或算法
最后,我们之前讲过很多方法来应对avoidable bias、variance,那么,对于data mismatch我们应该怎么处理呢?
2.6 addressing data mismatched
如果training set的分布和dev/test set不同,并且误差分析显示我们有data mismatch问题,那我们应该怎么做呢?这个问题没有完全系统的解决方案,但我们仍可以做一些尝试。
1、亲自做误差分析,尝试理解training set与dev/test set 的差异所在。为了避免对test set过拟合,在做误差分析时,我们应只人工看dev set而不是test set。
2、使training set更像dev set(如,人工合成数据),或收集更多像dev/test set的数据。
人工合成数据及其问题:Ng展示了一个语音合成的例子,并表明人工合成可以快速得到大量我们想要的数据,但这仍然有一个潜在的问题。比如我们有安静环境下的10k小时的语音数据以及1小时的汽车噪声语音数据。我们可以将这一小时的噪声语音重复10k次,并叠加到安静环境下的语音数据上。这样做后,人听起来可能没什么问题,但是学习算法有可能对这1小时的汽车噪声数据过拟合,如果可能的话,获取10k小时永不重复的汽车噪声语音数据,再合成,最后得到的学习算法效果要更优。
数据合成的潜在问题:由于我们只是针对全量数据中的一个子集做合成,那么学习算法可能对合成的这个子集过拟合,即学习算法只学到了全部模式(如全部的汽车)中的一个子集(某种特定车型,如轿车),当我们将本应该能识别的其他模式(如吉普车)输入后,学习算法并不能正确分辨,这时候,就是学习算法对这一子集(轿车)过拟合了。
2.7 transfer learning(迁移学习–串行学习)
深度学习中最强大的理念之一就是,有时,我们可以将神经网络从一个任务中学习得到的知识应用到另一个独立的任务中。比如,我们已经通过训练得到了一个可以识别物体的神经网络,比如识别猫,我们可以利用这里面的知识来帮助我们更好的识别X射线图。这就是所谓的迁移学习。
假设我们已经训练好了一个用于图像识别神经网络,如下图所示。
如果我们将这个神经网络拿来,让它adapt或transfer在不同任务中学到的知识,比如放射科诊断。我们可以将神经网络的最后一层输出层以及与它相关的权重删除,然后为最后的输出层重新赋随机初始化权重,然后让它在放射诊断数据上训练。如下图所示。
具体来说,在第一阶段的训练中,我们用图像识别任务训练模型,得到权重等参数,然后我们得到了一个能够做图像识别的神经网络。训练完成这个网络后,当我们要做迁移学习时,我们要做的就是换成新的X、Y数据集(比如放射诊断图-诊断结果),随机初始化最后一层的权重(
W[L],b[L]
),然后重新训练这个网络。对于重新训练网络,我们有几种方法:
1、如果放射诊断图数据量很少,我们可能只需要重新训练最后一两层的权重,并保持其他层的权重不变。
2、如果我们有足够多的数据,我们可以重新训练神经网路的所有参数。如果我们重新训练神经网路中的所有参数,那么在第一阶段对图像进行的训练过程就称为预训练(pre-training),因为我们在用图像识别数据预初始化或预训练神经网络的权重。如果以后再更新所有的权重,那么在放射诊断图上的训练就称为微调(fine-tuning)。
本例中,我们做的就是,把图像识别中学到的知识应用或迁移到放射诊断图中。这样做为什么有用呢?很多低层次的特征,如边缘检测、曲线检测、正样本检测,从非常大的图像识别中学习到这些能力,会对我们的算法做放射诊断图有帮助,因为算法学到了很多有关图像结构、形状等方面的信息,这其中的一些知识可能有用。所以学习了识别图像,它就可能学习到足够多的关于图像组成的信息(比如点、直线、曲线,甚至是对象的一小部分),而这些知识使得神经网络可以学的更快或者需要的数据更少。
迁移学习的意义?
当我们迁移源问题有很多数据,但是对迁移到的问题却又很少数据的时候(when you have a lot of data for the problem you’re transferring from and usually relatively less data for the problem you’re transferring to.)即,从数据量很多的问题迁移到数据量很少的问题,且两个问题是相关但又不同的。例如,假设图像识别任务中有100w个样本,这个样本量足可以让我们学习图像中的组成信息。但是对于放射诊断图,假设我们只有100个样本,而这个样本量对于神经网络时远远不够的。所以,我们从图像识别任务中学到的很多知识可以迁移到放射诊断图中,并帮助我们提升放射诊断图识别的性能,即使放射诊断图数量很少。但如果反过来,迁移到的问题比迁移源问题的数据多,那么,迁移学习带来的增益就非常少了。
什么时候使用迁移学习呢?如下图所示。其中,任务A和B有相同的输入,指的是都是图片或都是语音。
2.8 multi-task learning
在迁移学习中,步骤是串行的,但在多任务学习中,我们是同时学习的,试图让一个神经网络同时做几件事情,然后希望每一个任务都能帮到其他任务。
比如我们在开发无人驾驶车,无人驾驶车需要检测很多物体,比如行人、车辆、停车标志、交通灯等等。这样,如果输入x是一幅图像,那么y就有4个标签(如果要检测其他物体的话,y的维数会更高。如果数据集共有m个样本,那么矩阵Y就是4*m型),分别表示行人、车辆、停车标志、交通灯,如下图所示。
而我们要做的,就是训练一个神经网络来预测这些y值。其中,输出是4维的,分别代表行人、车辆、停车标志、交通灯。为了训练这个网络,我们要定义神经网络的损失函数
其中,L指logistic loss: −y(i)jlog(y^(i)j)−(1−y(i)j)log(1−y^(i)j)
这个例子与之前识别猫的例子的不同之处在于要对j从1到4求和。与softmax regression不同之处在于,softmax将单个标签分配给单个样本(即每个输入只含有一个样本),而本例中每个样本含有多个标签(是否有行人、有车、有停车标识、有交通灯),多个物体可能同时出现在一张图中。所以我们不是只给图片一个标签,而是遍历所有类型,并判断各类型的物体有没有出现在图片中。 如果训练了一个神经网络,并最小化成本函数,那么我们做的就是多任务学习。因为我们做的是建立单一神经网络,观察每张图,然后解决四个问题,网络会告诉我们每张图中是否有这四种物体。除此之外,我们还可以单独训练四个神经网络来分别识别这四种物体,而不是训练一个网络做四件事。但是, 神经网络的一些早期特征在识别不同物体时都会用到,然后我们就会发现用一个神经网络做四件事会比单独训练四个神经网络做四件事性能更好。这就是多任务学习的力量。
多任务学习也可以学习图片中只有部分物体被标记的情况,如下图所示。对没有标记的物体,我们使用“?”表示,然后在计算损失函数时,只对标签为0或1的值求和,忽略“?”表示的项。
那么, 什么时候可以使用多任务学习呢?
1、 训练的一组任务可以共用底层特征(如行人
车辆、停车指示、交通灯这些都在路上,具有一些道路的特征);
2、 对于每个任务,拥有的数据量是相似的(不是绝对正确的准则)。对于迁移学习,比如从A迁移到B,A可能有100w个样本,B可能有1k个样本。而对于多任务学习,比如我们有100个任务A1,A2,…,A100,每个任务约有1k个样本,如果我们尝试单独去做A100这个任务,那么我们只有约1k个样本去训练,而多任务学习通过在其他99个任务上的训练(共约99k个样本),可能对A100任务有大幅的提升,可以提供很多知识来增强这个任务的性能。对称的,对于其余99个任务中的1个,余下的99个任务也同样对它起到了增强和提升的作用。
3、 当我们可以训练一个足够大的神经网络并对所有任务都做的很好的时候,多任务学习更有意义。因此,多任务学习的替代方法是为每个任务训练一个单独的神经网络。多年前,一个研究人员发现了多任务学习会降低性能的唯一情况,就是神经网络不够大。但,当我们能够训练一个足够大的神经网络,那么多任务学习肯定不会或很少会降低性能。
在实践中,多任务学习要比迁移学习使用的少,只在计算机视觉中的目标检测中用的比较多
端到端深度学习
2.9 What is end-to-end deep learning
深度学习最令人振奋的动态之一,就是端到端深度学习的兴起。那么,什么是端到端深度学习呢?如下图所示。对于一些数据处理系统,它们需要多个阶段的处理,而对于端到端深度学习,就是忽略这些所有的阶段,用一个神经网络来代替。而端到端深度学习的挑战就是需要大量的数据才能让系统表现的好。因此,到底是传统的pipeline效果好还是端到端深度学习效果好,取决于我们拥有的数据量到底有多大。只有数据量足够大的时候,端到端深度学习才会闪耀光芒。
2.10 whether to use end-to-end learning
在决定要不要使用端到端学习之前,我们先来了解下端到端学习的优缺点:
优点:1、真正做到了让数据自己说话;2、对手工设计的组件需求更少(算法不用按照人类的设定,被迫去学习一些人设定的知识,而是完全从数据本身出发,学习数据所表现出的一些知识)。
缺点:1、需要大量的数据;2、排除了可能有用的手工设计组件。
学习算法有两个主要的知识来源:1、数据;2、手工设计的任何东西(组件、功能或其他东西)。当数据量很大时,手工设计的东西就没那么重要了,但是当数据量不大时,一个经过精心设计的系统可以将很多人类的认识注入到系统中,这对系统的性能是有帮助的。因此,手工设计的东西是一把双刃剑(double edged sword),它可能帮助,也可能无益(限制算法学习更有效的特征表示),但通常帮助多一些。
因此,当我们在构建一个机器学习系统并决定是否使用端到端深度学习时,关键问题就是:我们是否有足够的数据去学习从x到y的、满足复杂度需要的函数?