批量规范化(Batch Normalization, 简称 BN)是由 Sergey Ioffe 和 Christian Szegedy 在 2015 年提出的一种深度学习技术,用于解决深层神经网络中的梯度消失或梯度爆炸问题,并加速模型的训练过程。BN 是深度学习领域中的一个重要创新,它在许多网络架构(如 ResNet、GoogLeNet 等)中被广泛使用。
BN 的核心思想是:在每一层网络的输入数据中,使每个特征在一个小批量(mini-batch)数据中具有零均值和单位方差(标准化)。这样可以减小不同层之间的输入分布变化(Internal Covariate Shift),从而让网络更容易训练。
对于小批量中的每个特征,BN 的标准化过程如下:
计算 mini-batch 的均值和方差:
对于第 j j j 个特征,给定 mini-batch 数据 { x 1 , x 2 , . . . , x m } \{x_1, x_2, ..., x_m\} {x1,x2,...,xm},
μ B = 1 m ∑ i = 1 m x i (mini-batch 均值) \mu_B = \frac{1}{m} \sum_{i=1}^m x_i \quad \text{(mini-batch 均值)} μB=m1i=1∑mxi(mini-batch 均值)
σ B 2 = 1 m ∑ i = 1 m ( x i − μ B ) 2 (mini-batch 方差) \sigma_B^2 = \frac{1}{m} \sum_{i=1}^m (x_i - \mu_B)^2 \quad \text{(mini-batch 方差)} σB2=m1i=1∑m(xi−μB)2(mini-batch 方差)
标准化:
使用均值和方差对每个特征进行标准化,使其均值为 0,方差为 1:
x ^ i = x i − μ B σ B 2 + ϵ \hat{x}_i = \frac{x_i - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}} x^i=σB2+ϵxi−μB
其中, ϵ \epsilon ϵ 是一个很小的正值,防止分母为 0。
引入可学习参数:
为了保留网络的表达能力,BN 引入了两个可学习参数 γ \gamma γ 和 β \beta β:
y i = γ x ^ i + β y_i = \gamma \hat{x}_i + \beta yi=γx^i+β
其中:
这一步确保 BN 不会限制网络的表达能力。
最终输出:
y i = γ x i − μ B σ B 2 + ϵ + β y_i = \gamma \frac{x_i - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}} + \beta yi=γσB2+ϵxi−μB+β
减轻 Internal Covariate Shift 问题:
加速训练收敛:
缓解梯度消失和梯度爆炸:
减少对参数初始化的敏感性:
一定程度上具有正则化效果:
BN 通常插入到网络中的每一层卷积层或全连接层的激活函数之前。例如:
典型顺序:
BN 在 训练阶段 和 测试阶段 的行为略有不同:
训练阶段:
测试阶段:
PyTorch 中,BatchNorm
自动根据模型的 train()
和 eval()
模式切换训练和测试阶段。
在 PyTorch 中,可以使用 torch.nn.BatchNorm1d
、torch.nn.BatchNorm2d
和 torch.nn.BatchNorm3d
分别处理全连接网络、二维卷积网络和三维卷积网络。
import torch
import torch.nn as nn
# 定义一个简单的全连接网络
class FCNet(nn.Module):
def __init__(self):
super(FCNet, self).__init__()
self.fc1 = nn.Linear(784, 256)
self.bn1 = nn.BatchNorm1d(256)
self.fc2 = nn.Linear(256, 128)
self.bn2 = nn.BatchNorm1d(128)
self.fc3 = nn.Linear(128, 10)
def forward(self, x):
x = self.fc1(x)
x = self.bn1(x) # 批量规范化
x = torch.relu(x)
x = self.fc2(x)
x = self.bn2(x) # 批量规范化
x = torch.relu(x)
x = self.fc3(x)
return x
# 创建模型实例
model = FCNet()
print(model)
import torch
import torch.nn as nn
# 定义一个简单的卷积神经网络
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1)
self.bn1 = nn.BatchNorm2d(32) # 2D 批量规范化
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
self.bn2 = nn.BatchNorm2d(64) # 2D 批量规范化
self.fc1 = nn.Linear(64 * 8 * 8, 128)
self.bn3 = nn.BatchNorm1d(128) # 1D 批量规范化
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = self.conv1(x)
x = self.bn1(x) # 批量规范化
x = torch.relu(x)
x = self.conv2(x)
x = self.bn2(x) # 批量规范化
x = torch.relu(x)
x = torch.flatten(x, 1) # 展平
x = self.fc1(x)
x = self.bn3(x) # 批量规范化
x = torch.relu(x)
x = self.fc2(x)
return x
# 创建模型实例
model = CNN()
print(model)
批量规范化(Batch Normalization)是深度学习中一种重要的技术,通过对每一层的输入进行标准化,显著提升了深度神经网络的训练效率和性能。BN 已成为现代深度学习模型中不可或缺的组件,其引入的简洁性和高效性推动了更深层网络的发展。