Post-LN 把 LN 压在残差相加之后,方差稳了,梯度却要一层层穿过 LN;Pre-LN 把 LN 挪到模块输入,梯度通了,模块输出却直接堆进残差干道。 这篇论文把 Gemma、OLMo 等模型里已经出现的第三种做法命名为 Peri-LN:模块输入和输出都归一化。作者用方差递推和梯度上界解释它为什么有效,并在 400M / 1.5B / 3.2B、30B token、5 个种子上与 Post-LN、Pre-LN 对比。
三种放置的差别只在 LN 放在子层的哪个位置,但它决定了残差干道是不是被归一化。Post-LN 把 LN 放在残差相加之后(Figure 2 的 C),主路径被压住,梯度却要穿过 LN。
Pre-LN 只归一化模块输入(A),残差干道没有 LN,梯度路径更直;代价是模块输出不经归一化就加进干道。§3.2 指出,初始化时 Pre-LN 的方差近似随深度线性增长,但训练开始后会指数上升;Figure 1 用 1.5B 模型追踪了这一点。
Peri-LN 在模块输入和输出各放一个 LN(A + B),即 yl = xl + Norm(Module(Norm(xl)))。如果归一化后的模块输出方差近似常数 β0,则 Var(xl+1) ≈ Var(xl) + β0(Eq. 4),方差增长从乘法变成加法。Proposition 3.1 进一步给出:对最后一层 MLP 权重,Pre-LN 的梯度范数正比于 ||h||,而 Peri-LN 的上界带一个阻尼因子 1/||a||(Eq. 8)。
Table 1 的 3.2B 模型平均分 58.56,Pre-LN 56.69,Post-LN 46.45;C4 evaluation loss 3.11,Pre-LN 3.20。论文没有做显著性检验,这些是 5 个训练种子下的均值与标准差所对应的点差。
先建立问题:LN 放在哪里,决定了模块输出能不能污染残差干道;而这个问题在训练开始后才会暴露。
Transformer 的一个子层可以写成 yl = xl + Module(xl)。残差连接把 xl 原样送到下一层,Module 只负责在主干上加一个增量。LN 放在增量的哪一侧,决定了这个增量在汇入主干前是否被约束。
yl = Norm(xl + Module(xl))(Eq. 1)。主路径上的每一步都被归一化,激活不会逐层放大。
代价是反向传播要穿过每一层的 LN。§3.1–3.2 说,深层模型里这会削弱梯度流,可能出现部分梯度消失和更慢的收敛。
yl = xl + Module(Norm(xl))(Eq. 2)。残差主路径上没有 LN,梯度可以沿恒等路径直接回传。
代价是 Module(Norm(xl)) 没有归一化就加到 xl 上。模块输出一旦很大,就会沿着残差路径一路保留。
论文把后者和 Sun et al. (2024) 的 massive activations 联系起来:Pre-LN 的残差恒等路径没有归一化,大激活可以从浅层一直传到深层。§3.2 的原句是:
“Pre-LN normalizes xl before the module but leaves the module output unnormalized, allowing hidden-state variance to accumulate exponentially once parameter updates amplify the input.”
关键在“once parameter updates amplify the input”。初始化时,Pre-LN 的方差增长看起来只是随深度线性增加(Kedia et al., 2024,转引);但论文观察的是训练过程。Figure 1 用 1.5B 模型从初始化追到 6.3B token;§3.2 的文字结论是 Post-LN 的方差大致恒定,Pre-LN 在训练开始后指数上升。Figure 1 的 caption 则笼统写 “the growth in hidden-state variance for both Pre-LN and Post-LN architectures”,措辞比 §3.2 正文更宽泛。Peri-LN 的受控方差是 §3.3 引入 Output-LN 之后讨论的。
这不只是训练曲线好不好看。Figure 11 追踪 3.2B 模型的全局 top-100 绝对激活值:Pre-LN 在 0.5B token 左右就超过 FP16 可表示上限 65,504,而 Peri-LN 一直低于这条线。Appendix K 还提到,V100 不支持 BF16,这类溢出会直接变成数值问题。
Post-LN 让 LN 碰主路径,换来稳定方差,但梯度要穿过它;Pre-LN 让主路径保持干净,换来梯度通路,但模块输出可以不受约束地加进去。两条路都把同一个 trade-off 推到了极端。
两条主流路线不是谁对谁错,而是把同一个 trade-off 推向了相反的两端;先看清各自卡在哪。
Figure 2 把 LN 的可能位置拆成三个:A 在模块输入,B 在模块输出,C 在残差相加之后。三种策略的勾选表如下(转录自 Figure 2):
| 策略 | A · 模块输入 | B · 模块输出 | C · 残差相加之后 |
|---|---|---|---|
| Post-LN | × | × | ✓ |
| Pre-LN | ✓ | × | × |
| Peri-LN | ✓ | ✓ | × |
这张表已经说明了三者的结构差异:Post-LN 只有 C,Pre-LN 只有 A,Peri-LN 同时有 A 和 B,但没有 C。也就是说,Peri-LN 保留了 Pre-LN 的干净主路径,同时在模块输出汇入残差之前加了一道约束。
§4.4 和 Figure 5(a) 报告:在训练稳定的 run 里,final-layer gradient norm 满足 Post-LN > Pre-LN > Peri-LN。但 Table 1 的 benchmark 平均分排序是 Peri-LN > Pre-LN > Post-LN。两组排序方向相反。
论文没有把 final-layer gradient norm 当作排名指标;§5.2 更关心的是梯度在层间是否均匀:Figure 7 显示 Post-LN 在训练后期的低层梯度变小,Pre-LN 在初始化阶段反向传播时梯度变大,而 Peri-LN 在初始化和训练结束时都保持较均匀的逐层分布。推断(依据:§4.4 只报告排序,§5.2 才把“均匀”作为稳定性的解释;两处量的口径不同。)
Post-LN 在汇入之后归一化,Pre-LN 在汇入之前只归一化输入。前者让主路径被 LN 覆盖,后者让未归一化的模块输出直接进入主路径。Peri-LN 选的是第三条:在汇入之前,对模块输出本身做归一化。
核心只有一行公式;真正要理解的是它为什么能把方差增长从乘法变成加法,以及梯度上界里的阻尼因子从哪来。
与 Pre-LN 相比,Peri-LN 多了最外层的 Norm;与 Post-LN 相比,这个 Norm 没有放在残差相加之后,所以主路径仍然没有 LN。论文在 §3.3 里把这一步写成 Norm(Module(Norm(xl))),并指出如果这一项的方差近似常数 β0,就有:
这就是“外围归一化”的核心:它不改变残差主路径的结构,只在模块输出汇入主路径之前把增量的尺度固定住。主路径仍然可以直通梯度,但不会再被一个未归一化的大增量反复放大。
论文考虑最后一层 MLP 的权重 W(2),令 h = ReLU(x̃W(1) + b(1))。两种策略的梯度行为分别是:
模块输入先归一化,输出直接加回残差(Eq. 5)。梯度对最后一层 MLP 权重的范数正比于 ||h||(Eq. 6)。
当 massive activation 让 ||h|| 很大时,梯度范数可以随之爆炸,导致训练不稳定。
模块输入和输出都归一化(Eq. 7)。梯度上界带一个 1/||a|| 的阻尼因子(Eq. 8)。
即使 ||h|| 很大,这个比值也能保持有界。论文称之为 self-regularizing gradient。
注意这个上界的范围:它只针对最后一层 MLP 权重 W(2) 的梯度,是局部上界,不是逐层或全局上界。§3.4 与 Appendix C 给了形式化陈述和证明,但论文没有给出端到端的全局收敛证明。这个边界在 §07 还会再提一次。
下图只画前向放置。点按钮切换策略,观察 A、B、C 三个位置哪些被启用,以及对应的方差行为和梯度通路。
覆盖的分支:三个前向放置与 Figure 2 的勾选表一一对应——Post-LN 只有 C;Pre-LN 只有 A;Peri-LN 有 A 和 B。A/B/C 的位置定义逐字来自 Figure 2 与 §3.1–3.3 的公式。
没覆盖的分支:反向传播的具体路径、embedding/final LN、γ 的可学习性、Attention 与 MLP 两个子层的重复结构。图中的 Module 是二者的抽象;真实 block 里每个子层各有一套 A/B,见 §05 的结构图。
参数 → 结果(2 组):
这个交互没有数值常量;判定来自 Figure 2 的勾选表和 §3.1–3.3 的公式,不是从表格读数。
把实验条件摊开看:规模、数据、优化器和 SFT 都沿用 DCLM / Llama 3 的一套设置;论文没有报告 Peri-LN 的吞吐或显存开销。
模型规模是 400M、1.5B、3.2B(均不含 embedding 参数),每个规模训练 30B token,使用 5 个随机种子;序列长度 8192,数据是 DCLM-baseline,tokenizer 是 TikToken 的 cl100k base,架构主要跟随 Llama 3(SwiGLU MLP),归一化层主要用 RMSNorm,训练框架是 Megatron-LM(§4.1)。
| Global Batch | Weight Decay | Iterations | Optimizer | LR Schedule | Warmup | Weight Init. |
|---|---|---|---|---|---|---|
| 256 | 0.033 | 14400 | Adam | Cosine | 10% | 0.02 |
| Size | n_layers | n_heads | d_model | d_head |
|---|---|---|---|---|
| 400M | 24 | 8 | 1024 | 128 |
| 1.5B | 24 | 16 | 2048 | 128 |
| 3.2B | 32 | 16 | 2560 | 160 |
学习率方面,§4.2 说 Pre-LN 在所有规模上的最佳学习率都是 2 × 10-3,因此 Pre-LN 和 Peri-LN 都用这个值;Post-LN 的合适学习率更低,Appendix E.1 单独做了搜索。SFT 用 LIMA 的 1,000 条样本,训练 15 个 epoch,batch size 128,Adam 初始学习率 1e-5,cosine schedule;checkpoint 按 OpenBookQA、CommonSenseQA 和 GLUE NLI 上的表现挑选(Appendix D.2)。
从结构上看,Peri-LN 在每个子层多一次归一化:Pre-LN 每个子层一次,Peri-LN 是两次。论文没有报告这部分带来的吞吐、显存或 FLOPs 变化;Table 2 只给训练超参。能还原的是配置,不是耗时。推断(依据:全文没有吞吐/显存表格;§7.2 只讨论精度约束。)
把 Eq. 3 落成结构:输入 embedding 可选归一化,每个子层的输入和输出各一次 LN,最后再归一化输出。
这张图里有两个容易混淆的点。第一,Peri-LN 的残差主路径仍然没有 LN;它只是把每个子层的输出在加回残差之前归一化。第二,§3.3 的架构描述说 Peri-LN “further normalizes the input and final output embeddings”,Eq. 3 也在最后对 xL 做一次 Norm,但第 1 步(输入 embedding)标为 optional;§5.3 说,为了单独考察 output-LN 的作用,那个实验省略了 embedding LN。因此页面把输入侧画成 optional,而不把“Peri-LN 默认含 embedding LN”当成 Table 1 的设定。推断(依据:§3.3 的架构描述与 Eq. 3 的 optional 标注;§5.3 明说该实验省略 embedding LN。)
与 OLMo2-style 的 Peri-LN(含 QK-Norm)相比,论文在 Appendix H 里说两者整体表现可比,Peri-LN 在 400M 和 1B(原文正文;Appendix H 的 Figure 33 标的是 1.5B)规模上略有优势;但这条对比不是本文的主实验,Table 1 也不包含 QK-Norm 变体。
先看 Table 1 的完整转录,再用交互切换三个规模;最后看两个反直觉的发现:梯度范数排序与分数排序相反,以及强 weight decay 也补不上差距。
| Size | Arch. | ARC-Easy | HellaSwag | PIQA | SIQA | Winogrande | Avg. ↑ | Loss ↓ | SFT Avg. ↑ |
|---|---|---|---|---|---|---|---|---|---|
| 400M | Post-LN | 35.70 ±1.09 | 28.91 ±0.16 | 62.26 ±0.73 | 34.48 ±1.04 | 50.88 ±0.75 | 42.45 | 7.46 | 46.44 |
| 400M | Pre-LN | 54.87 ±1.63 | 34.17 ±1.66 | 68.79 ±1.34 | 39.73 ±0.59 | 50.88 ±2.35 | 49.69 | 3.43 | 49.96 |
| 400M | Peri-LN | 57.51 ±0.81 | 37.46 ±0.34 | 69.48 ±0.39 | 40.64 ±0.51 | 52.74 ±0.67 | 51.57 | 3.34 | 51.96 |
| 1.5B | Post-LN | 42.92 ±0.93 | 31.69 ±0.41 | 66.72 ±0.40 | 35.84 ±0.61 | 50.30 ±1.87 | 45.49 | 5.38 | 48.95 |
| 1.5B | Pre-LN | 61.51 ±1.22 | 39.88 ±1.53 | 71.41 ±0.88 | 41.23 ±0.97 | 54.51 ±2.07 | 53.71 | 3.29 | 53.89 |
| 1.5B | Peri-LN | 66.17 ±0.21 | 43.94 ±0.34 | 73.63 ±0.24 | 42.34 ±0.83 | 56.64 ±0.44 | 56.55 | 3.18 | 56.94 |
| 3.2B | Post-LN | 45.30 ±3.23 | 33.59 ±0.44 | 66.45 ±2.86 | 35.82 ±1.09 | 51.10 ±1.60 | 46.45 | 4.43 | 49.33 |
| 3.2B | Pre-LN | 65.24 ±2.32 | 44.23 ±2.32 | 73.86 ±1.19 | 42.68 ±0.07 | 57.42 ±2.51 | 56.69 | 3.20 | 57.08 |
| 3.2B | Peri-LN | 68.73 ±0.57 | 46.99 ±0.21 | 74.31 ±0.41 | 43.00 ±0.73 | 59.76 ±0.78 | 58.56 | 3.11 | 59.02 |
柱高 = 基准分数(0–100),数字标注为原始分数;不显示标准差。
口径:Avg 是 5 个基准的等权平均,不是按样本数加权。标准差来自论文报告的 5 个训练种子;论文没有说明用 ÷N 还是 ÷(N−1),本页不重算标准差。
交互里的 15 个柱值逐字来自 Table 1;切换规模只改变数据集,不改变口径。
三个规模的方向一致:400M 是 51.57 / 49.69 / 42.45,1.5B 是 56.55 / 53.71 / 45.49,3.2B 是 58.56 / 56.69 / 46.45(Peri-LN / Pre-LN / Post-LN,Table 1)。论文在 §4.5 还报告,Peri-LN 的跨种子标准差“reduced by more than half”。这是笼统表述;按 5 个基准的跨种子标准差均值复算(Table 1,等权平均):400M 从 1.514 降到 0.544、1.5B 从 1.334 降到 0.412、3.2B 从 1.682 降到 0.540,即平均而言降低一半以上。但并非每个基准都减半,最明显的反例是 3.2B SIQA:Pre-LN ±0.07,Peri-LN ±0.73(Table 1);3.2B HellaSwag 则是 ±2.32 → ±0.21。这里的均值由 Table 1 报告的标准差复算,论文没有说明标准差用 ÷N 还是 ÷(N−1)。
§4.4 的 Figure 5(a) 说,训练稳定时 final-layer gradient norm 的顺序是 Post-LN > Pre-LN > Peri-LN;Table 1 的分数顺序是 Peri-LN > Pre-LN > Post-LN。论文没有把这个梯度范数当作排名指标,而是在 §5.2 用 Figure 7 强调 Peri-LN 的逐层梯度分布更均匀。推断(依据:§4.4 只报告排序;§5.2 才把“层间均匀”作为稳定性的解释。两处量的口径不同,不能直接合并成“梯度越大越好/越差”。)
Table 7 是 400M 模型的 weight decay sweep。把系数从 0.033 加到 0.33(论文称 tenfold rise,§6.1;0.33 / 0.033 = 10),Pre-LN 的平均分从 49.01 升到 49.51,loss 从 3.03 降到 3;Peri-LN 同期从 50.68 升到 52.13,loss 从 2.93 降到 2.90。强 weight decay 能缓解 Pre-LN 的不稳定,但在同一设置下 Peri-LN 仍然更高。
| 400M | Model | wd 0 | wd 0.0033 | wd 0.033 | wd 0.33 |
|---|---|---|---|---|---|
| Final Training Loss | Pre-LN | 3.03 | 3.03 | 3.03 | 3 |
| Final Training Loss | Peri-LN | 2.94 | 2.94 | 2.93 | 2.90 |
| Averaged Benchmark Score | Pre-LN | 49.26 | 49.18 | 49.01 | 49.51 |
| Averaged Benchmark Score | Peri-LN | 51.41 | 51.14 | 50.68 | 52.13 |
Table 8 和 Table 9 也支持同一方向。Table 8 是 400M 的 Xavier 初始化对比:Xavier 初始化把 Pre-LN 的平均分从 49.01 提到 51.25,把 Peri-LN 从 50.68 提到 52.04。Table 9 改变初始化方差:Peri-LN 的 final pre-training loss 在 2.902–3.027 之间,Pre-LN 在 10/d 时到达 4.526。这些结果说明,调 weight decay 或初始化也能改善 Pre-LN,但论文的实验设置下,Peri-LN 在同样的调参范围内仍然更高。
| 400M | Architecture | Baseline (0.02) | Xavier Initialization |
|---|---|---|---|
| Loss | Pre-LN | 3.03 | 2.95 |
| Peri-LN | 2.93 | 2.91 | |
| Avg. | Pre-LN | 49.01 | 51.25 |
| Peri-LN | 50.68 | 52.04 |
| 400M | Initialization Variance | 10/d | He(2/d) | LeCun(1/d) | 1/(10d) | Baseline (0.02) |
|---|---|---|---|---|---|---|
| Loss | Pre-LN | 4.526 | 2.965 | 3.005 | 3.012 | 3.035 |
| Peri-LN | 3.027 | 2.929 | 2.915 | 2.902 | 2.916 |
论文的边界写在实验范围里:Decoder-only、最高 3.2B、30B token、主要用 RMSNorm;没有吞吐/推理开销实验。
§7.2 的原句是:“Both Pre-LN and Peri-LN architectures leave the main hidden state path unnormalized, so once large values arise in earlier layers, they persist through to later layers.” Peri-LN 阻止的是模块输出继续把方差加进主路径,不是清除主路径里已经存在的大值。如果问题主要来自残差状态本身,Peri-LN 不一定是足够的解。
实验覆盖 400M、1.5B、3.2B 三个 decoder-only 模型,30B token,DCLM-baseline,Llama 3 风格结构,主要用 RMSNorm。论文没有报告 Encoder-Decoder、ViT、多模态、MoE 或超过 3.2B 的实验;这些架构上的行为需要另行验证。
Table 1 报告的是 5 个训练种子的均值与标准差,论文没有做显著性检验,也没有给出置信区间。3.2B 平均分的差值是 +1.87 个百分点(58.56 − 56.69),C4 loss 差值是 0.09(3.20 − 3.11)。这些点差在三个规模上方向一致,但论文没有做显著性检验,不能读成统计显著。
Peri-LN 在每个子层多一次归一化,但论文没有报告吞吐、显存或 FLOPs 的对比。对训练吞吐敏感的场景,需要自己测这部分开销;不能从 Table 1 的分数直接推断“更划算”。推断(依据:全文没有吞吐/显存表格;§7.2 只讨论精度约束。)
Table 7 和 Table 8 显示,强 weight decay 或 Xavier 初始化都能改善 Pre-LN。Peri-LN 的优势是在这些调参范围内仍然更高,而不是“Pre-LN 无论怎么调都不行”。如果工程上已经有成熟的 Pre-LN 稳定配方,换架构的收益需要和改动成本一起算。
Proposition 3.1 给的是最后一层 MLP 权重梯度的上界,Appendix C 有形式化陈述与证明;论文没有给出整个训练过程的全局收敛保证。把它当成“Peri-LN 一定不会发散”的依据,会超出原文的范围。
一句话总结:Peri-LN 管的是“模块输出汇入残差之前”的那一步;它把 Pre-LN 的指数方差增长改成线性增长,但没有把残差主路径变成归一化路径,也没有承诺所有规模、所有架构都同样受益。