共计 1863 个字符,预计需要花费 5 分钟才能阅读完成。
背景痛点:为什么需要归一化?
刚开始接触深度学习时,我发现在训练深层网络时经常会遇到两个头疼的问题:

- 梯度消失:深层网络的梯度在反向传播时越来越小,导致底层参数几乎不更新
- 梯度爆炸:某些层的梯度突然变得极大,使得训练过程完全崩溃
这两个问题的根源在于网络各层的 输入分布不一致。想象一下,如果每一层接收到的数据分布都在剧烈变化,那么网络就需要不断调整来适应这种变化,导致训练极其不稳定。
BN 的核心思想
批量归一化 (Batch Normalization) 的解决方案很巧妙:在每一层的输入前,先对数据进行标准化处理。具体来说,就是对当前 batch 的数据做:
$$\hat{x} = \frac{x – \mu}{\sqrt{\sigma^2 + \epsilon}}$$
其中 $\mu$ 和 $\sigma$ 分别是当前 batch 的均值和方差,$\epsilon$ 是个很小的数防止除零。然后还会加入可学习的缩放和平移参数:
$$y = \gamma \hat{x} + \beta$$
这样既保持了数据的规范性,又保留了网络的表达能力。
PyTorch 实战示例
下面我们来看如何在 PyTorch 中使用 BN 层。以一个简单的 CNN 在 CIFAR-10 上的分类任务为例:
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
# 定义带 BN 的 CNN
class CNNWithBN(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(3, 32, 3, padding=1)
self.bn1 = nn.BatchNorm2d(32) # BN 层
self.conv2 = nn.Conv2d(32, 64, 3, padding=1)
self.bn2 = nn.BatchNorm2d(64) # BN 层
self.fc = nn.Linear(64*8*8, 10)
def forward(self, x):
x = F.relu(self.bn1(self.conv1(x))) # 在激活前应用 BN
x = F.max_pool2d(x, 2)
x = F.relu(self.bn2(self.conv2(x)))
x = F.max_pool2d(x, 2)
x = torch.flatten(x, 1)
x = self.fc(x)
return x
# 训练循环
model = CNNWithBN()
optimizer = optim.Adam(model.parameters(), lr=0.001)
criterion = nn.CrossEntropyLoss()
for epoch in range(10):
for inputs, labels in train_loader:
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
效果对比
我在 CIFAR-10 上对比了使用 BN 前后的训练曲线:
- 无 BN 的网络 :训练初期 loss 波动很大,需要很小的学习率(如 0.0001) 才能稳定
- 带 BN 的网络:可以使用更大的学习率(0.001),且 loss 下降更平稳,最终准确率提高了约 8%
常见陷阱及解决方案
- batch size 太小:BN 依赖 batch 统计量,batch size 小于 16 时效果会下降
-
解决方案:使用 Group Normalization 作为替代
-
学习率设置不当:BN 允许使用更大的学习率,但太大仍会导致震荡
-
建议:初始学习率设为 0.001,然后根据验证集表现调整
-
测试阶段忘记切换模式:
model.eval() # 测试时使用全局统计量而非 batch 统计量
进阶思考
虽然 BN 在 CNN 中效果显著,但在 RNN 中却不太适用,因为:
– RNN 的序列长度可变,batch 统计量不稳定
– 测试时可能遇到比训练时更长的序列
这时可以考虑使用 Layer Normalization,它对每个样本单独计算统计量,不受 batch 影响。
延伸阅读
- 原始论文:Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift
- PyTorch 官方文档中的 BN 实现细节
- Group Normalization 论文,解决小 batch size 问题
希望这篇笔记能帮你理解 BN 的核心思想并顺利应用到自己的项目中!
