第一章: Pytorch框架制作自己的数据集实现图像分类
第二章: Pytorch框架构建残差神经网络(ResNet)
第三章: Pytorch框架构建DenseNet神经网络
提示:本文第二部分为代码实现
神经网络模型想取得更高的正确率,一种显然的思路就是给模型添加更多的层。随着层数的增加,模型的准确率得到提升。但是如果出现过拟合现象,这时再增加更多的层,准确率会下降。在到达一定深度后加入更多层,模型可能产生梯度消失(梯度衰减到0)或梯度爆炸(梯度变成一个非常大的值)等问题。一般来说可以通过更好的初始化权重、添加BN层、设计更好的架构等解决此类问题。
残差网络(ResNet)则是通过残差连接解决此问题。残差网络结构非常容易修改和扩展,通过调整block内的channel数量以及堆叠的block数量,就可以很容易地调整网络的宽度和深度,来得到不同表达能力的网络,而不用过多地担心网络的“退化”问题,只要训练数据足够,逐步加深网络,就可以获得更好的性能表现。
提示:以下是本篇文章正文内容,下面案例可供参考
ResNet是在2015年由微软实验室提出,作者是何恺明(本科清华、博士香港中文大学出来的大神)、孙剑(现任西安交大人工智能学院首任院长)等人提出,其论文《Deep Residual Learning for Image Recognition》,斩获当年ImageNet竞赛中分类任务第一名,目标检测第一名。
卷积网络发展史中,VGG最高达到了19层,再就是GoogleNet,达到了22层。 增加网络的宽度和深度可以很好的提高网络的性能,深的网络一般都比浅的网络效果好。比如说VGG,该网络就是在AlexNex的基础上通过增加网络的深度大幅度提高了网络性能。但是,简单地不断增加深度,又会导致以下问题:
问题4随着网络层数的增加,网络发生了退化现象:随着网络层数增加,训练集错误率逐渐下降,然后趋于饱和,再增加深度时,错误率反而会增大,所以这并不是过拟合(过拟合在训练中错误率应该是一直减小)。
ResNet是一种残差网络,可以把它理解为一个模块,这个模块经过堆叠可以构成一个很深的网络。
ResNet通过增加残差连接(shortcut connection),显示地让网络中的层拟合残差映射(residual mapping)。
ResNet不再尝试学习 x x x到 H ( x ) H\left( x \right) H(x) 的潜在映射,而是学习两者之间的不同,或者说是残差(residual),然后为了计算 H ( x ) H(x) H(x),可将残差加到输入上。假设残差是 F ( x ) = H ( x ) − x F\left( x \right) =H\left( x \right) -x F(x)=H(x)−x,我们将尝试学习 F ( x ) + x F\left( x \right) +x F(x)+x,而不是直接学习 H ( x ) H(x) H(x)。
每个ResNet块都包含一系列层,残差连接把块的输入加到块的输出上。
由于加操作是在元素级别执行的,所以输入和输出的大小要一致。如果它们的大小不同,我们可以采用填充的方式。
ResNet网络结构为多个Residual Block串联
实验表明学习残差比直接学习输入、输出间映射要容易收敛,可达到更高的分类精度,ResNet在上百层都有很好的表现。
ResNet结构非常容易修改和扩展,通过调整block内的channel数量以及堆叠的block数量,就可以很容易地调整网络的宽度和深度,来得到不同表达能力的网络,而不用过多地担心网络“退化”问题,只要训练数据足够,逐步加深网络,就可以获得更好的性能表现。
代码如下:
import torchvision.models
import torch.nn.functional as F
import torch.nn as nn
代码如下:
class ResnetbasicBlock(nn.Module):
def __init__(self,in_channels, out_channels):
super().__init()# 继承父类属性
#第一层初始化
self.conv1 = nn.Conv2d(in_channels,
out_channels,
kernel_size=3, #使用3*3的卷积
padding=1, #填充减小的部分,保证原有图片不变,padding代表对图片的上下左右填充的像素值
bias=False #kernel_size = n , 损失 n - 1个像素
)
self.bn1 = nn.BatchNorm2d(out_channels) #对图像按照批次做标准化,使图像失去原有量纲
#第二层初始化
self.conv2 = nn.Conv2d(in_channels,
out_channels,
kernel_size=3, #使用3*3的卷积
padding=1,
bias=False
)
self.bn2 = nn.BatchNorm2d(out_channels)
#定义前向传播过程
def forward(self, x):
residual = x #残差
# 调用第一层,经过第一层权重
out.self.conv1(x)
out.F.relu(self.bn1(out), inplace=True)
# 调用第二层,经过第二层权重
out.self.conv2(out)
out.self.bn2(out)
out = out + residual
return F.rule(out) #激活输出
该代码实现了一个简单的残差块,根据实际情况需要将一个个残差块相连即可获得一个定制的残差神经网络。
代码如下:
model = torchvision.models.resnet34()
print(model)
调用Pytroch框架所提供的网络架构,输出显示后大家可以查看其各个层设计模式,以后也可以根据自己的需要去自己设计。
可以直接跑通,运行后会显示ResNet34的网络架构。
import torchvision.models
import torch.nn.functional as F
import torch.nn as nn
class ResnetbasicBlock(nn.Module):
def __init__(self,in_channels, out_channels):
super().__init()# 继承父类属性
#第一层初始化
self.conv1 = nn.Conv2d(in_channels,
out_channels,
kernel_size=3, #使用3*3的卷积
padding=1, #填充减小的部分,保证原有图片不变,padding代表对图片的上下左右填充的像素值
bias=False
)#kernel_size=n,损失 n - 1个像素
self.bn1 = nn.BatchNorm2d(out_channels)#对图像按照批次做标准化,使图像失去原有量纲
#第二层初始化
self.conv2 = nn.Conv2d(in_channels,
out_channels,
kernel_size=3, #使用3*3的卷积
padding=1,
bias=False
)
self.bn2 = nn.BatchNorm2d(out_channels)
#定义前向传播过程
def forward(self, x):
residual = x #残差
# 调用第一层,经过第一层权重
out.self.conv1(x)
out.F.relu(self.bn1(out), inplace=True)
# 调用第二层,经过第二层权重
out.self.conv2(out)
out.self.bn2(out)
out = out + residual
return F.rule(out) #激活输出
model = torchvision.models.resnet34()
print(model)