去年微调一个小型 Transformer 做文本分类。老实验学习率 5e-5,weight_decay 0.01,验证 F1 87.2。新实验想用更小的学习率精调,改成 2e-5,其他一律不动——结果 F1 掉到 85.6。训练曲线看着还行,loss 在降,但验证指标就是上不去。

我一度怀疑是学习率太小导致欠拟合。直到翻到 PyTorch 的 AdamW 源码,看到这一行才想通:
p.mul_(1 - lr * weight_decay)
注意这里乘的是 lr × weight_decay,不是单纯 weight_decay。也就是说,你设置的 0.01 并不是“每次更新衰减 1%”,而是“每次更新衰减 学习率 × 1%”。我把 lr 从 5e-5 降到 2e-5,同一个 weight_decay 0.01 的有效强度从 5e-7 掉到 2e-7——直接打了 4 折。模型在同样步数里获得的“向零收缩”的惩罚少了一大截,泛化性能掉下去也就不奇怪了。
权重衰减到底在干什么?
一句话:每次更新后把权重按比例往零拉一把。没有梯度时,权重按 θ = θ × (1 − lr·λ) 指数式衰退。这跟早年的 L2 正则化在数学上等价——损失函数加上 (λ/2)||θ||²,求导后梯度多出一项 λθ,SGD 更新变成:
θ = θ − lr·(∇L + λθ) = θ·(1 − lr·λ) − lr·∇L
看最后这个展开,梯度项和衰减项都带着同样的学习率因子 lr。所以当你调低 lr,衰减项和梯度项会一起变小。这个“一起”正是问题所在:你只想缩步长,却把正则化强度也缩了。
PyTorch 的 SGD 官方文档也写得很直白:最终参数更新是 param = param − lr × (grad + weight_decay × param)。weight_decay 并没有自己的更新通道,它依附在学习率通道上。
L2 正则化在 Adam 里为什么失灵?
你可能会想:那这不是一个很简单的线性关系吗,为什么需要专门讲?因为还有一个更隐蔽的坑——L2 正则化和 weight decay 在 Adam 时代已经分道扬镳了。
2019 年,Loshchilov 和 Hutter 在论文 Decoupled Weight Decay Regularization 里指出,把 L2 正则化直接加进 Adam,会掉进自适应学习率的陷阱:Adam 会用梯度二阶矩去归一化每一步更新,导致大梯度参数的惩罚被削弱、小梯度参数的惩罚被放大。于是权重衰减不再均匀地“拉向零”,而是被扭曲成某种奇怪的正则化。AdamW 的做法很简单——把 λθ 从梯度里单独拿出来,直接乘到参数上:
θ = θ·(1 − lr·λ) − lr·m̂/√v̂
这样,权重衰减不再受梯度二阶矩干扰,所以叫“解耦”。
但注意,上面公式里 λ 前面为什么还挂着一个 lr?因为每次更新的幅度必须与梯度更新匹配。如果 lr 减半而衰减项不变,权重会被无端拉向零。所以 AdamW 的解耦,只是把 weight decay 从 梯度计算 中解耦出来,并没有从 学习率缩放 中解耦出来。
换句话说,“解耦”针对的是 Adam 的自适应归一化,而不是学习率。你把 lr 调成原来的 1/10,effective_wd 也跟着变成原来的 1/10。很多文章说 AdamW 的 weight decay 与学习率无关,这是只把话听了一半。
| 场景 | lr | weight_decay | effective_wd=lr×wd |
|---|---|---|---|
| 原始设置 | 1e-3 | 0.01 | 1e-5 |
| lr 减半,wd 不变 | 5e-4 | 0.01 | 5e-6 |
| lr 减半,wd 加倍 | 5e-4 | 0.02 | 1e-5(不变) |
那到底该怎么调?
答案取决于你想保持什么不变。
如果你希望保持相同的正则化效力,最直接的办法是让 effective_wd 不变。学习率变为原来的 1/k,weight_decay 就乘 k。我的例子从 5e-5 换到 2e-5,k=2.5,所以 wd 应该从 0.01 提到 0.025。这样同样的 epoch 数下,累计施加的“向零拉力”和原来的实验一致。
如果你希望保持“梯度更新 vs 权重衰减”的相对比例,AdamW 其实已经自动保持了这个比例:梯度项按 lr 缩放,权重衰减项也按 lr 缩放。这时你可以不动 wd。但这只在训练阶段不变时成立。
如果你正在做 lr schedule 尾段——比如余弦退火已经走到后四分之一——学习率已经变得很小,梯度也接近零,权重衰减开始主导参数行为。此时如果不调低 wd,权重会被持续拉向零,导致泛化性能回落。很多经验丰富的训练者在后期同时降低 wd,不是因为他们不懂 effective_wd,而是因为这时候本来就有意改变正则化强度。
你以为的“解耦”和真实的“解耦”
很多人把 AdamW 的“解耦”理解成 weight decay 完全独立于学习率。实际上论文里解耦的对象是梯度更新和权重衰减:L2 正则化把 λθ 混在梯度里,Adam 的二阶矩会干扰它;AdamW 把 λθ 拿出来单独更新,所以叫 decoupled。但公式里这个单独的更新仍然乘着 lr,因此它只解决了 Adam 对 decay 的扭曲,没有解决 lr 对 decay 的缩放。
三条经验法则
- 先算 effective_wd = lr × weight_decay。改 lr 之前,问自己想让 effective_wd 变成多少。
- 如果你只是换学习率、其他条件都不变,按反比调 wd,让 effective_wd 稳定。
- 如果你在微调后期或者有意减少正则化,降低 wd 是合理操作,但心里要知道这是“改变正则化强度”,而不是“保持原设置”。
回头看我那次实验,真正的问题不是 lr 太小,而是我在没有意识的情况下削弱了正则化。调参最怕的不是参数值不合适,而是参数之间相互纠缠。学习率和 weight_decay 的纠缠是所有纠缠里最隐蔽、也最常见的一个。
下次改动学习率时,记得顺带看一眼 weight_decay——它可能正在悄悄跟着你的学习率一起变小。
原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/665.html