残差流越加越大,怎么让每一层看到尺度稳定的输入?
本课一问:残差流越加越大,怎么让每一层看到尺度稳定的输入?
这一课先不碰:Post-LN 为什么离不开 warmup、Pre-Norm 为什么更稳(C8 第 2 课兑现);QK-Norm 这类「按住注意力 logit」的归一化(C3 提过,C8 展开)。
② 从已有出发
拿贯穿例句「小明把苹果给了小王」里的「苹果」来说:它在残差流里是一行 5,120 维的向量,每往上走一层就被加上两次增量。上一课的结论:残差流 x_L = x₀ + Σ F_l 是所有子层写入之和。128 次写入如果各自方差为 1,最后的标准差是 11.36;在随机初始化的 32 层网络里,只开残差时残差流 RMS 从 1 涨到 6.3。越往上的子层,读到的数越大。我们要一个零件:每个子层读残差流之前,先把它的尺度拉回同一个范围。
③ 先自己设计:用 CV 里现成的 BatchNorm 行不行?
ResNet 用的就是 BatchNorm:对每一个特征,在一批样本上算均值和方差,减均值、除标准差。它在图像上效果很好,拿过来最省事。下面就用贯穿例句试:把「小明把苹果给了小王」和另一句话拼成一批,看「苹果」被归一化成什么。
- ① 朴素方案
- ② 它在哪失败
- ③ 改进方案
4 维向量是手工构造的教学数据;要看的只是「统计量从哪来」。
4 维向量是手工构造的教学数据,只用来看清「统计量从哪来」;真实隐藏向量有 5,120 维。
| 情形 | 批里有几个 token | BatchNorm 后的「苹果」 |
|---|
把统计的方向转 90°:不跨样本,只在一个 token 自己的 d 个数上统计。批里还有谁、批有多大、句子多长,都影响不到它。
4 维向量是手工构造的教学数据,只用来看清「统计量从哪来」;真实隐藏向量有 5,120 维。
| 情形 | 批里有几个 token | BatchNorm 后的「苹果」 | RMSNorm 后的「苹果」 |
|---|
失败的原因不需要实验:BatchNorm 的均值和方差是对批求的,所以输出必然依赖批里其他样本 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条BN 输出 = (x − 批均值) / √(批方差 + ε);批只有一个元素时 x = 批均值,分子恒为 0。 出处Ba et al. 2016 §1 ↗需联网 。语言模型偏偏最常见「批里的东西不齐」:句子长短不一要补齐,推理时一次只生成一个 token。
④ 改进到现代做法
第 1 步:LayerNorm——每个 token 自己统计
LayerNorm(Ba 等 2016)对每个 token 的 d 个数求均值 μ 和标准差 σ,算 (x − μ) / σ,再乘可学习的 γ、加可学习的 β。对 x = [1, 2, 3, 6]:μ = 3,方差 = (4 + 1 + 0 + 9) / 4 = 3.5,σ = 1.871,输出 [−1.069, −0.535, 0, 1.604],均值恰为 0。
第 2 步:RMSNorm——连均值都不减
RMSNorm(Zhang & Sennrich 2019)只除以均方根:RMS = √((1 + 4 + 9 + 36) / 4) = √12.5 = 3.536,输出 [0.283, 0.566, 0.849, 1.697],没有 β。它提出的理由是一个假设:LayerNorm 里真正起作用的是「缩放不变」,「平移不变」可以不要 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条原文:we hypothesize that re-centering invariance in LayerNorm is dispensable。这是动机,不是证明。 出处Zhang & Sennrich 2019 摘要 ↗需联网 ;实验上效果与 LayerNorm 相当,在他们测的几个模型上运行时间少 7%–64% 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条摘要:comparable performance against LayerNorm but reduces the running time by 7%~64% on different models。提速取决于实现与硬件,不能直接搬到别的框架上(见下方项目微基准)。 出处Zhang & Sennrich 2019 ↗需联网 。
两者的差别,在下面的组件里点两下就能看见:
改输入向量的任意一维,或者点下面的操作,每次结果都会记进操作记录。
| # | 输入 x | LayerNorm(x) | RMSNorm(x) |
|---|
试三件事:① 点「整体 ×3」:两列都「没变」——这就是缩放不变性,残差流整体变大 11 倍,子层读到的也还是同一个东西;② 点「整体 +2」:LayerNorm 一列没变,RMSNorm 一列变了——RMSNorm 放弃了平移不变,换来少算一个均值;③ 随便改一维,看 RMSNorm 的输出长度:永远是 √4 = 2。d = 5120 时它是 √5120 = 71.55——RMSNorm 把每个 token 都放到同一个半径的球面上,只保留方向。
极小真数字:平移 +2。 x’ = [3, 4, 5, 8]:LayerNorm 的均值变成 5、方差仍是 3.5,输出不变;RMSNorm 的 RMS = √((9 + 16 + 25 + 64) / 4) = √28.5 = 5.339,输出 [0.562, 0.749, 0.937, 1.499],变了。放大 ×3:x” = [3, 6, 9, 18],两者的输出都和原来一模一样(RMS 变成 3 × 3.536 = 10.607,正好约掉)。
口径:浏览器实时计算。权重由固定种子生成(随机初始化,没有训练),所以每次打开结果相同;换 N 或 gain 会重新生成整套权重。
上面是上一课的模拟器,这次默认勾着「子层输入先 RMSNorm」。操作:保持 N = 32、gain = 1,先取消这个勾,读摘要里的两个数(底层与顶层的梯度之比 20.4、残差流 RMS 6.3);再勾上,变成 3.5 和 4.3;最后再勾上「写回乘 1/√N」,两者分别回到 0.97 和 1.1。归一化管的是每个子层读到的输入,残差流本身的增长还要靠写回缩放来控制。
第 3 步:Qwen3.8 的写法——zero-centered RMSNorm
这张图只看 weight decay 单独往哪边拉(η、λ 取项目的 lr 3e-3 与 weight_decay 0.1),真实训练里梯度会和它拉锯;zero-centered 的理由是「默认值」换成了更安全的那个 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条数学上:AdamW 的解耦衰减 θ ← θ(1 − ηλ) 把被衰减的参数拉向 0;zero-centered 让「参数为 0」对应「增益为 1」。是否真的更稳是 Qwen 的实验结论(Qwen3-Next 模型卡与 Qwen3.8-Flash-Next 报告:所有 RMSNorm 用 zero-centered 形式),没有公开消融数字。 出处Qwen3.8-27B 模型卡 / R2 §1.4 ↗需联网 。
第 4 步:放在哪——Pre-Norm 与 Post-LN
同一个归一化,可以放在残差加法之后、主路之上(2017 年原版的 Post-LN),也可以放在每个子层的入口、主路之外(GPT-2 起的 Pre-Norm,Qwen3.8 也是):
两种摆法的结构差别可以直接从公式读出来:
- Post-LN:
x_(l+1) = LN(x_l + F(x_l))。LayerNorm 在主路上,每一层都把主路重新缩放一次;L2 的展开式 x_L = x₀ + Σ F 不再成立,从第 1 层到最后一层没有一条只做加法的直通路。 - Pre-Norm:
x_(l+1) = x_l + F(Norm(x_l)),最后再加一个最终 Norm。主路上只有加法,L2 的展开式和梯度直通路原样保留;代价是残差流本身不被归一化,所以输出前必须补一个最终 Norm(Qwen3.8 与我们的项目都有) 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条由两种写法的定义直接推出:Pre-Norm 下 x_L = x₀ + Σ F_l(Norm(x_l)) 成立;Post-LN 下每层都有 LN 作用在累加结果上。 出处待补 。
为什么 Post-LN 需要 warmup、Pre-Norm 可以不要? 这件事需要先讲初始化与学习率预热(C5、C8)。Xiong 等 2020 证明了:初始化时 Post-LN 靠近输出层的参数梯度期望很大,大学习率下不稳 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条Xiong et al. 2020 用平均场理论在初始化时刻做的分析;「因此需要 warmup、Pre-LN 可以去掉 warmup」有实验支持。归属:Pre-LN 至少见于 GPT-2(2019),Xiong 2020 是给它补的理论。 出处Xiong et al. 2020 ↗需联网 。这个疑问将在 C8 第 2 课兑现;这里只要求你认得两种摆法,并在下面的项目实测里看见差别。
第 5 步:同一个 RMSNorm,还被放在别处
| 位置 | 在 Qwen3.8 里 | 作用 | 细节在哪 |
|---|---|---|---|
| 每个子层入口(Pre-Norm) | 每层 2 个,形状 [5120] | 让子层读到尺度稳定的输入 | 本课 |
| 最后一层之后 | 1 个 [5120] | Pre-Norm 的残差流没被归一化,输出前补一次 | 本课 |
| 每个注意力头的 q、k(QK-Norm) | q_norm、k_norm 各 [256] | 按住注意力打分的尺度 | C3、C8 |
| Gated DeltaNet 内部 | [128] | 线性注意力输出的归一化 | C11 |
还有别的放法:OLMo 2 把归一化挪到子层输出端(h = x + Norm(F(x)));DeepSeek-V4 对 Q 和 KV 都做 RMSNorm,官方说因此不再需要 Kimi K2 的 QK-Clip——这些都是 C8「稳定性」的话题。
演进图:本课在第几代
从 BatchNorm 到 LayerNorm(2016),从 Post-LN(2017)到 Pre-LN(2018 年 Tensor2Tensor 已有,GPT-2 2019 年推广),再到 RMSNorm 与 Qwen3.8 的 zero-centered 写法,都在这张表的第三行。
⑤ 项目实测
对照组各只改一项:c4_postln 把归一化挪到加法之后;c4_postln_nowarmup_lr1e-2 与 c4_preln_nowarmup_lr1e-2 是同一对放法在「不 warmup、学习率 1e-2」下的对比;c4_layernorm 把 RMSNorm 换成 LayerNorm。把指标切到 grad_norm,看 Post-LN 开头那一段。
读图(2026-09-26 导出的数据,以组件显示为准):
- LayerNorm 对 RMSNorm:4.6266 对 4.6263,差 0.0003,在噪声内——这个规模上看不出区别,和原文「效果相当」一致。速度上,项目的算子微基准(Apple GPU,张量 32 × 256 × 256,前向 + 反向各 200 次取中位数)给出:PyTorch 自带、融合成一个内核的 LayerNorm 0.667 ms,RMSNorm 0.792 ms(torch 自带)/ 0.799 ms(手写)——在我们的机器上 LayerNorm 反而更快。RMSNorm 省下的是理论计算量(不算均值、没有 β),实际快慢取决于这台设备上有没有为它融合好的内核;大模型训练框架里通常有,所以原文的「更快」在那里成立 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条单台设备、单一张量形状;只说明「更少计算 ≠ 一定更快」,不说明其他硬件上的快慢。 出处c04-block.json · norm_bench(2026-09-26 导出) ↗ 。
- Post-LN 没有炸,而是卡住了:带 warmup、学习率 3e-3 时,它在第 40 步到达最低 6.612 后就停在 6.627,和上一课去掉残差的模型一样,只学会了字频;初始化时它每一块收到的梯度约 0.017,只有 Pre-Norm 基线(约 1.6)的百分之一左右,训练结束时最底层块的梯度只剩最顶层的 6 × 10⁻⁹。
- 不 warmup、学习率 1e-2:Pre-Norm 降到 5.680,Post-LN 仍停在 6.626。
- 这和常见说法「Post-LN 不 warmup 会发散」的表现形式不同:这里是停滞,不是 NaN;而且是单种子。它说明摆法确实决定了训不训得动,但为什么、在更深更大的模型上会不会变成发散,留到 C8 用初始化分析和 12 层对照来回答(仍是单种子)。C8 第 2 课的补充实验给了一半答案:学习率降到 1e-3 后,不 warmup 仍卡在 6.63,加 100 步 warmup 就训到 4.87——卡住的原因是「峰值学习率下的开局」,warmup 管的正是这个。
⑥ ⚠ 常见误解
「归一化之后每个向量一样长,信息丢了」✗ —— RMSNorm 对一个 token 只拿掉 1 个数(整体尺度),方向(5,119 个自由度)全部保留;可学习的逐维增益 (1 + w) 还能把需要的维度重新放大。
「LayerNorm 在 batch 上统计」✗ —— 那是 BatchNorm。LayerNorm 和 RMSNorm 只用一个 token 自己的 d 个数。
「RMSNorm 是 LayerNorm 打了折扣的近似」✗ —— 原文报告两者效果相当;这是实验结论,不是「必然一样好」的证明,但也谈不上打折。
「RMSNorm 一定比 LayerNorm 快」✗ —— 少算一个均值是真的;快不快还要看实现。融合成一个内核的 LayerNorm 可能比几个小算子拼起来的 RMSNorm 更快,上面的项目微基准就是为此放的。
⑦ 证据三问
- 它解决什么问题? 残差流随深度变大,子层读到的输入尺度各层不同;BatchNorm 在语言模型里依赖批的组成、生成时退化。
- 数学上为什么可能有效? 缩放不变性可以证明:Norm(α·x) = Norm(x)(α > 0),残差流整体放大多少倍,子层读到的都一样 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条RMS(αx) = α·RMS(x),分子分母同乘 α 约掉(忽略 ε)。LayerNorm 同时还有平移不变性。 出处待补 ;「只要缩放不变、不要平移不变」是 RMSNorm 的假设 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条Zhang & Sennrich 2019 的出发点。 出处RMSNorm 摘要 ↗需联网 。
- 实验上为什么最后选了它? RMSNorm 与 LayerNorm 效果相当而计算更少 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条只在原文测过的任务与实现上成立。 出处Zhang & Sennrich 2019 ↗需联网 ;Pre-Norm 更稳是 Xiong 2020 的理论 + 实验,以及 GPT-2 之后几乎所有大模型的共同选择(C8 细讲);在我们的项目里,基线学习率 3e-3 下 Post-LN 连带 warmup 的配置都只学会了字频(6.627),Pre-Norm 基线到了 4.626(Post-LN 要把学习率降到 1e-3 并加 warmup 才训得动,见 C8 第 2 课) 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条c4_postln 与基线只差 model.norm_pos 一项;单种子;表现为停滞而不是发散。C8 补充实验:学习率 1e-3 时 warmup 100 步把 Post-LN 从 6.627 救到 4.866。 出处本章实验课 ↗ 。
⑧ 一句话
归一化只拿掉每个 token 的整体尺度:残差流再大,子层读到的输入都回到同一个尺度。
⑨ 下一个缺口
到这里,一个块的骨架齐了:RMSNorm → 注意力 → 加回,RMSNorm → FFN → 加回。可打开 Qwen3.8 的权重,还有两处对不上 L1 的 FFN 和 C3 的注意力:FFN 有三个矩阵(gate_proj、up_proj、down_proj),注意力的 q_proj 输出 12,288 维,是 24 × 256 = 6,144 的两倍。多出来的是什么?下一课:门控。
⑩ 你可能会问
- 「为什么 Pre-Norm 更稳?」 —— C8 第 2 课兑现(先讲初始化、warmup,才能讲清)。
- 「ε 为什么是 1e-6,不是 0?」 —— 防止整行为 0 时除以 0。它远小于正常 token 的均方,几乎不影响结果;不同实现取 1e-5 或 1e-6。
🔍 ε 什么时候会起作用
只有当一个 token 的均方和 ε 可比时 ε 才有影响——例如残差流被写得极小、或在低精度下数值下溢。Qwen3.8 的 rms_norm_eps 是 1e-6,我们的项目默认 1e-5;BF16 与 FP16 下这类细节会在 C9「精度」里再遇到。 - 「归一化占多少参数?」 —— 全模型 660,480 个,0.0024%。账本见岔路课 参数到底花在哪。