从0训练LLM · 现代大模型体系 阅读 + 实验 ≈ 30 分钟 页内实验 ×2
C5 优化:参数怎么更新得又快又稳 第 4 课

为什么一开局就用峰值学习率会炸?

warmup:先小步,再放开
Adam 第 1 步每个参数恰好走 ±η。浏览器里真训练的小模型,峰值 η = 0.3 直接开局:η 是输出层权重典型大小的 24 倍,第 2 步 loss 从 5.55 跳到 35.4。让 η 在前 30 步线性爬升,第 2 步只有 5.35。warmup 管的是开局——峰值本身太大,后面照样会出尖峰。
❓

本课一问:第 2 课发现,做完偏置修正以后,Adam 第 1 步每个参数恰好走 ±η。如果 η 一开始就是峰值,会怎样?

这一课先不碰:学习率后期怎么降(第 5 课);Post-LN 结构为什么格外离不开 warmup(C8 兑现)。

从已有出发

「小明把苹果给了小王」送进一个刚初始化的模型,每个位置的 loss ≈ ln 248,320 = 12.42——它还什么都没学,这一刻的梯度是用一堆随机参数算出来的。前三课把「每一步怎么走」定下来了(AdamW)。这一课第一次碰「学习率」那一格:它不必从头到尾是同一个数。

从已有出发 · 累计数据流 点已学环节看形状与参数
解码层
从已有出发 · 训练的一步(点任一环节看它在 Qwen/Qwen3.8-27B 上有多大) 本课本章后面的课

loss 曲线要真训练才有,所以继续用浏览器里的小模型(《三國志演義》24,000 字,24,896 个参数);大模型的真实配置放在后面对照。

先自己设计:第 1 步就用峰值

最简单的就是常数学习率:定一个峰值 η,从第 1 步用到最后。下面两个 run 共用同一个初始化和取批顺序,只差「前 W 步要不要从小到大爬」:

  1. ① 朴素方案
  2. ② 它在哪失败
  3. ③ 改进方案
朴素方案常数学习率:第 1 步就用峰值 η
开局直接用峰值学习率 vs 先 warmup 字级 MLP · 24,896 参数 · 《三國志演義》24,000 字 · 浏览器内真训练
等待开始(滚动到这里会自动开始)

数字来源:浏览器实时训练(纯 JS,Float64)。模型、语料、种子写在上方;同一组对照里所有 run 共用初始化和取批顺序,只改被比较的那一项。换种子重跑可以看到噪声有多大——差异小于种子间波动时不下结论。

🎯

试三件事:① 默认设置下读第一行:不 warmup 的第 1–4 步 loss 是 5.549 → 35.421 → 22.059 → 16.096,warmup 是 5.549 → 5.348 → 4.805 → 3.820;再读第三行:第 1 步梯度非零的 21,408 个权重,位移 ÷ η 全在 0.8999–1.0000 之间——「每个参数都走满一个 η」不是比喻。② 把峰值切到 0.03:η 小于 W1 权重的典型大小,开局冲击几乎消失,两条线差不多——warmup 的必要性随峰值变大才出现。③ 峰值留在 0.3、换种子 2:不 warmup 第 2 步 50.3;再看绿线第 30 步以后,warmup 结束、η 到了峰值,仍然会冒出 12 左右的尖峰。

为什么会炸:第 1 步没有「小梯度就小步」这回事

SGD 的位移是 η × 梯度:梯度小的参数自然走得少。Adam 第 1 步做完偏置修正,m̂ = g、√v̂ = |g|,位移 = η·g ÷ (|g| + ε) ≈ ±η 。所有参数同时走满一步,方向只由梯度的符号决定。

这一步有多大,要和参数本身的大小比:

改进:warmup

线性 warmup(与 04-实践项目 minillm/optim.py 的 lr_scale 同一个式子)
= · min(1, / )
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
warmup 结束后 min(…) 恒为 1。第 1 步的 Adam 位移从 ±η_peak 变成 ±η_peak/W;之后的几十步里,v 已经积累了多个样本,分母也更可靠。

它为什么管用,有三条不同层次的理由:

  1. 第 1 步的位移按比例缩小:位移从 ±ηpeak 变成 ±ηpeak/W,上面的组件直接量得到 。
  2. 开局时自适应分母不可靠:v 在前几步只是很少几个梯度平方的平均,「这个参数的梯度通常有多大」还估不准;RAdam 的作者分析了这个早期方差,把 warmup 解释为一种降方差手段 。
  3. 大 batch 训练的经验:Goyal et al. 2017 用「学习率随 batch 线性放大 + 逐步 warmup」,把 ResNet-50 的 batch 放大到 8,192、在 256 块 GPU 上一小时训完且精度不降;不做 warmup,大 batch 开局就难以优化 。

真实配置里的 warmup(全部来自原文):

模型warmup升到的峰值
Transformer(Vaswani 2017)4,000 步随步数的公式(式 3)
GPT-3 175B前 3.75 亿 token0.6×10−4
Llama 3 405B8,000 步8×10−5
DeepSeek-V3前 2K 步2.2×10−4
DeepSeek-V4-Flash前 2,000 步2.7×10−4
Kimi K3总步数的 1%报告未给具体值
我们的项目基线100 步(共 400 步)3×10−3

旧版课程写过「warmup 取总步数的 1%–10%,常用 3%」,没有给出处;上表的真实配置从 Kimi K3 的 1% 到我们项目的 25% 都有,长度要和峰值一起调。出处:Vaswani 2017 §5.3(本地 PDF);GPT-3 附录 B 与表 2.1;Llama 3 据 R4 从原文摘录;DeepSeek-V3 §4.2、V4 §4.2.2、Kimi K3 §3(本地 PDF);项目 configs/baseline.json。

在我们的项目里

项目 MILESTONES 记录过一次预跑:基线把 warmup 从 100 步改成 40 步,最终验证 loss 从 4.63 变成 4.74——那次的日志没有保留,需要重跑确认。重跑的对照实验(同一学习率有无 warmup、高学习率下有无 warmup)会出现在这里:

项目真实日志 · warmup 对照

⚠ 常见误解

⚠

「warmup 是让模型先适应一下数据。」这个说法解释不了任何数字。它真正改变的只有一件事:前 W 步的学习率。有用的原因是上面三条:第 1 步的位移、早期不可靠的 v、大 batch 的开局。

⚠

「有了 warmup,峰值就可以随便大。」warmup 只保护开局。组件里峰值 0.3 的绿线在第 30 步以后照样出现 12 左右的尖峰——峰值本身太大,要靠调小它、后期衰减(第 5 课)和梯度裁剪(第 6 课)。

⚠

「warmup 越长越稳,越长越好。」warmup 期间学习率偏小,等于少训了几步;Kimi K3 只用总步数的 1%。项目预跑里 warmup 变短让 loss 变差,但那次日志没保留,方向可信、数值待确认。长度和峰值要一起调。

在演进地图上的位置

优化的演进:每一代都被上一代的某个真数字逼出来(点名字去那一课;完整版在章首页)
  1. 全量梯度下降
  2. 小批量随机梯度下降 SGD
  3. 动量(重球法)
  4. Adam:每个参数一把尺子
  5. AdamW:解耦权重衰减
  6. 学习率 warmup
  7. 学习率衰减:cosine → WSD
  8. batch 大小:渐增,还是一开始就大
  9. 全局梯度范数裁剪
  10. Muon:按矩阵的奇异方向更新
时间维 ①学习率 warmupGoyal 2017;RAdam 2019 给出方差解释你在这里
解决了前 W 步让 η 线性爬升;同样的峰值与种子,warmup 30 步时第 2 步 loss 为 5.35。
卡在warmup 只管开局:之后若一直用常数学习率,Adam 在谷底附近来回跳;cosine 又必须事先定好总步数。
数字口径:峡谷步数、Newton-Schulz 范围、DeepSeek-V3 与 WSD 的步数账在构建时现算;标「浏览器实训」的来自本章 MicroTrainer 的默认设置(种子 1,Chrome 实测);DeepSeek-V3 数字出自其报告 §4.2(本地 PDF);Moonlight「约 2 倍」出自 arXiv 2502.16982 摘要;Kimi K2「max logit > 1000」出自 arXiv 2507.20534;Qwen3.8-Flash-Next 为官方技术报告自报。

证据三问

问本课的回答
① 它解决什么问题?开局第 1 步每个参数同时走满 η,在峰值较大时把模型一步推到离谱的位置
② 数学上为什么可能有效?第 1 步位移由 ±η 变成 ±η/W 是直接代入的结果 ;「早期自适应学习率方差过大」是 RAdam 的分析
③ 实验上为什么最后选了它?大 batch 图像分类(Goyal 2017)、此后的 LLM 预训练几乎都用;我们的微型模型上可以直接看到有无 warmup 的开局差别

一句话

📌

Adam 第一步每个参数都走满 η;warmup 让「第一步」先小下来。

🚦

先停在这里:记住「开局的问题 = 每个参数同时走满一步」,进下一课。
再深一层:读 RAdam 的摘要与 §3,看它怎么把「warmup 为什么有效」变成一个可以计算的方差问题。

下一个缺口

warmup 之后呢?第 2 课的峡谷里,Adam 在 β₂ = 0.95、η = 0.5 时一直在谷底附近跳;组件里峰值 0.3 在 warmup 之后也还有尖峰。学习率要一直停在峰值吗?事先不知道要训多久,又该怎么降? → 第 5 课:不知道要训多久,学习率该怎么降?

回扣先记下:原版 Transformer(Post-LN)对 warmup 的依赖比现在的 Pre-LN 模型强得多,原因在归一化放在哪——C8 兑现。

你可能会问

这一课还没有收到真实提问;你的提问会记到 05-问答记录/C5-L4.md。

🔍 warmup 为什么是线性的?别的形状行不行?

线性只是最常用、最好描述的一种;Transformer 原文的公式在 warmup 之后按 1/√step 衰减,warmup 段本身也是线性的。组件里决定开局冲击的是「第 1 步的 η 有多小、多少步后到峰值」,形状细节是次要的。形状对最终效果的影响属于实验问题,本课没有找到可核实的系统对比,不下结论。

🔍 除了学习率,batch 也有「warmup」吗?

有:GPT-3 的 batch 从 32K token 逐步增大,DeepSeek-V3 在前 469B token 内从 3,072 条增加到 15,360 条。但也有人取消了它——见岔路课:batch 能无限加大吗?