稳定性:放大后为什么会炸
主线定位
点任一已学环节,看这一步的输入 → 输出形状、参数量,以及它解决了什么问题(数字取自 Qwen/Qwen3.8-27B 真实 config)。
- 上游:C5 优化让一个模型训得动(Adam、warmup、裁剪、Muon);C6 规模定了训多大、超参怎么随规模变;C7 数据定了喂什么。C5 和 C6 各留下几个「C8 兑现」的伏笔:Post-LN 为什么离不开 warmup、开着裁剪为什么还 spike、原版 Muon 的 max logit 为什么超过 1,000、μP 怎么让学习率不随宽度变。
- 本章:把模型放大之后训练出事的五种方式,各自对应到一个能测的量。结论是:给训练装仪表,每块仪表各有上限。
- 下游:C9 精度——logit 漂到上千时,BF16 相邻两个可表示数相差 4,稳定性和数值格式在那里汇合;C14 评测与仪表把本章的仪表变成日常监控;C15 前沿讲残差流的新结构(mHC、Gated Residual、AttnRes)与激活截断。
Google 的 Deep Learning Tuning Playbook 有一句话可以当本章的入口:任何模型,学习率大到一定程度都会不稳定;不稳定只有在它逼你用更小的学习率时,才是问题。本章每一课都是在回答「怎样不降学习率,也不炸」。
本章问题链
每一课只回答一个问题;上一课留下的缺口,就是下一课的问题。
| 课 | 这一课的问题 | 朴素方案在哪个真数字上失败 | 一句话 |
|---|---|---|---|
| 第 1 课 | 深网为什么一初始化就炸? | N(0,1) 初始化:4,096 维时每层 ×64,第 22 层超过 FP32 上限 | 方差逐层累乘;现代 LLM 把它交给归一化,初始化只管残差写回与开局 logits(loss ≈ ln V) |
| 第 2 课 | 原版 Transformer 为什么离不开 warmup? | Post-LN 对参数扰动的放大随层数线性增长;我们的 Post-LN 在学习率 1e-3 下不 warmup 卡在 unigram,加 100 步 warmup 就训得动 | Post-LN 越深越放大扰动,只能靠 warmup 起步;Pre-LN 主路只剩加法,于是稳,代价是深层被稀释 |
| 第 3 课 | 开着梯度裁剪,为什么还会 loss spike? | PaLM 开着裁剪仍约 20 次 spike;同一批数据换早 checkpoint 不 spike | 裁剪管步长,不管走到哪;spike 是数据 × 参数状态,要盯状态 |
| 第 4 课 | 怎么按住 logit? | 分数 8/7/9 放大 10 倍 → 99.995%;K2 原版 Muon 的 max logit 超过 1,000 | ÷√d 只管初始化那一刻;QK-Norm 钉住 q、k 长度,z-loss 拉回 log Z,QK-Clip 超标后缩权重 |
| 第 5 课 | 小模型上调好的学习率,大模型能用吗? | SP 下 Adam 一步的改动 ∝ 宽度 × η:宽 20 倍就大 20 倍 | μP 按宽度缩放每层的初始化与学习率,让每步改动与宽度无关 |
| 实验课 | 给我们自己的模型装上稳定性仪表 | — | 一次只改一项、先写预测、连同条件报告 |
演进地图
本章给训练装的五块仪表,每块都有一个上限:
| 仪表 | 量什么 | 上限怎么来 | 在哪一课 |
|---|---|---|---|
| 初始化方差 / 开局 loss | 第 0 步每层的 RMS;开局 loss − ln V | fan-in 缩放;归一化;残差写回 1/√(2L) | 第 1 课 |
| 残差流与梯度尺度 | 参数扰动对输出的放大;逐层梯度 | 归一化放进支路(Pre-LN)或放大残差(DeepNet) | 第 2 课 |
| 梯度范数趋势 | 裁剪前的梯度范数:突刺与缓慢上涨 | 裁剪只管单步;趋势用来提前报警 | 第 3 课 |
| 注意力 logit 与 log Z | 逐层最大 q·k/√d;输出 logit 的整体水平 | QK-Norm(锚点每头 256 维,上界 16·g²)、QK-Clip(τ = 100)、z-loss | 第 3、4 课 |
| 每一步的更新量随宽度 | 一步更新后隐层输出的相对变化 | μP:隐层学习率 ∝ 1/fan_in | 第 5 课 |
贯穿例句
全章沿用「小明把苹果给了小王」(C3 起用锚点 Qwen3.8 的真 tokenizer 切成 5 个 token)。它在每一课的用法不同,都写在那一课的「从已有出发」里:第 1 课让这 5 个位置的向量穿过 64 层随机初始化的网络;第 2 课让它们穿过 Post-LN / Pre-LN 两种堆叠;第 3 课看「给了」这一行注意力在两个候选间的取舍;第 4 课用 C3 那一行分数 8 / 7 / 9;第 5 课把 5 个 token 在隐层的输入当成一个 batch。向量本身都是随机数代替的(页面写明),要看的只是尺度。实验课回到我们自己在《三國志演義》上训练的模型,例句不在它的训练分布里,所以那里换成看整个验证集。
三层交互
| 层 | 本章里的组件 | 在哪一课 |
|---|---|---|
| 概念动画 | 同一个块两种归一化位置的逐步动画(C4 的 BlockFlow);演进地图 | 第 2 课、各课 |
| 算法模拟器(真算法、小数据) | 64 层随机网络的逐层 RMS 与真溢出;Post / Pre-LN 的手写反向传播与扰动放大;悬崖一步;softmax 饱和、q/k 对齐、四种按法与 z-loss;Adam 第 1 步随宽度的改动 | 第 1–5 课 |
| 真模型 / 真数据 | 我们自己从 0 训练的模型:Post / Pre × 学习率 × warmup、QK-Norm × 学习率、初始化四档的真实日志,带最大注意力 logit 探针;锚点与前沿模型的官方 config | 第 1–5 课与实验课 |
项目推进:给我们的模型装上稳定性仪表
对应 04-实践项目/MILESTONES.md 的「C8 稳定性」。分工照旧:代码 AI 来写,决策你来做。norm_pos、qk_norm、init_std 三个开关与最大注意力 logit 探针已经实现,实验脚本 experiments/exp_c8_stability.py 导出本章组件读取的 c08-stability.json。
- 要不要 QK-Norm?依据:QK-Norm 开 / 关在三档学习率下的最大注意力 logit 终值与 val loss(第 4 课、实验课)。
- warmup 能不能省?依据:Pre-LN 不 warmup 在学习率 1e-2 与 3e-2 下的 val 与最大 logit,对照有 warmup 的基线(第 2 课、实验课)。归一化放在哪,C4 已经选了 Pre-LN;本章的数据给出了「为什么」。
- 初始化标准差取多少?依据:四档 init_std 的开局 loss − ln V 与最终 val(第 1 课、实验课)。
验收标准(全部可测,取自 MILESTONES):
- 是否发散(
status);梯度范数峰值(grad_norm_max_all);最大注意力 logit 终值;开局 loss 与 ln V 的差——四个量写进报告,并与基线并排。 - 开局 loss − ln V 不大于基线的 0.0606(ref_baseline 开局 7.6852 减 ln 2048)。
- 两个配置相差小于噪声底线时不下结论,换 3 个种子取均值。噪声底线以 C14 为准:同配置 5 次重跑极差 0.016,3σ ≈ 0.020(ref_baseline 与 baseline 这一对相差约 0.014)。
- 本轮缺口(写进报告):Post-LN 的补充实验已做(学习率 1e-3 下 100 步 warmup 救回,见第 2 课),更长 warmup 与更深模型的组合还没有测;μP 版本的对照没有实现。
坑与带走
| 坑 | 症状 | 后果 | 怎么办 |
|---|---|---|---|
| 权重直接用 N(0,1) | 第 0 步就出现 inf / NaN | 一步都训不了 | 按 fan-in 缩放,或固定小标准差 + Pre-Norm(第 1 课) |
| 共享 embedding 用大 σ 却不缩放 logits | 开局 loss 远高于 ln V(σ = 1 时约 55) | 前几百步白训,最终 val 也更差 | 开局自检 loss ≈ ln V;PaLM 的做法是 logits 乘 1/√n(第 1 课) |
| Post-LN + 大学习率不 warmup | 我们的项目里 loss 卡在 unigram 附近,不发散也不下降 | 模型只学到字频 | 用 Pre-Norm + 最终 norm;坚持 Post-LN 就要小学习率 + 长 warmup(第 2 课) |
| 只看 loss,不看梯度范数与注意力 logit | spike 来得毫无预兆 | 回滚、跳数据、浪费算力 | 记录裁剪前梯度范数、逐层最大注意力 logit、输出 logit;算 spike score(第 3 课) |
| 以为 ÷√d 就管住了注意力 logit | 高学习率下 max logit 涨到上千 | softmax 饱和、梯度传不回、spike | QK-Norm / QK-Clip;输出端 z-loss(第 4 课) |
| 小模型调好的学习率直接搬到宽模型 | 大模型开局不稳或学得慢 | 反复重调,算力浪费 | μP,或拟合超参缩放律(第 5 课、C6 第 4 课) |
这一章你应该带走的(各课「一句话」):
- 方差逐层累乘:N(0,1) 每层放大 √d;按 fan-in 缩放能止住累乘,现代 LLM 把这件事交给归一化,初始化只管残差写回有多大、开局 logits 有多大(loss ≈ ln V)。
- Post-LN 把每个子层都放在主路上,越深越放大参数扰动,只能靠 warmup 慢慢起步;Pre-LN 让主路只剩加法,于是稳——代价是深层写入被稀释。
- 裁剪只限制每一步走多远,管不住走到了哪:logit 被一步步养大之后,一步普通大小的更新就能让 softmax 翻转——spike 是数据 × 参数状态的产物,要盯的是状态。
- logit 有两处会失控:注意力的 q·k 与输出层的 log Z;÷√d 只管得住初始化那一刻,QK-Norm 钉住 q、k 的长度,z-loss 把 log Z 拉回 0,QK-Clip 超标时回头缩权重。
- 标准参数化下 Adam 每一步让隐层输出变化 ∝ 宽度 × η;μP 按宽度缩放每层的初始化与学习率,让每一步改多少与宽度无关,小模型上调好的学习率就能直接搬。
深入这一章
每条都实际打开核对过(2026-09-26):写清它讲清了什么、对应哪一课、为什么推荐。外部链接都需要联网;论文有本地 PDF 的直接链本地。spaces.ac.cn 对脚本访问返回 403,四篇苏剑林的文章按 Wayback 存档核对了标题、日期与小节。
🎮 想更直观 10–30 分钟
🔬 想吃透原理 1–3 小时
📄 想读原文 按需
排除了什么(也是筛选标准):① OPT-175B 的训练日志(metaseq chronicles,README 可访问)——日志是逐事件的 PDF,本章没有逐页核对,「多次重启」的说法只见于二手转述,不收;② Cerebras 博客上的同名 μP 指南——与 EleutherAI 博客是同一篇合写文章,只收一处;③ 五道口纳什归一化视频的配套 notebook——链接 404,只保留视频;④ 苏剑林博客导航里的《为什么梯度裁剪的默认模长是 1?》——属于 C5 的主题,本章没有核对内容;⑤ Laker Newhouse《Understanding Muon》——第 3 章讲 MuonClip 与权重约束,内容与 C5 第 7 课重合更多,放在第 4 课侧栏而不进三档;⑥ 只列「QK-Norm / z-loss / μP 是什么」、不讲它们各自在什么真数字上被逼出来的速通与转载。另注:OLMo 2 把 QK-norm 的首提写成 Dehghani 2023,旧 M8 课把 DeepSeek-V4「不用 QK-Clip」写在 §2.3.3——两处都已在正文纠正。