2015年,Sergey Ioffe和Christian Szegedy在ICML上发表了一篇论文,提出了Batch Normalization。这篇论文后来成为深度学习领域被引用最多的工作之一。但很少有人注意到,这项最初为计算机视觉设计的技术,在自然语言处理领域却"水土不服"——Transformer选择了完全不同的Layer Normalization。
更令人惊讶的是,2025年CVPR的一篇论文发现,Transformer中的归一化层产生的输入-输出映射竟然类似于tanh函数,以至于用简单的 $\tanh(\alpha x)$ 就能替代复杂的归一化操作。这个发现动摇了"归一化层是神经网络必不可少的组件"这一共识。
为什么神经网络需要归一化?为什么Transformer选择了LayerNorm而不是BatchNorm?为什么LLaMA进一步简化为RMSNorm?这些问题背后,是深度学习十年来的技术博弈与认知演进。
一个被误解的概念:Internal Covariate Shift
归一化层的诞生,源于一个被称为Internal Covariate Shift(内部协变量偏移)的问题。
在机器学习中,“协变量偏移”(Covariate Shift)指的是训练数据和测试数据的输入分布不同。Ioffe和Szegedy将这个概念延伸到神经网络内部:当网络训练时,每一层的参数更新都会改变其后所有层的输入分布。
graph TD
subgraph ICS["Internal Covariate Shift 问题示意"]
A["输入数据 x"] --> B["第1层<br/>参数 θ₁"]
B --> C["激活 a₁<br/>分布 P₁"]
C --> D["第2层<br/>参数 θ₂"]
D --> E["激活 a₂<br/>分布 P₂"]
E --> F["第3层<br/>参数 θ₃"]
F --> G["输出"]
H["训练过程中<br/>θ₁, θ₂, θ₃ 更新"] --> I["P₁, P₂ 分布变化"]
I --> J["后续层需要<br/>不断适应新分布"]
style I fill:#ffcccc
style J fill:#ffcccc
end
用数学语言描述:假设网络第 $l$ 层的输入为 $x^{(l)}$,随着前面层参数 $\theta^{(1)}, \theta^{(2)}, ..., \theta^{(l-1)}$ 的更新,$x^{(l)}$ 的分布也在不断变化。这意味着第 $l$ 层需要不断适应新的输入分布,如同追逐一个移动的目标。
这个问题的直观后果是:深层网络训练困难,需要精心设计学习率和初始化策略。BatchNorm的解决方案是强制将每层的输入标准化为零均值、单位方差的分布,从而"固定"输入分布。
然而,学术界对Internal Covariate Shift的解释一直存在争议。2018年,Santurkar等人在NeurIPS上发表的论文"How Does Batch Normalization Help Optimization?“指出,BatchNorm有效的原因可能并不是因为它减少了Internal Covariate Shift,而是因为它使优化景观更加平滑,梯度更可预测。
这个争议揭示了深度学习研究的一个特点:一个技术可能在实践中非常有效,但其背后的理论解释可能并不完全准确。
BatchNorm:计算机视觉的基石
Batch Normalization的核心思想是:在 mini-batch 的维度上计算均值和方差,然后对每个特征进行标准化。
graph LR
subgraph BN["BatchNorm 计算维度"]
direction TB
A["样本1"] --> A1["特征1 | 特征2 | 特征3"]
B["样本2"] --> B1["特征1 | 特征2 | 特征3"]
C["样本3"] --> C1["特征1 | 特征2 | 特征3"]
D["样本4"] --> D1["特征1 | 特征2 | 特征3"]
A1 --- E["↓ 沿样本维度计算统计量 ↓"]
B1 --- E
C1 --- E
D1 --- E
E --> F["μ₁, σ₁² | μ₂, σ₂² | μ₃, σ₃²"]
style E fill:#e6f3ff
style F fill:#cce5ff
end
假设一个 mini-batch 有 $m$ 个样本,每个样本有 $d$ 个特征。对于第 $k$ 个特征,BatchNorm计算:
$$\mu_k = \frac{1}{m} \sum_{i=1}^{m} x_{i,k}$$$$\sigma_k^2 = \frac{1}{m} \sum_{i=1}^{m} (x_{i,k} - \mu_k)^2$$$$\hat{x}_{i,k} = \frac{x_{i,k} - \mu_k}{\sqrt{\sigma_k^2 + \epsilon}}$$然后通过可学习的参数进行缩放和平移:
$$y_{i,k} = \gamma_k \hat{x}_{i,k} + \beta_k$$这里 $\gamma$ 和 $\beta$ 是可学习参数,$\epsilon$ 是防止除零的小常数。
BatchNorm的一个关键特性是:训练时使用当前 mini-batch 的统计量,推理时使用训练过程中累积的全局统计量(移动平均)。这种设计在计算机视觉中工作得很好,因为:
- 图像数据通常是固定大小的,batch中的每个样本维度相同
- 视觉任务中batch size通常较大(如32、64、128),统计量估计准确
- 卷积层后使用BatchNorm已成为标准做法
但在自然语言处理领域,BatchNorm遇到了根本性的困难。
LayerNorm:Transformer的必然选择
当Transformer在2017年提出时,它选择了Layer Normalization而不是Batch Normalization。这个选择并非偶然。
LayerNorm由Jimmy Lei Ba、Jamie Ryan Kiros和Geoffrey Hinton在2016年提出。与BatchNorm跨样本计算统计量不同,LayerNorm在每个样本内部计算统计量:
graph LR
subgraph LN["LayerNorm 计算维度"]
direction TB
A["样本1"] --> A1["特征1 | 特征2 | 特征3"]
B["样本2"] --> B1["特征1 | 特征2 | 特征3"]
C["样本3"] --> C1["特征1 | 特征2 | 特征3"]
A1 --> E["→ 沿特征维度计算 →"]
A1 --> F["μ₁, σ₁²"]
B1 --> G["→ 沿特征维度计算 →"]
B1 --> H["μ₂, σ₂²"]
C1 --> I["→ 沿特征维度计算 →"]
C1 --> J["μ₃, σ₃²"]
style F fill:#cce5ff
style H fill:#cce5ff
style J fill:#cce5ff
end
$$\mu_i = \frac{1}{d} \sum_{j=1}^{d} x_{i,j}$$$$\sigma_i^2 = \frac{1}{d} \sum_{j=1}^{d} (x_{i,j} - \mu_i)^2$$$$y_{i,j} = \gamma_j \frac{x_{i,j} - \mu_i}{\sqrt{\sigma_i^2 + \epsilon}} + \beta_j$$注意关键区别:BatchNorm对每个特征跨样本归一化,LayerNorm对每个样本跨特征归一化。
这个看似简单的变化,解决了NLP任务中的三个核心问题:
变长序列问题。NLP中的句子长度各不相同。如果使用BatchNorm,不同batch中参与计算的token数量不同,归一化常数不稳定,导致训练不稳定。LayerNorm对每个token独立计算,完全不受序列长度影响。
小批量问题。大语言模型训练时,由于显存限制,batch size往往较小(如1-4)。BatchNorm在小batch下统计量估计不准确,性能急剧下降。LayerNorm不依赖batch size,即使batch size为1也能正常工作。
推理一致性。BatchNorm在训练和推理时行为不同(训练用batch统计量,推理用全局统计量),这种不一致可能导致性能下降。LayerNorm在训练和推理时计算方式完全相同,没有这个问题。
import torch
import torch.nn as nn
class LayerNorm(nn.Module):
def __init__(self, dim, eps=1e-5):
super().__init__()
self.eps = eps
self.weight = nn.Parameter(torch.ones(dim))
self.bias = nn.Parameter(torch.zeros(dim))
def forward(self, x):
# x shape: (batch_size, seq_len, dim)
mean = x.mean(dim=-1, keepdim=True)
var = x.var(dim=-1, keepdim=True, unbiased=False)
x_norm = (x - mean) / torch.sqrt(var + self.eps)
return x_norm * self.weight + self.bias
Pre-Norm还是Post-Norm:位置之争
原始Transformer(Post-Norm)将LayerNorm放在残差连接之后:
$$\text{output} = \text{LayerNorm}(x + \text{Sublayer}(x))$$但2020年,Xiong等人在论文"On Layer Normalization in the Transformer Architecture"中发现,这种设计会导致训练不稳定。他们用均值场理论(Mean Field Theory)证明:在初始化时,Post-LN Transformer靠近输出层的参数梯度期望值很大,使用大学习率会导致训练不稳定,因此需要学习率warm-up阶段。
解决方案是将LayerNorm放在残差连接之前(Pre-Norm):
$$\text{output} = x + \text{Sublayer}(\text{LayerNorm}(x))$$graph TD
subgraph PostNorm["Post-Norm (原始Transformer)"]
A1["输入 x"] --> B1["子层操作<br/>Attention/FFN"]
A1 --> C1["残差连接 (+)"]
B1 --> C1
C1 --> D1["LayerNorm"]
D1 --> E1["输出"]
end
subgraph PreNorm["Pre-Norm (现代Transformer)"]
A2["输入 x"] --> B2["LayerNorm"]
B2 --> C2["子层操作<br/>Attention/FFN"]
A2 --> D2["残差连接 (+)"]
C2 --> D2
D2 --> E2["输出"]
end
PostNorm -.->|"梯度需穿过LayerNorm"| F["梯度流动受阻碍"]
PreNorm -.->|"梯度直接传递"| G["梯度流动顺畅"]
Pre-Norm的优势可以用梯度流动来解释。在Post-Norm中,梯度需要穿过LayerNorm才能传递到前面的层,而LayerNorm会重新缩放梯度。在Pre-Norm中,梯度可以通过残差连接无损地向前传递,因为残差路径上没有任何操作。
graph LR
subgraph GradFlow["梯度流动对比"]
direction TB
A["Post-Norm 梯度"] --> B["← 梯度穿过LayerNorm被缩放"]
B --> C["← 梯度穿过子层"]
C --> D["← 梯度穿过残差"]
D --> E["← 梯度到达前面层<br/>可能消失或爆炸"]
F["Pre-Norm 梯度"] --> G["← 梯度穿过LayerNorm被缩放"]
G --> H["← 梯度穿过子层"]
I["← 梯度通过残差直接传递"] --> J["无损传递到前面层"]
F --> I
style E fill:#ffcccc
style J fill:#ccffcc
end
这个发现解释了为什么现代大模型(GPT-2之后、LLaMA等)都采用Pre-Norm架构:它允许直接使用大学习率训练,不需要warm-up阶段,训练更加稳定。
当然,Pre-Norm也有代价。有研究发现Pre-Norm可能导致"表征崩塌”——后面层的表征可能变得相似,降低了模型的表示能力。但在实践中,训练稳定性的收益往往大于这个代价。
RMSNorm:更简单的选择
2020年,Zhang和Sennrich在论文"Root Mean Square Layer Normalization"中提出了RMSNorm,这是一个对LayerNorm的简化。
他们的核心洞察是:LayerNorm有两个功能——重新居中(re-centering,通过减去均值)和重新缩放(re-scaling,通过除以标准差)。re-centering真的必要吗?
实验表明,只需要re-scaling就够了。RMSNorm的计算公式:
$$\text{RMSNorm}(x) = \gamma \odot \frac{x}{\sqrt{\frac{1}{d}\sum_{i=1}^{d}x_i^2 + \epsilon}}$$graph TD
subgraph Compare["LayerNorm vs RMSNorm 计算对比"]
A["输入 x"] --> B["LayerNorm"]
A --> C["RMSNorm"]
B --> D["1. 计算均值 μ"]
D --> E["2. 计算方差 σ²"]
E --> F["3. 标准化: (x-μ)/σ"]
F --> G["4. 缩放平移: γ·x̂ + β"]
C --> H["1. 计算RMS"]
H --> I["2. 缩放: x/RMS"]
I --> J["3. 乘权重: γ·x/RMS"]
style D fill:#ffe6e6
style G fill:#ffe6e6
style H fill:#e6ffe6
style J fill:#e6ffe6
end
与LayerNorm相比,RMSNorm省略了均值计算,只计算均方根(RMS)进行缩放。
这个简化带来了两个好处:
计算效率。不需要计算均值,减少了一次reduction操作。在大模型训练中,这个节省是显著的。论文报告RMSNorm比LayerNorm快7%-64%。
更稳定的训练。有研究表明,在残差连接的场景中,LayerNorm的re-centering操作可能导致信息丢失,而RMSNorm避免了这个问题。
LLaMA系列模型选择了RMSNorm,这个选择背后是效率和稳定性的权衡。在千亿参数规模的模型中,每一个计算的简化都意味着显著的资源节省。
import torch
import torch.nn as nn
class RMSNorm(nn.Module):
def __init__(self, dim, eps=1e-6):
super().__init__()
self.eps = eps
self.weight = nn.Parameter(torch.ones(dim))
def forward(self, x):
# 计算均方根
rms = torch.rsqrt(x.pow(2).mean(dim=-1, keepdim=True) + self.eps)
return x * rms * self.weight
归一化方法的完整版图
理解归一化方法的关键是搞清楚它们在哪个维度上计算统计量。考虑一个形状为 $(N, C, H, W)$ 的四维张量(图像)或 $(N, L, D)$ 的三维张量(文本):
graph TD
subgraph Methods["归一化方法分类"]
A["归一化方法"] --> B["BatchNorm (BN)"]
A --> C["LayerNorm (LN)"]
A --> D["InstanceNorm (IN)"]
A --> E["GroupNorm (GN)"]
A --> F["RMSNorm"]
B --> B1["跨样本计算<br/>适合大批量视觉任务"]
C --> C1["跨特征计算<br/>适合NLP/序列任务"]
D --> D1["跨空间计算<br/>适合风格迁移"]
E --> E1["分组计算<br/>适合小批量视觉任务"]
F --> F1["仅缩放<br/>现代LLM首选"]
style B fill:#e6f3ff
style C fill:#e6ffe6
style F fill:#fff3e6
end
Batch Normalization (BN):在 $N$ 维度上计算,对每个通道独立归一化。适合大批量的视觉任务,但对小batch敏感,训练/推理行为不一致。
Layer Normalization (LN):在 $C \times H \times W$ 或 $D$ 维度上计算,对每个样本独立归一化。适合NLP任务,不受batch size影响,训练/推理一致。
Instance Normalization (IN):在 $H \times W$ 维度上计算,对每个样本的每个通道独立归一化。主要用于风格迁移任务。
Group Normalization (GN):将通道分组,在每组内的 $H \times W$ 上计算。Kaiming He和Yuxin Wu在2018年提出,解决了BN在小batch下的问题,在目标检测、分割等任务中表现良好。
RMS Normalization:LayerNorm的简化版本,不计算均值,只计算均方根进行缩放。被LLaMA、Mistral等现代LLM广泛采用。
graph LR
subgraph Dimensions["各方法归一化维度示意 (图像 tensor: N×C×H×W)"]
direction TB
subgraph BN["BatchNorm"]
BN1["沿 N 轴<br/>每个通道独立"]
end
subgraph LN["LayerNorm"]
LN1["沿 C×H×W 轴<br/>每个样本独立"]
end
subgraph IN["InstanceNorm"]
IN1["沿 H×W 轴<br/>每个样本每个通道独立"]
end
subgraph GN["GroupNorm"]
GN1["分组后沿 H×W 轴<br/>每组独立"]
end
end
graph TD
subgraph Timeline["归一化技术发展时间线"]
A["2015<br/>BatchNorm<br/>Ioffe & Szegedy"] --> B["2016<br/>LayerNorm<br/>Ba, Kiros & Hinton"]
B --> C["2017<br/>InstanceNorm用于风格迁移"]
C --> D["2018<br/>GroupNorm<br/>Wu & He"]
D --> E["2019<br/>RMSNorm<br/>Zhang & Sennrich"]
E --> F["2020<br/>Pre-Norm理论<br/>Xiong et al."]
F --> G["2023<br/>LLaMA采用RMSNorm"]
G --> H["2025<br/>Dynamic Tanh<br/>Zhu et al."]
end
Dynamic Tanh:归一化层真的必要吗?
2025年CVPR的一篇论文"Transformers without Normalization"提出了一个惊人的发现:Transformer中的归一化层产生的输入-输出映射类似于tanh函数。
研究者观察到,LayerNorm的输出可以近似表示为:
$$\text{LayerNorm}(x) \approx \tanh(\alpha x)$$graph TD
subgraph DyT["LayerNorm vs Dynamic Tanh"]
A["输入 x"] --> B["LayerNorm"]
A --> C["Dynamic Tanh"]
B --> D["计算均值 μ"]
D --> E["计算方差 σ²"]
E --> F["标准化 (x-μ)/σ"]
F --> G["缩放平移 γx̂ + β"]
G --> H["输出 ~ tanh(αx)"]
C --> I["DyT(x) = tanh(αx)"]
I --> J["输出"]
style H fill:#ffe6e6
style J fill:#e6ffe6
end
基于这个观察,他们提出了Dynamic Tanh (DyT):
$$\text{DyT}(x) = \tanh(\alpha x)$$其中 $\alpha$ 是一个可学习的参数。这个简单的操作可以直接替代LayerNorm或RMSNorm,在图像分类、语言模型、自监督学习等多种任务上取得了与归一化层相当甚至更好的性能。
这个发现挑战了"归一化层是神经网络必不可少的组件"这一共识。它表明,归一化层的核心作用可能只是提供一个S形的非线性变换,限制激活值的范围,防止极端值的出现。
当然,DyT目前还处于研究阶段,大规模工业应用的可行性还需要更多验证。但这个发现无疑加深了我们对归一化层本质的理解。
如何选择归一化方法
在实际应用中,选择哪种归一化方法需要考虑多个因素:
graph TD
subgraph Decision["归一化方法选择决策树"]
A["任务类型?"] --> B["视觉任务"]
A --> C["NLP/序列任务"]
B --> D["Batch Size?"]
D -->|"大 (32+)"| E["BatchNorm"]
D -->|"小 (<32)"| F["GroupNorm"]
C --> G["模型规模?"]
G -->|"超大模型"| H["RMSNorm + Pre-Norm"]
G -->|"中小模型"| I["LayerNorm + Pre-Norm"]
style E fill:#e6f3ff
style F fill:#fff3e6
style H fill:#e6ffe6
style I fill:#ffe6f3
end
任务类型:计算机视觉任务通常选择BatchNorm(大批量)或GroupNorm(小批量);NLP和序列建模任务选择LayerNorm或RMSNorm。
Batch Size:大批量(32+)可用BatchNorm;小批量用LayerNorm/RMSNorm/GroupNorm。
序列长度:变长序列必须用LayerNorm/RMSNorm,BatchNorm无法处理。
模型规模:超大模型倾向于RMSNorm,计算效率更高。
训练稳定性:Pre-Norm架构比Post-Norm更稳定,适合深层网络。
一个实用的经验法则:如果你的任务是NLP或使用Transformer架构,默认选择Pre-Norm + RMSNorm;如果任务是计算机视觉且batch size较大,选择BatchNorm;如果batch size较小,选择GroupNorm。
从技术演进看深度学习
归一化层的十年演进,折射出深度学习领域的技术发展规律。
BatchNorm的提出源于对Internal Covariate Shift的理论分析,但后来的研究表明,它有效的真正原因可能更加复杂。LayerNorm的选择最初更多是工程直觉,后来才有了Pre-Norm优于Post-Norm的理论解释。RMSNorm的简化更是直接质疑了"标准做法"的必要性。而Dynamic Tanh的发现则彻底挑战了归一化层的必要性。
graph LR
subgraph Evolution["认知演进"]
A["2015<br/>BatchNorm解决<br/>Internal Covariate Shift"] --> B["2018<br/>BatchNorm真正原因<br/>是平滑优化景观"]
B --> C["2020<br/>Pre-Norm比Post-Norm<br/>梯度更稳定"]
C --> D["2020<br/>RMSNorm质疑<br/>re-centering必要性"]
D --> E["2025<br/>Dynamic Tanh质疑<br/>归一化层必要性"]
end
这个过程说明:深度学习技术往往先在实践中证明有效,理论解释随后跟上,有时甚至会发现最初的解释并不准确。这要求实践者既要理解技术原理,又要保持开放心态,随时准备接受新的发现。
对于今天的模型开发者来说,理解归一化层的原理和权衡,比记住"应该用哪个"更重要。因为正确的选择永远取决于具体场景,而技术的最佳实践也在不断演进。
参考文献
- Ioffe, S., & Szegedy, C. (2015). Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift. ICML 2015.
- Ba, J. L., Kiros, J. R., & Hinton, G. E. (2016). Layer Normalization. arXiv:1607.06450.
- Xiong, R., et al. (2020). On Layer Normalization in the Transformer Architecture. ICML 2020.
- Zhang, B., & Sennrich, R. (2019). Root Mean Square Layer Normalization. NeurIPS 2019.
- Wu, Y., & He, K. (2018). Group Normalization. ECCV 2018.
- Santurkar, S., et al. (2018). How Does Batch Normalization Help Optimization? NeurIPS 2018.
- Zhu, J., et al. (2025). Transformers without Normalization. CVPR 2025.
- Vaswani, A., et al. (2017). Attention Is All You Need. NeurIPS 2017.
- Radford, A., et al. (2019). Language Models are Unsupervised Multitask Learners. OpenAI Technical Report.
- Touvron, H., et al. (2023). LLaMA: Open and Efficient Foundation Language Models. arXiv:2302.13971.