第 10 章 · 学习是怎么发生的

正则化与泛化

训练能跑稳了,新问题来了:模型在训练集上考了满分,一到没见过的数据就露馅。 这叫过拟合——它把训练题“背下来”了,却没真正“学会”。这一章讲清楚什么是泛化、什么是过拟合, 以及一整套对付它的常用招:weight decay、Dropout、early stopping、数据增强。

读完这一章,你会明白

  • 泛化才是目标:训练集好不算好,没见过的数据上好才算好;
  • 怎么从训练/验证曲线一眼看出过拟合、欠拟合;
  • 偏差与方差为什么此消彼长,泛化的“甜区”在哪;
  • L2 / L1 / weight decay 为什么能让模型“更平滑、别太自信”;
  • Dropout 怎么靠“随机罢工”逼网络别依赖个别神经元,以及测试时为什么要关掉它;
  • early stopping数据增强这两招,以及“更多数据”为什么是最强正则。

1. 泛化:考的是“没见过的题”

我们训练模型,真正想要的不是它在训练数据上表现好,而是它在将来没见过的新数据上也表现好—— 这个能力叫泛化(generalization)。就像考试:你要的是“真会做题”, 而不是“把练习册答案背下来”。练习册全对但一考新题就崩,那是白学。

所以我们要把数据分开考

为了诚实地衡量泛化,数据会被分成训练集(用来学)和测试集(用来考,训练时绝不能碰)。 通常还留一份验证集用来边训边监控。怎么分、怎么用,是下一章(第 11 章)的主题; 这一章先聚焦“怎么让模型别把训练集背下来”。

2. 过拟合 vs 欠拟合

训练中会遇到两种“没学好”:

训练轮次 损失 这里该停(early stop) 验证损失回升 = 过拟合 训练损失一直降

典型过拟合信号:训练损失(绿)一路下降,但验证损失(黄)降到某点后反而回升——模型开始背训练集了。

正则化(regularization)就是一类专治过拟合的手段。它们的共同思路只有一句话: 给模型加点“约束”或“干扰”,逼它别把训练集硬背下来,而去学更通用的规律。 在动手之前,先看一眼过拟合和欠拟合背后那对更本质的概念。

3. 偏差与方差:欠拟合和过拟合的“根”

欠拟合和过拟合,其实是同一枚硬币的两面,背后是一对此消彼长的量: 偏差(bias)方差(variance)

打靶比喻

把预测想成打靶:高偏差是每一箭都稳稳地偏向同一边(准星歪了,再稳也脱靶); 高方差是箭散得到处都是(准星没歪,但手一直在抖)。 我们真正想要的,是又准又稳——但现实里,压低一个往往会抬高另一个

模型在新数据上的总误差,可以粗略拆成三块:

总误差 ≈ 偏差2 + 方差 + 不可约噪声 前两项是我们能调的;第三项是数据本身的噪声,再强的模型也消不掉

关键在于:模型越复杂(层更深、参数更多、训练更久),偏差越小,但方差越大; 越简单则反过来。所以总误差通常是一条 U 形曲线——两头都差,最优点在中间那个“不太死板、也不太敏感”的甜区。

误差 简单 复杂 模型复杂度 → 甜区 偏差²(欠拟合) 方差(过拟合) 总误差

复杂度越高,偏差(蓝)越小、方差(黄)越大;总误差(绿)是 U 形,谷底就是泛化最好的“甜区”。

想明白这一点,正则化的本质就清楚了:它是主动往模型上加约束,牺牲一点点偏差,换来方差的大幅下降, 从而把总误差推到更靠近谷底的位置。下面第 4–7 节的四招——weight decay、Dropout、early stopping、数据增强—— 全都在做这同一件事,只是切入点不同。

4. L2 正则 / weight decay:别让权重太“嚣张”

过拟合的模型常有一个特征:某些权重变得非常大,对个别特征反应过激(“一朝被蛇咬”式的死记)。 L2 正则的办法是:在损失里加一项“所有权重的平方和”,让“权重太大”本身也成为一种“错”:

总损失 = 原损失 + λ · Σ 权重2 λ 控制惩罚力度;它等价于每步让权重“缩水”一点,所以又叫 weight decay(权重衰减)

效果是把权重往 0 拉一把,模型变得更“平滑、克制”,不会为了迁就某几个训练样本而走极端,泛化通常更好。 在代码里,它就是第 8 章优化器接口的一个开关:

src/deeplearning/optimizer/optimizer_base.h
void set_weight_decay(double wd);   // 只对 weight 生效, bias 不衰减  1
  1. 给优化器设一个 weight_decay,训练时每步就会顺带把权重往 0 收一点。注意只惩罚权重、不惩罚 bias;Adam 与 AdamW 对它的耦合方式不同(第 8 章)。
还有个近亲:L1 正则

如果把惩罚项从“权重平方和”换成“权重绝对值之和”(λ·Σ|权重|),就是 L1 正则。 两者都压小权重,但性格不同:L2 把权重均匀地往 0 挤,得到一堆“都挺小但都不为 0”的权重,更平滑; L1 则倾向于把一部分权重直接压成 0,相当于自动做“特征筛选”,得到稀疏的模型。 想让模型自己挑出少数关键特征,用 L1;只想让它整体收敛、别走极端,用 L2(也是深度学习里的默认选择)。

5. Dropout:让神经元“随机罢工”

Dropout是个又简单又神奇的招:训练时,每一步随机“关掉”一部分神经元 (比如随机让 20% 的神经元输出 0),每步关掉的还不一样。测试时再把它们全打开。

像一支“谁都可能请假”的球队

如果训练时随时有队员被随机叫去罢工,整支队就不敢过度依赖某个明星球员,每个人都得练出真本事、 学会互相配合。网络也一样:Dropout 逼它不把宝押在个别神经元上,而是学出更鲁棒、更分散的表示, 于是更不容易过拟合。相当于同时训练了无数个“缺人版”的小网络,再取平均。

这里有个容易被忽略的细节:训练时关掉了一部分神经元,测试时又全开,两边的输出规模就对不上了。 比如训练时随机丢掉一半,那一层的输出总量平均只有平时的一半;测试时全开,总量却翻倍,后面的层就“懵”了。 解法是做一次缩放:常见做法叫 inverted dropout——训练时把没被丢掉的神经元输出除以保留比例 (丢一半就乘 2),把总量补回来;这样测试时啥都不用改,直接全开即可。记住一句话:Dropout 只在训练时开,测试/推理时关。

6. Early stopping:见好就收

回看上面那张曲线图:验证损失降到最低点后开始回升,那个拐点就是“学得刚刚好、还没开始背书”的时刻。 early stopping(早停)的做法直白得可爱:一边训一边盯验证集,一旦它连续几轮不再改善,就停, 并回退到验证表现最好的那个存档。既省算力,又正好卡在过拟合之前。

7. 数据增强,以及“更多数据”这剂猛药

还有一类正则化是在数据上做文章:

正则化,一句话收束

这些招看着五花八门,内核是同一个:故意给学习过程“添点乱”或“加点约束”,不让模型舒舒服服把训练集背下来。 weight decay 约束权重、Dropout 随机罢工、early stop 见好就收、增强/更多数据摊薄记忆——目标都只有一个:泛化

小结

  • 泛化才是目标:要的是没见过的数据上也好,而不是把训练集背下来。
  • 过拟合 = 训练好、测试差(背题);欠拟合 = 都差(没学会)。看训练/验证曲线的“裂口”即可判断。
  • 偏差 vs 方差:欠拟合是高偏差、过拟合是高方差;总误差是 U 形,正则化用一点偏差换方差,逼近谷底“甜区”。
  • weight decay(L2):惩罚大权重,让模型更平滑克制;L1 则会把部分权重压成 0,得到稀疏模型。
  • Dropout:训练时随机关神经元(并做缩放),测试时全开;逼网络别依赖个别单元。
  • early stopping:验证损失回升前收手;数据增强/更多数据是最本质的正则。

我们一直在说“训练集、验证集、测试集”“看验证损失”——可这些到底该怎么分、怎么读指标? 下一章我们就把评估与数据这件事讲透:数据集划分、准确率/精确率/召回、混淆矩阵、预处理与调试。