无论是VGGNet还是GoogleNet,都通过增加网络深度使得网络获得了性能上的巨大成功。但是事实上,并不能简单地通过在深度上堆叠网络来达到获得性能更好的网络模型的目的,其原因有二:一是增加网络深度会带来梯度消失和梯度爆炸的问题,当然这可以通过归一化处理和Batch Normalization得到很大程度的解决;二是退化问题,如图3.22所示,即随着网络深度增加,精度达到饱和,继续增加深度,反而会导致精度快速下降,误差增大。56层神经网络的表现明显要比20层的差,这说明更深的网络在训练过程中的难度更大,因此何恺明提出了ResNet残差网络来解决这个问题。
图3.22 56层和20层网络误差比较
残差网络依旧保留其他神经网络的非线性层的输出 F ( x ),但从输入直接引入一个跳转连接到非线性层的输出上,使得整个映射变为
这就是残差网路的核心公式,换句话说,残差是网络搭建的一种操作,任何使用了这种操作的网络都可以称之为残差网络。一个具体的残差模块的定义如图3.23所示,一个残差模块有2条路径 F ( x )和 x : F ( x )路径拟合残差 H ( x ) -x ,可称为残差路径, x 路径为恒等映射(identity mapping),称其为“shortcut”。让特征矩阵隔层相加,需要注意 F ( x )和 x 形状要相同。所谓相加,是特征矩阵相同位置上的数字进行相加。在图3.23中, 为逐元素相加(element-wise addition),所以要求参与运算的 F ( x )和 x 的尺寸必须相同。
图3.23 残差模块
可以认为残差网络的原理其实是让模型的内部结构至少有恒等映射的能力,以保证在堆叠网络的过程中,网络至少不会因为继续堆叠而产生退化。
ResNet就是通过不断堆叠这种残差模块来得到不同层数的网络模型。表3.4共提出了5种深度的ResNet,分别是18、34、50、101和152。首先看表最左侧,这些ResNet网络都分成5部分,分别是:conv1、conv2_x、conv3_x、conv4_x、conv5_x。
表3.4 典型的ResNet
以101层为例,首先有个输入7×7×64的卷积,然后经过3+4+23+3=33个building block,每个block为3层,所以有33×3=99层,最后有个fc层(用于分类),所以1+99+1=101层,总共实有101层网络。需要注意的是,101层网络仅仅指卷积或者全连接层,而激活层或者池化层并没有计算在内。
比较50层和101层,可以发现,它们唯一的不同在于conv4_x。ResNet50有6个block,而ResNet101有23个block,相差17个block,也就是17×3=51层。
ResNet使用的残差模块有两种结构:一种是两层结构BasicBlock,如图3.24a所示,ResNet18/34采用的残差块是BasicBlock;另一种是三层结构Bot-tleneck,如图3.24b所示。第一层的1×1的卷积核的作用是对特征矩阵进行降维操作,将特征矩阵的维度由256降为64;第三层的1×1的卷积核是对特征矩阵进行升维操作,将特征矩阵的维度由64升成256。降低特征矩阵的维度主要是为了减少参数的个数。如果采用BasicBlock,则参数的个数为256×256×3×3×2=1179648;而采用Bottleneck,参数的个数为1×1×256×64+3×3×64×64+1×1×256×64=69632。先降后升为了主分支上输出的特征矩阵和捷径分支上输出的特征矩阵形状相同,以便进行加法操作。ResNet50/101/152采用的是Bottleneck残差块。
图3.24 残差模块结构