从0训练LLM · 现代大模型体系 实验 实验 ≈ 30 分钟 页内实验 ×5
C8 稳定性:放大后为什么会炸 实验课

实验课:给我们自己的模型装上稳定性仪表

实验课:给我们的模型装上稳定性仪表
同一份语料、同一个种子,只改一项:归一化位置 × 学习率 × warmup、QK-Norm × 学习率、初始化标准差。先写预测,再读仪表——是否发散、梯度范数峰值、最大注意力 logit 终值、开局 loss 与 ln V 的差——最后为项目拍板:要不要 QK-Norm、warmup 能不能省、初始化取多少。
🧪

这一课不讲新概念。前五课的每一条结论,都放到我们自己从 0 训练的 3.7M 参数模型上核对。所有图表直接读实验导出的真实日志;每张图下面的「口径」一行写明模型、语料、步数、种子,「读图」一行由数据现算。

为什么这里不用例句:我们的模型是在《三國志演義》上训练的,词表只有 2,048,「小明把苹果给了小王」不在它的训练分布里;这一课看的是整个验证集上的仪表读数,不是某一句话。

实验是怎么设计的

一次只改一项,其余全部与基线相同(4 层、d = 256、8 头、RoPE、Pre-LN · RMSNorm、SwiGLU、AdamW lr 3e-3、cosine、warmup 100、裁剪 1.0、fp32、400 步、种子 1337):

组改了什么回答哪一课的问题
① 归一化位置Post / Pre × lr 1e-2 / 3e-2,全部不 warmup;另加 12 层的 Post / Pre,和 12 层有 warmup 的 Post第 2 课
② QK-Norm开 / 关 × lr 3e-3 / 1e-2 / 3e-2(warmup 100)第 3、4 课
③ 初始化init_std ∈ 0.002 / 0.02 / 0.2 / 1.0第 1 课

每次评估(每 20 步)在验证集前 8 个 256-token 窗口上多做一次前向,记下所有层、所有头 softmax 之前的最大 q·k/√d(「最大注意力 logit」),以及输出 logit 的最大绝对值;梯度范数是裁剪前的全局范数,每 5 步记一次均值与最大值。

从已有出发 · 训练的一步(点任一环节看它在 Qwen/Qwen3.8-27B 上有多大) 本课本章后面的课
✍️

先写下你的预测(读完前五课再猜,猜错比猜对更有用):

  1. 不 warmup、学习率 1e-2 时,Post-LN 和 Pre-LN 谁会出事?「出事」会是发散成 NaN,还是别的样子?
  2. 不开 QK-Norm,学习率从 3e-3 放大 10 倍到 3e-2,最大注意力 logit 的终值会放大几倍?
  3. 开了 QK-Norm 之后,最大注意力 logit 能不能超过 √32 ≈ 5.66?
  4. init_std = 1 时,开局 loss 是多少?(第 1 课的组件能算出来)

一、先看验收表

项目实测 · C8 验收表

MILESTONES「C8 稳定性」的验收只看四个量:是否发散、梯度范数峰值、最大注意力 logit 终值、开局 loss 与 ln V 的差。这张表把 17 个对照 run 的四个量排在一起(有几个 run 在不同组里重复出现,比如基线同时是 QK-Norm 关 · lr 3e-3 和 init_std 0.02)。

二、归一化放在哪(第 2 课)

项目实测 · 不 warmup、高学习率:Post-LN vs Pre-LN

对照你的预测 1:Post-LN 没有发散成 NaN,而是卡在 unigram 基线——最终 val 与「只按字频猜」的 6.6247 几乎一样;梯度范数也没有飙升(和同设置的 Pre-LN 逐对比一比「梯度范数峰值」)。这是「训不动」的一种样子——第 2 课的 β 图给了一种解释:Post-LN 对参数扰动更敏感,开局那几步大更新可能把它推进一个出不来的区域;但这是解读,本轮没有做能确认机制的消融。「更小的学习率 + warmup 能不能救回来」已经补测(第 2 课「补充实验」):4 层 Post-LN 学习率 1e-3 时,不 warmup 6.627、warmup 100 步 4.865;3e-4 时 5.496 / 5.478;词向量放大 16 倍仍停在 6.626。比 100 步更长的 warmup 还没有测。切到「最大注意力 logit」:Pre-LN 不 warmup 时也在长,只是没有卡住。

三、QK-Norm(第 3、4 课)

项目实测 · QK-Norm 开 / 关:最大注意力 logit

对照预测 2、3:关着 QK-Norm,学习率 3e-3 → 3e-2,最大 logit 终值从 49.9 到 6784;开着 QK-Norm,最大值能超过 5.66,因为 5.66 是增益为 1 时的上界,增益是可学习的——逐层终值表里能看到每一层各自长到了多少。

四、初始化(第 1 课)

项目实测 · 初始化标准差四档

对照预测 4:第 1 课的蒙特卡洛与这里的实测应该对得上;表里「预测」一列用的就是第 1 课那个公式。

五、最大注意力 logit:所有 run 放在一起

项目实测 · 最大注意力 logit 随训练怎么长

六、把结论对回前五课

课那一课的结论在我们的模型上看什么
第 1 课开局 loss ≈ ln V;σ 太大开局 logits 爆,太小学不动四档初始化的开局 loss − ln V 与最终 val;开局 logit 标准差的预测与实测
第 2 课Post-LN 对扰动敏感,离不开 warmupPost-LN 四组都卡在 unigram,包括有 warmup 的 12 层组;Pre-LN 不 warmup 也在学
第 3 课spike 的前提是参数状态:logit 被一步步养大最大注意力 logit 随学习率、随 warmup 的增长(本规模上没有真的 spike)
第 4 课QK-Norm 从源头按住注意力 logit开 / 关对比:学习率越大,最大 logit 终值差得越多(倍数见「三」的读图);val loss 不变差
第 5 课SP 下每一步的改动 ∝ 宽度 × η本轮 C8 实验不涉及;C6 的宽度 × 学习率扫描见第 5 课
⚖️

这些结论只在这个规模上成立:3.7M 参数(12 层组约 10M)、约 50 万 token 的语料、400 步、单种子 。没有一条曲线出现真正的 loss spike——PaLM 说 spike 只在最大的模型上出现,我们能看到的是它的前提(logit 的增长)。实验课的价值不在「证明谁最好」,在于练习先写下预测、只改一项、连同条件报告结论,以及学会读仪表。

七、为项目拍板

🧭

你要拍板的三件事(对应章首页的项目里程碑):

  1. 要不要 QK-Norm?依据「三」:最大注意力 logit 终值差多少,val loss 有没有变差(差距小于噪声的不算)。
  2. warmup 能不能省?依据「二」:Pre-LN 不 warmup 时 val 比基线差多少、最大 logit 长到多少;Post-LN 不在候选里(C4 已选 Pre-LN)。
  3. 初始化标准差取多少?依据「四」:开局 loss − ln V 与最终 val。

验收标准(全部可测):选定配置不发散;开局 loss − ln V 不大于基线的 0.0606;梯度范数峰值与最大注意力 logit 终值写进报告并与基线对比;两个配置相差小于噪声底线(C14:同配置 5 次重跑极差 0.016,3σ ≈ 0.020)时,不下结论,换 3 个种子取均值。

🔍 自己复现这个实验

脚本在 04-实践项目/experiments/exp_c8_stability.py,训练配置沿用 04-实践项目/configs/baseline.json,开关在 model.norm_pos、model.qk_norm、model.init_std 与 train.lr、train.warmup_steps;与其他章配置相同的 run(C4 的两组不 warmup、C5 的 lr 1e-2、C6 的 lr 3e-2)直接复用。导出到 知识平台/src/data/project/c08-stability.json,本页所有图表自动读它。最大注意力 logit 由 experiments/common.py 的探针在每次评估时记录,不参与训练。「warmup 能不能救回 Post-LN」的四个补充 run(lr 1e-3、3e-4 各有无 warmup)已导出在 postln_high_lr,读数见第 2 课「补充实验」。

一句话

📌
一次只改一项、先写预测、连同条件报告:仪表(梯度范数、最大注意力 logit、开局 loss − ln V)比「这次没炸」更能迁移到大模型上。

下一个缺口

训练一个参数,要几字节? → C9 第 1 课:训练一个参数,要几字节?