Batch Norm 原论文
Ioffe & Szegedy, 2015
观察不同归一化方法如何将数据标准化到不同范围。
💡 颜色: 蓝色=负值, 白色=0, 红色=正值
一句话定义:归一化是将数据调整到标准范围的技术,使神经网络训练更稳定、更快收敛。不同的归一化方法在不同维度上进行标准化。
想象全国高考:
神经网络中:
在深度网络中,每一层的输入分布会随着前面层参数的更新而改变。这就像:
归一化的作用:
在 batch 维度上计算均值和方差:
训练 vs 推理:
在 特征维度上计算均值和方差:
去掉均值中心化,只用 RMS(均方根):
| 方法 | 归一化维度 | 适用场景 | 依赖 Batch |
|---|---|---|---|
| BatchNorm | N, H, W | CNN | ✅ 是 |
| LayerNorm | D (或 L, D) | Transformer, RNN | ❌ 否 |
| RMSNorm | D | 现代 LLM | ❌ 否 |
| GroupNorm | 组内 C | 小 batch CNN | ❌ 否 |
| InstanceNorm | H, W | 风格迁移 | ❌ 否 |
import torchimport torch.nn as nn
# ===== Batch Normalization =====# 适用于 CNN: (N, C, H, W)bn = nn.BatchNorm2d(num_features=64) # 64 个通道x_cnn = torch.randn(32, 64, 28, 28) # batch=32, 64通道, 28x28out_bn = bn(x_cnn)print(f"BN 输出形状: {out_bn.shape}") # [32, 64, 28, 28]
# ===== Layer Normalization =====# 适用于 Transformer: (N, L, D)ln = nn.LayerNorm(normalized_shape=512) # 在最后一个维度归一化x_transformer = torch.randn(32, 100, 512) # batch=32, 100个token, 512维out_ln = ln(x_transformer)print(f"LN 输出形状: {out_ln.shape}") # [32, 100, 512]
# ===== RMS Normalization (手动实现) =====class RMSNorm(nn.Module): def __init__(self, dim: int, eps: float = 1e-6): super().__init__() self.eps = eps self.weight = nn.Parameter(torch.ones(dim)) # 可学习 scale
def forward(self, x: torch.Tensor) -> torch.Tensor: # x: (batch, seq_len, dim) rms = torch.sqrt(torch.mean(x ** 2, dim=-1, keepdim=True) + self.eps) return x / rms * self.weight
rms_norm = RMSNorm(dim=512)out_rms = rms_norm(x_transformer)print(f"RMSNorm 输出形状: {out_rms.shape}") # [32, 100, 512]
# ===== 验证归一化效果 =====print(f"\n归一化前 - 均值: {x_transformer.mean():.4f}, 标准差: {x_transformer.std():.4f}")print(f"LN 后 - 均值: {out_ln.mean():.4f}, 标准差: {out_ln.std():.4f}")import numpy as np
def layer_norm(x, gamma, beta, eps=1e-5): """ Layer Normalization x: (batch, seq_len, dim) gamma, beta: (dim,) 可学习参数 """ # 在最后一个维度计算统计量 mean = np.mean(x, axis=-1, keepdims=True) var = np.var(x, axis=-1, keepdims=True)
# 归一化 x_norm = (x - mean) / np.sqrt(var + eps)
# 缩放和平移 return gamma * x_norm + beta
def rms_norm(x, gamma, eps=1e-6): """ RMS Normalization x: (batch, seq_len, dim) gamma: (dim,) 可学习参数 """ rms = np.sqrt(np.mean(x ** 2, axis=-1, keepdims=True) + eps) return (x / rms) * gamma
# 测试x = np.random.randn(2, 10, 64) # batch=2, 10个token, 64维gamma = np.ones(64)beta = np.zeros(64)
out_ln = layer_norm(x, gamma, beta)out_rms = rms_norm(x, gamma)
print(f"输入统计 - 均值: {x.mean():.4f}, 标准差: {x.std():.4f}")print(f"LN 输出 - 均值: {out_ln.mean():.4f}, 标准差: {out_ln.std():.4f}")print(f"RMSNorm 输出 - 均值: {out_rms.mean():.4f}")