在进行机器学习建模时,为什么需要验证集(validation set)?
在进行机器学习建模时,为什么需要评估集(validation set)?
笔者最近有一篇文章被拒了,其中有一位审稿人提到论文中的一个问题:”应该在验证集上面调整参数,而不是在测试集“。笔者有些不明白为什么除了训练集、测试集之外,还需要额外划分一个验证集。经过查找资料,在《Deep Learning with Python》这本书上面我发现了比较好的解释,于是将这部分内容摘录在本博文中,并且翻译为中文。
下文摘自《Deep Learning with Python》4.2小节,翻译如下:
不在同样的数据上面验证模型的原因显然在于:在几轮训练之后,模型就会过拟合。即,相较于模型在训练数据上一直在变好的表现,模型在新样本上的表现会在某一时刻开始变差。
机器学习的目的是构造有很强泛化能力—在新样本上有着良好的表现—的模型,而过拟合是我们需要重点解决的问题。这一小节,我们将会聚焦于如何去衡量模型的泛化能力:如何去评估模型。
训练集、验证集和测试集
评估模型的重点在于将可用数据还分为三个部分:训练集(training set)、验证集(validation set)和测试集(test set)。在训练集上面训练模型,并且在验证集上面评估模型。一旦模型被准备好,最后就在测试集上面测试模型。
为什么不直接使用两个数据集:一个训练集和一个测试集?直接在训练集上面训练模型,在测试集上面评估模型,这样不是更简单一些吗?
不这样做的原因在于,开发一个模型通常需要我们去调整模型的配置:例如,选择最佳的全连接层数或者每一层的节点数(这些被称之为模型的超参数,以区分于模型自身的参数,如:模型的权重和偏置)。我们通过模型在验证集上面的表现来做这种调整。本质上,这种调整也是一种学习的过程:在某种参数空间中寻找最佳的模型配置。结果,根据模型在验证集上面的表现来调整其配置会很快地导致模型在验证集上面过拟合,即便模型从来没有直接在验证集上进行训练。
产生这一现象的原因即所谓的“信息泄漏“。每一次基于模型在验证集上面的表现来调整某个超参数的时候,某些关于验证集的信息就会泄漏给模型。如果我们仅仅作一次这样的调整,那么只会有很少的信息被泄漏,那么你的验证集依然可以被用来评估模型。然而,如果你多次重复这一过程——运行一个实验,在验证集上面评估模型,然后修改模型——那么关于验证集的越来越多的信息会被泄漏个模型。
最后,我们只会得到一个在验证集上面表现良好的模型,因为你就是朝着这个方向去优化它的。然后我们所关心的是模型在新数据上面的表现,而不是验证集,所以我们需要应用一个完全不同的,全新的数据集来评价这个模型,即测试集。我们的模型不能够直接地或者间接地接触过任何关于测试集的信息。如果模型基于测试集的表现来进行调整的话,那么对模型的泛化能力的评价是存在缺陷的。
将现有数划分为训练集、验证集和测试集看起来是很直接的做法,然而这边还有一些高级的方式在数据有限的情况下来完成这种划分,包括:hold-out validation、k-fold validation和iterated k-fold validation with shuffling(这些方法细节便不再赘述,网上可以找到很多资料)。
牢记以下几点:
(1)数据代表性:我们希望训练数据和测试数据能够很好地代表手上的数据。例如,如果我们试图将手写字符进行分类,然后我们手头上有一组根据它们的类别来排列的样本。如果你使用80%的数据作为训练集,另外20%数据作为测试集的话,这会导致训练集中只包含0-7,而测试集中只包含8-9。这看起来是一个滑稽的错误,然而这种情况其实是很常见的。因此,我们需要在分割数据的时候,将现有数据进行随机地打乱。
(2)时间之箭:如果你试图根据过去来预测未来的话,你不应该在划分数据之前随机打乱数据,因此这样会导致“时间泄漏”:你的模型最后很有可能会在来自未来的数据上训练。在这种情况下,你应该保证你的测试集在时间上是落后于训练集的。
(3)数据冗余:如果数据中的某些样本出现两次,那么打乱数据之后将其划分为训练集和验证集会导致训练集和测试集之间的数据冗余。最坏的结果就是,你会在部分的训练集上测试你的模型。一定要保证你的训练集和验证集是不相关的。