AdamW权重衰减:为什么不等于L2

黎 浩然/ 17 10 月, 2026/ 大语言模型/LARGELANGUAGEMODEL/LLM, 教程/TUTORIAL, 计算机/COMPUTER/ 0 comments

AdamW的weight decay不等于在损失里再加一个L2项。L2会把λw加入数据梯度,随后一起进入Adam的一阶和二阶矩;AdamW把参数收缩与自适应梯度更新分开。相同的学习率和衰减数值,并不保证两种写法走出相同的一步。

文章目录
  1. 从普通SGD的等式说起
  2. AdamW到底把哪部分解耦了
  3. 零数据梯度下,一步就不同
  4. 用八项精确检查复现
  5. 同一个衰减值,为什么训练久了不一样
  6. 梯度为0与梯度不存在要分开
  7. 参数分组决定衰减落到谁身上
  8. 比较配方前,先比较一次更新
  9. 参考与验证范围

最容易看清差异的方法,是先让数据梯度为零。下面用精确分数推导一个标量更新,再解释为什么学习率、实际更新次数和参数分组都应写进实验记录。Read in English。

从普通SGD的等式说起

令数据损失为L(w),在损失中添加λ‖w‖²/2,其梯度为g+λw。没有动量的普通SGD更新为w′=w−η(g+λw)=(1−ηλ)w−ηg。按这套系数约定,它确实等价于先做比例收缩,再做数据梯度更新。

系数约定也要一致:若写成λ‖w‖²而没有1/2,梯度贡献就是2λw,不能直接照抄同一个λ。这个等式依赖更新对梯度的线性形式。Adam根据梯度历史构造矩估计,再按坐标缩放;把λw放进梯度之后,它也会影响这些状态。因此不能把普通SGD下的代数等价直接搬过去。

Decoupled Weight Decay Regularization讨论的就是这一区别。论文最初于2017年提交,后发表于ICLR 2019;这里解释其机制,不把历史方法包装成新发布,也不将论文的实验结论推成任何任务上的必胜保证。

L2加入损失

数据梯度 + λw
进入一阶/二阶矩
自适应缩放后更新
AdamW解耦

数据梯度进入矩估计
自适应梯度更新
另加 −ηλw 收缩
原创更新路径图:差异是衰减项是否进入自适应矩估计,不只是参数名不同。

AdamW到底把哪部分解耦了

把用于最小化数据目标的梯度记作gₜ。AdamW的矩估计来自gₜ,而不把λw混进去;更新同时包含−ηₜλw这一收缩项。PyTorch 2.14的AdamW算法说明明确写出衰减不累积进动量和方差。

解耦并不是“衰减与学习率无关”。在这里引用的实现形式中,每次收缩因子仍然是1−ηₜλ。改变学习率日程,即使weight_decay数值不变,纯衰减路径也会改变。

也不要把“Adam”的名字当作完整算法定义。一些实现允许选择解耦行为,配置与版本会影响实际更新;比较时要看所用实现的公式和开关,而不是只对照优化器类名。

零数据梯度下,一步就不同

采用一个有意简化的标量例子:w=1、数据梯度g=0、η=0.1、λ=0.1、ε=0.001,并令β₁=β₂=0。这样矩的历史依赖被移除,自适应分母可写为|g|+ε;这不是默认训练配置,也不是推荐超参数。

若L2耦合到梯度,g̃=0.1,更新量是0.1×0.1/(0.1+0.001)=10/101,所以w′=91/101≈0.90099。AdamW的数据梯度更新量为0,只做(1−0.1×0.1)×1,得到0.99。

差异不是浮点舍入,而是两条更新路径的含义不同。这个反例足以否定“AdamW只是把L2换了个名字”,但不能告诉你哪个λ会让真实模型泛化最好。

用八项精确检查复现

下面只使用Python标准库Fraction。函数实现的是β₁=β₂=0的教学公式,没有运行PyTorch、GPU或模型微调;ε在本例严格为正。

# Scalar teaching update, beta1=beta2=0. No PyTorch/model run.
from fractions import Fraction as F

def adam_l2(w,g,eta,lam,eps):
    regularized = g+lam*w
    return w-eta*regularized/(abs(regularized)+eps)

def adamw(w,g,eta,lam,eps):
    return (1-eta*lam)*w-eta*g/(abs(g)+eps)

w,g,eta,lam,eps = F(1),F(0),F(1,10),F(1,10),F(1,1000)
a,b = adam_l2(w,g,eta,lam,eps),adamw(w,g,eta,lam,eps)
assert b == F(99,100)
assert a == F(91,101)
assert a != b
assert adam_l2(w,F(2,5),eta,0,eps)==adamw(w,F(2,5),eta,0,eps)
assert adamw(w,g,0,lam,eps)==w
assert adamw(-w,g,eta,lam,eps)==-F(99,100)
x=w
for _ in range(10):
    x=adamw(x,g,eta,lam,eps)
assert x==F(99,100)**10
assert adamw(w,g,2*eta,lam,eps)==F(98,100)
print("8 update checks passed; L2=91/101, AdamW=99/100")

本地执行通过八项检查:两种更新的精确结果、二者不等、λ=0时一致、η=0时不动、负参数收缩方向、十步纯衰减与学习率翻倍的影响。这里没有通过一个最简函数冒充完整AdamW训练器。

同一个衰减值,为什么训练久了不一样

在没有数据更新的纯衰减路径中,wₜ=w₀∏ₛ(1−ηₛλ)。若学习率固定,就是w₀(1−ηλ)ᵗ。λ不是一次运行结束时的固定缩小比例;学习率与真正执行的更新次数都会进入乘积。

把每一步理解为保留一部分原权重,还要求0≤ηₛλ<1;超出该范围可能出现符号翻转,不能继续把因子称为正比例收缩。这不是训练收敛条件。
例如ηλ=0.01时,一步保留99%,十步约保留90.44%,一百步约保留36.60%。这只是展示收缩累积,不能解释为验证集指标将按相同比例改善或变差。真实训练还有数据梯度与矩状态。

若更改梯度累积设置,使同一训练token预算下optimizer.step次数发生变化,也要重新比较衰减日程。上午的梯度累积文章追踪的是目标归一化;这里多了每次更新都会发生的参数收缩。

t=0 · 1.0

t=1 · 0.99

t=10 · 0.904382

t=100 · 0.366032

原创纯衰减计算:w₀=1、η=0.1、λ=0.1、无数据更新,wₜ=0.99ᵗ。不是模型训练曲线。

梯度为0与梯度不存在要分开

本例g=0指一个明确存在的零梯度值,不是.grad为None。PyTorch zero_grad说明提醒,优化器对零梯度与None可能走不同路径:前者执行一步,后者跳过该参数的更新。

因此不能把一次参数没变直接解释为weight_decay没有作用。先检查该参数是否在优化器分组中、这步是否获得梯度、是否实际执行了更新,再看组内学习率与衰减值。

对一般AdamW,即使当前数据梯度为零,之前积累的非零矩状态仍可能继续产生自适应更新。本文能够把“零梯度”与“纯衰减”对齐,是因为教学例子设β为零并移除了历史项;真实优化器需要把状态也纳入比较。

参数分组决定衰减落到谁身上

模型通常有多个参数组,不同组可能使用不同学习率和衰减。仅记录一个全局weight_decay,不能证明所有可训练参数采用同一设置。检查最终传入优化器的参数列表与每组配置,比检查配置文件中的默认值更直接。

哪些参数需要排除衰减,应根据模型与训练设计明确决定,不能把一条网上规则当作所有模型的定律。还要确认没有参数漏组、重复加入,或在恢复训练时意外改变分组对应关系。

如果损失函数已经显式加了L2,而优化器又启用AdamW衰减,就同时存在耦合正则项和解耦收缩。这可以是有意设计,但不是“只开了一次weight decay”;应在实验说明里清楚列出。

比较配方前,先比较一次更新

固定一个小参数、梯度、学习率和优化器状态,分别计算预期与实际更新。先检查权重收缩是否按声明发生,再恢复动量、混合精度、裁剪与真实数据路径。尤其要确认梯度裁剪发生在什么位置:若把显式L2合入梯度后再裁剪,正则贡献也进入裁剪;AdamW单独的收缩不因此变成同一个算式。一次训练结束后的loss曲线无法唯一定位这些差异。

恢复实验还应记录优化器状态与学习率调度进度。只加载权重而重建零矩状态,与完整恢复不是同一个起点;因此两次训练不一致时,不应先把原因归结为随机种子。

这篇没有给出通用最优λ。读者真正可以带走的是一份更清楚的更新契约:数据梯度是什么、哪些量进入矩估计、每组衰减在哪里执行、总共执行多少次。若这个反例帮你排清了AdamW与L2的混用,欢迎通过文末支持区自愿支持。

参考与验证范围

依据AdamW论文原文、PyTorch 2.14 AdamW参考和zero_grad行为说明,于2026年10月17日核对。两幅图、标量构造和代码是原创教学内容;本地验证不包含真实优化器、模型性能或多卡运行。

支持

如果文中的解释或示例帮你解决了问题、节省了时间,欢迎自愿打赏支持本站。

微信支持二维码,点击查看大图
微信
支付宝支持二维码,点击查看大图
支付宝
Buy Me a Coffee,点击支持本站
Buy Me a Coffee

二维码可点击放大。更多支持方式见支持页面。

Share this Post

Leave a Comment

您的邮箱地址不会被公开。 必填项已用 * 标注

*
*