🎯 课程主题
层归一化(Layer Normalization)——Transformer 中稳定训练的关键组件。
📝 核心知识点
1. 归一化的必要性
- 概念说明:归一化使数据量纲一致,加速模型收敛。
- 关键细节:
- 不做归一化时,参数空间中 Loss 曲面弯曲复杂,梯度下降路径曲折
- 归一化后,数据在同一起跑线,更容易找到最小 Loss 值
- 更快找到最优参数 $W$
2. 层归一化 vs 批归一化(BN)
- 概念说明:LN 和 BN 公式相同,区别在于归一化的对象不同。
- 关键细节:
- 批归一化(BN):针对同一批次中不同样本的同一神经元做归一化
- 例如:样本1、样本2、样本3 在神经元 $Y_1$ 上的输出做归一化
- 常用于图像任务(CNN)
- 层归一化(LN):针对同一样本在同一层的所有神经元做归一化
- 例如:样本1 在某一层的输出 $Y_1, Y_2, Y_3, \ldots, Y_N$ 做归一化
- 常用于序列任务(RNN、Transformer)
- 批归一化(BN):针对同一批次中不同样本的同一神经元做归一化
3. 层归一化的适用场景
- 概念说明:LN 适用于可变长序列任务。
- 关键细节:
- Transformer 处理可变长序列,BN 在变长序列上受限
- LN 对每个样本独立计算,不受序列长度影响
- 图像任务用 BN,序列任务用 LN
4. 可学习参数
- 概念说明:归一化公式中有两个可学习参数。
- 关键细节:
- $\gamma$(缩放因子)和 $\beta$(偏置)
- 通过反向传播更新
- 用于调整归一化的最终结果
🧮 核心公式与推导
层归一化公式:
$$\text{LN}(x) = \gamma \cdot \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} + \beta$$
其中:
- $x$:同一样本在同一层的所有神经元输出 ${Y_1, Y_2, \ldots, Y_N}$
- $\mu = \frac{1}{N}\sum_{i=1}^{N} Y_i$:均值
- $\sigma^2 = \frac{1}{N}\sum_{i=1}^{N}(Y_i - \mu)^2$:方差
- $\gamma$:可学习的缩放因子
- $\beta$:可学习的偏置
- $\epsilon$:防止除零的小常数
BN 与 LN 对比:
| 特性 | 批归一化(BN) | 层归一化(LN) |
|---|---|---|
| 归一化对象 | 同批次不同样本的同一神经元 | 同一样本同一层所有神经元 |
| 适用场景 | 图像(CNN) | 序列(RNN、Transformer) |
| 变长序列 | 受限 | 支持 |
| 公式 | 相同 | 相同 |
物理意义:将每层输出归一化到均值为 0、方差为 1 的分布,再通过 $\gamma, \beta$ 恢复表达能力。
🏗️ 模型架构与数据流向
编码器单层结构:Input → Multi-Head Attention → Add & Norm → FFN → Add & Norm → Output
💻 代码实战
import torch
import torch.nn as nn
class LayerNorm(nn.Module):
"""层归一化实现"""
def __init__(self, d_model, eps=1e-6):
"""
d_model: 归一化的特征维度D
eps: 防止除零
"""
super().__init__()
self.gamma = nn.Parameter(torch.ones(d_model)) # 缩放因子, 初始为1
self.beta = nn.Parameter(torch.zeros(d_model)) # 偏置, 初始为0
self.eps = eps
def forward(self, x):
"""
x: [batch, L, d_model]
return: [batch, L, d_model] 归一化后的输出
"""
# 对最后一个维度(d_model)做归一化
mean = x.mean(dim=-1, keepdim=True) # [batch, L, 1]
var = x.var(dim=-1, keepdim=True, unbiased=False) # [batch, L, 1]
# 归一化
x_norm = (x - mean) / torch.sqrt(var + self.eps)
# 缩放和偏移
return self.gamma * x_norm + self.beta
# 示例
d_model = 512
ln = LayerNorm(d_model)
x = torch.randn(2, 4, d_model) # [batch, L, D]
output = ln(x)
print(output.shape) # torch.Size([2, 4, 512])
print(output.mean(dim=-1)) # 接近0
print(output.std(dim=-1)) # 接近1(再乘gamma)
# PyTorch内置实现 (推荐使用)
ln_builtin = nn.LayerNorm(d_model)
output = ln_builtin(x)
⚠️ 常见问题与避坑指南
- LN 是对同一样本的所有特征做归一化,不是跨样本
- $\gamma$ 和 $\beta$ 是可学习参数,通过反向传播更新
- 序列任务用 LN,图像任务用 BN,不要混用
- $\epsilon$ 防止方差为 0 时除零错误
💡 个人总结与延伸
层归一化是 Transformer 稳定训练的关键,通过对每层特征做归一化,加速收敛并缓解梯度问题。与 BN 相比,LN 不依赖批次大小,适合变长序列。现代大模型中,LN 有 Pre-Norm(先归一化再计算)和 Post-Norm(先计算再归一化)两种变体,GPT 等模型常用 Pre-Norm 以提升深层训练稳定性。此外还有 RMSNorm 等简化变体被广泛使用。