---
# System prepended metadata

title: ResNet
tags: [學習紀錄]

---

# ResNet
###### tags:  `學習紀錄`

[toc]

---
## Before Meeting
:::success

:::

[refer](https://zhuanlan.zhihu.com/p/54289848)
[refer](https://blog.csdn.net/buyi_shizi/article/details/53336192?utm_source=itdadao&utm_medium=referral)
[refer](https://arxiv.org/abs/1512.03385)
[refer](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py)
[refer](https://blog.csdn.net/sunqiande88/article/details/80100891)
[refer]()
[refer]()


---

## Recent Paper

---

### ResNet

:::success
#### Abstracion
- 何凯明等人在2015年提出的ResNet，在ImageNet比赛classification任务上获得第一名，获评CVPR2016最佳论文。因为它“简单与实用”并存，之后许多目标检测、图像分类任务都是建立在ResNet的基础上完成的，成为计算机视觉领域重要的基石结构。
- ResNet要解决什么问题
    - 自从深度神经网络在ImageNet大放异彩之后，后来问世的深度神经网络就朝着网络层数越来越深的方向发展。直觉上我们不难得出结论：增加网络深度后，网络可以进行更加复杂的特征提取，因此更深的模型可以取得更好的结果。
    - 但事实并非如此，人们发现随着网络深度的增加，模型精度并不总是提升，并且这个问题显然不是由过拟合（overfitting）造成的，因为网络加深后不仅测试误差变高了，它的训练误差竟然也变高了。作者提出，这可能是因为更深的网络会伴随梯度消失/爆炸问题，从而阻碍网络的收敛。作者将这种加深网络深度但网络性能却下降的现象称为退化问题（degradation problem）。
    - 文中给出的实验结果进一步描述了这种退化问题：当传统神经网络的层数从20增加为56时，网络的训练误差和测试误差均出现了明显的增长，也就是说，网络的性能随着深度的增加出现了明显的退化。ResNet就是为了解决这种退化问题而诞生的
    - ![](https://i.imgur.com/xDPI4HQ.png)

- ResNet怎么解决网络退化问题
    - 随着网络层数的增加，梯度爆炸和梯度消失问题严重制约了神经网络的性能，研究人员通过提出包括Batch normalization在内的方法，已经一定程度上缓解了这个问题，但依然不足以满足需求。
    - 作者想到了构建恒等映射（Identity mapping）来解决这个问题，问题解决的标志是：增加网络层数，但训练误差不增加。为什么是恒等映射呢，我是这样子想的：20层的网络是56层网络的一个子集，56层网络的解空间包含着20层网络的解空间。如果我们将56层网络的最后36层全部短接，这些层进来是什么出来也是什么（也就是做一个恒等映射），那这个56层网络不就等效于20层网络了吗，至少效果不会相比原先的20层网络差吧。同样是56层网络，不引入恒等映射为什么就不行呢？因为梯度消失现象使得网络难以训练，虽然网络的深度加深了，但是实际上无法有效训练网络，训练不充分的网络不但无法提升性能，甚至降低了性能
    - ![](https://i.imgur.com/udKRmvC.png)

    - 那怎么构建恒等映射呢？简单地说，原先的网络输入x，希望输出H(x)。现在我们改一改，我们令H(x)=F(x)+x，那么我们的网络就只需要学习输出一个残差F(x)=H(x)-x。作者提出，学习残差F(x)=H(x)-x会比直接学习原始特征H(x)简单的多。


:::
:::info
#### Detail
- ResNet网络结构与代码实现
    - ResNet主要有五种主要形式：Res18，Res34，Res50，Res101，Res152；
    - 如下图所示，每个网络都包括三个主要部分：输入部分、输出部分和中间卷积部分（中间卷积部分包括如图所示的Stage1到Stage4共计四个stage）。尽管ResNet的变种形式丰富，但都遵循上述的结构特点，网络之间的不同主要在于中间卷积部分的block参数和个数存在差异。下面我们以ResNet18为例，看一下整个网络的实现代码是怎样的。
    - ![](https://i.imgur.com/3XY2zzF.png)
    - 在ResNet类中的forward( )函数规定了网络数据的流向：
        - 数据进入网络后先经过输入部分（conv1, bn1, relu, maxpool）；
        - 然后进入中间卷积部分（layer1, layer2, layer3, layer4，这里的layer对应我们之前所说的stage）；
        - 最后数据经过一个平均池化和全连接层（avgpool, fc）输出得到结果；
    - 具体来说，resnet18和其他res系列网络的差异主要在于layer1~layer4，其他的部件都是相似的。
    - 网络输入部分
        - 所有的ResNet网络输入部分是一个size=7x7, stride=2的大卷积核，以及一个size=3x3, stride=2的最大池化组成，通过这一步，一个224x224的输入图像就会变56x56大小的特征图，极大减少了存储所需大小。
        - ![](https://i.imgur.com/2Fgv08K.png)

    - 网络中间卷积部分
        - 中间卷积部分主要是下图中的蓝框部分，通过3*3卷积的堆叠来实现信息的提取。红框中的[2, 2, 2, 2]和[3, 4, 6, 3]等则代表了bolck的重复堆叠次数。
        - ![](https://i.imgur.com/8EIwQdW.png)
        - 刚刚我们调用的resnet18( )函数中有一句 ResNet(BasicBlock, [2, 2, 2, 2], **kwargs)，这里的[2, 2, 2, 2]与图中红框是一致的，如果你将这行代码改为 ResNet(BasicBlock, [3, 4, 6, 3], **kwargs)， 那你就会得到一个res34网络。
     - 残差块实现
         - 下面我们来具体看一下一个残差块是怎么实现的，如下图所示的basic-block，输入数据分成两条路，一条路经过两个3*3卷积，另一条路直接短接，二者相加经过relu输出，十分简单。
         - ![](https://i.imgur.com/kv7pHq5.png)
         - ![](https://i.imgur.com/gRaaitK.png)
         - 代码比较清晰，不做分析了，主要提一个点：downsample，它的作用是对输入特征图大小进行减半处理，每个stage都有且只有一个downsample。后面我们再详细介绍。
    - 网络输出部分
        - 网络输出部分很简单，通过全局自适应平滑池化，把所有的特征图拉成1*1，对于res18来说，就是1x512x7x7 的输入数据拉成 1x512x1x1，然后接全连接层输出，输出节点个数与预测类别个数一致。








:::
:::warning
#### Conclusion
- ResNet的常见改进
    - 改进一：改进downsample部分，减少信息流失。前面说过了，每个stage的第一个conv都有下采样的步骤，我们看左边第一张图左侧的通路，input数据进入后在会经历一个stride=2的1*1卷积，将特征图尺寸减小为原先的一半，请注意1x1卷积和stride=2会导致输入特征图3/4的信息不被利用，因此ResNet-B的改进就是就是将下采样移到后面的3x3卷积里面去做，避免了信息的大量流失。ResNet-D则是在ResNet-B的基础上将identity部分的下采样交给avgpool去做，避免出现1x1卷积和stride同时出现造成信息流失。ResNet-C则是另一种思路，将ResNet输入部分的7x7大卷积核换成3个3x3卷积核，可以有效减小计算量，这种做法最早出现在Inception-v2中。其实这个ResNet-C 我比较疑惑，ResNet论文里说它借鉴了VGG的思想，使用大量的小卷积核，既然这样那为什么第一部分依旧要放一个7x7的大卷积核呢，不知道是出于怎样的考虑，但是现在的多数网络都把这部分改成3个3x3卷积核级联。
    - ![](https://i.imgur.com/yE7CrEU.png)

    - 改进二：ResNet V2。这是由ResNet原班人马打造的，主要是对ResNet部分组件的顺序进行了调整。各种魔改中常见的预激活ResNet就是出自这里。
    - ![](https://i.imgur.com/SuFXUmf.png)
    - 原始的resnet是上图中的a的模式，我们可以看到相加后需要进入ReLU做一个非线性激活，这里一个改进就是砍掉了这个非线性激活，不难理解，如果将ReLU放在原先的位置，那么残差块输出永远是非负的，这制约了模型的表达能力，因此我们需要做一些调整，我们将这个ReLU移入了残差块内部，也就是图e的模式。这里的细节比较多，建议直接阅读原文：Identity Mappings in Deep Residual Networks ，就先介绍这么多

- 从模型集成角度理解ResNet的有效性
    - ResNet 中其实是存在着很多路径的集合，整个ResNet类似于多个网络的集成学习，证据是删除部分ResNet的网络结点，不影响整个网络的性能，但是在VGG上做同样的事请网络立刻崩溃，由此可见相比其他网络ResNet对于部分路径的缺失不敏感。更多细节具体可参见NIPS论文： Residual Networks Behave Like Ensembles of Relatively Shallow Networks ；
    - ![](https://i.imgur.com/aM3wEsR.png)




- ResNet是当前计算机视觉领域的基石结构，是初学者无法绕开的网络模型，仔细阅读论文和源码并进行实验是极有必要的。


:::
[refer](https://arxiv.org/abs/1512.03385)
[refer]()
[refer]()
[refer]()
[refer]()

---
:::success
#### Abstracion
:::
:::info
#### Detail


:::
:::warning
#### Conclusion

:::
[refer]()
[refer]()
[refer]()
[refer]()
[refer]()
[refer]()

---