【BasicNet系列:四】ResNet 论文笔记解读+pytorch代码分析+网络结构图

本文深入探讨了ResNet网络如何通过残差学习解决深度网络中的退化问题,介绍了ResNet的基本结构、不同变种,以及在ImageNet竞赛中的优秀表现。通过PyTorch代码展示了ResNet18和ResNet50的实现,并讨论了ResNet的常见改进,如ResNet-B和ResNet-D。此外,还提供了ResNet18和ResNet50的网络结构图。
摘要由CSDN通过智能技术生成

2015 ImageNet classification top1
2016 CVPR Best

Deep Residual Learning for Image Recognition

Resnet及其变种的结构梳理、有效性分析与代码解读(PyTorch)

1、ResNet解决了什么?

  • 2015年

  • ImageNet比赛classification任务上获得第一名

  • 更深的网络会伴随梯度消失/爆炸问题,阻碍网络收敛,degradation problem

    • Batch normalization
    • Identity mapping(构建恒等映射)——ResNet

2、ResNe怎么解决网络退化?

title

title

残差学习的结构如图有点类似与电路中的“短路”,所以是一种短路连接(shortcut connection)。
增加一个identity mapping(恒等映射),将原始所需要学的函数H(x)转换成F(x)+x,F(x)的优化 会比H(x)简单的多。

Residual block通过shortcut connection实现,通过shortcut将这个block的输入和输出进行一个element-wise的加叠,这个简单的加法并不会给网络增加额外的参数和计算量,同时却可以大大增加模型的训练速度、提高训练效果,并且当模型的层数加深时,这个简单的结构能够很好的解决退化问题。

title

上面公式中:

  • h 表示 shortcut 使用什么形式的变换(Identity map)
  • F 是 residual function。F= y-h(x)
  • f 为Residual Units输出处使用的函数(relu)

3、ResNet网络结构

输入部分、输出部分和中间卷积部分(四个stage),网络之间的不同主要在于中间卷积部分的block参数和个数存在差异。

title

  • 输入部分(conv1, bn1, relu, maxpool)
  • 网络中间卷积部分

title

  • Resnet18 、 50

ResNet34及ResNet101分别具有两种不同的基本“shortcut connection”结构。
ResNet34使用BasicBlock,ResNet101使用 Bottleneck作为“shortcut connection”。

“shortcut connection” 只是元素级相加操作

title

  • ResNet34

title

  • shortcut

     def __init__(self, in_planes, planes, stride=1):
         super(BasicBlock, self).__init__()
         self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
         self.bn1 = nn.BatchNorm2d(planes)
         self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
         self.bn2 = nn.BatchNorm2d(planes)
    
         self.shortcut = nn.Sequential()
         if stride != 1 or in_planes != self.expansion*planes:# 上图虚线shortcut
             self.shortcut = nn.Sequential(
                 nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False),
                 nn.BatchNorm2d(self.expansion*planes)
             )
    
     def forward(self, x):
         out = F.relu(self.bn1(self.conv1(x)))
         out = self.bn2(self.conv2(out))
         out += self.shortcut(x)
         out = F.relu(out)
         return out
    

downsample 主要用来处理H(x)=F(x)+x中F(x)和xchannel维度不匹配问题

title

  • ⭐残差块实现

title

图 : ResNet网络的短路连接机制(**其中+代表的是元素级相加操作**)
- 结构

bootlenect和直线shortcut组成。整个bootlenect+shortcut称为Residual uint。几个Residual uint的叠加称为Residual block。Resnet结构都是由4个Residual block组成的。

ResNet34使用BasicBlock,ResNet101使用 Bottleneck作为“bootlenect”,引入1×1卷积

title

- 1x1卷积作用?
    - 对通道数进行升维和降维(跨通道信息整合)
    - 比其他尺寸的运算复杂度低
    - 引入了更多的非线性映射(relu)

title
- downsample,它的作用是对输入特征图大小进行减半处理,每个stage都有且只有一个downsample。

  • 网络输出部分

全局自适应平滑池化,把所有的特征图拉成1*1,然后接全连接层输出,输出节点个数与预测类别个数一致。

  • 设计规律

    • 卷积层主要是3×3卷积
    • 不使用dropout,全部使用BN
    • 对于相同的输出特征图大小的层,即同一stage,具有相同数量的3x3滤波器;
    • 当feature map大小降低一半时,feature map的数量增加一倍,这保持了网络层的复杂度。
    • 每个stage通过步长为2的卷积层执行下采样(downsample),而却这个下采样只会在每一个stage的第一个卷积完成,有且仅有一次。
    • 网络以全局平均池化层和softmax的1000路全连接层结束。

4、ResNet常见改进

  • 改进downsample部分,减少信息流失。
    每个stage的第一个conv都有下采样的步骤。
    • ResNet-B的改进就是就是将下采样移到后面的3x3卷积里面去做,避免了信息的大量流失。
    • ResNet-D则是在ResNet-B的基础上将identity部分的下采样交给avgpool去做,避免出现1x1卷积和stride同时出现造成信息流失。

title

  • ResNet V2

title

- a:相加后需要进入ReLU做一个非线性激活再输出,使残差块输出永远是非负的,制约了模型的表达能力
- e:a中输出处ReLU移入残差块内部

5、反向传播

这一块有没有大佬补充一下~~~

6、Resnet代码

resnet18,第一层是没有downsample的,因为输入与输出通道数一样,其余层都有downsample。

ResNet Pytorch code

  • layers1:

    [ResidualBlock(
    (conv1): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (relu): ReLU(inplace)
    (conv2): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn2): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    ),
    ResidualBlock(
    (conv1): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (relu): ReLU(inplace)
    (conv2): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn2): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    ),
    ResidualBlock(
    (conv1): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (relu): ReLU(inplace)
    (conv2): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn2): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )]

  • layers2:

    [ResidualBlock(
    (conv1): Conv2d(16, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
    (bn1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (relu): ReLU(inplace)
    (conv2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (downsample): Sequential(
    (0): Conv2d(16, 32, kernel_size=(3, 3), stride=(2, 2)

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值