过拟合的风险
了解过拟合如何破坏模型。
很快,我们将开始调整神经网络,使其尽可能准确。但在那之前,我们需要一个可靠的测试方法来衡量这种准确性。然而,机器学习的测试存在一个微妙且违反直觉的陷阱,稍不注意就可能导致问题。
旁注:本章简要说明这个测试陷阱的位置,以及如何规避它。
过拟合(Overfitting)
从本课程的第一部分开始,我们一直使用两组独立的样本:一组用于训练算法,另一组用于测试。让我们回顾一下:为什么不能用同一组样本同时进行训练和测试?
我们用一个比喻来回答这个问题。假设我们要教一群小朋友基础数学,并准备了60道选择题形式的乘法测验。我们计划将其中大部分作为家庭作业布置给他们,另外挑选10道作为期末考试,用来检验孩子们的学习效果。
现在有两种分配方式:一种是把全部60道题都当作家庭作业,然后从中再挑10道作为考试题;另一种是将题目分成两部分——50道作为作业,剩下的10道专门留作考试。我们应该选哪一种?
显然我们会选择第二种,原因在于:我们不希望孩子只是死记硬背答案,而是真正理解乘法的规则。因此,我们必须用他们从未见过的新题目来测试他们的掌握程度。否则,他们答对可能只是因为记得之前做过的题目和答案。
这个逻辑同样适用于监督学习系统的训练。如果我们训练一个网络识别比格犬的照片,我们的目标是让它能识别任意比格犬图像,而不仅仅是训练时见过的那些。说起来容易,但实际操作中,监督学习系统和人类一样,容易记住训练样本,而不是从中归纳出通用规律。早在训练与测试一节中,我们就将这种现象称为过拟合。
为了应对过拟合,我们引入了测试集的概念。就像前面故事中的老师一样,我们在一组数据上训练神经网络,在另一组未曾参与训练的数据上进行测试。这样才能真实评估模型在实际应用中的表现——因为在生产环境中,模型面对的正是它从未见过的数据。
由于过拟合的存在,网络在熟悉的训练数据上表现更准确,而在陌生的测试数据上准确率则较低。相应地,训练数据上的损失值通常较低,而测试数据上的损失值更高。
调整我们的神经网络代码
让我们通过实验验证这一点。我们修改神经网络代码,使其在每一轮迭代中分别记录训练集和测试集的损失与准确率。接着运行该版本的网络,共训练10,000轮,采用批量梯度下降(即一次性使用所有样本),隐藏节点数 n_hidden_nodes=200,学习率 lr=0.01:
经过10,000轮训练后,得到如下结果:
0 > 训练损失: 2.43321 - 测试损失: 2.42661
1 > 训练损失: 2.38746 - 测试损失: 2.38024
…
9999 > 训练损失: 0.14669 - 测试损失: 0.22979
训练准确率: 96.13%,测试准确率: 93.25%
训练集与测试集的损失曲线对比
下图展示了训练过程中两类损失的变化趋势:
可以看到,初始阶段两者接近,但很快出现分化。随着训练推进,网络在训练集上的损失下降速度明显快于测试集。通常情况下,损失越低,准确率越高——事实也确实如此:训练结束时,网络对96%的训练样本判断正确,但仅对93%的测试样本正确。如果没有测试集,我们会误以为错误率低于4%,而实际上接近7%。这一显著差异正是过拟合的结果:网络在训练数据上表现更好,仅仅因为它“见过”这些数据。
这里我们称之为盲测原则:必须使用模型从未见过的数据来测试其性能。只要遵守这一原则,就不会出现模型在真实场景中表现远不如测试时那样好的情况。
你可能会认为遵循盲测原则很容易,但遗憾的是,人们常常在无意中违背它。事实上,正如我们即将发现的那样,我们已经犯过这样的错误了。