Interview Prep · 归一化 / 残差 / 初始化 (Normalization / Residual / Init)

归一化 / 残差 / 初始化 面试 Cheat Sheet

BatchNorm / LayerNorm / RMSNorm / Pre-vs-Post-LN / DeepNorm / QK-Norm / 残差缩放 / Xavier·Kaiming / GPT-2 init / μP / DyT + 公式推导 + From-Scratch PyTorch + 25 高频题(L1 必会 · L2 进阶 · L3 顶级 lab)

Source: docs/tutorials/normalization_init_tutorial.md SHA256: 0e158f6f3151 Rendered: 2026-07-12 04:17 UTC

§0 TL;DR Cheat Sheet

9 句话搞定 Normalization / Residual / Init

一页拿下面试核心要点(详见后文 §1–§11 推导)。

  1. 为什么要归一化:深网络逐层放大 / 缩小激活,方差以 $g^L$ 指数发散或塌缩;归一化把每层激活拉回受控尺度,关键收益是平滑了 loss landscape(更小的梯度 Lipschitz / β-smoothness,Santurkar 2018),从而能用更大学习率、堆更深——不是"减少 internal covariate shift"那套旧说法。
  2. BatchNorm:沿 batch(+空间)维对每个 channel 归一化,$\hat x=\frac{x-\mu_\mathcal{B}}{\sqrt{\sigma_\mathcal{B}^2+\epsilon}}$;训练用 batch 统计 + 维护 running mean/var,推理用 running stats → train$\ne$eval,且强依赖 batch 大小(小 batch / 变长序列 / RL / online 全踩雷)。
  3. LayerNorm:沿特征维 per-token 归一化(与 batch 完全解耦),$y=\gamma\odot\frac{x-\mu}{\sqrt{\sigma^2+\epsilon}}+\beta$;batch=1 也能用、变长序列也能用、train$=$eval——所以 Transformer / RNN 用它而不用 BN。
  4. RMSNorm:丢掉 re-centering,只按 RMS 缩放 $\bar x=\frac{x}{\sqrt{\frac1d\sum_i x_i^2+\epsilon}}\odot\gamma$(无均值、无 $\beta$);论点是 re-scaling 不变性比 re-centering 更重要,省一次 reduction,LLaMA 之后的事实默认。
  5. Pre-LN vs Post-LN:Post-LN(原始 Transformer,LN 在残差相加之后)质量上限略高但需 LR warmup、深了不稳;Pre-LN(LN 在残差分支内部)有干净恒等梯度路径 → 稳、免 warmup,但残差流幅度随深度按 $\sqrt L$ 增长、深层贡献被稀释,必须补一个 final LN。
  6. 放置变体:DeepNorm(放大残差 $\alpha x_l$ + 缩小 init → 训 1000 层)、Sandwich / double LN(Gemma2 分支前后各一个)、QK-Norm(点积前归一化 Q、K,压住 attention logits 防爆)。
  7. 残差 + 缩放:$y=x+F(x)$ 的雅可比 $I+\partial F/\partial x$ 给出梯度高速路(恒等项保证梯度不消失);缩放技巧把分支起点压向恒等——$1/\sqrt N$ 深度缩放、LayerScale(learnable per-channel $\lambda$)、ReZero(learnable 标量 init 0)、SkipInit。
  8. 初始化:核心目标是方差保持——Xavier(tanh,$\text{Var}(W)=\frac{2}{n_\text{in}+n_\text{out}}$)、Kaiming(ReLU,$\text{Var}(W)=\frac{2}{n_\text{in}}$,那个 2 补偿 ReLU 砍掉的一半方差);残差网再按深度下调,GPT-2 把残差投影权重 $\times\frac{1}{\sqrt{2N}}$;Fixup 以 init 为主(+ 少量可学 scalar)就免归一化训深残差网。
  9. μP / 归一化-free / 工程:μP 让最优超参(尤其 LR)宽度不变 → 小宽度调好 zero-shot 迁移到大模型;Fixup / NFNets / DyT 探索去归一化(前沿方向,非定论);工程上盯紧 final LN、$\epsilon$ 位置、fp32 reduction、fused kernel。

§1 为什么要归一化 + 残差

深网络的根本病灶是"尺度在深度上失控"。 把一个信号过 $L$ 个线性层,如果每层把激活方差乘以一个增益 $g$,那么 $L$ 层后方差变成 $g^L\cdot\text{Var}(\text{input})$。$g\gt 1$ 就指数爆炸、$g\lt 1$ 就指数消失——只有 $g=1$ 这个临界点才稳定,而随机初始化几乎不可能恰好命中。反向传播同理:梯度也按某个增益逐层连乘,于是要么梯度爆炸(loss 变 NaN),要么梯度消失(深层学不动)。这就是 2015 年前"很难训超过一二十层网络"的核心障碍。

Tip

$g^L$ 是简化模型,别当全部 $g^L$ 是个标量 / 平均场近似——真实每层增益数据相关、含非线性 / attention / normalization,完整的信号传播稳定性还涉及 Jacobian 谱 / dynamical isometry、均值漂移、跨层相关、训练中参数漂移。但 $g^L$ 抓住了最本质的"指数尺度失控",是理解归一化 / 残差 / init 的最小入口模型。顶级面试若深问,要点明它是简化,稳定性 $\ne$ 只看方差连乘。

两类结构性药方分别攻这个病(外加 init / 参数化,§8–§9,是第三条轴)——三者概念上分工、工程上强耦合:norm 控局部尺度、residual 改善梯度路径、init 设定 step-0 临界性;现代深网的稳定性是三者的联合设计(见 §5.3 Pre-LN 残差流增长、§8 残差缩放、§10 norm-free 靠 init+scaling):

二者配合(Pre-LN Transformer = 残差 + LayerNorm + 合适 init)才让"几十到上千层"成为常规操作。

1.1 internal covariate shift 的叙事——以及它被推翻

BatchNorm 原始论文(Ioffe & Szegedy, 2015)给出的动机是 internal covariate shift(ICS,内部协变量偏移):随着前面层参数在训练中更新,每一层输入的分布也在不停漂移,后面层得不断追着这个移动的分布重新适配,拖慢训练;BN 通过固定每层输入的均值方差来"稳住分布",所以训练更快。这个故事直觉好懂、流传极广——但它大概率不是 BN 真正起作用的原因。

Santurkar et al.(How Does Batch Normalization Help Optimization?, 2018, arXiv 1805.11604)用两组实验把这个叙事拆了:

  1. 故意制造 ICS,BN 照样 work:在 BN 层之后注入随时间变化的随机噪声(人为放大分布漂移,ICS 明显增大),带 BN 的网络训练速度 / 精度几乎不受影响。如果 BN 的价值真在"消除 ICS",这里早该崩了。
  2. BN 真正改变的是优化地形:他们证明 BN 让 loss 关于参数更平滑——loss 与梯度的 Lipschitz 常数变小(更好的 β-smoothness),梯度更可预测、更稳定。地形更平滑意味着可以放心走更大的步子(更大 LR)而不越过 / 震荡,这才是 BN 加速收敛、允许大 LR 的机制。
Warning

面试别再背 "BN 减少 covariate shift" 这是被强实证质疑、主流不再视为主因的旧叙事。更稳的说法:归一化的主要收益是让损失地形更平滑、梯度更良态(well-conditioned)(并带来支持更大学习率、隐式正则、尺度不变性等多重好处),从而能训更深;"稳定每层输入分布"至多是表象,不是公认的因果机制。把 covariate shift 当成"已证明的唯一原因"是经典踩坑(§11、Q21)。

一句话心智模型

归一化不是在"对齐分布",而是在给优化器修一条更平的路(小 Lipschitz);残差不是在"加特征",而是在给梯度修一条不堵车的高速路(恒等雅可比)。两条都是为了让"很深"这件事在数值上可行。

§2 BatchNorm

2.1 公式:沿 batch 维,逐 channel

设一个 mini-batch $\mathcal{B}=\{x_1,\dots,x_m\}$,对每个 channel / 特征 $c$ 独立统计:

$$\mu_c = \frac{1}{m}\sum_{i=1}^m x_{i,c}, \qquad \sigma_c^2 = \frac{1}{m}\sum_{i=1}^m (x_{i,c}-\mu_c)^2,$$

$$\hat x_{i,c} = \frac{x_{i,c}-\mu_c}{\sqrt{\sigma_c^2+\epsilon}}, \qquad y_{i,c} = \gamma_c\,\hat x_{i,c} + \beta_c.$$

关键是沿哪个维度求统计:对 $[N, C]$ 的全连接特征,沿 $N$(batch)维、每个 $C$ 一组 $(\mu,\sigma)$;对 $[N, C, H, W]$ 的卷积特征,沿 $(N, H, W)$ 求、每个 channel $C$ 一组。所以 BN 的统计量是 "跨样本" 的——一个样本的归一化结果依赖同 batch 里的其他样本,这是它一切麻烦的根源。$\gamma_c,\beta_c$ 是逐 channel 的可学缩放 / 偏移,让网络能恢复"非零均值 / 非单位方差"的表达(否则强行标准化会限制表达力)。

2.2 train vs eval:running stats 与 momentum

推理时往往一次只来一个样本,没有 batch 可统计;而且我们要确定性输出(同一输入每次结果一致),不能让结果随同 batch 的其他样本变。于是 BN 在训练时额外维护一份 running(滑动平均)统计,推理时改用它:

$$\hat\mu \leftarrow (1-\rho)\,\hat\mu + \rho\,\mu_\mathcal{B}, \qquad \hat\sigma^2 \leftarrow (1-\rho)\,\hat\sigma^2 + \rho\cdot\frac{m}{m-1}\sigma_\mathcal{B}^2,$$

其中 $\rho$ 是 momentum(PyTorch 里默认 0.1),$m$ 是 batch size。于是:

Warning

前向归一化用有偏方差,running_var 用无偏估计(高频考点) 这两处的 $\sigma_\mathcal{B}^2$ 不是同一个量:前向归一化用有偏方差(除以 $m$,对应 PyTorch unbiased=False),但更新 running_var 时用的是无偏估计 $\frac{m}{m-1}\sigma_\mathcal{B}^2$(Bessel 修正)——这是 PyTorch BatchNorm 的实际行为,容易被忽略。

Warning

train$\ne$eval 是 BN 的硬约束(高频考点) BN 是少数几个"训练和推理走不同计算路径"的层。忘记切 model.eval() 会让推理用 batch 统计 → 结果随 batch 内容抖动、复现不了;BN 层在小 eval batch 上还会数值异常。这点和 LayerNorm / RMSNorm 形成鲜明对比——后者 train 和 eval 完全同构。

2.3 为什么 BN 不适合序列 / 小 batch / RL

BN 的"跨样本统计"在很多场景下直接失效:

Blocked

"BN 是默认归一化" 是 CV 时代的惯性 在 CNN + 大 batch 分类任务上 BN 仍然好用;但一进序列建模 / 小 batch / RL,BN 的跨样本耦合 + train$\ne$eval 就成了负担。现代 LLM 栈里 BN 基本绝迹,主力是 LayerNorm / RMSNorm。

§3 LayerNorm

3.1 公式:沿特征维,per-token

LayerNorm(Ba, Kiros & Hinton, 2016, arXiv 1607.06450)把统计维度从 batch 转到特征。对单个 token / 单个样本的隐藏向量 $x\in\mathbb{R}^d$:

$$\mu = \frac{1}{d}\sum_{i=1}^d x_i, \qquad \sigma^2 = \frac{1}{d}\sum_{i=1}^d (x_i-\mu)^2,$$

$$\hat x = \frac{x-\mu}{\sqrt{\sigma^2+\epsilon}}, \qquad y = \gamma\odot\hat x + \beta, \quad \gamma,\beta\in\mathbb{R}^d.$$

对一个 $[B, T, d]$ 的 Transformer 张量,LN 沿最后一维 $d$ 求 $(\mu,\sigma)$——每个 $(b,t)$ 位置一组统计,完全不跨样本、不跨 token。$\gamma,\beta$ 是 $d$ 维逐通道仿射(elementwise affine)。

3.2 为什么适配 Transformer / RNN

LN 的统计只在一个 token 的特征内部完成,于是 BN 的所有痛点一次消除:

Tip

BN 沿 batch、LN 沿 feature(一句话区分) 同一个 $[N, C]$ 张量:BN 把它竖着切(固定 channel、跨样本求统计),LN 把它横着切(固定样本、跨 channel 求统计)。BN 问"这个特征在整批里什么尺度",LN 问"这个样本内部各特征什么尺度"。前者引入跨样本依赖,后者没有——这就是 LN 适配序列的全部理由。

Warning

LN 的 $\gamma,\beta$ 不是可有可无 强行标准化到零均值单位方差会砍掉表达力(比如 sigmoid 前你可能就需要非零均值);$\gamma,\beta$ 让网络把尺度 / 偏移学回来。去掉仿射(elementwise_affine=False)在某些任务可行,但默认保留。注意 RMSNorm 只保留 $\gamma$、砍掉 $\beta$(§4)。

§4 RMSNorm

4.1 只 re-scale,不 re-center

RMSNorm(Zhang & Sennrich, 2019, arXiv 1910.07467)的出发点是一个假设:LayerNorm 的成功主要来自 re-scaling 不变性(把向量缩放到固定尺度),而不是 re-centering(减均值)。 既然如此,干脆把减均值这一步省掉,只用 均方根(RMS) 做缩放:

$$\text{RMS}(x) = \sqrt{\frac{1}{d}\sum_{i=1}^d x_i^2 + \epsilon}, \qquad \boxed{\;\bar x = \frac{x}{\text{RMS}(x)}\odot\gamma\;}$$

对比 LayerNorm,RMSNorm 做了两处删减:(1) 不减均值 $\mu$(少一次 reduction),(2) 通常不要 $\beta$ 偏移(只留 $\gamma$ 缩放)。本质上 LN 既给 $x$ 平移又缩放,RMSNorm 只缩放。

4.2 为什么 re-scaling 比 re-centering 重要 + 成本

直觉:网络真正怕的是激活尺度失控($g^L$ 那套),而尺度由 $\lVert x\rVert$ / RMS 主导,和均值关系不大。Zhang & Sennrich 的消融显示:在 LN 里只保留 re-scaling、去掉 re-centering,多数任务性能几乎不掉;反过来只保留 re-centering 则掉得多。所以 RMSNorm 用更少的运算拿住了 LN 的主要红利。

成本上 RMSNorm 比 LN 省:

OK

LLaMA 之后的事实默认 LLaMA、Qwen、Mistral、Gemma 等近代 LLM 基本都用 RMSNorm(配 Pre-LN 放置)。面试问"现代 LLM 的归一化",标准答案是 Pre-RMSNorm;能补一句"因为 re-scaling 是主要收益、re-centering 可省"就到位了。

Warning

RMSNorm 没有 re-centering / 没有 bias 把 LN 代码直接当 RMSNorm 用会出错:RMSNorm 不减均值(所以它对输入的整体平移不变——加个常数 $c$ 后输出会变,而 LN 不变),也没有 $\beta$。一个直接后果:RMSNorm 后的激活均值不被强制归零,下游若假设零均值要小心。

§5 Pre-LN vs Post-LN(最关键的一节)

这是归一化里最容易被深问的点:LN 到底放在残差的哪一侧? 两种放法行为差异巨大。

5.1 两种放置

记一个子层(attention 或 FFN)为 $\text{Sublayer}(\cdot)$:

$$\textbf{Post-LN(原始 Transformer, Vaswani 2017)}:\quad x_{l+1} = \text{LN}\big(x_l + \text{Sublayer}(x_l)\big),$$

$$\textbf{Pre-LN(现代 LLM 主流)}:\quad x_{l+1} = x_l + \text{Sublayer}\big(\text{LN}(x_l)\big).$$

差别看似只是 LN 挪了个位置,实则改变了残差路径的纯净度

5.2 梯度幅度论证(Xiong et al. 2020)

Xiong et al.(On Layer Normalization in the Transformer Architecture, 2020, arXiv 2002.04745)在初始化处做了梯度尺度分析,给出干净结论:

OK

一句话抓住 Pre vs Post Pre-LN 给残差留了干净恒等梯度路(梯度按 $\sim 1/\sqrt L$ 有界、跨层均衡)→ 稳、免 warmup;Post-LN 把梯度尺度堆在顶层(与 $L$ 无关地偏大)→ 需 warmup、深了不稳。这就是为什么 GPT/LLaMA 一律 Pre-LN。

注意:"Pre-LN 免 warmup"特指它去掉了 Post-LN 那种梯度不均衡导致的 warmup 刚需;实践中现代 Pre-LN 大模型(GPT-3/LLaMA)仍然配 warmup——那是 Adam 早期 $\hat v$ 方差大、大 batch 等另一层动机(与 LN 放置无关,见优化器篇 §7.1),别把"Pre-LN"读成"完全不需要 warmup"。

5.3 Pre-LN 的代价:残差流随深度膨胀

Pre-LN 不是免费的。看残差主干:$x_{l+1} = x_l + F_l\big(\text{LN}(x_l)\big)$。每个分支输出 $F_l(\text{LN}(\cdot))$ 因为输入被 LN 归一化、量级大致 $O(1)$,于是方差逐层累加

$$\text{Var}(x_l) \approx \text{Var}(x_0) + \sum_{j\lt l}\text{Var}\big(F_j\big) \;\propto\; l \quad\Longrightarrow\quad \text{std}(x_l)\propto\sqrt{l}.$$

残差流的幅度随深度按 $\sqrt l$ 增长。后果:每个分支内部的 LN 都要除以这个越来越大的 $\text{std}(x_l)$,于是深层子层的相对贡献被稀释——加进去的 $O(1)$ 更新相对于已经 $\sqrt l$ 量级的主干越来越微不足道,网络的"有效深度"饱和,极端时退化成"恒等主干主导、深层近乎摆设"(有人称 representation / identity collapse)。这也是为什么 Pre-LN 网络必须在最后补一个 final LN(把膨胀的残差流拉回正常尺度再送进输出头),以及催生了 DeepNorm / Sandwich 等想兼顾两端的变体。

Warning

Pre-LN 一定要有 final LN(高频踩坑) Pre-LN 结构里,最后一层之后残差流量级已是 $\sqrt L$ 级、且未被任何 LN 收口。不补 final LN 直接接 LM head,输出分布会失控、训练质量明显下降。GPT-2/3、LLaMA 都在 transformer 栈之后、输出投影之前加了这个 final LN——别漏。

5.4 为什么 Post-LN 质量上限有时更高

既然 Pre-LN 这么稳,为何还提 Post-LN?因为当 Post-LN 能训稳时(充分 warmup + 调参),它的最终质量往往略优。原因正是 §5.3 的反面:Post-LN 每层都把残差流重新归一化,深层贡献不会被稀释,"有效深度"利用得更充分。代价是训练脆弱(窗口窄、依赖 warmup、深了容易崩)。所以工程上的取舍是:追求稳定 / 可扩展性 → Pre-LN(现代 LLM 默认);在可控规模上榨质量 → Post-LN 或 DeepNorm 这类"修好的 Post-LN"。

§6 放置与变体

围绕"LN 放哪 / 归一化什么",社区演化出一批变体,面试常被点名:

6.1 DeepNorm:把 Post-LN 修到能训 1000 层

DeepNorm(Wang et al., DeepNet, 2022, arXiv 2203.00555)是一个改良版 Post-LN,目标是同时拿到 Post-LN 的质量和 Pre-LN 的稳定。两个动作:

$$x_{l+1} = \text{LN}\big(\alpha\,x_l + \text{Sublayer}(x_l)\big), \qquad \text{且把子层权重的一部分初始化按 } \beta \text{ 缩小}.$$

对一个 $N$ 层单栈,取 $\alpha=(2N)^{1/4}\gt 1$(放大残差主干),同时把子层权重的一部分——FFN 的两层权重、attention 的 value 投影 $W^V$ 与输出投影 $W^O$——按增益 $\beta=(8N)^{-1/4}\lt 1$ 缩小初始化(Query/Key 投影 $W^Q,W^K$ 保持标准 Xavier 初始化,不被 $\beta$ 缩小;编码器-解码器另有公式)。直觉:放大 $x_l$ 让残差主干在相加时占主导(接近 Pre-LN 的恒等稳定性),缩小子层 init 让每步"模型更新量"被理论上界住、不随深度爆炸。结果是 Post-LN 的放置 + 受控的更新幅度 → 稳定训练到 1000 层。记忆点:DeepNorm = up-scale 残差 + down-scale init 的 Post-LN

6.2 Sandwich / double LN:分支前后各一个

Gemma2 等用 sandwich norm(双 LN):在每个子层的残差分支前后各放一个归一化

$$x_{l+1} = x_l + \text{PostNorm}\Big(\text{Sublayer}\big(\text{PreNorm}(x_l)\big)\Big).$$

PreNorm 像 Pre-LN 一样给子层喂归一化输入(稳梯度),PostNorm 再把子层输出的量级收口(防止它无界地灌进残差流,缓解 §5.3 的膨胀)。代价是多一个 LN 的算力。可看成"Pre-LN 的稳定 + 对分支输出额外加一道闸"。

6.3 QK-Norm:归一化 Q、K 稳住 attention logits

QK-Norm(Henry et al., Query-Key Normalization, 2020, arXiv 2010.04245)针对的是注意力 logits 爆炸:训练中 $q^\top k$ 可能随尺度漂移到极大,softmax 进入饱和区(near one-hot),梯度消失 / 训练发散(大模型、长训练尤甚,也叫 attention entropy collapse)。修法极简——在点积之前对每个 head 的 $q,k$ 各做一次归一化(L2 或 RMS/LayerNorm),再算 logits:

$$\tilde q = \text{Norm}(q),\quad \tilde k = \text{Norm}(k), \qquad \text{logits} = \frac{\tilde q^\top \tilde k}{\tau}\ (\tau\ \text{可学温度}).$$

归一化后 $q,k$ 的模长被钳住,logits 不再随尺度爆炸 → attention 稳定。Gemma3、Chameleon、ViT-22B 等都用了 QK-Norm(Gemma2 当时用的是 attention/logit soft-capping,Gemma3 才改用 QK-Norm 并去掉 soft-capping),已成为大规模训练的标配稳定器之一。

6.4 GroupNorm 与 WeightNorm

Tip

一句话归位四种 norm BN 沿 batch、LN 沿 feature、GN 沿 group(batch 无关、桥接 LN 与 IN)、WN 归一化的是权重而非激活。面试问"小 batch 检测用什么归一化"答 GroupNorm;问"现代 LLM"答 RMSNorm;问"稳 attention logits"答 QK-Norm。

§7 残差连接 + 残差缩放

7.1 残差为什么 work:三种视角

残差块 $y = x + F(x)$(He et al., ResNet, 2015, arXiv 1512.03385)能训很深,有三个互补解释:

  1. 恒等映射 / 梯度高速路:雅可比 $\frac{\partial y}{\partial x} = I + \frac{\partial F}{\partial x}$。那个 $I$ 在典型情况下显著改善梯度传播——哪怕 $\frac{\partial F}{\partial x}$ 因深度而变小,梯度仍能主要经恒等项传回(但这不是严格的数学保证:若某分支恰好学到 $F(x)=-x$,使 $I+\frac{\partial F}{\partial x}=0$,该层梯度会被精确抵消为 0;这种精确抵消在随机初始化 + 梯度下降下几乎不会发生)。$L$ 个残差块串起来,$\frac{\partial x_L}{\partial x_0}=\prod_{l}\big(I+\frac{\partial F_l}{\partial x}\big)$ 展开后含一个纯恒等项(外加各阶交叉项),典型情况下梯度主要经恒等项无损传回。这大幅缓解了 $g^L$ 消失,但对任意 $F$ 并非严格保证。
  2. 优化更易 / 学残差比学映射容易:若理想映射接近恒等,让 $F$ 去拟合"残差"(差量)比让一整层拟合恒等容易得多——初始化在 0 附近就已经接近恒等,优化从一个好起点出发。
  3. 浅路径集成(ensemble of shallow paths,Veit et al., 2016, arXiv 1605.06431):一个 $L$ 块残差网在前向上等价于 $2^L$ 条不同深度路径的集合(每块选"走 $F$"或"走恒等"),其中短路径占主导,有效梯度主要来自这些浅路径——所以深残差网"像很多浅网的集成",优化自然更容易。

7.2 残差流(residual stream)视角

机理可解释性里有个统一图景:残差主干是一条贯穿全网的共享通信总线(residual stream)。每个子层从总线读(经 LN 取出当前状态)、算一个更新、把更新加回总线。信息默认沿总线恒等保留,每层只决定"往上加什么"。这个视角解释了很多现象:为什么 Pre-LN 残差流会随深度累加膨胀(§5.3,大家都往同一条总线写)、为什么残差缩放(下面)有用(控制每层往总线写的强度)、为什么能在中间层"读出"语义。

7.3 残差缩放:把分支起点压向恒等

深残差网的一个隐患(§5.3):分支输出无节制地灌进残差流,使其方差线性膨胀、训练初期不稳。一族技巧给残差分支乘一个小缩放,让训练从接近恒等的状态起步

Tip

残差缩放的统一直觉 LayerScale / ReZero / SkipInit / $1/\sqrt N$ 做的是同一件事:让残差分支在初始化时接近 0、网络从恒等起步,于是梯度良态、训练稳定,再让网络自己学该往残差流里加多强。"init 成接近恒等"是训练超深网络的一条暗线(也是 §8 init 的核心)。

§8 初始化

归一化和残差治标,初始化治本——它决定网络在第 0 步的方差 / 梯度尺度是否良态。(注:init 只保证良态起点;训练全程的稳定还要靠参数化 / LR / optimizer / 残差缩放 / norm 放置一起兜——见 §1 的"三轴联合设计"。)

8.1 目标:方差保持(variance preservation)

希望前向激活方差与反向梯度方差逐层大致守恒,别让 $g^L$ 把它们带跑。对一个权重 $W\in\mathbb{R}^{n_\text{out}\times n_\text{in}}$、输入各分量独立同方差的线性层 $z=Wx$:

$$\text{Var}(z_j) = n_\text{in}\,\text{Var}(W)\,\mathbb{E}[x^2].$$

(对零均值的 $x$,$\mathbb{E}[x^2]=\text{Var}(x)$ 二者一致;但深层 ReLU 网络中作为下一层输入的 $x$ 是上一层 ReLU 输出、并非零均值,此时须用 $\mathbb{E}[x^2]$——这与 §8.3 后续正确使用 $\mathbb{E}[y^2]$ 而非 $\text{Var}(y)$ 一致。)要 $\text{Var}(z)=\mathbb{E}[x^2]$(前向守恒)需 $n_\text{in}\text{Var}(W)=1$;要反向梯度方差守恒需 $n_\text{out}\text{Var}(W)=1$。两者一般不能同时满足,于是有了不同折中。

8.2 Xavier / Glorot:给 tanh / 线性的折中

Xavier/Glorot(Glorot & Bengio, AISTATS 2010)面向对称、近线性激活(tanh、线性),取前向与反向两个条件的折中:

$$\text{Var}(W) = \frac{2}{n_\text{in}+n_\text{out}} \quad\Longrightarrow\quad W\sim U\!\Big[-\sqrt{\tfrac{6}{n_\text{in}+n_\text{out}}},\ \sqrt{\tfrac{6}{n_\text{in}+n_\text{out}}}\Big]\ \text{或对应高斯}.$$

前提是激活在 0 附近近似线性(tanh 满足、ReLU 不满足),所以对 ReLU 网它偏小。

8.3 Kaiming / He:给 ReLU 补回那个因子 2

Kaiming/He(He et al., 2015, arXiv 1502.01852)指出:ReLU 把负半轴清零,砍掉约一半方差——$\mathbb{E}[\text{ReLU}(z)^2]=\tfrac12\text{Var}(z)$(对零均值对称 $z$)。要在 ReLU 后仍守恒,需补一个因子 2:

$$\tfrac12\,n_\text{in}\,\text{Var}(W)=1 \quad\Longrightarrow\quad \boxed{\;\text{Var}(W)=\frac{2}{n_\text{in}}\;}\ (\text{fan\_in 模式},\ \text{std}=\sqrt{2/n_\text{in}}).$$

这个 2 是 Xavier 与 Kaiming 在 $n_\text{in}=n_\text{out}$(如常见方阵 / 等宽层)特例下的实质区别——一般情形下两者方差之比是 $\frac{n_\text{in}+n_\text{out}}{n_\text{in}}=1+\frac{n_\text{out}}{n_\text{in}}$,只有 $n_\text{in}=n_\text{out}$ 时才恰好等于 2(共同本质:Kaiming 是在纯前向条件 $n_\text{in}\text{Var}(W)=1$ 上补一个 ReLU 砍半的因子 2,Xavier 是前向 / 反向两条件的折中平均)。这个因子却决定了深 ReLU 网(VGG / ResNet 级)能不能训:用 Xavier 的 $1/n_\text{in}$ 喂 ReLU,每层信号能量被 ReLU 砍半又没补回,$L$ 层后二阶矩 $\mathbb{E}[y^2]\approx (1/2)^L$ 指数消失;用 Kaiming 才守恒(§A 的 [e] 验证:Kaiming 后 post-ReLU 二阶矩 $\mathbb{E}[y^2]\approx1$,Xavier-for-ReLU $\approx 0.5$ 并逐层砍半)。这里守恒的量是二阶矩 $\mathbb{E}[y^2]$(喂给下一层的信号能量),而非 $\text{Var}(y)$——ReLU 让输出均值非零,$\text{Var}(y)=1-1/\pi\approx0.68$。

Warning

Xavier vs Kaiming 不是"换个公式",是"是否补 ReLU 的因子 2" tanh / 线性用 Xavier($\frac{2}{n_\text{in}+n_\text{out}}$);ReLU / LeakyReLU 用 Kaiming($\frac{2}{n_\text{in}}$,LeakyReLU 还要按负斜率改增益)。给 ReLU 网用 Xavier 会系统性偏小 → 深了激活 / 梯度消失。

8.4 残差网的深度感知下调 + GPT-2 的 $1/\sqrt{2N}$

即便每层都 Xavier/Kaiming,残差流仍会累加膨胀(§5.3)。所以深残差网在 per-layer init 之外还要按深度下调残差分支

GPT-2 的经典技巧:把残差投影层(attention 的输出投影 + FFN 的 down 投影,即"往残差流写"的那两个矩阵)的权重在 init 时乘 $\frac{1}{\sqrt{2N}}$,$N$=层数。为什么是 $2N$ 而非 $N$?因为每个 transformer 层往残差流写两次(attn 一次、FFN 一次),$N$ 层共 $2N$ 次累加;按 $1/\sqrt{2N}$ 缩放每次写入,使 $2N$ 次累加后残差流方差仍 $O(1)$。nanoGPT 等实现都对 c_proj 类权重套这个缩放(§A 的 [f] 验证:不缩放方差随深度线性涨,$1/\sqrt{2N}$ 缩放后有界)。

8.5 Fixup:以 init 为主(+ 少量可学 scalar)免归一化训深残差网

Fixup(Zhang et al., 2019, arXiv 1901.09321)把"用 init 控方差"推到极致——完全不用任何归一化层,仅靠精心设计的初始化就训出能打 BN-ResNet 的深残差网。三招:

  1. 每个残差分支的最后一层初始化为 0(分支起点输出 0 → 块为恒等,残差流初始方差不爆);
  2. 分支内其他层的权重额外乘 $L^{-1/(2m-2)}$ 下调($m$=每分支层数、$L$=块数),抵消深度累加;
  3. 加入少量可学标量偏置 / 乘子补偿被砍掉的仿射自由度。

意义:归一化不是训深网络的充要条件——把方差 / 梯度的尺度问题在初始化处一次性解决,就能去掉 BN/LN。这条直接通向 §10 的 normalizer-free 路线。(Transformer 上的对应工作是 T-Fixup,主张配好 init 后可免 warmup / 免 LN——见参考文献,arXiv id 待核。)

§9 μP(maximal update parametrization)

9.1 问题:标准参数化下最优 LR 随宽度漂移

标准参数化(SP,即 Xavier/Kaiming + 全网同一个 LR)有个隐蔽缺陷:当模型宽度 $n$ 变化时,各层激活和参数更新的尺度跟着错配,于是最优超参(尤其学习率)会随宽度漂移。后果很实际——你在小模型上辛苦调出的最佳 LR,搬到大模型上不再最优,每加宽一次就得重调;而大模型一次调参的算力成本极高。

根因(Yang et al., Tensor Programs V, 2022, arXiv 2203.03466 给出的极限分析):在 SP 下让宽度 $n\to\infty$,要么激活 / 更新随 $n$ 爆掉(需调小 LR),要么进入 lazy / kernel 区(特征几乎不更新、等于没在学 feature)。两种极限都不是我们想要的"宽了还能稳定地大幅更新特征"。

9.2 μP:让超参宽度不变 → zero-shot 迁移

μP(maximal update parametrization)是唯一能在任意宽度都保持"最大化且稳定的特征学习"的缩放方案:它把初始化方差、学习率、输出乘子都写成宽度(fan_in)的函数,逐层分别缩放,使得——

典型缩放(Adam 下,示意):隐藏层 LR $\propto 1/\text{fan\_in}$、隐藏层 init 方差 $\propto 1/\text{fan\_in}$、输出 logits 乘 $1/\text{fan\_in}$;输入 / 输出层与隐藏层用不同的缩放。落地为 μTransfer:在一个小宽度代理模型上把 LR / warmup / init 等超参调好,zero-shot 直接迁移到几十上百倍大的目标模型,省掉在大模型上重调的天价算力(被用于 GPT-3 规模、Cerebras-GPT、MiniCPM 等)。

Tip

μP 面试金句 SP 下"最优 LR 随宽度漂移",所以小模型调的参不能直接用到大模型;μP 把 init / LR / 输出乘子按 fan_in 重新缩放,使每层特征更新在宽度上 $\Theta(1)$、最优 LR 宽度不变 → 小宽度调参、大宽度 zero-shot 迁移(μTransfer)。一句话:μP 是让超参可跨宽度迁移的参数化。

§10 归一化-free 与前沿

归一化层带来 train/eval 差异(BN)、跨设备同步(多卡 BN)、额外 reduction 等麻烦,于是一直有人问:能不能不要归一化? 这是研究方向,非定论,但思路很有启发。

10.1 Fixup / NFNets:用 init + 显式方差控制替代归一化

10.2 DyT(Dynamic Tanh):用可学 tanh 替掉 LN

DyT(Transformers without Normalization, 2025, arXiv 2503.10622,arXiv id 以引用核查为准)来自一个观察:训练好的 LayerNorm 的输入-输出曲线,长得像一条被压扁的 $\tanh$(对中间值近线性、对离群值 S 形饱和)。既然 LN 的效果近似一个逐元素 squashing,那干脆省掉求均值 / 方差的 reduction,直接学一个 tanh

$$\text{DyT}(x) = \gamma\odot\tanh(\alpha\,x) + \beta,$$

其中 $\alpha$ 是一个可学标量(控制输入尺度、对应 LN 里"除以 std"的作用),$\gamma,\beta$ 是逐通道仿射。论文报告在 ViT / LLM / diffusion 等多处用 DyT 替换 LN/RMSNorm,效果相当,且去掉了归一化的统计量计算(不再需要逐 token 的 reduction)。

🎯 前沿,诚实定位 Fixup / NFNets / DyT 共同传递一个信息:归一化在理论上不是训练深网络的必要条件——它的核心作用(控方差、平滑地形、压离群值)可被"好 init / 显式方差控制 / 可学 squashing"等手段替代。但 LN/RMSNorm 仍是当前生产系统的稳妥默认(鲁棒、即插即用、生态成熟)。面试谈这些要点明"研究方向 / 有前景",别说成"已取代归一化"。

§11 工程实践 + 复杂度对比 + 常见误区

11.1 四种归一化对比

归一化归一化维度依赖 batchtrain$\ne$eval可学参数相对成本
BatchNorm沿 batch(+空间),逐 channel(推理用 running stats)$\gamma,\beta$中(两次 reduction + 维护 running stats + 多卡需同步)
LayerNorm沿特征维,per-token$\gamma,\beta$中(多算一个统计量——均值;朴素实现两次 reduction,fused/Welford 单遍可算完)
RMSNorm沿特征维 RMS,per-token$\gamma$(无 $\beta$)低(一次平方和 reduction,无均值、无偏移)
GroupNorm沿组内 channel(+空间),逐 sample$\gamma,\beta$中(组内 reduction,batch 无关)

11.2 工程细节

11.3 常见误区(footguns)

Blocked

误区 1:把 covariate shift 当成归一化有效的唯一/已证原因 已被 Santurkar 2018 实证推翻(§1.1)。正确归因是"平滑 loss 地形 / 梯度更良态"。这是最经典的面试陷阱。

Blocked

误区 2:Pre-LN 忘了 final LN Pre-LN 残差流随深度按 $\sqrt L$ 膨胀且末端无 LN 收口,漏掉 final LN 直接喂输出头会掉点(§5.3)。

Blocked

误区 3:把 LN 代码当 RMSNorm 用 RMSNorm 不减均值、没有 $\beta$,且对输入整体平移不变;照搬 LN 的减均值 / 加 bias 逻辑就错了(§4.2)。

Blocked

误区 4:在 RL / 变长序列 / 小 batch 上用 BatchNorm 跨样本统计 + train$\ne$eval 在这些场景全面失效,应换 LayerNorm / GroupNorm(§2.3)。

Blocked

误区 5:给 ReLU 网用 Xavier 初始化 少了补 ReLU 的因子 2,深了激活 / 梯度指数衰减;ReLU 用 Kaiming(§8.3)。

§12 25 高频面试题

按难度分三档,点开看答案要点 + 易踩坑。L2/L3 是顶级 lab 深水区(Pre/Post 梯度论证、Kaiming 推导、μP、DeepNorm、norm-free、QK-Norm、covariate-shift debunk 等)。

L1必会题

Q1. 为什么深网络需要归一化?归一化到底解决了什么?
  • 深网络激活 / 梯度方差按 $g^L$ 指数爆炸或消失,只有 $g=1$ 临界点才稳,随机 init 难命中
  • 归一化把每层激活拉回固定尺度,掐断 $g^L$ 连乘 → 可用更大 LR、堆更深
  • 现代正确归因:让 loss 地形更平滑、梯度更良态(Santurkar 2018),不是"减少 covariate shift"

只说"加速收敛",讲不出方差尺度 / loss 地形这一层;或还在背 covariate shift。

Q2. 写出 BatchNorm 的公式,它沿哪个维度统计?
  • 逐 channel 沿 batch(卷积再加空间 $H,W$)求 $\mu_c,\sigma_c^2$,$\hat x=\frac{x-\mu_\mathcal{B}}{\sqrt{\sigma_\mathcal{B}^2+\epsilon}}$,再 $\gamma_c\hat x+\beta_c$
  • 统计是跨样本的 → 一个样本的归一化依赖同 batch 其他样本
  • $[N,C]$ 沿 $N$;$[N,C,H,W]$ 沿 $(N,H,W)$,每 channel 一组

把 BN 说成沿特征维(那是 LN);或忘了它跨样本这个关键性质。

Q3. BatchNorm 训练和推理(eval)有什么不同?为什么?
  • 训练用当前 batch 统计归一化,并以 momentum 更新 running mean/var
  • 推理用冻结的 running stats(不看 batch),保证确定性 + 单样本可用
  • 所以 BN 是 train$\ne$eval 的层,忘切 eval() 会让推理结果随 batch 抖动

不知道有 running stats / momentum;或以为推理也用 batch 统计。

Q4. 写出 LayerNorm 公式,它和 BN 沿的维度有何不同?
  • 对单 token 向量 $x\in\mathbb{R}^d$ 沿特征维 $d$ 求 $\mu,\sigma$,$y=\gamma\odot\frac{x-\mu}{\sqrt{\sigma^2+\epsilon}}+\beta$
  • $[B,T,d]$ 沿最后一维,每个 $(b,t)$ 一组统计,不跨样本、不跨 token
  • BN 沿 batch(跨样本),LN 沿 feature(样本内)——这是本质区别

把 LN 也说成跨 batch;或答不出"per-token、与 batch 解耦"。

Q5. RMSNorm 是什么?和 LayerNorm 差在哪?
  • 只按 RMS 缩放:$\bar x=\frac{x}{\sqrt{\frac1d\sum x_i^2+\epsilon}}\odot\gamma$
  • 相比 LN 删两样:不减均值(无 re-centering)、无 $\beta$ 偏移
  • 论点:re-scaling 是 LN 主要收益,re-centering 可省 → 更便宜,LLaMA 后默认

只说"RMSNorm 更快",讲不出"去掉减均值 + 去掉 bias"两处删减。

Q6. LayerNorm 在 Transformer 里放在哪?有哪两种放法?
  • Post-LN:$x_{l+1}=\text{LN}(x_l+\text{Sublayer}(x_l))$,LN 在残差相加之后(原始 Transformer)
  • Pre-LN:$x_{l+1}=x_l+\text{Sublayer}(\text{LN}(x_l))$,LN 在残差分支内部(现代 LLM 主流)
  • 现代 LLM 用 Pre-LN + 一个 final LN

只知道"有个 LN",说不清放在残差的哪一侧、两种放法叫什么。

Q7. 为什么 Transformer / RNN 用 LayerNorm 而不用 BatchNorm?
  • 变长序列 + padding 让"沿 batch 求每个位置统计"语义可疑、难对齐
  • batch 耦合:BN 一个样本依赖同 batch 其他样本;序列任务常小 batch / batch=1
  • LN per-token、与 batch 解耦、train$=$eval,天然适配序列 / 自回归 decode

只说"习惯用 LN",答不出 batch 耦合 + 变长 + train/eval 这几条具体原因。

Q8. 残差连接为什么能帮助训练很深的网络?
  • $y=x+F(x)$ 雅可比 $I+\partial F/\partial x$,那个 $I$ 给梯度一条恒等高速路,破 $g^L$ 消失
  • 学残差比学整映射容易(理想接近恒等时从好起点出发)
  • 等价于 $2^L$ 条路径的集成、短路径主导,优化更易(Veit 2016)

只说"防梯度消失",讲不出雅可比恒等项 / 残差易学 / 浅路径集成这几个视角。

Q9. 归一化里的 $\gamma,\beta$(scale/shift)是干嘛的?去掉行不行?
  • 强行标准化到零均值单位方差会砍掉表达力;$\gamma,\beta$ 让网络把尺度 / 偏移学回来
  • $\gamma$ 缩放、$\beta$ 平移,逐通道
  • RMSNorm 只保 $\gamma$、去掉 $\beta$;去掉全部仿射在某些任务可行但默认保留

以为 $\gamma,\beta$ 可有可无;或不知道 RMSNorm 砍掉了 $\beta$。

Q10. Xavier 和 Kaiming 初始化的区别?各用于什么激活?
  • Xavier:$\text{Var}(W)=\frac{2}{n_\text{in}+n_\text{out}}$,给 tanh / 线性(对称近线性激活)
  • Kaiming:$\text{Var}(W)=\frac{2}{n_\text{in}}$,给 ReLU,那个 2 补偿 ReLU 砍掉的一半方差
  • 两者方差之比是 $1+n_\text{out}/n_\text{in}$,只有 $n_\text{in}=n_\text{out}$ 时才恰好等于 2(这是常被过度泛化的特例,不是普遍规律)
  • 给 ReLU 网用 Xavier 会偏小 → 深了激活 / 梯度消失

只背两个公式,说不清"差别就是补不补 ReLU 的因子 2";或以为"因子恰好是 2"对任意 $n_\text{in},n_\text{out}$ 都成立。

L2进阶题

Q11. Pre-LN vs Post-LN:行为差异 + 梯度论证。
  • Post-LN 需 LR warmup、深了不稳,但质量上限略高;Pre-LN 稳、免 warmup,但残差流随深度膨胀、需 final LN
  • Xiong 2020:Post-LN 顶层梯度 $\Theta(d\sqrt{\ln d})$(与 $L$ 无关地偏大、跨层不均)→ 必须 warmup
  • Pre-LN 每层梯度 $O(d\sqrt{(\ln d)/L})$(随 $L$ 衰减、有界均衡)→ 大 LR 免 warmup

只说"Pre-LN 更稳",给不出顶层梯度偏大 / 随深度衰减这个定量论证。

Q12. 为什么 RMSNorm 去掉 re-centering 没事?re-scaling 和 re-centering 谁更重要?
  • 网络怕的是激活尺度失控($g^L$),尺度由 RMS / 模长主导,和均值关系不大
  • 消融:LN 里只保 re-scaling 性能几乎不掉,只保 re-centering 掉得多 → re-scaling 主导
  • 所以 RMSNorm 用更少运算拿住主要红利

只说"省了均值计算",答不出"re-scaling 是主要收益"这个论点依据。

Q13. 为什么 BatchNorm 不适合变长序列 / 小 batch / RL?
  • 变长:padding 污染统计 + 不同位置分布不同,"沿 batch 求每位置统计"语义差
  • 小 batch:统计估计噪声 $\propto1/m$,$m$ 小则归一化抖动,$m=1$ 直接失效
  • RL:数据非平稳 + 强相关 + train/eval 频繁切,running stats 与实际脱节

只笼统说"BN 不好用",讲不出三个场景各自的失效机理。

Q14. 推导 Kaiming 初始化的方差,为什么是 $2/n_\text{in}$?
  • 线性层 $\text{Var}(z)=n_\text{in}\text{Var}(W)\mathbb{E}[x^2]$(对零均值 $x$ 即 $\text{Var}(x)$),要前向守恒需 $n_\text{in}\text{Var}(W)=1$
  • ReLU 把负半轴清零:$\mathbb{E}[\text{ReLU}(z)^2]=\frac12\text{Var}(z)$,砍掉一半方差
  • 补因子 2:$\frac12 n_\text{in}\text{Var}(W)=1\Rightarrow\text{Var}(W)=\frac{2}{n_\text{in}}$

写不出 $\text{Var}(z)=n_\text{in}\text{Var}(W)\mathbb{E}[x^2]$,或不知道那个 2 来自 ReLU 砍半。

Q15. 残差为什么能破梯度消失?给出反向传播的式子。
  • $L$ 块串联:$\frac{\partial x_L}{\partial x_0}=\prod_l(I+\frac{\partial F_l}{\partial x})$
  • 展开含一个纯恒等项(再加各阶交叉项)→(典型情况下)梯度主要经恒等项无损传回,但不是对任意 $F$ 的严格保证(如 $F(x)=-x$ 会使该层贡献恰好抵消为 0,只是随机初始化+梯度下降下几乎不会发生)
  • 即使 $\partial F/\partial x\to0$,恒等项在典型情况下仍把梯度大部分无损传回浅层

只说"加了 skip",写不出雅可比连乘里那个恒等项为什么救梯度。

Q16. 残差缩放($1/\sqrt N$ / LayerScale / ReZero)解决什么?怎么做?
  • 解决:深残差网分支无节制灌入残差流 → 方差线性膨胀、初期不稳
  • $1/\sqrt N$:分支乘 $1/\sqrt N$ 使 $N$ 层累加方差仍 $O(1)$;LayerScale:可学 per-channel $\lambda$(init 极小);ReZero:可学标量 $\alpha$ init 0(起点精确恒等)
  • 统一直觉:让分支起点接近 0、网络从恒等起步,梯度良态

只记住名字,说不出"让残差分支起点≈恒等"这个共同机理。

Q17. GPT-2 把残差投影权重乘 $1/\sqrt{2N}$ 是干嘛?为什么是 $2N$ 不是 $N$?
  • 控制残差流方差:每次往残差流写入按 $1/\sqrt{2N}$ 缩放,使累加后方差仍 $O(1)$
  • $2N$:每个 transformer 层往残差流写两次(attn 输出投影 + FFN down 投影),$N$ 层共 $2N$ 次
  • 作用在 attn/FFN 的输出投影(残差投影)权重的 init 上

以为是每层一次($N$);或不知道作用在"残差投影"这两个特定矩阵上。

Q18. QK-Norm 是什么?解决什么问题?
  • 点积前对每个 head 的 $q,k$ 各做一次归一化(L2/RMS),再算 logits
  • 解决 attention logits 随尺度爆炸 → softmax 饱和 / entropy collapse / 训练发散(大模型尤甚)
  • 归一化后 $q,k$ 模长被钳住,logits 不爆;Gemma3 / Chameleon / ViT-22B 在用(Gemma2 当时用的是 soft-capping,Gemma3 才改用 QK-Norm)

只说"归一化 QK",讲不出它防的是 logits 爆炸 / softmax 饱和。

Q19. DeepNorm 怎么训到 1000 层?它和 Pre/Post-LN 什么关系?
  • 改良 Post-LN:$x_{l+1}=\text{LN}(\alpha x_l+\text{Sublayer}(x_l))$,$\alpha=(2N)^{1/4}\gt1$ 放大残差
  • 同时用增益 $\beta=(8N)^{-1/4}\lt1$ 缩小 FFN + attention 的 $W^V,W^O$ 这部分子层 init($W^Q,W^K$ 仍用标准 Xavier init),把每步模型更新量界住
  • up-scale 残差(接近 Pre-LN 稳定)+ down-scale init(更新有界)→ Post-LN 质量 + 稳定到 1000 层

把 DeepNorm 当成 Pre-LN;或只记 $\alpha$ 不记"还要缩小 init"。

Q20. GroupNorm / InstanceNorm 和 BN/LN 是什么关系?什么时候用 GN?
  • GN 把 channel 分 $G$ 组,每样本每组内归一化,不依赖 batch
  • $G=1$ 退化为 LayerNorm,$G=C$ 退化为 InstanceNorm(GN 桥接二者)
  • 用途:小 batch 视觉(检测 / 分割 batch=2~4,BN 崩、GN 稳)

不知道 GN 用 $G$ 桥接 LN 与 IN;或答不出小 batch 检测这个典型场景。

L3高级题

Q21. internal covariate shift 是 BatchNorm 有效的真正原因吗?
  • 不是(大概率)。这是原始论文的叙事,已被 Santurkar 2018 实证推翻
  • 证据一:BN 后注入噪声故意增大 ICS,训练几乎不受影响
  • 证据二:BN 真正让 loss / 梯度的 Lipschitz 变小(地形更平滑)→ 支持大 LR
  • SkipInit 进一步显示 BN 在残差网的作用是 init 时缩小分支、偏向恒等

还把 covariate shift 当公认原因;或不知道有实验直接证伪。

Q22. μP 是什么?为什么标准参数化下最优 LR 会随宽度漂移?
  • SP 下宽度变则各层激活 / 更新尺度错配,宽度 $n\to\infty$ 要么爆炸要么进 lazy/kernel 区
  • 于是最优 LR 随宽度变,小模型调的参不能直接用到大模型
  • μP 把 init 方差 / LR / 输出乘子按 fan_in 缩放,使特征更新在宽度上 $\Theta(1)$、最优 LR 宽度不变 → μTransfer(小宽度调、大宽度 zero-shot 迁移)

只知道"μP 能迁移超参",讲不出 SP 为何漂移 / μP 缩放了什么。

Q23. 怎么不用任何归一化层训练深残差网络?(Fixup / NFNets)
  • Fixup:分支末层 init 0(块起点恒等)+ 其他层乘 $L^{-1/(2m-2)}$ 下调 + 加可学标量偏置/乘子
  • NFNets:Scaled Weight Standardization + 解析缩放残差块 $x+\alpha F(x/\beta)$ + Adaptive Gradient Clipping
  • 共同点:把"控方差 + 大 batch 稳定"用 init / 显式手段补回,说明 norm 非必需

只说"调 init",给不出"末层置 0 + 深度下调"或 NFNets 三件套的具体做法。

Q24. DyT(Dynamic Tanh)是什么?归一化是训练的必要条件吗?
  • 观察:训练好的 LN 输入-输出曲线像被压扁的 $\tanh$(中间近线性、离群值饱和)
  • DyT:$\gamma\odot\tanh(\alpha x)+\beta$,可学标量 $\alpha$ 替"除以 std",去掉求均值/方差的 reduction
  • 含义:归一化理论上非必要(其作用可被 squashing / init / 显式方差控制替代),但 LN/RMSNorm 仍是稳妥生产默认

把 DyT 说成"已取代归一化"(过头);或讲不出它来自"LN≈tanh"这个观察。

Q25. 给你一个非常深的网络(几百到上千层),你怎么组合 init / 归一化 / 残差让它稳定训练?
  • 残差必须有(恒等梯度路),分支起点压向恒等:末层 init 0 或 LayerScale/ReZero、按深度乘 $1/\sqrt N$(GPT-2 的 $1/\sqrt{2N}$)
  • 归一化 Pre-LN/RMSNorm(免 warmup、稳)+ 别漏 final LN;要 Post-LN 质量则上 DeepNorm(放大残差 + 缩小 init,可达 1000 层)
  • init 按激活选 Xavier/Kaiming 做方差保持,深度感知下调;想免归一化走 Fixup/NFNets
  • 超参用 μP 在小宽度调好再迁移;attention 不稳加 QK-Norm;全程 fp32 reduction
  • 核心暗线:让网络从"接近恒等 + 方差守恒"的良态起点出发

只报单一技巧;或忽略 final LN / 残差缩放 / 深度感知 init 的组合拳与"恒等起步"这条主线。

§A 附录:sanity check

本 tutorial 的代码在 docs/tutorials/code/normalization.py 有最小可跑版本(纯 PyTorch、CPU 几秒、6 个 assert,覆盖 [a]–[f])。它应满足以下关键不变量:

  1. [a] LayerNorm 自实现 == nn.LayerNorm:用总体方差(unbiased=False,除以 $d$)、$\epsilon$ 放根号内,仿射后应与 PyTorch 在浮点误差内逐元素相等(atol≈1e-5)。
  2. [b] RMSNorm 自实现 == nn.RMSNorm,且 RMSNorm 对平移不变性与 LN 不同:给输入整体加常数 $c$,LayerNorm 输出几乎不变(它减均值 → re-centering 不变),而 RMSNorm 输出会变(它只 re-scale、不减均值)——这正是 §4 "RMSNorm 没有 re-centering" 的可执行验证。
  3. [c] BatchNorm train$\ne$eval:train 模式用 batch 统计(输出每特征近似零均值)并把 running mean 从 0 推离;切到 eval 用 running stats,对同一输入输出明显不同——验证 §2.2 的双路径。
  4. [d] Post-LN 把参数梯度堆在顶层(top-heavy),Pre-LN 则堆在底层(bottom-heavy):搭一摞 48 层同构残差块(末尾接一个 linear head——避免 loss 直接作用在 Post-LN 的归一化输出上产生"梯度被压成 0"的假象),一次 forward+backward,量每个块 Linear 权重梯度的顶/底比值(last/first)。Pre-LN $\approx0.40$——即底层梯度约为顶层的 $1/0.40=2.5\times$;用对称失衡度量 $\max(r,1/r)$ 看,这个偏斜幅度(2.5)其实和 Post-LN 的 2.35 相当、甚至略大,关键差异是偏斜方向相反(Pre-LN 偏底、Post-LN 堆顶)。这印证的是 §5.2 Xiong et al. 的渐进论断——随深度 $L$ 增长,Post-LN 顶层梯度保持 $\Theta(d\sqrt{\ln d})$ 不随 $L$ 衰减,Pre-LN 各层尺度则整体按 $1/\sqrt L$ 收缩,是渐进意义上更良态,而不是"这一次固定深度实验里比值接近 1"。用顶/底比值而非绝对梯度,因为它能部分消除 loss 选择 / 输出归一化的混淆(这是个隐蔽的实验设计坑)。
  5. [e] Kaiming 保二阶矩、Xavier-for-ReLU 衰减:单位二阶矩输入($\mathbb{E}[x^2]=1$)过 Linear+ReLU,量 post-ReLU 的二阶矩 $\mathbb{E}[y^2]$(喂给下一层的信号能量,也是 He 推导真正传播的量):Kaiming($\sqrt{2/n_\text{in}}$)后 $\mathbb{E}[y^2]\approx1$(守恒),Xavier-for-ReLU($\sqrt{1/n_\text{in}}$)后 $\approx0.5$(每层砍半 → 深了消失)——验证 §8.3 的因子 2。注意测的是 $\mathbb{E}[y^2]$ 而非 $\text{Var}(y)$:ReLU 使输出均值非零,故 $\text{Var}(y)=1-1/\pi\approx0.68$,而逐层守恒 / 传播的量是二阶矩 $\mathbb{E}[y^2]$。
  6. [f] GPT-2 残差缩放 $1/\sqrt{2N}$ 把残差流方差界住:模拟 $N$ 层 transformer、每层往残差流写两次(共 $2N$ 次)$O(1)$ 更新,不缩放则方差随写入次数线性增长,乘 $1/\sqrt{2N}$ 后方差有界——验证 §8.4。

下面是几段示意代码(CPU 可跑、Chinese 注释、与上面脚本逻辑一致)。

(a) LayerNorm + RMSNorm 从零实现,并与 PyTorch 对齐:

import torch
import torch.nn as nn

def layernorm_from_scratch(x, weight, bias, eps=1e-5):
    """沿最后一维归一化。x: [..., d]。总体方差(unbiased=False),eps 放根号内。"""
    mean = x.mean(dim=-1, keepdim=True)                       # [..., 1] 均值
    var  = x.var(dim=-1, unbiased=False, keepdim=True)        # [..., 1] 总体方差(/d),与 torch 一致
    return (x - mean) / torch.sqrt(var + eps) * weight + bias # 标准化 + 仿射

def rmsnorm_from_scratch(x, weight, eps=1e-6):
    """只按 RMS 缩放:不减均值、无 bias。x: [..., d]。"""
    ms = x.pow(2).mean(dim=-1, keepdim=True)                  # [..., 1] 均方
    return x / torch.sqrt(ms + eps) * weight                  # 除以 RMS,再逐通道缩放

d = 64
x = torch.randn(8, d)                                         # [B, d]
ln  = nn.LayerNorm(d, eps=1e-5)                              # 默认仿射 weight=1, bias=0
assert torch.allclose(layernorm_from_scratch(x, ln.weight, ln.bias), ln(x), atol=1e-5)

rms = nn.RMSNorm(d, eps=1e-6)                                # 需 torch>=2.4
assert torch.allclose(rmsnorm_from_scratch(x, rms.weight), rms(x), atol=1e-5)

# RMSNorm 对整体平移不不变,LayerNorm 不变:
c = 5.0
assert (ln(x + c) - ln(x)).abs().max() < 1e-4                              # LN re-centering 不变
assert (rmsnorm_from_scratch(x + c, rms.weight) - rmsnorm_from_scratch(x, rms.weight)).abs().max() > 1e-2

(b) 一摞深残差块,比较 Pre-LN 与 Post-LN 跨深度的梯度范数:

import torch
import torch.nn as nn

class ResidualStack(nn.Module):
    """深残差栈 + 末尾 linear head。Pre-LN: h=h+Linear(LN(h)); Post-LN: h=LN(h+Linear(h))。
       head 很关键:否则 Post-LN 输出已被 LN 归一化,loss=mean(out^2) 近似常数会把所有梯度压成 0(混淆)。"""
    def __init__(self, depth, d, pre_ln=True):
        super().__init__()
        self.pre_ln = pre_ln
        self.lns  = nn.ModuleList(nn.LayerNorm(d) for _ in range(depth))
        self.lins = nn.ModuleList(nn.Linear(d, d) for _ in range(depth))
        self.head = nn.Linear(d, d)                           # 末尾投影,去掉输出归一化的混淆

    def forward(self, h):                                     # h: [B, d]
        for ln, lin in zip(self.lns, self.lins):
            h = h + lin(ln(h)) if self.pre_ln else ln(h + lin(h))
        return self.head(h)

def block_grad_topheavy(depth, d, pre_ln):
    """一次 forward+backward,返回 last/first 块权重梯度范数之比(>1 = 梯度堆在顶层)。
       用相对比值而非绝对梯度范数,是为了降低对 loss 选择 / 输出归一化的敏感度;
       本脚本仅用单一 seed + 单一 quadratic loss 做了单次验证,"对 loss 选择稳健"
       本身未做多 loss / 多 seed 的穷举实证,如需严格支持该论断应补充统计
       (多 seed 均值±方差、至少一种非二次 loss)。"""
    torch.manual_seed(0)                                      # 两种放置用同一 init,公平对比
    stack = ResidualStack(depth, d, pre_ln=pre_ln)
    stack(torch.randn(16, d)).pow(2).mean().backward()       # 标量 loss
    gn = [lin.weight.grad.norm().item() for lin in stack.lins]
    return gn[-1] / gn[0]

r_pre  = block_grad_topheavy(48, 64, pre_ln=True)            # 期望 ≈0.40(bottom-heavy,底层梯度约2.5倍于顶层)
r_post = block_grad_topheavy(48, 64, pre_ln=False)          # 期望 ≈2.35(top-heavy,>1)
# Post-LN 顶/底比 >1:梯度堆在靠近输出的顶层 -> 必须 warmup。Pre-LN 则偏底层(bottom-heavy),
# 偏斜幅度与 Post-LN 相近、方向相反 -> 不是"均衡",而是渐进意义上更良态(随 L 增长按 1/sqrt(L) 收缩)。

(c) Kaiming 方差保持(vs 给 ReLU 误用 Xavier):

import torch
import torch.nn.functional as F

fan_in, fan_out, N = 512, 512, 4096
x = torch.randn(N, fan_in)                                   # E[x^2]=1 (单位二阶矩) [N, fan_in]
W_kaiming = torch.randn(fan_out, fan_in) * (2.0 / fan_in) ** 0.5   # He: std=sqrt(2/fan_in)
W_xavier  = torch.randn(fan_out, fan_in) * (1.0 / fan_in) ** 0.5   # 给 ReLU 误用 Xavier: std=sqrt(1/fan_in)
# 测 post-ReLU 二阶矩 E[y^2](喂下一层的信号能量、He 推导传播的量),不是 Var(y)
ms_kaiming = F.relu(x @ W_kaiming.t()).pow(2).mean()        # ReLU 砍半,2/fan_in 补回 -> E[y^2]≈1
ms_xavier  = F.relu(x @ W_xavier.t()).pow(2).mean()         # 没补因子 2 -> E[y^2]≈0.5,逐层砍半
# 期望 E[y^2]_kaiming≈1(守恒)、E[y^2]_xavier≈0.5(深了指数消失)。
# 注:Var(y)≈0.68(ReLU 使均值非零),逐层守恒的是二阶矩 E[y^2] 而非 Var。

运行 python docs/tutorials/code/normalization.py 的真实输出(CPU,纯 PyTorch,含 [a]–[f] 六个 assert 的汇总):

[a] LayerNorm from scratch vs nn.LayerNorm: max|Δ| = 2.38e-07  OK
[b] RMSNorm vs nn.RMSNorm: max|Δ| = 2.38e-07; mean-shift LN |Δ|=9.54e-07 (~0, re-centers) vs RMS |Δ|=3.05e+00 (>0, only re-scales)  OK
[c] BatchNorm train!=eval: max|Δ| = 8.37e+00; running_mean moved 0.701 from 0; train per-feature mean = 8.15e-08 (~0)  OK
[d] per-block weight-grad top/bottom ratio (last/first over 48 blocks): Pre-LN=0.40 (bottom-heavy)  Post-LN=2.35 (top-heavy, >1)  -> opposite skew, comparable magnitude; Post-LN piles gradient near the output, needs warmup  OK
[e] post-ReLU second moment E[y^2] (input E[x^2]=1): Kaiming = 1.000 (~1, preserved)  Xavier = 0.499 (~0.5, halves per layer)  OK
[f] residual-stream var growth over 50 layers (100 writes): unscaled ×101.1  vs  1/sqrt(2N)-scaled ×2.00  OK

all normalization / residual / init sanity checks passed ✓
OK

读数解释

  • [a]/[b] 自实现 LN/RMSNorm 与 PyTorch 一致(max$|\Delta|$=2.4e-7);平移测试里 LN 几乎不变(9.5e-7)、RMSNorm 明显变化(3.05),印证 §4 "RMSNorm 只 re-scale 不 re-center"。
  • [c] BatchNorm running_mean 从 0 被推到 0.70、train 模式每特征均值≈0,且 train≠eval,印证 §2.2 双路径。
  • [d] 块权重梯度的顶/底比(last/first):Pre-LN $0.40$(bottom-heavy,底层梯度约 2.5 倍于顶层),Post-LN $2.35$($\gt1$,梯度堆在顶层)——两者偏斜幅度相当、方向相反,印证 §5.2 Xiong et al. 的渐进论断(Post-LN 顶层梯度 $\Theta(d\sqrt{\ln d})$ 不随深度 $L$ 衰减 → 需 warmup;Pre-LN 各层尺度按 $1/\sqrt L$ 收缩,是渐进意义上更良态,而非"这一次固定深度比值接近 1")(加 head 去掉了输出归一化的混淆)。
  • [e] post-ReLU 二阶矩 Kaiming $\mathbb{E}[y^2]=1.00$(守恒)、Xavier-for-ReLU $=0.50$(每层砍半),印证 §8.3 的因子 2。
  • [f] 残差流方差不缩放 50 层(100 次写入)后 ×101(线性涨)、$1/\sqrt{2N}$ 缩放后 ×2.0(有界),印证 §8.4 GPT-2 "N 层、每层写两次残差流、共 2N 次" 的技巧。

📚 参考文献