一个学习率管得了所有参数吗?
本课一问:上一课的峡谷只有两个方向。一个真模型有几百亿个参数,它们的梯度大小能差多少?一个学习率管得过来吗?
这一课先不碰:weight decay 放在哪(第 3 课);学习率随步数怎么变(第 4、5 课);一个权重矩阵的整体结构(第 7 课)。
从已有出发
「小明把苹果给了小王」进模型的第一步,是按 token 查 embedding 表的行(C1)。这一批数据里出现过的 token,它们那几行会收到梯度;没出现过的 token,那一行这一步的梯度恰好是 0。再往后,注意力、FFN、输出层的梯度大小又各不相同。同一个模型里的参数,「该走多大一步」显然不是一回事。
用哪个模型测。锚点 Qwen3.8-27B 的训练过程没有公开,我们也不在页面里训练它。所以这一课用一个在浏览器里真训练的字级小模型:《三國志演義》前 24,000 字,4 个字的上下文预测下一个字,24,896 个参数(结构写在组件标题下)。它小,但梯度是真算出来的;同样的测量在我们项目的 3.7M 参数模型上也会做(本课最后)。
先自己设计:全体参数共用一个 η
最省事的就是上一课的做法:动量 SGD,全体参数一个 η。先量一量它要面对的梯度。
- ① 朴素方案
- ② 它在哪失败
- ③ 改进方案
数字来源:浏览器实时训练(纯 JS,Float64)。模型、语料、种子写在上方;同一组对照里所有 run 共用初始化和取批顺序,只改被比较的那一项。换种子重跑可以看到噪声有多大——差异小于种子间波动时不下结论。
试三件事(先看「朴素方案」):① 读表格:embedding E 的梯度均方根只有输出层 W2 的约 1/55,而 E 里约 77% 的数这一步恰为 0。② 切到「训练 100 步后」:99%/1% 的比值降到约 560,但各组之间仍差好几倍——这不是初始化才有的现象。③ 换「第 2 批」「第 3 批」:比值在 860–950 之间,零的比例在 12% 左右——换一批数据,结论不变。
改进:Adam
Adam(Kingma & Ba 2014)对每个参数单独做两件事:像上一课那样对梯度做滑动平均(一阶矩 m,方向更稳);再对梯度的平方做滑动平均(二阶矩 v,记住这个参数的梯度通常有多大),最后用 m 除以 √v。梯度一直大的参数被压小,梯度一直小的被放大——每个参数有了一把自己的尺子。
试三件事(在上面「改进方案」的账本里):① t = 1:缓方向梯度 −9、陡方向梯度 150,位移都是 0.1000(= η)。② 把「偏置修正」切到「关」:第 1 步变成 3.162η;再把 β₂ 切到 0.95:变成 0.447η——偏置修正就是为了消掉这个开局的偏差。③ 把 t 拖到 20:陡方向已经越过谷底(y 变成负数),m 正在由正转负,步长降到 η 的一半以下(0.443η);缓方向仍是 0.958η——梯度大的方向,步子反而没那么大。
放回峡谷里和前两种方法比。注意 Adam 的 η 是另一个单位,下面给它单独一条滑杆:
试三件事:① 默认设置下读表:GD 241 步、动量 87 步、Adam(η = 0.3)83 步。② hover Adam 轨迹的前几个点:它一开始沿对角线走——两个方向每步各走约 0.3,不管梯度差了 17 倍。③ 把 β₂ 切到 0.95(大模型的常用值),再把 Adam 的 η 拖到 0.5:400 步内进不去 1% 圈,轨迹在谷底附近来回跳。β₂ 小,v 记性短,谷底附近梯度一变小,分母跟着变小,步子又放大——常数学习率停不稳,第 5 课回到这个问题。
代价一:每个参数多存两份
m 和 v 都与参数同形。以 Qwen3.8-27B 的 embedding 表为例:
| 维度 | 含义 | 真实规模 | 小规模 |
|---|---|---|---|
| V | 词表大小(embedding 行数) | 248,320 | 6 |
| d | 隐藏维度 hidden_size | 5120 | 4 |
代价二:它只认坐标轴
Adam 的缩放是逐坐标的:第 i 个参数除以第 i 个参数自己的 √v̂。峡谷的两条轴恰好对齐坐标轴时,这就是完美的缩放。如果峡谷是斜的呢?
试三件事:① 把转角从 0° 拖到 45°:GD 始终 241 步、动量始终 87 步——它们只用梯度向量本身,整张图转一下,轨迹跟着转。② 同时看 Adam:83 步涨到 233 步;右边曲线把每 5° 的结果都算了出来。③ 把 Adam 的 η 改成 0.2 再拖一遍:0° 时 101 步,45° 时 327 步。逐坐标的尺子,只在「坐标轴 = 曲率主方向」时量得准。一个权重矩阵的「主方向」一般不对齐任何一个坐标,第 7 课回到这里。
在我们的项目里
同样的测量(各参数组梯度的均方根、分位数与零占比)会在项目的 3.7M 参数 Transformer 上做一遍,第 0 步和第 200 步各一次:
⚠ 常见误解
「Adam 的学习率和 SGD 的学习率是同一个东西。」不是。SGD 的位移 = η × 梯度,η 的单位是「参数 ÷ 梯度」;Adam 的位移 ≈ η × (±1),η 的单位就是参数本身。所以 GPT-3 的 Adam 取 0.6×10−4、我们微型模型的动量 SGD 取 0.03,两个数放在一起比没有意义。
「Adam 是按曲率缩放的,相当于二阶方法。」v 是梯度平方的滑动平均,不是 Hessian。峡谷里陡方向的梯度恰好也大,所以看起来像;但到了谷底附近梯度变小,v 仍记着以前的大梯度——它量的是「梯度通常有多大」,不是「这里有多弯」。上面的旋转实验也说明它不是真正的二阶方法:真二阶方法对旋转不敏感。
「Adam 自适应,所以不用调学习率。」峡谷上取 β₂ = 0.95 时,η 从 0.3 调到 0.5 就进不了 1% 圈;实验课里 AdamW 的三个学习率,最终 loss 也不一样。自适应的是「各参数之间的相对步长」,整体步长 η 仍然要调。
在演进地图上的位置
- 全量梯度下降
- 小批量随机梯度下降 SGD
- 动量(重球法)
- Adam:每个参数一把尺子
- AdamW:解耦权重衰减
- 学习率 warmup
- 学习率衰减:cosine → WSD
- batch 大小:渐增,还是一开始就大
- 全局梯度范数裁剪
- Muon:按矩阵的奇异方向更新
证据三问
| 问 | 本课的回答 |
|---|---|
| ① 它解决什么问题? | 不同参数的梯度尺度差上千倍、还有大量参数这一步梯度为 0,一个全局 η 顾此失彼 |
| ② 数学上为什么可能有效? | 偏置修正后第 1 步每个参数恰好走 ±η;把某个参数的梯度整体乘一个常数,它的更新不变(逐坐标缩放不变) 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条忽略 ε 时代数上直接成立;旋转后不成立(见上面的旋转实验) 出处Kingma & Ba 2014 摘要与 §2 ↗需联网 ;「这样的缩放有利于优化」是动机,不是定理 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条原论文用在线凸优化框架给了 regret 界;对深网为什么有效没有证明 出处待补 |
| ③ 实验上为什么最后选了它? | 原论文在多种任务上对比;此后 LLM 预训练长期默认 Adam 系:GPT-3 用 Adam(β₂ = 0.95)、DeepSeek-V3 用 AdamW(β₂ = 0.95) 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条2025 年起中国前沿实验室的矩阵参数转向 Muon(第 7 课) 出处DeepSeek-V3 §4.2;GPT-3 附录 B ↗ |
一句话
Adam 给每个参数配一把自己的尺子:步长约等于 η,与梯度大小无关。
先停在这里:记住「m 管方向、v 管尺度、第 1 步恰好 ±η」,进下一课。
再深一层:读 Adam 原论文算法 1,把上面账本里每一列和算法里的每一行对上。
下一个缺口
Adam 有了。可训练 LLM 时几乎都还要加一个 weight decay,把参数往 0 轻轻拉。把它加进 Adam 的梯度里,它还是原来那个 weight decay 吗? → 第 3 课:Adam 里的 weight decay 为什么失效了?
回扣先记下:「第 1 步每个参数都走满 η」会在第 4 课变成一个问题;「只认坐标轴」会在第 7 课变成 Muon 的出发点。
你可能会问
这一课还没有收到真实提问;你的提问会记到 05-问答记录/C5-L2.md。
🔍 Adam 之前还有哪些「自适应」方法?
Adam 论文自己说它借鉴了之前的算法(摘要:「on which Adam was inspired」),正文讨论的是 AdaGrad 和 RMSProp:前者把历史梯度平方全部累加(步长只会越来越小),后者改成滑动平均(Adam 的 v 就是这个思路)。RMSProp 出自 Hinton 的课程讲义,没有正式论文。这些细节本课没有逐一核实原文,只作脉络参考。
🔍 PaLM 为什么不用 Adam?
PaLM 用的是 Adafactor(省显存的 Adam 变体,不存完整的 v),并把 β₂ 设成随步数变化的 1 − k−0.8。原文给的理由正好对应本课的零梯度现象:稀有 token 的 embedding 很久才收到一次梯度,短窗口里二阶矩估计得不准(R4 从 PaLM 原文 arXiv 2204.02311 摘录)。