共计 1613 个字符,预计需要花费 5 分钟才能阅读完成。
问题背景
在深度学习训练中,过拟合是指模型在训练集上表现优异,但在测试集上性能显著下降的现象。传统解决方案包括:
- 增加训练数据
- 使用 L1/L2 权重正则化
- 采用 Dropout 层
- 早停法 (Early Stopping)
但这些方法各有局限:数据增强成本高,正则化需要精细调参,Dropout 会延长训练时间。Batch Normalization(BN) 则从数据分布的角度提供了新的解决思路。
BN 核心原理
数学形式化
BN 层的计算可分为两个阶段:
-
标准化:对每个特征维度独立计算 mini-batch 的均值和方差
$$\mu_B = \frac{1}{m}\sum_{i=1}^{m}x_i$$
$$\sigma_B^2 = \frac{1}{m}\sum_{i=1}^{m}(x_i-\mu_B)^2$$
$$\hat{x_i} = \frac{x_i – \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}$$ -
缩放平移:引入可学习参数 $\gamma$ 和 $\beta$
$$y_i = \gamma \hat{x_i} + \beta$$
内部协变量偏移 (ICS)
ICS 是指神经网络中间层输入分布随训练发生变化的现像。这会导致:
- 后续层需要不断适应新的输入分布
- 梯度更新效率降低
- 更容易陷入局部最优
BN 通过强制每层的输入保持稳定分布,有效缓解了 ICS 问题。
正则化机制
随机性来源
BN 的正则化效果主要来自:
- mini-batch 统计量的随机波动
- 这种噪声类似于 Dropout,但作用机制不同
与传统正则化对比
| 方法 | 作用层面 | 实现方式 |
|---|---|---|
| L2 正则化 | 权重 | 惩罚大权重值 |
| Dropout | 激活值 | 随机屏蔽神经元 |
| BN | 数据分布 | 规范化激活统计量 |
代码验证
import torch
import torch.nn as nn
# 设置随机种子保证可复现
torch.manual_seed(42)
# 带 BN 的简单 CNN
class CNNWithBN(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(3, 16, 3)
self.bn1 = nn.BatchNorm2d(16)
self.conv2 = nn.Conv2d(16, 32, 3)
self.bn2 = nn.BatchNorm2d(32)
self.fc = nn.Linear(32*6*6, 10)
def forward(self, x):
x = F.relu(self.bn1(self.conv1(x)))
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)
return self.fc(x)
# 训练循环对比
for epoch in range(epochs):
model.train()
for x, y in train_loader:
# 常规训练步骤
...
# 验证阶段
model.eval()
with torch.no_grad():
# 验证集评估
...

图:使用 BN(蓝色) 与不使用 BN(红色) 的训练验证准确率对比
生产建议
激活函数搭配
- ReLU:最常用组合,梯度稳定
- LeakyReLU:注意负半轴斜率设置 (通常 0.01)
- SELU:自带归一化特性,有时可省去 BN
小批量处理
当 batch size < 16 时:
- 考虑 LayerNorm(适合 RNN/Transformer)
- GroupNorm(将通道分组计算统计量)
- 实例归一化 (风格迁移常用)
延伸思考
推理阶段为什么用移动平均
- 保证输出确定性
- 避免依赖 batch 统计量
- 计算效率考虑
BN 能否替代其他正则化
实践中发现:
- BN 可以与 Dropout 互补使用
- 深层网络仍需权重衰减 (L2)
- 数据量极小时 BN 效果会下降
总结
BN 通过规范化激活分布,从三个层面提升模型泛化能力:
- 缓解内部协变量偏移
- 允许使用更大学习率
- 提供适度的正则化效果
实际项目中,建议在卷积 / 全连接层后立即添加 BN,并配合合理的初始化方法。
正文完
发表至: 深度学习
近一天内
