文章目录
- 1、简介
- 2、批量归一化公式
- 3、BN 层的接口
- 4、代码示例
- 5、小结
🍃作者介绍:双非本科大三网络工程专业在读,阿里云专家博主,专注于Java领域学习,擅长web应用开发、数据结构和算法,初步涉猎人工智能和前端开发。
🦅个人主页:@逐梦苍穹
📕所属专栏:人工智能
🌻gitee地址:xzl的人工智能代码仓库
✈ 您的一键三连,是我创作的最大动力🌹
1、简介
在神经网络的搭建过程中,Batch Normalization (批量归一化)是经常使用一个网络层,其主要的作用是控制数据的分布,加快网络的收敛。
我们知道,神经网络的学习其实在学习数据的分布,随着网络的深度增加、网络复杂度增加,一般流经网络的数据都是一个 mini batch,每个 mini batch 之间的数据分布变化非常剧烈,这就使得网络参数频繁的进行大的调整以适应流经网络的不同分布的数据,给模型训练带来非常大的不稳定性,使得模型难以收敛。
如果我们对每一个 mini batch 的数据进行标准化之后,数据分布就变得稳定,参数的梯度变化也变得稳定,有助于加快模型的收敛。
2、批量归一化公式
f ( x ) = λ ⋅ x − E ( x ) Var ( x ) + ϵ + β f(x) = \lambda \cdot \frac{x - \mathbb{E}(x)}{\sqrt{\text{Var}(x) + \epsilon}} + \beta f(x)=λ⋅Var(x)+ϵx−E(x)+β
- λ 和 β 是可学习的参数,它相当于对标准化后的值做了一个线性变换,λ 为系数,β 为偏置;
- ϵ \epsilon ϵ 通常指为 1e-5,避免分母为 0;
- E(x) 表示变量的均值;
- Var(x) 表示变量的方差;
BN层是指“批量归一化层”(Batch Normalization Layer),它是在神经网络中用来进行批量归一化操作的层。
批量归一化层的主要目的是通过归一化每一层的输入,使得每一层的输入分布更加稳定,从而加速训练过程并提高模型性能。
数据在经过 BN 层之后,无论数据以前的分布是什么,都会被归一化成均值为 β,标准差为 γ 的分布。
注意:
- BN 层不会改变输入数据的维度,只改变输入数据的的分布
- 在实际使用过程中,BN 常常和卷积神经网络结合使用,卷积层的输出结果后接 BN 层。
3、BN 层的接口
torch.nn.BatchNorm2d(num_features, eps=1e-05, momentum=0.1, affine=True)
- 由于每次使用的 mini batch 的数据集,所以 BN 使用移动加权平均来近似计算均值和方差,而 momentum 参数则调节移动加权平均值的计算;
- affine = False 表示 γ=1,β=0,反之,则表示 γ 和 β 要进行学习;
- BatchNorm2d 适用于输入的数据为 4D,输入数据的形状 [N,C,H,W]
其中:N 表示批次,C 代表通道数,H 代表高度,W 代表宽度
由于每次输入到网络中的时小批量的样本,我们使用指数加权平均来近似表示整体的样本的均值和方法,其更新公式如下:
running_mean = momentum * running_mean + (1.0 – momentum) * batch_mean
running_var = momentum * running_var + (1.0 – momentum) * batch_var
上面的式子中,batch_mean 和 batch_var 表示当前批次的均值和方差。而 running_mean 和 running_var 是近似的整体的均值和方差的表示。当我们进行评估时,可以使用该均值和方差对输入数据进行归一化。‘
4、代码示例
(代码即注释)
# -*- coding: utf-8 -*-
# @Author: CSDN@逐梦苍穹
# @Time: 2024/7/29 17:11import torch # 导入PyTorch库
import torch.nn as nn # 导入PyTorch中的神经网络模块
import torch.optim as optim # 导入PyTorch中的优化器模块
import torch.nn.functional as F # 导入PyTorch中的函数模块# 设置随机种子以确保结果可重复
torch.manual_seed(0)# 定义一个简单的卷积神经网络模型,使用批量归一化
class SimpleCNN(nn.Module):def __init__(self):super(SimpleCNN, self).__init__()# TODO 定义卷积层1,输入通道数为3,输出通道数为16,卷积核大小为3x3,步长为1,填充为1self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1) self.bn1 = nn.BatchNorm2d(16) # 对卷积层1进行批量归一化# TODO 定义卷积层2,输入通道数为16,输出通道数为32,卷积核大小为3x3,步长为1,填充为1self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1) self.bn2 = nn.BatchNorm2d(32) # 对卷积层2进行批量归一化self.fc1 = nn.Linear(32 * 8 * 8, 10) # 定义全连接层,输入尺寸为32*8*8,输出尺寸为10def forward(self, x):x = F.relu(self.bn1(self.conv1(x))) # 卷积层1后进行批量归一化,然后通过ReLU激活函数x = F.max_pool2d(x, 2) # 最大池化层,池化核大小为2x2x = F.relu(self.bn2(self.conv2(x))) # 卷积层2后进行批量归一化,然后通过ReLU激活函数x = F.max_pool2d(x, 2) # 最大池化层,池化核大小为2x2x = x.view(x.size(0), -1) # 将x展平为一维x = self.fc1(x) # 通过全连接层return x# 模拟训练数据
batch_size = 16 # 批量大小为16
num_channels = 3 # 通道数为3
height, width = 32, 32 # 图像高度和宽度为32
num_classes = 10 # 类别数为10# 创建一个简单的数据集
x = torch.randn(batch_size, num_channels, height, width) # 生成随机输入张量,形状为(batch_size, num_channels, height, width)
y = torch.randint(0, num_classes, (batch_size,)) # 生成随机标签,形状为(batch_size,)# 初始化模型、损失函数和优化器
model = SimpleCNN() # 实例化模型
criterion = nn.CrossEntropyLoss() # 定义交叉熵损失函数
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9) # 定义优化器,使用随机梯度下降法,学习率为0.01,动量为0.9# 前向传播
outputs = model(x) # 计算模型输出
loss = criterion(outputs, y) # 计算损失# 反向传播和优化
optimizer.zero_grad() # 清零梯度
loss.backward() # 反向传播计算梯度
optimizer.step() # 更新模型参数# 打印损失和批量归一化层的运行均值和方差
print(f'Loss: {loss.item()}') # 打印损失值
print(f'Running mean of first BN layer: {model.bn1.running_mean}') # 打印第一层批量归一化的运行均值
print(f'Running var of first BN layer: {model.bn1.running_var}') # 打印第一层批量归一化的运行方差
print(f'Running mean of second BN layer: {model.bn2.running_mean}') # 打印第二层批量归一化的运行均值
print(f'Running var of second BN layer: {model.bn2.running_var}') # 打印第二层批量归一化的运行方差
运行结果:
"C:\Program Files\Python39\python.exe" D:\Python\AI\神经网络\10-批量归一化.py
Loss: 2.573316812515259
Running mean of first BN layer: tensor([-0.0056, 0.0143, -0.0037, -0.0068, 0.0059, 0.0054, 0.0151, 0.0005,-0.0021, 0.0096, -0.0178, -0.0070, -0.0003, -0.0143, 0.0096, -0.0145])
Running var of first BN layer: tensor([0.9206, 0.9367, 0.9336, 0.9363, 0.9488, 0.9425, 0.9182, 0.9328, 0.9261,0.9360, 0.9302, 0.9286, 0.9404, 0.9280, 0.9289, 0.9302])
Running mean of second BN layer: tensor([ 0.0248, 0.0364, -0.0138, 0.0471, -0.0746, 0.0464, 0.0405, 0.0621,0.0327, -0.0391, -0.0227, 0.0368, -0.0107, 0.0006, 0.0374, -0.0079,-0.0669, 0.1178, -0.0184, 0.1392, -0.0039, -0.0067, 0.1190, -0.0364,0.0417, -0.0583, -0.0099, 0.0407, -0.0307, 0.1127, -0.0287, -0.0231])
Running var of second BN layer: tensor([0.9157, 0.9151, 0.9154, 0.9156, 0.9185, 0.9150, 0.9183, 0.9199, 0.9129,0.9151, 0.9160, 0.9133, 0.9173, 0.9184, 0.9150, 0.9123, 0.9164, 0.9212,0.9128, 0.9205, 0.9133, 0.9138, 0.9194, 0.9156, 0.9149, 0.9158, 0.9163,0.9151, 0.9144, 0.9187, 0.9223, 0.9124])Process finished with exit code 0
5、小结
批量归一化层,该层的作用主要是用来控制每层数据的流动时的均值和方差,防止训练过程出现剧烈的波动,模型难以收敛,或者收敛较慢。
批量归一化层在计算机视觉领域使用较多。