5. 你的开发集和测试集

让我们回到一开始那个猫咪图片识别的例子来。你投入运营了一个手机App,用户可以上传很多不同类型的图片到你的App来。此时,你希望在App上实现一个自动识别猫咪图片的功能。

你的团队通过从不同的网站抓取到很多猫图(正例)和非猫图(反例)组成了一个很大的数据集,然后按照70%/30%的法则将数据集分为了训练集和测试集两部分。通过使用这些数据,团队实现了一个在训练集和测试集上均表现良好的猫咪检测器。

但是,当你将这个检测器部署到手机App上的时候,发现它的性能变得相当糟糕!

这……发生了什么?

你发现用户上传的图片数据和团队从网站上抓取下来作为训练集的图片数据存在差异:用户上传的图片普遍使用手机拍摄,这些图片的分辨率比较低,清晰度差甚至曝光不足,然而,你的训练集/测试集上的图片则是来自网页抓取的图片。因此,你的分类器算法并不能很好的泛化到App的实际场景中——识别来自手机拍摄的图片。

在大数据时代来临之前,使用70%/30%的比例将数据集随机分割成训练集和测试集是传统机器学习的通用法则。这种做法是可行的,但是,当越来越多的应用部署在与训练集(来自网页抓取的图片)有着不同分布的使用场景(用户手机拍摄的图片)中的时候,这种分割做法就比较糟糕了。

我们通常定义:

  • 训练集(Training Set):对算法或者模型进行训练所使用的数据集;
  • 开发集(Dev(development) Set​​):用于调整参数,选择特征和做出其他算法相关决定的数据集,又称作“交叉验证集”(Hold-Out Cross Validation Set);
  • 测试集(Test set​​):只用来评估算法性能而不会对使用何种算法或者参数做出决策的数据集。

一旦定义好了开发集和测试集之后,你的团队将会尝试很多新的想法,例如,设置不同的学习算法参数来看一下哪种效果最佳。总之,开发集和测试集的使用可以让你的团队对算法调优进行快速迭代。

换句话说,设置开发集和测试集的目的是指导你的团队对机器学习系统做出最正确的优化。

因此,你应该遵从下列原则:

  • 选择能够映射出你在未来将要获得的数据,且表现出良好效果的开发集和测试集。

也就是说,你的测试集不应该仅仅包含现阶段可用数据的30%,特别是当你期望得到的数据(用户的手机拍摄的图片)和你的训练集的数据(网站抓取的图片)来自不同分布的时候。

如果你还没有上线你的App,那么你可能还没有任何用户,因此无法获取符合未来数据分布的图片,但是您仍然可以尝试去模拟这种分布。比如,请求你的朋友们使用手机拍些猫咪的图片给你。一旦应用上线,就可以使用用户上传的数据去更新你的开发集和测试集了。

如果真的没有任何办法去获取那些符合未来数据分布的图片的话,也许你可以使用上边提到的网站抓取的图片来优化算法,但是应该清醒地意识到这种方式训练出来的系统的泛化(Generalize)性能肯定是不好的。

你需要有一定的判断力来决定投入多少预算去提高开发集和测试集的质量。切记不要假定你的训练集和测试集有着相同的分布,尝试挑选那些能够很好的体现出你最终想要的结果的数据作为测试样本,而不仅仅是挑那些和训练集有着相同分布的数据。