主干网络论文阅读(按论文时间顺序):
论文阅读 LeNET CONVOLUTIONAL NEURAL NETWORKS FOR ISOLATED CHARACTER RECOGNITION-CSDN博客
论文阅读 AlexNet ImageNet Classification with Deep ConvolutionalNeural Networks-CSDN博客
论文阅读 VGGNet VERY DEEP CONVOLUTIONALNETWORKSFORLARGE-SCALEIMAGERECOGNITION-CSDN博客
论文阅读 GoogleNet(Inception) Going deeper with convolutions-CSDN博客
论文阅读 ResNet Deep Residual Learning for Image Recognition-CSDN博客
论文阅读 ResNext Aggregated Residual Transformations for Deep Neural Networks-CSDN博客
残差网络可以解决梯度消失梯度爆炸问题,但最重要的是解决了网络退化问题。
网络退化: 图中可见,网络层数增加,准确率反而下降
实验发现,随着网络深度的增加,精度达到饱和,然后迅速退化。然而这种退化并不是由过拟合引起的(过拟合的话,训练集上准确率不该下降)
按照正常的逻辑来说,神经网络越深训练的效果应该会越好,因为假设一个比较浅的网络已经可以达到不错的效果,那么即使之后堆上去的网络什么也不做,模型的效果也不会变差。问题就出现在这里,什么都不做(即恒等映射identity mapping)就是神经网络最难做到的东西---网络参数难以做到恒等映射
提出残差网络:
X 为浅层网络的输出。如果我们想要得到的映射为H(X),可以让输入和后续网络层的输出相加(跳连接/捷径链接shortcut connection),让添加的非线性网络层去拟合残差映射F(X):=H(X)-X。原始的映射就可以写成F(X)+X。 这个残差网络块的输出为。需要保证F(x)和x的维度一样,才能相加,维度不一致体现在两个方面上:1、空间不一致---在跳接部分给输入的x加上线性映射W;2、深度不一致---全0填充或跳接时加1×1卷积层升维
设这个网络前四层已经足够满足我们的性能要求,那么新增加的层便显得有些多余,如果这个新的网络也要达到性能100%,则新增加的层要做的事情就是“恒等映射”,也即后面几个紫色的层要实现的效果为 。这样一来,网络的性能一样能达到100%。而退化现象也表明了,实际上新增加的几个紫色的层,很难做到恒等映射。又或者能做到,但在有限的时间内很难完成
而折线(跳连接)把数据原封不动得送到FC层的前面,这意味着粉色的层可以简单地将多个非线性层的权重推向0,只要输出零/零映射,最终输出结果就是恒等映射的,网络实现零映射比直接实现恒等映射容易的多。
实际网络性能通常未能达到100%,可以假设前四层的性能到了98%,如果不添加跳连接,增加三个紫色层之后的新网络同样难以进行优化。而通过跳连接,可以把前四层的输出先送到FC层前面,也就相当于告诉紫色层:”兄弟你放心,我已经做完98%的工作了,你看看能不能在剩下的2%中发点力,你要是找不出提升性能的效果也没事,直接把把参数置零、输出零就行,照样会有98的准确率,不会导致准确率下降。
当然,实际上网络运行的时候,我们并不会知道哪几层就能达到很好的效果,然后在它们的后面接一个跳连接,于是一开始便在两个层或者三个层之间添加跳连接,形成残差块,每个残差块只关注当前的残余映射,而不会关注前面已经实现的底层映射。
作者使用了这两种残差块
深度残差网络:
维度计算(以50-layer为例)
- Input的img为256×256×3,经过矩阵变换得到3×224×224
- conv1_x是经过kernel_size(卷积边长) = 7,in_channel(输入频道数) = 3,output_channel(输出频道数) = 64,stride(步长) = 2,padding(边框边界) = 3的卷积
- 可以计算得到输出矩阵的边长应该为 output_size = (224 - 7 + 3 ×2 ) \ 2 + 1 = 112,因此输出64 × 112 × 112的特征矩阵(feature map)
- conv2_x 经过3 × 3,步长=2,padding = 1的池化后得到(112-3 + 2)\2+1 = 56,因此输出 64 × 56 × 56 的feature map
- 然后再经过如上图所示的三层块结构(BottleBlock)
- 从conv2_x到conv5_x总共经过了(3+4+6+3)=16个BottleBlock块
- 对conv2_x的三个块
- 块1
- F4经过kernel size = 1, in_channel=64, out_channel=64, stride=1的卷积,bn,relu,得到64x56x56的feature map.
接着经过一个kernel size=3,in_channel=64,out_channel=64的卷积,bn,relu,得到64x56x56的feature map.
接着经过一个kernel size=3,in_channel=64,out_channel=256的卷积, - bn得到256x56x56的feature map:F4_1
将F4经过一个kernel size=1,in_channel=64,out_channel=256,stride=1的卷积,bn得到256x56x56的feature map:F4_2
F4_1+F4_2后,再经过激活函数relu得到256x56x56 的 F5
- F4经过kernel size = 1, in_channel=64, out_channel=64, stride=1的卷积,bn,relu,得到64x56x56的feature map.
- 块1
后面略
第一次看时遇到的小问题:
最大池化后已经是64通道了,为啥做3*3的卷积之前还要用1*1卷积?
答:因为这个残差块要用三次,三次后输出要求是256通道的,所以要一种用1*1卷积改维度
上面的网络结构图中:
梯度消失和梯度爆炸:
神经网络反向传播,梯度的计算需要乘激活函数的导数,越靠前的层激活函数的导数的连乘就越多,比如函数是sigmod函数,导数最大值也只能是0.25,连乘就梯度消失;反之如果该值大于1,就梯度爆炸。
梯度消失和梯度爆炸可以通过归一化初始化或中间层归一化来解决;使用relu激活函数也可以一定程度解决(导数是1就不消失爆炸,导数是0直接不更新)