文章目录
1 训练/开发/测试集划分(Train/dev/test distributions)
1.1为什么重视训练/开发/测试集划分?
开发(dev)集也叫做验证集(development set),有时称为保留交叉验证集(hold out cross validation set)。机器学习的工作流程是,尝试很多思路,用训练集训练不同的模型,然后使用开发集来评估不同的思路,然后选择一个,然后不断迭代去改善开发集的性能,直到最后得到一个满意的模型,然后再用测试集去评估。
设立训练集,开发集和测试集的方式大大影响了在建立机器学习应用方面取得进展的速度。同样的团队,即使是大公司里的团队,设立这些数据集的方式,有时真的会让团队的进展变慢而不是加快。
1.2 一个数据集划分的例子:训练集和测试集不同分布
现在,举个例子,如果要开发一个猫分类器,在美国、英国、其他欧洲国家,南美洲、印度、中国,其他亚洲国家和澳大利亚,这些区域里运营,那么应该如何设立开发集和测试集呢?
其中一种做法是,可以选择其中 4 个区域,比如前四个,但也可以是随机选的区域的数据构成开发集。然后其他四个区域构成测试集。
事实证明,这个做法非常糟糕,因为这个例子中,开发集和测试集来自不同的分布。我们要让开发集和测试集来自同一分布。设立开发集加上一个单实数评估指标,这就是像是定下目标,那就是要瞄准的靶心,因为一旦建立了这样的开发集和指标,团队就可以快速迭代,尝试不同的想法,跑实验,可以很快地使用开发集和指标去评估不同分类器,然后尝试选出最好的那个。所以,机器学习团队一般都很擅长使用不同方法去逼近目标,然后不断迭代,不断逼近靶心,针对开发集上的指标优化。
然后在左边的例子中,设立开发集和测试集时存在一个问题,团队可能会花上几个月时间在开发集上迭代优化,结果发现,当最终在测试集上测试系统时,来自这四个国家或者说下面这四个地区的数据(即测试集数据)和开发集里的数据可能差异很大,所以可能会收获"意外惊喜",并发现,花了那么多个月的时间去针对开发集优化,在测试集上的表现却不佳。
所以,如果开发集和测试集来自不同的分布,就像你设了一个目标,让团队花几个月尝试逼近靶心,结果在几个月工作之后发现,测试的时候,你说,“等等,要把目标移到这里”,然后团队可能会说"好吧,为什么你让我们花那么多个月的时间去逼近那个靶心,然后突然间可以把靶心移到不同的位置?"。
所以,为了避免这种情况,建议将所有数据随机洗牌,放入开发集和测试集,所以开发集和测试集都有来自八个地区的数据,并且开发集和测试集都来自同一分布。
1.3 另一个实例:测试集变了
这里有另一个例子,这是个真实的故事,但有一些细节变了。
有一个机器学习团队,花了好几个月在开发集上优化,开发集里面有中等收入邮政编码的贷款审批数据。那么具体的机器学习问题是,输入𝑥为贷款申请,是否可以预测输出𝑦,𝑦是他们有没有还贷能力?所以这系统能帮助银行判断是否批准贷款。所以开发集来自贷款申请。但是在这上面训练了几个月之后,团队突然决定要在,低收入数据上测试一下。
当然了,这个分布数据里面中等收入和低收入数据是很不一样的,而且他们花了大量时间针对前面那组数据优化分类器,导致系统在后面那组数据中效果很差。所以这个特定团队实际上浪费了 3 个月的时间,不得不退回去重新做很多工作。
这里实际发生的事情是,这个团队花了三个月瞄准一个目标,三个月之后经理突然问"你们试试瞄准那个目标如何?",这新目标位置完全不同,所以这件事对于这个团队来说非常崩溃。
1.4 划分训练/开发/测试集的建议
所以建议在设立开发集和测试集时,要选择这样的开发集和测试集,能够反映未来会得到的数据,认为很重要的数据,必须得到好结果的数据,特别是,这里的开发集和测试集可能来自同一个分布。所以不管未来会得到什么样的数据,一旦算法效果不错,要尝试收集类似的数据,而且,不管那些数据是什么,都要随机分配到开发集和测试集上。因为这样,才能将瞄准想要的目标,让团队高效迭代来逼近同一个目标,希望最好是同一个目标。
我们还没提到如何设立训练集,但重点在于,设立开发集以及评估指标,真的就定义了要瞄准的目标。我们希望通过在同一分布中设立开发集和测试集,就可以瞄准所希望的机器学习团队瞄准的目标。而设立训练集的方式则会影响逼近那个目标有多快。
2 开发集和测试集的大小(Size of dev and test sets)
在深度学习时代,设立开发集和测试集的方针也在变化,我们来看看一些最佳做法。
2.1 小数据时代的合理大小划分
在机器学习中,把你取得的全部数据用 70/30 比例分成训练集和测试集。或者如果你必须设立训练集、开发集和测试集,你会这么分 60%训练集,20%开发集,20%测试集。在机器学习的早期,这样分是相当合理的,特别是以前的数据集大小要小得多。所以如果你总共有 100 个样本,这样 70/30 或者 60/20/20 分的经验法则是相当合理的。如果你有几千个样本或者有一万个样本,这些做法也还是合理的。
2.2 大数据时代的合理大小划分
但在现代机器学习中,我们更习惯操作规模大得多的数据集,比如说有样本这样分可能更合理,98%作为训练集,1%开发集,1%测试集。因为如果你有 1 百万个样本,那么 1%就是 10,000 个样本,这对于开发集和测试集来说可能已经够了。所以在现代深度学习时代,有时我们拥有大得多的数据集,所以使用小于 20%的比例或者小于 30%比例的数据作为开发集和测试集也是合理的。而且因为深度学习算法对数据的胃口很大,我们可以看到那些有海量数据集的问题,有更高比例的数据划分到训练集里,那么测试集呢?
要记住,测试集的目的是完成系统开发之后,测试集可以帮我们评估投产系统的性能。方针就是,令测试集足够大,能够以高置信度评估系统整体性能。所以除非需要对最终投产系统有一个很精确的指标,一般来说测试集不需要上百万个例子。对于你的应用程序,也许你想,有 10,000 个例子就能给你足够的置信度来给出性能指标了,也许 100,000 个之类的可能就够了,这数目可能远远小于比如说整体数据集的 30%,取决于你有多少数据。
对于某些应用,也许不需要对系统性能有置信度很高的评估,也许你只需要训练集和开发集,不单独分出一个测试集也是可以的。事实上,有时在实践中有些人会只分成训练集和测试集,他们实际上在开发集上迭代,所以这里没有测试集,他们有的是训练集和开发集,但没有测试集。如果你真的在调试这个集,这个开发集或这个测试集,这最好称为开发集。
总结一下,在大数据时代旧的经验规则,这个 70/30 不再适用了。现在流行的是把大量数据分到训练集,然后少量数据分到开发集和测试集,特别是当有一个非常大的数据集时。以前的经验法则其实是为了确保开发集足够大,能够达到它的目的,就是评估不同的想法,然后选出𝐴还是𝐵更好。测试集的目的是评估最终的成本偏差,你只需要设立足够大的测试集,可以用来评估就行了,可能只需要远远小于总体数据量的 30%。
3 什么时候该改变开发/测试集和指标?
3.1 为什么要改变开发/测试集和指标?
我们已经学过如何设置开发集和评估指标,就像是把目标定在某个位置,让团队瞄准。但有时候在项目进行途中,可能意识到,目标的位置放错了。这种情况下,应该移动目标。
3.2 一个需要改变评估指标的例子:进一步说明为什么需要改变指标。
我们来看一个例子,假设在构建一个猫分类器,试图找到很多猫的照片,向爱猫人士用户展示,决定使用的指标是分类错误率。所以算法𝐴和𝐵分别有 3%错误率和 5%错误率,所以算法𝐴似乎做得更好。
但我们实际试一下这些算法,算法𝐴由于某些原因,把很多色情图像分类成猫了。如果你部署算法𝐴,那么用户就会看到更多猫图,因为它识别猫的错误率只有 3%,但它同时也会给用户推送一些色情图像,这是公司完全不能接受的,用户也完全不能接受。
相比之下,算法𝐵有 5%的错误率,这样分类器就得到较少的图像,但它不会推送色情图像。所以从你们公司的角度来看,以及从用户接受的角度来看,算法𝐵实际上是一个更好的算法,因为它不让任何色情图像通过。
那么在这个例子中,发生的事情就是,算法 A 在评估指标上做得更好,它的错误率达到3%,但实际上是个更糟糕的算法。在这种情况下,评估指标加上开发集它们都倾向于选择算法𝐴,因为它们会说,看算法 A 的错误率较低,这是定下来的指标评估出来的。但公司和用户更倾向于使用算法𝐵,因为它不会将色情图像分类为猫。所以当这种情况发生时,当评估指标无法正确衡量算法之间的优劣排序时,在这种情况下,原来的指标错误地预测算法 A 是更好的算法这就发出了信号,应该改变评估指标了,或者要改变开发集或测试集。在这种情况下,分类错误率指标可以写成这样:
𝑚𝑑𝑒𝑣是开发集例子数,用𝑦𝑝𝑟𝑒𝑑(𝑖) 表示预测值,其值为 0 或 1,𝐼这符号表示一个函数,统计出里面这个表达式为真的样本数,所以这个公式就统计了分类错误的样本。这个评估指标的问题在于,它对色情图片和非色情图片一视同仁,但其实真的希望分类器不会错误标记色情图像。比如说把一张色情图片分类为猫,然后推送给不知情的用户,他们看到色情图片会非常不满。
我们将这个称为𝑤(𝑖),其中如果图片𝑥(𝑖)不是色情图片,则𝑤(𝑖) = 1。如果𝑥(𝑖)是色情图片,𝑤(𝑖)可能就是 10 甚至 100,这样赋予了色情图片更大的权重,让算法将色情图分类为猫图时,错误率这个项快速变大。这个例子里,把色情图片分类成猫这一错误的惩罚权重加大 10 倍。
如果希望得到归一化常数,在技术上,就是𝑤(𝑖)对所有𝑖求和,这样错误率仍然在 0 和 1 之间,即:
加权的细节并不重要,实际上要使用这种加权,必须自己过一遍开发集和测试集,在开发集和测试集里,自己把色情图片标记出来,这样才能使用这个加权函数。
但粗略的结论是,如果评估指标无法正确评估好算法的排名,那么就需要花时间定义一个新的评估指标。这是定义评估指标的其中一种可能方式(上述加权法)。评估指标的意义在于,准确告诉两个分类器,哪一个更适合应用。我们不需要太注重新错误率指标是怎么定义的,关键在于,如果对旧的错误率指标不满意,那就不要一直沿用不满意的错误率指标,而应该尝试定义一个新的指标,能够更加符合偏好,定义出实际更适合的算法。
你可能注意到了,到目前为止我们只讨论了如何定义一个指标去评估分类器,也就是说,我们定义了一个评估指标帮助我们更好的把分类器排序,能够区分出它们在识别色情图片的不同水平,这实际上是一个正交化的例子。
处理机器学习问题时,应该把它切分成独立的步骤。一步是弄清楚如何定义一个指标来衡量事情的表现,然后我们可以分开考虑如何改善系统在这个指标上的表现。我们要把机器学习任务看成两个独立的步骤,用目标这个比喻,第一步就是设定目标。
所以要定义要瞄准的目标,这是完全独立的一步,这是可以调节的一个旋钮。如何设立目标是一个完全独立的问题,把它看成是一个单独的旋钮,可以调试算法表现的旋钮,如何精确瞄准,如何命中目标,定义指标是第一步。
再次,如何定义𝐽并不重要,关键在于正交化的思路,把设立目标定为第一步,然后瞄准和射击目标是独立的第二步。
3.3 一个需要改变开发/测试集的实例
在继续之前,我们再讲一个例子。假设你的两个猫分类器𝐴和𝐵,分别有用开发集评估得到 3%的错误率和 5%的错误率。或者甚至用在网上下载的图片构成的测试集上,这些是高质量,取景框很专业的图像。但也许你在部署算法产品时,你发现算法𝐵看起来表现更好,即使它在开发集上表现不错,你发现你一直在用从网上下载的高质量图片训练,但当你部署到手机应用时,算法作用到用户上传的图片时,那些图片取景不专业,没有把猫完整拍下来,或者猫的表情很古怪,也许图像很模糊,当你实际测试算法时,你发现算法𝐵表现其实更好。
这是另一个指标和开发集测试集出问题的例子,问题在于,做评估用的是很漂亮的高分辨率的开发集和测试集,图片取景很专业。但用户真正关心的是,他们上传的图片能不能被正确识别。那些图片可能是没那么专业的照片,有点模糊,取景很业余。
所以方针是,如果在指标上表现很好,在当前开发集或者开发集和测试集分布中表现很好,但实际应用程序,真正关注的地方表现不好,那么就需要修改指标或者你的开发测试集。换句话说,如果发现开发测试集都是这些高质量图像,但在开发测试集上做的评估无法预测应用实际的表现。因为应用处理的是低质量图像,那么就应该改变开发测试集,让数据更能反映实际需要处理好的数据。
但总体方针就是,如果当前的指标和当前用来评估的数据和真正关心必须做好的事情关系不大,那就应该更改指标或者开发测试集,让它们能够更好地反映算法需要处理好的数据。
有一个评估指标和开发集让我们可以更快做出决策,判断算法𝐴还是算法𝐵更优,这真的可以加速你和你的团队迭代的速度。所以,即使无法定义出一个很完美的评估指标和开发集,直接快速设立出来,然后使用它们来驱动团队的迭代速度。如果在这之后,发现选的不好,有更好的想法,那么完全可以马上改。对于大多数团队,最好不要在没有评估指标和开发集时跑太久,因为那样可能会减慢你的团队迭代和改善算法的速度。