深度学习入门:BN批量归一化的原理与实战应用

1次阅读
没有评论

共计 1863 个字符,预计需要花费 5 分钟才能阅读完成。

image.webp

背景痛点:为什么需要归一化?

刚开始接触深度学习时,我发现在训练深层网络时经常会遇到两个头疼的问题:

深度学习入门:BN 批量归一化的原理与实战应用

  • 梯度消失:深层网络的梯度在反向传播时越来越小,导致底层参数几乎不更新
  • 梯度爆炸:某些层的梯度突然变得极大,使得训练过程完全崩溃

这两个问题的根源在于网络各层的 输入分布不一致。想象一下,如果每一层接收到的数据分布都在剧烈变化,那么网络就需要不断调整来适应这种变化,导致训练极其不稳定。

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%

常见陷阱及解决方案

  1. batch size 太小:BN 依赖 batch 统计量,batch size 小于 16 时效果会下降
  2. 解决方案:使用 Group Normalization 作为替代

  3. 学习率设置不当:BN 允许使用更大的学习率,但太大仍会导致震荡

  4. 建议:初始学习率设为 0.001,然后根据验证集表现调整

  5. 测试阶段忘记切换模式

    model.eval()  # 测试时使用全局统计量而非 batch 统计量

进阶思考

虽然 BN 在 CNN 中效果显著,但在 RNN 中却不太适用,因为:
– RNN 的序列长度可变,batch 统计量不稳定
– 测试时可能遇到比训练时更长的序列

这时可以考虑使用 Layer Normalization,它对每个样本单独计算统计量,不受 batch 影响。

延伸阅读

  1. 原始论文:Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift
  2. PyTorch 官方文档中的 BN 实现细节
  3. Group Normalization 论文,解决小 batch size 问题

希望这篇笔记能帮你理解 BN 的核心思想并顺利应用到自己的项目中!

正文完
 0
评论(没有评论)