权重衰退

给参数加点'惩罚',让模型保持简洁,不为训练数据上的噪声过度妥协。

知识课 · 约 25 分钟 · 更新于 2026-06-08

直觉:过拟合的模型,参数都在干嘛?

如果把过拟合模型与正常模型的参数 分布 画出来, 会观察到一个共同的现象——

过拟合的模型,参数往往非常大 。

为什么会这样?因为为了精确拟合每一个训练样本(包括其中的 噪声 ), 模型需要在某些方向上"用力过猛"——这种"用力过猛"的代价就是某些权重被推到极端值。

反过来想:如果 限制权重不能太大 ,模型就被迫 放弃 那些"靠极端权重才能拟合的噪声",转而抓住更 本质 的规律—— 泛化能力反而会更好。

顺着这个思路,问题就转化成了: 怎样在训练过程中限制权重过大? 最直接的做法,就是在原来的损失上多加一项专门惩罚"大权重"的代价。

L2 正则化:在损失上加一个惩罚项

实现"惩罚大权重"的最直接做法:

其中 是所有权重的平方和, (lambda)是一个新的超参数,控制惩罚力度。 因为用的是 L2 范数(平方和),这个方法叫做 L2 正则化 。

这一项的作用:

  • 权重越大,惩罚项越大,loss 也越大——优化器会被 "拉回" 权重不要太大的方向
  • 控制"拉力"大小: = 0 等于不正则; 很大时模型被强行压成"小权重"

为什么叫"权重 衰退 "?

把刚才得到的总损失 拿来对 求梯度—— 的梯度照旧;新增的那一项 (下文称为 L2 正则项 ) 贡献 。 惯例上把这个 直接吸收进 ( 本就是要靠实验定的超参,整体差一个常数因子 不影响方法本身 ), L2 项的梯度就写成简洁的 。 本节后面所有公式与代码都默认采用这个约定。

把总梯度代入梯度下降并合并同类项:

看出来了吗——除了正常的梯度更新,每一步还 额外 把 乘上一个略小于 1 的因子 。 相当于让权重每步都 "衰退"一点点 ——这就是 权重衰退 (Weight Decay)这个名字的来源。

的影响规律

和模型容量一样, 也是一个需要权衡的超参数:

  • :完全不正则,回到原始模型, 可能继续过拟合
  • 太小(如 1e-6):惩罚几乎可忽略, 基本无效
  • 适中(如 1e-3 ~ 1e-2): 权重被适度约束,过拟合明显缓解,泛化能力提升
  • 太大(如 10):所有权重都被压到 0 附近——模型表达力丧失,掉到欠拟合

典型经验值: 1e-4 ~ 1e-2 ,需要在验证集上调。

实践 1:手写 L2 正则项

我们先把 L2 项手动加到 loss 里——这样能直观看到每一步多了哪几行代码、 以及"惩罚"是怎么计算出来的。

提示:手写 L2 一般作为 教学用途 。 实际项目中我们直接用下一节介绍的内置参数,代码更简洁、运行更快。

实践 2:使用 optim 内置的 weight_decay

实际项目中没人会手写 L2 项——PyTorch 所有 optimizer 都内置了 weight_decay 参数:

把 L2 系数当作 weight_decay 传进去, optimizer 在每一步 step() 时会自动对每个参数做 —— 效果与上一节"手写 L2"完全一致,只是少写了几行代码。

下面用一段对照实验来 验证 这种等价性:

Playground:扫描 看正则效果

下面这个 playground 在浏览器里实时训练一个小 MLP—— 训练数据只有 个点(特意取很少,方便诱发过拟合), 而验证集有 个点。 切换不同的 , 观察决策边界与 train / val loss 曲线的变化:

依次切换 (每次切换后点重置再训到收敛),可以观察到一条由弱到强的渐变曲线:

  1. (不加正则):决策边界贴着每一个训练点扭来扭去, val loss 显著高于 train loss——典型的过拟合形态
  2. (很弱):惩罚项相比 BCE 小一两个量级, 边界相比 略有平滑,但仍能看到训练点附近的"小鼓包",依然偏过拟合
  3. (适中):边界变得平滑, val loss 与 train loss 之间的间隙明显收窄——这是最接近"良好拟合"的档位
  4. (偏强):权重被压得很小, 边界进一步简化、靠近一条直线,开始牺牲表达力
  5. (过强):权重几乎被压到 0, 模型给不出有意义的边界,掉到欠拟合