阶段 1 · 最小学习机器

归一化层:把乱跑的数值
拉回同一起跑线

上一章《过拟合与正则化》让拟合和参数两股力拔河;参数压住了,数值却没人管。 第 1 层改一点点参数,第 5 层收到的数就挪了位置,每层都在追一个移动的靶子。 归一化做的事小得不可思议:把这层收到的数减去平均,再按散开的程度缩一缩。 但它让深层网络第一次真正能训起来。

1

数值尺度会一路失控

一个 20 层的网络,前向传播就是 20 次"乘一乘、加一加,再过一道激活函数"。 如果每一层都让数值的尺度放大一点点——哪怕只放大 10%—— 20 层之后就是 1.1²⁰ ≈ 6.7 倍。反过来,每层缩小一点点,就会一路缩到趋近于 0。

这会带来两个后果:数值跑到激活函数的饱和区(曲线两端变平、斜率接近 0 的区段), 梯度就传不回来;或者数值大得溢出,直接变成 NaN。 归一化就是每一层之后都做一次"重新校准": 它防住的是数值挤进饱和区这一路;初始化、学习率那些坑,得靠别的办法。

🎯 类比 像一个接力队。第 1 棒跑得快一点、慢一点,后面每一棒都必须重新调整自己的节奏, 整个队永远配合不好。
归一化做的事就是:不管第 1 棒怎么跑,交棒时都把棒子放在固定的位置上。 后面的人不用一直重学,只要专心练好自己的那一段。

2

把分布挪一挪,看它会撞上什么

左边是某一层收到的数,右边是同一批数过归一化之后的样子。 下面两个滑块:均值 μ 管这堆数的中心在哪,标准差 σ 管它们摊得多开。 (这两个词数学那节有一块专门讲,这里先按"中心"和"摊得多开"用。)

核心大图 · 拖动两个滑块,看右边怎么变

某一层的激活分布

过归一化之后

落在饱和区的比例
—
平均梯度缩放倍数
—

💡 归一化之后发生了什么

不管左边怎么挪,右边那张图都被掰成均值 0、标准差 1。 它只动整堆数的位置和宽窄,不动数之间的相对大小——归一化之后,谁比谁大、大多少,还和原来一样, 所以不同的输入不会变得分不出来。
它也没有让信息变多,只是让数值的尺度可预测。

3

BatchNorm 的三步

① 算统计量在这一批数据上,算出每个特征的均值 μ 和 标准差 σ。
② 标准化每个数减 μ 除以 σ,硬生生掰成「均值 0、标准差 1」。
③ 学一个缩放乘上可学习的 γ,加上可学习的 β。
这一步最关键——它让网络自己决定"要不要真的归一化"。

三步合起来就是一条公式——数学那节那张卡会把它写成式子,再拆成四步画给你看。

💡 为什么必须有 γ 和 β

如果只做前两步,就强行规定"每层输入必须均值 0、方差 1"。 万一某个特征"大一点才有用"呢?γ 和 β 给了网络反悔的权利。
极端情况下 γ = σ、β = μ,整个归一化被完全抵消——所以从表达能力看,加上它们不会让模型更差。 但网络通常不会把它们全抵消:抵消掉,归一化带来的训练稳定也就没了。 留着一个能反悔的旋钮,换来的正是训练的稳。

但第 ① 步藏着一个真实的麻烦:μ 和 σ 是从"这一批"数据估出来的,它本身就有误差。 批越小,这个估计越不准。

互动 · 批越小,统计量抖得越厉害

⚠️ batch = 1 时它会彻底失效 批里只有一条数据时,"这一批的均值"就是那条数据本身,标准差是 0。 除以 0 是算不出来的——所以所有实现都在分母上加一个很小的正数 ε(比如 1e-5)挡着。 但分子 x − μ 这时也正好是 0,0 除以 ε 还是 0,于是所有输出恒等于 β—— 信息被完全抹掉了,而且和输入再无关系。
这就是为什么 BatchNorm 做不了在线学习(数据一条一条来、来一条学一条)、也做不了 batch size = 1 的训练。 把下面的批大小拖到 1,看左边的直方图会铺满整个区间。

4

训练和推理,用的是两套数

训练时有"一批"数据,可以算 μ 和 σ。但推理的时候你可能只来一条数据, 算不出批次统计量。所以:

训练时 用当前这一批的 μ、σ
推理时 用训练期间累积的滑动平均 μ̂、σ̂   μ̂ ← 0.9·μ̂ + 0.1·μbatch

训练和推理时 BatchNorm 用的统计量不一样,PyTorch(这里用的深度学习框架)里用 model.train() 和 model.eval() 这两个开关切换。 忘了切,训练指标看着很好,一上线结果全乱——这是新手最常见的 bug 之一。

互动 · 滑动平均怎么追上一个一直在漂移的真实统计量

真实均值 μ
—
滑动平均 μ̂
—
估计误差
—

⚠️ 推理时错用 batch 统计量会怎样 同一个样本,单独送进去和放进一批里送进去,会得到完全不同的预测结果。
因为单独送进去时,它就变成了"这一批"的全部——归一化之后输出恒等于 β。
这就是为什么评测时必须 model.eval()。 而且这种 bug 在训练时完全看不出来,只在部署后暴露。

🎯 类比 像一个刚入职的员工。培训期间(训练)他跟着小组一起干活, 每次都用"小组的平均水平"来校准自己。
但正式上岗(推理)时他经常一个人面对客户—— 这时他得用培训期间攒下的经验平均值,而不是当场看周围同事在干什么。 没切换过来的人,会在独自面对客户时手足无措。

5

沿哪个方向算,决定它能不能用

两者的公式一模一样,唯一的区别是:在哪个方向上算均值和方差。 把数据想成一张表格——一批 6 张图、每张 8 个特征,就是 6 行 8 列: BatchNorm 竖着切,LayerNorm 横着切。

互动 · 切换看看归一化的是哪一条线

对比项BatchNormLayerNorm
归一化方向沿着批次方向:同一个特征,跨样本沿着特征方向:同一个样本,跨特征
依赖批次吗依赖。batch 太小会严重不稳,=1 完全失效完全不依赖
训练/推理一致不一致,需要滑动平均完全一致
变长序列很麻烦(一批句子里长短差很多,统计量会混在一起)天然支持
自回归生成(一个字一个字往外吐)batch 通常就是 1,没法用没问题
主要用在哪CNN(处理图像的网络,batch 大且尺寸固定)Transformer(处理句子的网络)、RNN(更早的序列网络)、大模型

💡 为什么 Transformer(句子网络)一律用 LayerNorm 三个原因叠在一起:
① 长度不一——一批句子里每句长短差很多,BatchNorm 的统计量会被长短句搅乱;
② batch 不能太大——大模型的 batch 受显存限制,常常只有几十甚至几条;
③ 推理时只是一条——生成文本是一个 token 一个往外吐,根本凑不齐一批。
LayerNorm 只看单条样本内部,天然没有这三个问题。

6

RMSNorm:省掉减均值

数学那节那张卡把归一化写成了两步:减均值(中心化)和除标准差(缩放)。 RMSNorm 要问的是:减均值这一步真的必要吗?

均方根(RMS)就是先把每个数平方、平均,再开方——它不管中心在哪,只看这堆数「能有多大」。

互动 · 同一组数据,两种算法的每一步

💡 为什么省这一步值钱

归一化在每一层、每一个 token(一小段文字)上都要算一遍。 少一次「把一堆数合成一个数」的计算,在 700 亿参数的大模型上就是实打实的速度提升。
而且实证结果是:效果几乎一样——按 RMSNorm 论文的说法,真正起作用的主要是缩放(re-scaling),减均值这一步本来就可以省。 LLaMA、Qwen、Mistral 系列全部用 RMSNorm,就是这个原因。

7

放在残差里面,还是外面

残差连接做一件事:让一层的输入绕过这一层、直接加到输出上—— 写成 x + F(x),F 就是这一层做的事。这条"绕行"的路,让梯度可以原样往回走。 归一化层放在这条绕行路的里面还是外面,决定了这条路是不是真的通畅。

残差连接:输入绕过这一层,直接加到输出

x 这一层 F + 绕过这一层,直接加过去 x + F(x)

互动 · 20 层之后,梯度还剩多少(真实的连乘)

最后一层收到的梯度
1.000
第 1 层收到的梯度
—

对比项Post-Norm(原版)Pre-Norm(现代)
写法x ← LN( x + F(x) )x ← x + F( LN(x) )
残差通路被归一化挡住,梯度必须穿过去 完全干净,一路直通到底
需要 warmup 吗非常需要,否则容易炸(损失突然变成 NaN、训练崩掉;warmup:训练开头几百步,把学习率从很小慢慢调大)没那么敏感
谁在用原版 Transformer、BERT GPT 系列、LLaMA、几乎所有现代大模型(LLM)

容易混淆的一点:GPT-2 从这一版起改用了 Pre-Norm(归一化挪到子层之前;子层是 Transformer 里的一次注意力或一次前馈,「Block」就是「一个子层 + 残差 + 归一化」的一整块), 同时还在整个堆叠的最后额外加了一个 LayerNorm。那是输出层的归一化,不是 Block 内部的 Post-Norm——两件事不要混(下一章《初始化与训练稳定性》会从方差的角度再对一遍)。

💡 下一章会从另一个角度再看一遍它

下一章 《初始化与训练稳定性》会从方差的角度再看一遍同一个问题,两边的结论一致: Pre-Norm 让残差通路上没有东西挡住梯度,所以 ∂y/∂x = 1 这个恒等项能原封不动地传下去。
上面表格里那个 warmup,就是因为 Post-Norm 让梯度更难走,训练开头才需要把学习率慢慢加上去。

M

数学 · 四步,把数字排整齐

前面说过「归一化就是把数值减去均值、再除以标准差」。这句话只有十几个字, 但它到底在干什么,一张图就能看完——下面四步走完,这一章的公式你就全看懂了。

动画 · 一团数字,四步之后变整齐(灰色大点是上一步在哪)

卡上的 μ、σ 跟着第 2 节那两个滑块变;γ、β 跟着下面动画的那两个滑块变。

🎯 用「排队拍合影」理解这四步 一群小朋友高矮不一,站得也歪。摄影师做四件事:
① 让所有人站到同一条线上(减掉平均位置)→ ② 从镜头里看他们一样高(除掉个子差异)→
③ 摄影师自己决定要不要放大(乘 γ)→ ④ 自己决定往左还是往右挪一点(加 β)。
① 和 ② 是「整理」,③ 和 ④ 是「网络自己说了算」—— 这正是为什么归一化不会把网络变笨:它随时可以把整理过的效果抵消掉。

🎬 自己验一遍

把动画的四步点完,再去第 2 节拖那两个滑块。
第 2 节那个「标准差 σ」滑块管的是某一层收到的数摊得多开;这里的第 ② 步,就是把那个 σ 除掉。 拖大它,第 2 节右边那张图仍然被掰回均值 0、标准差 1。

📐 看不明白 μ 和 σ?只有三个词的事

上面整节都在用这两个词。如果你本来是懂的,跳过这一块。 如果卡在这儿,下面三句话够用了。

均值 μ 把所有数加起来,除以个数。
就是「这堆数的中心在哪」——图上那条橙色虚线。
标准差 σ 先看每个数离中心多远,把这些距离平方、平均,再开方。
就是「这堆数摊得有多开」——图上那个橙色箭头有多长。
为什么除以 σ,宽度就变成 1? 因为 σ 本身就是「平均偏离多少」。
除以它,等于把「平均偏离」这把尺子定义成 1—— 以后不管谁来量,都用同一把尺子。
8

所有方法,按方向排开

前面几节讲的都是 BatchNorm 和 LayerNorm。这一节把常见的归一化方法排开—— 它们的分歧大多出在同一件事上:均值方差是沿着哪个方向算的。

方法归一化什么特点
BatchNorm 2015 同一特征,跨样本 让深层 CNN 第一次真正能训起来。是归一化这个方向的开山之作
LayerNorm 2016 同样本,跨特征 和 batch 无关,适合序列。成了 Transformer 的标配
InstanceNorm单样本单通道内(通道:图片的一层特征图) 风格迁移(把一张照片画成另一张的样子)里常用,会抹掉每张图自己的对比度这类整体信息
GroupNorm单样本,把通道分成若干组分别归一化 不依赖 batch,小 batch 场景的救星。扩散模型的 UNet(一种图像生成网络)大量使用
RMSNorm只除均方根,不减均值 更快、更省,效果接近。LLaMA / Qwen / Mistral 都用
WeightNorm对权重而不是激活做归一化 早期方法,和这里讲的(对激活做归一化)不是一路
QK-Norm对注意力里的 Q、K 分别归一化(注意力:让每个词决定该多看哪些别的词;Q、K 是每个词发出的「问题」和「标签」) 防止注意力分数(logits:还没压成概率的分数)爆炸,训练超大模型时能提高稳定性
DeepNorm放大残差分支的比例 让 1000 层 Transformer 也能稳定训练
9

这份校准什么时候会失灵

归一化是深度学习里少有的、几乎只有好处没有坏处的东西。但「几乎没有」不等于没有—— 它有几条边界,而其中最新的一条是 2025 年才出现的。

代价说明
BatchNorm 离不开 batch 小 batch 不稳、batch=1 失效、变长序列麻烦、在线学习用不了、训练推理必须区分—— 五条限制全来自同一个设计选择
归一化在推理时也要算 LayerNorm / RMSNorm 对每个 token(一小段文字)都要做一次「把一堆数合成一个数」的计算, 在长序列生成里是实打实的开销
RMSNorm 在部分任务上略差 省掉均值中心化是有代价的,只是大多数任务上感觉不到
γ、β 不能省 它们参数很少,但去掉会损失表达力—— 网络需要保留"拒绝归一化"的权利
它不是万能的 它防住的是数值挤进饱和区这一路。初始化太离谱、学习率设错—— 这些问题它救不了
💡 怎么选:一张速查表

CNN 图像分类(batch 大且定长)→ BatchNorm
Transformer / LLM → RMSNorm(或 LayerNorm),放在子层之前(Pre-Norm)
RNN / 序列模型 → LayerNorm
batch 很小 → GroupNorm 或 LayerNorm
扩散模型 → GroupNorm(UNet 里随处可见)

2025 年出现的两条,都指向同一个方向

⚖️ Pre-Norm 更稳,但 Post-Norm 更好 上面速查表说 Transformer / LLM 用 Pre-Norm,那是工程默认。研究上还有另一半: Pre-Norm 更稳的原因(残差通路上什么都没有)也正是它效果略差的原因—— 那条恒等通路太干净了,正则化反而变弱。第一次自己搭,照速查表来; 2025 年的 HybridNorm(NeurIPS 2025)是想两边都要:让 Post-Norm 的效果配上 Pre-Norm 的稳定性。
🌿 也许根本不需要归一化 CVPR 2025 有一篇叫《Transformers without Normalization》, 提出一个逐元素的 DyT(x) = tanh(α·x), 直接换掉整个归一化层——没有均值、没有方差、也不用把一堆数合成一个数。
它给出的解释是:归一化层顺手做到的那件事(把极端值压回去), tanh 本来就会做。

这两条都还新,别当成定论。但它们说明一件事: 「归一化是必需的」这句话,至少已经不是共识了。

所以,它不成立的地方在哪

它不成立的地方什么时候真的会痛怎么办
BatchNorm 的原始解释是错的(它说效果来自「内部协变量偏移」:每层收到的数的分布,随着前面层的参数更新一直在变) 你在做技术决策或写文章,引用的还是那个被引用了上千次的因果解释 换成「让损失面变平滑、允许更大的学习率」——2018 年的对照实验把协变量偏移人为注入回去,BatchNorm 依然有效,所以那个解释靠不住
「越稳」不等于「越好」 你在追极限效果,而选 Pre-Norm 只是因为「大家都用它」 知道自己换掉了什么:Post-Norm 的正则化更强、效果通常更好,代价是要小心地做 warmup。HybridNorm 是 2025 年给的一个折中
归一化层可能不是必需的 你在做推理优化,而归一化每次都要把一堆数合成一个数,正好卡在长序列生成的每一步上 可以试试 DyT 这类逐元素替代。但它是 2025 年的结果,先在小规模上验证,别直接上生产
BatchNorm 离不开 batch 小 batch、变长序列、在线学习、或者推理时本来就是一条 换成 LayerNorm / GroupNorm / RMSNorm。这不是 bug,是同一个设计选择的必然后果
它救不了别的毛病 你的模型不收敛,而你以为「有归一化了应该没问题」 它只防住数值挤进饱和区这一路;初始化和学习率的问题,它管不了。先去看《初始化与训练稳定性》和《超参怎么选》

最常被问的两个问题,结论先放这里:BatchNorm 的减法和 RMSNorm 省掉的那次减法不是一回事——一个跨样本,一个是同样本跨特征;第一次自己选,先看数据是不是变长序列、batch 小不小,剩下的照上面速查表来。

既然 RMSNorm 省掉减均值效果也差不多,那 BatchNorm 的减法是不是也没用?

不是一回事。BatchNorm 减的是跨样本的均值(那是它依赖 batch 的根源), RMSNorm 省掉的是同样本内跨特征的均值。前者是负担,后者基本是白送的。

那我现在该用哪个?

先看两件事:你的数据是不是变长的序列(是 → 直接 LayerNorm/RMSNorm); batch 小不小(小到统计量开始抖,就换掉 BatchNorm)。都不是的话,上面那张速查表够用。

10

小结

这一章看上去只是一个除法。但它和「正则化」用的是同一个思路: 不是禁止网络去做某件事,而是让它做那件事变得很贵。

它对应哪条线 ⑦ 拧得动——归一化把每层收到的数值按回可用区间,防止它们挤进激活函数的饱和区——那是梯度消失的一大来源;但初始化太离谱、学习率设错,它救不了。 它同时站在 ① 表达力 vs 泛化上:归一化是一条「软」约束——不是禁止网络做什么,只是让某些数值状态更难出现,γ、β 还留了反悔的权利
一句话 归一化的做法,本质上是在给网络加一条「每层收到的数值要处在可用区间」的偏好,同时又用 γ 和 β 把随时反悔的权利留给了网络自己。
它牺牲了什么 牺牲了计算和自由度(回扣暗线 B):每个 token(一小段文字)、每一层都要多做一次「把一堆数合成一个数」的计算; BatchNorm 还额外牺牲了「离开 batch 也能活」——小 batch 不稳、batch=1 直接失效、训练和推理必须分成两套。
🎬 自己验一遍

回到第 2 节那两张直方图。把「标准差 σ」滑块拖到最右边 4.5—— 左边那堆数越摊越平,「落在饱和区的比例」从默认的 50% 涨到 60% 左右; 右边那张图却始终被掰回均值 0、标准差 1。

然后回到第 3 节,把「批大小 B」拖到 1:这一次连归一化都救不了,直方图会铺满整个区间。
两个瞬间合起来就是这张本质卡:归一化给的是「尺度可控」这个软偏好,而不是「永远正确」这个硬保证。

它在六条暗线里站在哪

暗线这一章的回答
A 信息流动 形状完全不变:(B, T, d) 进、(B, T, d) 出,元素个数一个都没变 (B、T、d 就是「几条样本、每条多长、每个位置几个特征」三个方向)。 变的只是每个数的尺度。
这也是这一章每张图都在问的那个问题:同一批数,你沿着哪个方向算均值和方差? BatchNorm 沿样本方向,LayerNorm 沿特征方向——公式一模一样,方向不同
B 什么被牺牲了 计算 + 自由度。每个 token、每一层多做一次「把一堆数合成一个数」的计算; BatchNorm 还牺牲了「与 batch 无关」的能力——小 batch 不稳、batch=1 失效、 训练/推理不一致、变长序列麻烦、逐字生成时也没法用,五条限制全来自同一个设计选择
C 参数账本 参数少得可以忽略:LayerNorm 在每个归一化点只有 2 个长度为 d 的向量(γ、β),RMSNorm 只有 1 个(γ)。 在一个 d=4096、32 层的模型里,大约是 2 × 4096 × 32 ≈ 26 万个参数——对 70 亿来说不到 0.004%。
但计算量不小:每个 token 一次求均值 + 一次求方差(RMSNorm 只求均方根)—— 都是「读进来、算一算、写回去」,所以这笔账的重点不在算了多少次,而在搬了多少数据
D 跑在什么上 卡在读写上。归一化做的事可以概括成「读进来 → 算一个总数 → 写回去」, 读写的数据量比算术量大得多,所以它几乎总在等内存。
这也解释了 RMSNorm 为什么值钱:省掉「减均值」那一步,省的是读写而不是计算—— 少读一次就是真的快。完整的账在 《硬件与算力账本》
E 它假设了什么 假设「尺度是一个可以独立于内容被拿掉的量」——也就是「数值大一点小一点只是尺度问题,语义没变」。 BatchNorm 还额外假设了「同一批里的样本可以互相代表」(batch 内独立同分布)。 后一个假设在变长序列和逐字生成里直接破了——这就是 LayerNorm 存在的理由
F 违背了哪个直觉 直觉是「归一化只是为了数值好看、算得快」。 真正的答案是它改变了损失曲面的形状——让梯度更可预测、允许更大的学习率。

带走的那张图 · 同一张表格,两把刀

BatchNorm:竖着切(同一列) 同一个特征,跨样本 LayerNorm:横着切(同一行) 同一个样本,跨特征

同一张表格,两把刀:竖着切是 BatchNorm,横着切是 LayerNorm。

🎯 前后钩子

它接住了上一章的什么:过拟合与正则化(《过拟合与正则化》) 在损失上加了一项惩罚;这一章加的是另一种约束——两者都是「不禁止,只让它变难」。

它给下一章留了什么:归一化只解决尺度。真正让几十上百层能一起训起来的另一半是 残差连接 + 初始化尺度——那就是 《初始化与训练稳定性》的主题, 也是 Transformer 能推到几千层规模的前提。

一句话带走归一化

归一化 = 把每层收到的数值减去均值、除以标准差,让每层都站在同一起跑线。 它只动位置和宽窄,不动数之间的相对大小;加 γ、β 是为了保留"拒绝归一化"的权利。
BatchNorm 跨样本统计(CNN 用),LayerNorm 跨特征统计(Transformer 用)—— 公式完全一样,只是方向不同。 RMSNorm 再砍掉减均值那一步,更快且效果接近,是大模型的默认选择。
放在残差外面(Post-Norm)会挡住梯度,放在里面(Pre-Norm)则一路通畅—— 所以绝大多数现代 LLM 都用 Pre-Norm。

11

拓展阅读

上面讲的都是「够用」的版本。想往下挖,这里有三个入口—— 它们不是必修内容,是给想再往前走一步的读者准备的。

📄 这一章的说法从哪来

💻 工业界怎么写

左边是上面讲过的逻辑,右边是它在 PyTorch 里的样子——每一行都对着。

∑ 更严格的形式

正文为了讲清楚,把两个地方简化了。真要动手实现时,这两条才是完整的。

第 1 条 · 训练时统计量是「边走边记」的,不是重算的

正文第 4 节说「推理时用滑动平均」,这条就是那个滑动平均的更新式。 m 是动量(PyTorch 默认 0.1):每次只用一小部分当前 batch 的统计量去修正长期记忆。
这也解释了为什么 batch 很小时 BatchNorm 会坏:μbatch 本身就抖,而这个式子会让抖动 一节一节存进长期记忆里,推理时取出来的滑动平均值也跟着抖。

第 2 条 · 同一个公式,两种走法

这两行长得几乎一样——差别只在「μ 和 σ² 从哪来」。
训练时从当前这批数据里算(所以和 batch 绑死);推理时从记下来的长期值里取(所以能脱离 batch)。
BatchNorm 全部的麻烦,都来自这两行不是同一个式子。 LayerNorm / RMSNorm 没这个问题——它们两行完全一样。