Resnet在cnn图像方面有着非常突出的表现,它利用 shortcut 短路连接,解决了深度网络中模型退化的问题。相比普通网络每两层/三层之间增加了短路机制,通过残差学习使深层的网络发挥出作用。
这里提到几个概念:
神经网络层数越多,网络就能进行更加复杂的特征提取,理论上可以取得更好的结果。但实验却发现网络深度增加时,准确度出现饱和,甚至是下降。(这不是过拟合的问题,因为训练误差也很大。而且batch normalization等技术解决了梯度消失和梯度爆炸的问题)
梯度消失和梯度爆炸的解决方法:对输入数据和中间层的数据进行归一化操作,这种方法可以保证网络在反向传播中采用随机梯度下降(SGD),从而让网络达到收敛。但是,这个方法仅对几十层的网络有用,当网络再往深处走的时候,这种方法就无用武之地了。
下图中我们看到56层的网络比20层的效果更差:
残差即观测值与估计值之间的差。
假设我们要建立深层网络,当我们不断堆积新的层,但增加的层什么也不学习(极端情况),那么我们就仅仅复制浅层网络的特征,即新层是浅层的恒等映射(Identity mapping),这样深层网络的性能应该至少和浅层网络一样,那么退化问题就得到了解决。
假设要求解的映射为 H(x),也就是观测值,假设上一层 resnet/上一个残差块输出的特征映射为 x(identity function跳跃连接),也就是估计值。那么我们就可以把问题转化为求解网络的残差映射函数 F(x) = H(x) - x。
如果网络很深,出现了退化问题,那么我们就只需要让我们的残差映射F(x)等于 0,即要求解的映射 H(x)就等于上一层输出的特征映射 x,因为x是当前输出的最佳解,这样我们这一层/残差块的网络状态仍是最佳的一个状态。
但是上面提到的是理想假设,实际情况下残差F(x)不会为0,x肯定是很难达到最优的,但是总会有那么一个时刻它能够无限接近最优解。采用ResNet的话,就只用小小的更新F(x)部分的权重值就行了,可以更好地学到新的特征。
我们再从数学角度分析:
y l = h ( x l ) + F ( x l , W l ) y_l = h(x_l) + F(x_l, W_l) yl=h(xl)+F(xl,Wl)
x l + 1 = f ( y l ) x_{l+1} = f(y_l) xl+1=f(yl)
其中 x l x_l xl 和 x l + 1 x_{l+1} xl+1 代表残差单元的输入和输出, F F F 是我们学习到的残差, h ( x l ) = x l h(x_l) = x_l h(xl)=xl 表示恒等映射, f f f 是relu激活函数。
那么,从浅层 l l l 到深层 L L L 我们学习到的特征就是:
x L = x l + ∑ i = 1 L − 1 F ( x i , W i ) x_L = x_l + \sum_{i=1}^{L-1}F(x_i, W_i) xL=xl+∑i=1L−1F(xi,Wi)
ResNet block有两种,一种两层结构,一种是三层的bottleneck结构,即将两个3x3的卷积层替换为1x1 + 3x3 + 1x1,它通过1x1 conv来巧妙地缩减或扩张feature map维度,从而使得我们的3x3 conv的filters数目不受上一层输入的影响,它的输出也不会影响到下一层。中间3x3的卷积层首先在一个降维1x1卷积层下减少了计算,然后在另一个1x1的卷积层下做了还原。既保持了模型精度又减少了网络参数和计算量,节省了计算时间。
注意:
对于短路连接,如果残差映射F(x)的维度与跳跃连接x的维度不同,那咱们是没有办法对它们两个进行相加操作的,必须对x进行升维操作,让他俩的维度相同时才能计算:
在resnet结构图中,虚线表示feature map数量发生了改变,虚线残差结构有降维的作用,并在捷径分支上通过1x1的卷积核进行降维处理,下面详细讲一下虚线部分的结构:
上图是ResNet18层和ResNet34层网络的虚线残差结构。注意下每个卷积层的步距stride,以及捷径分支上的卷积核的个数(与主分支上的卷积核个数相同)。
上图是ResNet50/101/152的残差结构,在该残差结构当中,主分支使用了三个卷积层:
该残差结构同样在捷径分支上有一层1x1的卷积层,它的卷积核个数与主分支上的第三层卷积层卷积核个数相同,注意每个卷积层的步距。
ResNet网络参考了VGG19网络,在其基础上进行了修改,并通过短路机制加入了残差单元,变化主要体现在ResNet直接使用stride=2的卷积做下采样,并且用global average pool层替换了全连接层。
注意ResNet的激活函数放在跳接之后。
上图中输入图片size为(224, 224, 3)
经过第一个7x7的卷积层,输出channel为64,步长为2,注意pad为3,即在周围填充三圈
经过一个3x3的最大池化层,步长为2,注意pad为1
与VGGNet不同的是,ResNet除了一个3x3的最大池化层,其他下采样全都是使用卷积层实现
如上图,我们称conv2_x、conv3_x、conv4_x、conv5_x为四个卷积组,conv2_x的下采样由最大池化层实现,其他三个卷积组的下采样,都是由邻接上一个卷积组的残差块实现。
那到底哪些残差结构是虚线残差结构呢?对于我们ResNet18/34/50/101/152,表中conv3_x, conv4_x, conv5_x所对应的一系列残差结构的第一层残差结构都是虚线残差结构。因为这一系列残差结构的第一层都有调整输入特征矩阵shape的使命(将特征矩阵的高和宽缩减为原来的一半,将深度channel调整成下一层残差结构所需要的channel)。为了方便理解,下面给出了ResNet34的网络结构图,图中简单标注了一些信息。
对于我们ResNet50/101/152,其实在conv2_x所对应的一系列残差结构的第一层也是虚线残差结构。因为它需要调整输入特征矩阵的channel,根据表格可知通过3x3的max pool之后输出的特征矩阵shape应该是[56, 56, 64],但我们conv2_x所对应的一系列残差结构中的实线残差结构它们期望的输入特征矩阵shape是[56, 56, 256](因为这样才能保证输入输出特征矩阵shape相同,才能将捷径分支的输出与主分支的输出进行相加)。所以第一层残差结构需要将shape从[56, 56, 64] --> [56, 56, 256]。注意,这里只调整channel维度,高和宽不变(而conv3_x, conv4_x, conv5_x所对应的一系列残差结构的第一层虚线残差结构不仅要调整channel还要将高和宽缩减为原来的一半)。
ResNet的一个重要设计原则是:当feature map大小降低一半时,feature map的数量增加一倍,这保持了网络层的复杂度。
改进前后一个明显的变化是采用pre-activation,BN和ReLU都提前了。而且作者推荐短路连接采用恒等变换,这样保证短路连接不会有阻碍。
笔记基于以下参考整理而来:
ResNet详解——通俗易懂版
你必须要知道CNN模型:ResNet
经典分类CNN模型系列其四:Resnet
ResNet系列网络结构
残差resnet网络原理详解
ResNet网络结构详解与模型的搭建
最后一个参考中还给出了视频的讲解链接,有时间再看:
ResNet网络结构详解视频
使用pytorch搭建ResNet并基于迁移学习训练
使用tensorflow搭建ResNet网络并基于迁移学习的方法进行训练