不知道要训多久,学习率该怎么降?
本课一问:warmup 之后,学习率要一直停在峰值吗?事先不知道要训多久,又该怎么降?
这一课先不碰:衰减那一段该喂什么数据(C7 兑现);总共该训多少 token(C6)。batch 要不要也随训练变,见岔路课。
从已有出发
训练往后走,模型对「小明把苹果给了小王」每个位置的预测一步步变准,loss 越降越慢。第 4 课管住了开局;这一课看后半程:loss 快降不动的时候,步子还该那么大吗?
继续用两个替身:峡谷(看机制)和浏览器里的小模型(看真实的 loss 曲线);大模型的真实调度都来自公开报告。
先自己设计:常数学习率一直训到底
最省事的:warmup 之后就停在峰值,一直训到结束。先回到峡谷看它在谷底附近会怎样——把 Adam 的 β₂ 切到大模型常用的 0.95、η 拖到 0.5:
轨迹冲到谷底附近后停不下来:400 步内始终进不了 1% 圈。步子是「每步约 η」,离谷底只剩不到 η 的距离时,每一步都会迈过头。再看真训练的 loss:
- ① 朴素方案
- ② 它在哪失败
- ③ 改进方案
数字来源:浏览器实时训练(纯 JS,Float64)。模型、语料、种子写在上方;同一组对照里所有 run 共用初始化和取批顺序,只改被比较的那一项。换种子重跑可以看到噪声有多大——差异小于种子间波动时不下结论。
cosine(Loshchilov & Hutter 2016 提出的 SGDR 里的形状)让学习率按半个余弦从峰值降到 ηmin:前期几乎保持大步,越往后降得越快,最后停在 ηmin。上图里的蓝线:在第 480 步已经比常数低(3.693 对 3.781),到第 600 步低 0.138。但它有一个硬伤:余弦的形状由总步数决定,开训之前就必须定好训多久。
试三件事(在「朴素方案」里):① 默认设置读表:常数 3.815、cosine 3.677、WSD 3.729。② 把种子切到 2 再跑:3.748 / 3.666 / 3.694,顺序不变。③ 把峰值切到 3×10−3:三条线挤得很近——学习率本来就小时,降不降差别不大;衰减的收益来自「峰值时的步子相对谷底太大」。
为什么降学习率,loss 会在衰减段明显下降?峡谷给了一个可以看见的解释:大步长让参数一直在谷壁之间来回,平均位置离谷底有一段距离;步长变小,它才能落到更低的地方 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条这是二次近似下的解释;真实大模型的 loss 面如何解释衰减段的骤降,仍有不同的理论模型,本课不展开 出处待补 。所以衰减段的下降来自「步子变小」,不是模型在这几百步里突然学会了新知识。
改进:WSD——把「什么时候降」推迟到决定停下的时候
cosine 的 p 是「衰减段走过的比例」,分母就是预定的总长。决定多训一半怎么办?下面是公开报告里写明的五条真实调度,底部的 what-if 面板专门回答这个问题:
what-if:训到一半想多训一段,cosine 和 WSD 各要怎么办?
试三件事:① 纵轴选「η ÷ 峰值」比形状:DeepSeek-V3 在前 10T / 14.8T ≈ 68% 的 token 里完全是平的,之后才用 cosine 降——它不是纯 cosine,是「先保持、再衰减」的混合调度。② 在图上移动鼠标到 DeepSeek-V3 的 cosine 段中间,和下方公式面板的 1.21×10−4 对一下。③ 展开 what-if,把「训到原计划的几倍」拖到 1.5:原计划的 cosine 在 T 处已经降到 10%;要是一开始就知道训 1.5T,它在 T 处应该还在 32.5%——两条线从第一步起就不一样,中途改主意只能重跑。
WSD(Warmup-Stable-Decay)是 MiniCPM 给这种「先保持、最后一段再降」的调度起的名字:warmup 之后学习率保持常数,只在最后约 10% 的 token 里衰减 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条命名与做法出自 MiniCPM;衰减段 loss 明显下降是它报告的现象 出处MiniCPM(Hu et al. 2024) ↗需联网 。它最大的好处是稳定段可以随时分叉:想要哪个长度的模型,就从稳定段的对应位置接一段衰减。Hägele et al. 2024 进一步报告,「常数 + cooldown」的 scaling 行为和 cosine 一样可预测,而且一条训练就能复用出多个长度的点 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条原文:scales predictably and reliably similar to cosine 出处Hägele et al. 2024 摘要 ↗需联网 。
在小模型上把「分叉」真做一遍:
数字来源:浏览器实时训练(纯 JS,Float64)。模型、语料、种子写在上方;同一组对照里所有 run 共用初始化和取批顺序,只改被比较的那一项。换种子重跑可以看到噪声有多大——差异小于种子间波动时不下结论。
试三件事:① 把「实验」切到「WSD 分叉 vs 重跑 cosine」:拿到 240 / 420 / 600 步三个模型,WSD 一共训练 732 步,cosine 要 1,260 步。② 读表格:每个长度上 cosine 都更低(3.757 / 3.726 / 3.677 对 3.831 / 3.766 / 3.729)——省下的算力是有代价的。③ 把「WSD 衰减段占比」从 20% 改成 30% 再跑(回到「三种调度同跑」):WSD 的最终 loss 从 3.729 降到约 3.71,和 cosine 的差距缩小但没有消失。
现代做法:有分歧
- Kimi K3 选 cosine:报告说两种调度的最优峰值学习率和 batch 差别很大,共用一组超参比较会偏向其中一个;于是为两者各做一遍独立的 scaling-law 搜索,各自在最优超参下比较,cosine 的最终 loss 一直更低 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条官方自报,没有第三方复现;值钱的是「两边各自调优再比」的方法 出处Kimi K3 技术报告 §3.2 ↗ 。上面小模型的结果方向与之一致,但那是同一组超参下的比较,恰好是 K3 说的不公平比法。
- DeepSeek 用混合调度:DeepSeek-V3 保持 2.2×10−4 到 10T token,之后 4.3T token 内 cosine 降到 2.2×10−5,再分两段常数收尾;DeepSeek-V4.1-Flash 保持到 28T、28T → 40T cosine 降到 10%、最后 5T 保持。
- MiniCPM、Hägele 的论点是可复用、可随时停;K3 的论点是在各自最优超参下 cosine 的终点更低。两者并不矛盾——它们在回答不同的问题(省算力做实验 vs 单次训练的最终 loss)。
项目里同样会跑三种调度的对照(cosine 即基线、常数、WSD),并标出 WSD 开始衰减的那一步:
⚠ 常见误解
「cosine 就是降到 0。」公式允许,实际很少这么做:GPT-3 停在峰值的 10%,之后以 10% 继续训;DeepSeek-V4.1-Flash 最后 5T token 停在 10%;我们的项目基线也是 10%。LrScheduleDemo2 的表里有每条调度「最后 ÷ 峰值」的比例。
「衰减段 loss 突然下降,说明模型在这段时间学会了新东西。」同样的数据、同样的模型,只把步子变小,loss 就会下降——小模型的 WSD 曲线里,第 480 步前和常数完全重合,开始衰减后才分开。下降主要来自优化本身;至于衰减段喂高质量数据能不能额外获益,是 C7 的问题。
「用同一组超参比一下 cosine 和 WSD,就知道哪个好。」两者的最优峰值与 batch 不同;共用一组超参,等于替其中一个选了超参(Kimi K3 的提醒)。本课小模型的对比就是这种「不公平比法」,所以只能说明现象,不能下「谁更好」的结论。
在演进地图上的位置
- 全量梯度下降
- 小批量随机梯度下降 SGD
- 动量(重球法)
- Adam:每个参数一把尺子
- AdamW:解耦权重衰减
- 学习率 warmup
- 学习率衰减:cosine → WSD
- batch 大小:渐增,还是一开始就大
- 全局梯度范数裁剪
- Muon:按矩阵的奇异方向更新
证据三问
| 问 | 本课的回答 |
|---|---|
| ① 它解决什么问题? | 常数学习率在谷底附近停不稳;cosine 必须预先定总步数,中途改主意要重跑 |
| ② 数学上为什么可能有效? | 二次近似下,步长决定参数围绕谷底波动的幅度,步长变小才能落得更低 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条局部二次近似下的解释,不是对大模型 loss 面的证明 出处待补 ;cosine、WSD 的具体形状没有最优性推导 |
| ③ 实验上为什么最后选了它? | 靠实验,而且有分歧:MiniCPM、Hägele 支持 WSD 的可复用性;Kimi K3 在独立调优后选 cosine;DeepSeek 用两者的混合 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条各家都是在自己的规模与数据上得到的结论 出处DeepSeek-V3 §4.2;Kimi K3 §3.2;MiniCPM;Hägele 2024 ↗ |
一句话
大学习率负责走远,小学习率负责落底;WSD 把「何时落底」推迟到决定停下的时候。
先停在这里:记住「常数停不稳、cosine 要先定长度、WSD 可分叉但未必最低」,进下一课。
再深一层:读 Kimi K3 报告 §3.2 那一段(本地 PDF 第 10 页),再读 Hägele 的摘要,想想它们各自在回答什么问题。
下一个缺口
学习率的时间表定了。可训练中偶尔会遇到一批「异常」数据,梯度一下子大了几十倍——一次超大的梯度,会不会把模型甩飞? → 第 6 课:一个超大的梯度会把模型甩飞吗?
回扣先记下:WSD 的衰减段 loss 下降得最快,「这段时间喂什么数据最划算」会在 C7(数据)兑现。
你可能会问
这一课还没有收到真实提问;你的提问会记到 05-问答记录/C5-L5.md。
- 「batch 要不要也随训练变化?」见岔路课:batch 能无限加大吗?
🔍 为什么多数配置停在峰值的 10%,而不是降到 0?
公开报告里只写了做法,没有给出选择 10% 的推导;GPT-3 的写法是「降到 10% 之后以 10% 继续训练」。这属于经验选择。我们的小模型也用 10%(与项目 optim.py 的 min_lr_ratio = 0.1 一致),你可以在项目里改 train.min_lr_ratio 自己试。