在VGG中,卷积网络达到了19层,在谷歌网络中,网络史无前例地达到了22层。 那么,网络的精度会随着网络层数的增加而增加吗? 在深度学习中,随着网络层数的增加,通常会出现以下问题
计算资源消耗模型容易拟合的梯度消失/梯度爆炸问题的产生问题1可以通过GPU集群解决,对一个企业资源不是大问题; 通过收集大量数据并结合Dropout规范化等方法也能有效地避免问题2的拟合[4]; 问题Batch Normalization也可以避免。 我们似乎不用大脑,只需要增加网络层数就能获益,但实验数据让我们头疼不已。
作者发现,随着网络层数的增加,出现了网络退化的现象。 随着网络层数的增加,训练集loss逐渐降低,然后趋于饱和,而sqdzfj随着网络深度的进一步增加,训练集loss反而增大。 请注意,这不是过度拟合。 因为通过过度拟合训练loss一直在减少。
网络老化后,浅层网络可以获得比深层网络更好的训练效果。 此时,如果把低层的特征传达给上层,效果至少应该不比浅层网络差。 或者,如果某个VGG-100网络在第98层使用了与VGG-16第14层一模一样的特征,则VGG-100的效果应该与VGG-16的效果相同。 因此,可以通过在VGG-100的98层和14层之间添加“直接映射”(Identity Mapping )来获得该效果。
在信息论中,由于DPI (数据处理不等式)的存在,在前向传输过程中,随着层数变深,功能图中包含的图像信息逐层减少,但由于ResNet的直接映射的加入,各层网络必然包含比各层更多的图像信息
基于使用这种直接映射连接网络不同层的直接思想,残差网络应运而生。
1 .残差网络1.1残差块残差网络由一系列残差块构成(图1 )。 残差块可以表示为:
残差块分为两个部分直接映射部分和残差部分。 是直接映射,反应在图1中为左曲线; 残差部分,一般由两个或三个卷积操作组成。 即,图1中右侧包含卷积的部分。
图1 :残差块
图1的Weight在卷积网络中是指卷积操作,addition是指单位加操作。
在卷积网络中,其可能与原始特征映射的数目不同,并且在该情况下,必须使用卷积来执行向上维度或向下维度(图2 )。 此时,残差块表示如下。
其中。 其中,关于卷积操作,实验结果的卷积对模型的性能提高是有限制的,所以一般只在提高维度或降低维度时使用。
图2:1*1残差块
通常,此版本的残差块称为resnet_v1,keras代码实现如下:
defRES_block_V1(x,input_filter,output_filter ) : RES _ x=conv 2d (kernel _ size=(3,3 ),filters padding='same'(x ) res_x=BatchNormalization ) ) res_x ) res_x ) RES strides=1, padding='same'(res_x ) res_x=BatchNormalization ) (RES_x ) if input _ filter==output _ filter 33650 id dter维filters=output_filter,strides=1,padding='same ' ) x ) ) x RES_x](output=activation(relu ) x ) retururer
使用VGG表达式构建Plain VGG网络,并在Plain VGG卷积网络之间插入身份映射。 请注意,如果需要提升维或需要降低维,请添加卷积。 在实现过程中,通常是直接堆叠堆栈残差块的方式。
defresnet_v1(x ) : x=conv 2d (kernel _ size=(3,3 ),filters=16,strides=1,padding='same ',activate
se(10, activation='softmax', kernel_initializer='he_normal')(x) return outputs1.3 为什么叫残差网络
在统计学中,残差和误差是非常容易混淆的两个概念。误差是衡量观测值和真实值之间的差距,残差是指预测值和观测值之间的差距。对于残差网络的命名原因,作者给出的解释是,网络的一层通常可以看做 , 而残差网络的一个残差块可以表示为 ,也就是 ,在单位映射中, 便是观测值,而 是预测值,所以 便对应着残差,因此叫做残差网络。
2. 残差网络的背后原理残差块一个更通用的表示方式是
现在我们先不考虑升维或者降维的情况,那么在[1]中, 是直接映射, 是激活函数,一般使用ReLU。我们首先给出两个假设:
假设1: 是直接映射;假设2: 是直接映射。那么这时候残差块可以表示为:
对于一个更深的层 ,其与 层的关系可以表示为
这个公式反应了残差网络的两个属性:
层可以表示为任意一个比它浅的l层和他们之间的残差部分之和; , 是各个残差块特征的单位累和,而MLP是特征矩阵的累积。根据BP中使用的导数的链式法则,损失函数 关于 的梯度可以表示为
上面公式反映了残差网络的两个属性:
在整个训练过程中, 不可能一直为 ,也就是说在残差网络中不会出现梯度消失的问题。 表示 层的梯度可以直接传递到任何一个比它浅的 层。通过分析残差网络的正向和反向两个过程,我们发现,当残差块满足上面两个假设时,信息可以非常畅通的在高层和低层之间相互传导,说明这两个假设是让残差网络可以训练深度模型的充分条件。那么这两个假设是必要条件吗?
2.1 直接映射是最好的选择对于假设1,我们采用反证法,假设 ,那么这时候,残差块(图3.b)表示为
对于更深的L层
为了简化问题,我们只考虑公式的左半部分 ,损失函数 对 求偏微分得
上面公式反映了两个属性:
当 时,很有可能发生梯度爆炸;当 时,梯度变成0,会阻碍残差网络信息的反向传递,从而影响残差网络的训练。所以 必须等1。同理,其他常见的激活函数都会产生和上面的例子类似的阻碍信息反向传播的问题。
对于其它不影响梯度的 ,例如LSTM中的门机制(图3.c,图3.d)或者Dropout(图3.f)以及[1]中用于降维的 卷积(图3.e)也许会有效果,作者采用了实验的方法进行验证,实验结果见图4
图3:直接映射的变异模型
图4:变异模型(均为110层)在Cifar10数据集上的表现
从图4的实验结果中我们可以看出,在所有的变异模型中,依旧是直接映射的效果最好。下面我们对图3中的各种变异模型的分析
Exclusive Gating:在LSTM的门机制中,绝大多数门的值为0或者1,几乎很难落到0.5附近。当 时,残差块变成只有直接映射组成,阻碍卷积部分特征的传播;当 时,直接映射失效,退化为普通的卷积网络;Short-cut only gating: 时,此时网络便是[1]提出的直接映射的残差网络; 时,退化为普通卷积网络;Dropout:类似于将直接映射乘以 ,所以会影响梯度的反向传播; conv: 卷积比直接映射拥有更强的表示能力,但是实验效果却不如直接映射,说明该问题更可能是优化问题而非模型容量问题。所以我们可以得出结论:假设1成立,即
2.2 激活函数的位置
[1] 提出的残差块可以详细展开如图5.a,即在卷积之后使用了BN做归一化,然后在和直接映射单位加之后使用了ReLU作为激活函数。
图5:激活函数在残差网络中的使用
在2.1节中,我们得出假设“直接映射是最好的选择”,所以我们希望构造一种结构能够满足直接映射,即定义一个新的残差结构 :
上面公式反应到网络里即将激活函数移到残差部分使用,即图5.c,这种在卷积之后使用激活函数的方法叫做post-activation。然后,作者通过调整ReLU和BN的使用位置得到了几个变种,即5.d中的ReLU-only pre-activation和5.d中的 full pre-activation。作者通过对照试验对比了这几种变异模型,结果见图6。
图6:基于激活函数位置的变异模型在Cifar10上的实验结果
而实验结果也表明将激活函数移动到残差部分可以提高模型的精度。
该网络一般就在resnet_v2,keras实现如下:
def res_block_v2(x, input_filter, output_filter): res_x = BatchNormalization()(x) res_x = Activation('relu')(res_x) res_x = Conv2D(kernel_size=(3,3), filters=output_filter, strides=1, padding='same')(res_x) res_x = BatchNormalization()(res_x) res_x = Activation('relu')(res_x) res_x = Conv2D(kernel_size=(3,3), filters=output_filter, strides=1, padding='same')(res_x) if input_filter == output_filter: identity = x else: #需要升维或者降维 identity = Conv2D(kernel_size=(1,1), filters=output_filter, strides=1, padding='same')(x) output= keras.layers.add([identity, res_x]) return outputdef resnet_v2(x): x = Conv2D(kernel_size=(3,3), filters=16 , strides=1, padding='same', activation='relu')(x) x = res_block_v2(x, 16, 16) x = res_block_v2(x, 16, 32) x = BatchNormalization()(x) y = Flatten()(x) outputs = Dense(10, activation='softmax', kernel_initializer='he_normal')(y) return outputs3.残差网络与模型集成
Andreas Veit等人的论文[3]指出残差网络可以从模型集成的角度理解。如图7所示,对于一个3层的残差网络可以展开成一棵含有8个节点的二叉树,而最终的输出便是这8个节点的集成。而他们的实验也验证了这一点,随机删除残差网络的一些节点网络的性能变化较为平滑,而对于VGG等stack到一起的网络来说,随机删除一些节点后,网络的输出将完全随机。
图7:残差网络展开成二叉树
Reference[1] He K, Zhang X, Ren S, et al. Deep residual learning for image recognition[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2016: 770-778.
[2] He K, Zhang X, Ren S, et al. Identity mappings in deep residual networks[C]//European Conference on Computer Vision. Springer, Cham, 2016: 630-645.
[3] Veit A, Wilber M J, Belongie S. Residual networks behave like ensembles of relatively shallow networks[C]//Advances in Neural Information Processing Systems. 2016: 550-558.
[4]. Srivastava N, Hinton G, Krizhevsky A, et al. Dropout: a simple way to prevent neural networks from overfitting. In JMLR, 2014.