卷积神经网络CNN(2)—— BN(Batch Normalization) 原理与使用过程详解

前言

Batch Normalization是由google提出的一种训练优化方法。参考论文:Batch Normalization Accelerating Deep Network Training by Reducing Internal Covariate Shift
网上对BN解释详细的不多,大多从原理上解释,没有说出实际使用的过程,这里从what, why, how三个角度去解释BN。

What is BN

Normalization是数据标准化(归一化,规范化),Batch 可以理解为批量,加起来就是批量标准化。
先说Batch是怎么确定的。在CNN中,Batch就是训练网络所设定的图片数量batch_size。

Normalization过程,引用论文中的解释:
这里写图片描述
输入:输入数据x1…xm(这些数据是准备进入激活函数的数据)
计算过程中可以看到,
1.求数据均值
2.求数据方差
3.数据进行标准化(个人认为称作正态化也可以)
4.训练参数γ,β
5.输出y通过γ与β的线性变换得到新的值
在正向传播的时候,通过可学习的γ与β参数求出新的分布值

在反向传播的时候,通过链式求导方式,求出γ与β以及相关权值
这里写图片描述

Why is BN

解决的问题是梯度消失与梯度爆炸。
关于梯度消失,以sigmoid函数为例子,sigmoid函数使得输出在[0,1]之间。
这里写图片描述
事实上x到了一定大小,经过sigmoid函数的输出范围就很小了,参考下图
这里写图片描述
如果输入很大,其对应的斜率就很小,我们知道,其斜率(梯度)在反向传播中是权值学习速率。所以就会出现如下的问题,
这里写图片描述
在深度网络中,如果网络的激活输出很大,其梯度就很小,学习速率就很慢。假设每层学习梯度都小于最大值0.25,网络有n层,因为链式求导的原因,第一层的梯度小于0.25的n次方,所以学习速率就慢,对于最后一层只需对自身求导1次,梯度就大,学习速率就快。
这会造成的影响是在一个很大的深度网络中,浅层基本不学习,权值变化小,后面几层一直在学习,结果就是,后面几层基本可以表示整个网络,失去了深度的意义。

关于梯度爆炸,根据链式求导法,
第一层偏移量的梯度=激活层斜率1x权值1x激活层斜率2x…激活层斜率(n-1)x权值(n-1)x激活层斜率n
假如激活层斜率均为最大值0.25,所有层的权值为100,这样梯度就会指数增加。

How to use BN

先解释一下对于图片卷积是如何使用BN层。
这里写图片描述
这是文章卷积神经网络CNN(1)中5x5的图片通过valid卷积得到的3x3特征图(粉红色)。这里假设通道数为1,batch为4,即大小为[4,1,3,3] (n,c,h,w)。特征图里的值,作为BN的输入,这里简化输出只有一个channel,也就是这一个4x3x3个数值通过BN计算并保存均值与方差,并通过当前均值与方差计算归一化的值,最后根据γ,β以及归一化得值计算BN层输出。假如输入是3个通道,就是在通道的维度上进行bn,所以会有3个γ,β参数。

这里需要着重说明的细节:
网络训练中以batch_size为最小单位不断迭代,很显然,新的batch_size进入网络,由于每一次的batch有差异,实际是通过变量,以及滑动平均来记录均值与方差。训练完成后,推断阶段时通过γ, β,以及记录的均值与方差计算bn层输出。

结合论文中给出的使用过程进行解释
这里写图片描述
输入:待进入激活函数的变量
输出:
1.对于K个激活函数前的输入,所以需要K个循环。每个循环中按照上面所介绍的方法计算均值与方差。通过γ,β与输入x的变换求出BN层输出。
2.在反向传播时利用γ与β求得梯度从而改变训练权值(变量)。
3.通过不断迭代直到训练结束,得到γ与β,以及记录的均值方差。
4.在预测的正向传播时,使用训练时最后得到的γ与β,以及均值与方差的无偏估计,通过图中11:所表示的公式计算BN层输出。
至此,BN层的原理与使用过程就解释完毕,给出的解释都是本人觉得值得注意或这不容易了解的部分,如有錯漏,请指正。
BN层正向传播之前存在勘误,博文已经过修改

  • 79
    点赞
  • 424
    收藏
    觉得还不错? 一键收藏
  • 30
    评论
卷积神经网络(Convolutional Neural Network,CNN)是一类包含卷积计算且具有深度结构的前馈神经网络,是深度学习中应用最广泛的一种模型之一。下面以一个基于PyTorch实现的CNN实例应用为例,详细说明CNN的实现过程。 ## 数据集 本例使用的是Fashion-MNIST数据集,该数据集包含了10个类别的服装图片,每个类别包含6000张28x28像素的灰度图像,其中训练集包含了60000张图片,测试集包含了10000张图片。可以使用PyTorch内置的函数`torchvision.datasets.FashionMNIST`来获取该数据集。 ## 模型结构 本例使用了一个较为简单的CNN模型,包含两个卷积层和两个全连接层,具体结构如下: ``` CNN( (conv1): Conv2d(1, 16, kernel_size=(5, 5), stride=(1, 1)) (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (conv2): Conv2d(16, 32, kernel_size=(5, 5), stride=(1, 1)) (pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (fc1): Linear(in_features=512, out_features=128, bias=True) (fc2): Linear(in_features=128, out_features=10, bias=True) ) ``` 其中`Conv2d`表示卷积层,`MaxPool2d`表示最大池化层,`Linear`表示全连接层。`conv1`用于提取图像的低级特征,`pool1`用于降低特征图的分辨率,`conv2`用于进一步提取图像的高级特征,`pool2`再次降低特征图的分辨率,最后通过两个全连接层进行分类。 ## 实现过程 ### 1. 导入相关库 ``` import torch import torch.nn as nn import torch.optim as optim import torchvision import torchvision.transforms as transforms ``` ### 2. 加载数据集 ``` transform = transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))]) trainset = torchvision.datasets.FashionMNIST(root='./data', train=True, download=True, transform=transform) trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True, num_workers=2) testset = torchvision.datasets.FashionMNIST(root='./data', train=False, download=True, transform=transform) testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=False, num_workers=2) ``` ### 3. 定义CNN模型 ``` class CNN(nn.Module): def __init__(self): super(CNN, self).__init__() self.conv1 = nn.Conv2d(1, 16, kernel_size=5) self.pool1 = nn.MaxPool2d(kernel_size=2) self.conv2 = nn.Conv2d(16, 32, kernel_size=5) self.pool2 = nn.MaxPool2d(kernel_size=2) self.fc1 = nn.Linear(512, 128) self.fc2 = nn.Linear(128, 10) def forward(self, x): x = self.conv1(x) x = nn.functional.relu(x) x = self.pool1(x) x = self.conv2(x) x = nn.functional.relu(x) x = self.pool2(x) x = x.view(-1, 512) x = self.fc1(x) x = nn.functional.relu(x) x = self.fc2(x) return x net = CNN() ``` ### 4. 定义损失函数和优化器 ``` criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9) ``` ### 5. 训练模型 ``` for epoch in range(10): # 进行10轮训练 running_loss = 0.0 for i, data in enumerate(trainloader, 0): inputs, labels = data optimizer.zero_grad() # 梯度清零 outputs = net(inputs) # 前向传播 loss = criterion(outputs, labels) # 计算损失函数 loss.backward() # 反向传播 optimizer.step() # 更新参数 running_loss += loss.item() if i % 200 == 199: # 每200个batch输出一次损失函数 print('epoch[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 200)) running_loss = 0.0 ``` ### 6. 测试模型 ``` correct = 0 total = 0 with torch.no_grad(): for data in testloader: images, labels = data outputs = net(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print('Accuracy on test set: %d %%' % (100 * correct / total)) ``` 以上就是一个基于PyTorch实现的CNN模型的实现过程,如果有需要可以根据实际情况进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值