ResNet网络详解并使用pytorch搭建模型、并基于迁移学习训练

本文详细介绍ResNet网络结构,包括超深网络的挑战、残差模块的设计思路及其在不同深度网络中的实现方式。此外,还介绍了如何利用PyTorch搭建ResNet,并通过迁移学习加速训练过程。

1.ResNet网络详解

网络中的创新点:
(1)超深的网络结构(突破1000层)
(2)提出residual模块
(3)使用Batch Normalization加速训练(丢弃dropout)

(1)超深的网络结构

如果简单的将一些的卷积和池化层堆叠起来,层数深的网络结构表现反而会越来越差,作者总结了两个问题:
①随着网络的不断加深,梯度消失梯度爆炸的问题会越来越明显;这类问题可以通过对数据进行标准化处理、权重初始化、Batch Normalization标准化进行解决

退化问题(degradation problem):解决了①的问题后,可能仍然存在层数深的效果没有层数少的效果好,在论文中提出了残差结构,可以通过残差结构解决退化问题。

(2)提出residual模块

何凯明讲的残差结构;
在这里插入图片描述
ResNet中的残差结构:

左图是针对于网络层数较少的网络(原文说是34层)所使用的残差结构,右图是对50/101/152所提出的残差结构。左图所需要的参数大概需要118w,右图所需要的参数大概需要7W。
在这里插入图片描述
左图的残差结构的主分支是由两层3x3的卷积层组成,右侧的连接线是shortcut分支也称捷径分支。在主分支上经过一系列卷积层之后得到的特征矩阵与直接通过捷径分支的输入特征矩阵相加,然后再进行ReLU激活。

右图的残差结构与左边相比其输入输出都加上了一个1x1的卷积层,第一个卷积层起降维的作用,第二个卷积层起还原channel维度的作用。

:为了让主分支上的输出矩阵能够与我们捷径分支上的输出矩阵进行相加,必须保证这两个输出特征矩阵有相同的shape

不同深度的ResNet网络结构配置以及ResNet-18网络模型

在这里插入图片描述
在这里插入图片描述
在ResNet34网络结构图中有一些虚线的残差结构,对于虚线的残差结构,其输入和输出的shape不一样,只有通过虚线残差结构得到输出后,再将其输入到实线残差结构中才能保证实线残差结构的输入特征矩阵和输出特征矩阵的shape一样。

虚线与实线残差结构的不同之处
(1)第一个3x3卷积层的步长不同,因为需要将特征向量的高和宽从56缩减为28;
(2)卷积核个数不同,因为需要128个卷积核将特征向量的channel从64变为128;
(3)捷径分支增加了一个1x1的卷积核,步长为2,也是要缩减高和宽,增加channel。
在这里插入图片描述
对于更深层的残差结构变化同理:
(1)主分支的第一个1x1卷积层起降维作用,将特征矩阵的深度从256降到128;第二个3x3卷积层的步长为2,将特征矩阵的高和宽缩减为28;第三层1x1卷积层将深度增加到512。
(2)捷径分支同样采用1x1的卷积核处理,缩减高和宽,增加深度。
在这里插入图片描述
对于18层、34层的网络,通过最大池化下采样后得到的特征矩阵输出是[56x56x64],而其Conv2_x所需要的输入也为[56,56,64],因此不需要在第一层使用虚线残差结构。而对于50层、101层、152层的网络,Conv2_x所需要的输入特征矩阵的shape为[56,56,256],因此其Conv2_x的第一层需要使用虚线残差结构,仅调整特征矩阵的深度,Conv3_x、Conv4_x、Conv5_x的第一层虚线残差结构会调整宽、高、深度。

(3)使用Batch Normalization加速训练

Batch Normalization的目的是使一批(batch)特征矩阵(feature map)满足均值为0,方差为1的分布规律。

原理推荐去看吴恩达老师讲的Batch正则化
也可以看导师的优快云:
Batch Normalization详解以及pytorch实验

导师提到了使用BN时需要注意的问题

(1)训练时要将traning参数设置为True,在验证时将trainning参数设置为False。在pytorch中可通过创建模型的model.train()和model.eval()方法控制。

(2)batch size尽可能设置大点,设置小后表现可能很糟糕,设置的越大求的均值和方差越接近整个训练集的均值和方差。

(3)建议将bn层放在卷积层(Conv)和激活层(例如Relu)之间,且卷积层不要使用偏置bias,因为没有用。

2.迁移学习

使用迁移学习的优势
(1)能够快速的训练出一个理想的结果;
(2)当数据集较小时也能训练出理想的效果。
:如果使用别人预训练模型参数时,要注意别人的预处理方法。

在这里插入图片描述
比如一张图像,通过一系列的卷积层和全连接层搭建了网络结构。这个模型训练完成后,第一个卷积层可能学习到了一些角点信息,卷积层二可能学习到一些纹理信息,随着卷积层的不断加深,后面的卷积层可能学习到识别眼睛、嘴巴等信息。最后通过全连接层将一系列特征进行组合,输出类别概率。
对于浅层的卷积层所学习的信息,有可能不仅在本网络适用,在其他网络也适用。因此可以将学习好的网络的浅层网络的参数迁移到新的网络中,这样新的网络也拥有了识别底层通用特征的能力,就能够更加快速的学习新的数据据的高维特征。

常见的迁移学习方式
(1)载入权重后训练所有参数;
(2)载入权重后只训练最后几层参数;
(3)载入权重后在原网络基础上再添加一层全连接层,仅训练最后一层全连接层。

3.使用Pytorch搭建ResNet网络

文件结构:

ResNet
  ├── model.py:           ResNet模型搭建
  ├── train.py:           训练脚本
  ├── predict.py:         单张图像预测脚本
  └── batch_predict.py:   批量图像预测脚本

model.py

定义残差结构,上文中提到18层、34层的残差结构与50层、101层、152层的残差结构是不一样的。

定义18层、34层的残差结构

class BasicBlock(nn.Module):                   #定义18层、34层对应的残差结构
    expansion = 1                              #expansion对应残差结构中主分支采用的卷积核个数是否变化

    def __init__(self, in_channel, out_channel, stride=1, downsample=None, **kwargs):    #定义初始函数及残差结构所需要使用的一系列层结构,其中下采样参数downsample对应虚线的残差结构
        super(BasicBlock, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=out_channel,         #stride等于1时对应实线残差结构,因为当步长为1时卷积不会改变特征矩阵的高和宽
                               kernel_size=3, stride=stride, padding=1, bias=False)      #output=(input-kernel_size+2*padding)/stride+1=(input-3+2*1)/1+1=input(向下取整)
        self.bn1 = nn.BatchNorm2d(out_channel)                                           #stride等于2时对应虚线残差结构,要将特征矩阵的高和宽缩减为原来的一半
        self.relu = nn.ReLU()                                                            #使用BN时不需要使用偏置
        self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel,
                               kernel_size=3, stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(out_channel)
        self.downsample = downsample

    def forward(self, x):                           #定义正向传播过程,输入特征矩阵x
        identity = x                                #将x赋值给identity
        if self.downsample is not None:             #如果没有输入下采样函数,那么对应实线的残差结构,就跳过这里
            identity = self.downsample(x)           #如果输入下采样函数不等于None,就将输入特征矩阵x输入到下采样函数中得到捷径分支的输出

        out = self.conv1(x)                         #主分支的输出
        out = self.bn1(out)
        out = self
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值