当前位置:   article > 正文

残差网络ResNet_残差块代码

残差块代码

经典传统网络,看到残差时,不得不做个笔记因为太重要了

VGG中,卷积网络达到了19层,在GoogLeNet中,网络史无前例的达到了22层。那么,网络的精度会随着网络的层数增多而增多吗?在深度学习中,网络层数增多一般会伴着下面几个问题

计算资源的消耗
模型容易过拟合
梯度消失/梯度爆炸问题的产生

问题1可以通过GPU集群来解决,对于一个企业资源并不是很大的问题;问题2的过拟合通过采集海量数据,并配合Dropout正则化等方法也可以有效避免;问题3通过Batch Normalization也可以避免。貌似我们只要无脑的增加网络的层数,我们就能从此获益,但实验数据给了我们当头一棒。
作者发现,随着网络层数的增加,网络发生了退化(degradation)的现象:随着网络层数的增多,训练集loss逐渐下降,然后趋于饱和,当你再增加网络深度的话,训练集loss反而会增大。注意这并不是过拟合,因为在过拟合中训练loss是一直减小的。
当网络退化时,浅层网络能够达到比深层网络更好的训练效果,这时如果我们把低层的特征传到高层,那么效果应该至少不比浅层的网络效果差,或者说如果一个VGG-100网络在第98层使用的是和VGG-16第14层一模一样的特征,那么VGG-100的效果应该会和VGG-16的效果相同。所以,我们可以在VGG-100的98层和14层之间添加一条直接映射(Identity Mapping)来达到此效果。
从信息论的角度讲,由于DPI(数据处理不等式)的存在,在前向传输的过程中,随着层数的加深,Feature Map包含的图像信息会逐层减少,而ResNet的直接映射的加入,保证了L+1 层的网络一定比 lL层包含更多的图像信息。

基于这种使用直接映射来连接网络不同层直接的思想,残差网络应运而生。

  1. 残差网络
    1.1 残差块
    残差网络是由一系列残差块组成的(图1)。一个残差块可以用表示为:在这里插入图片描述
    在这里插入图片描述
    残差块
    图1中的Weight在卷积网络中是指卷积操作,addition是指单位加操作。
    在这里插入图片描述
    在这里插入图片描述
    一般,这种版本的残差块叫做resnet_v1,keras代码实现如下:
def res_block_v1(x, input_filter, output_filter):
    res_x = Conv2D(kernel_size=(3,3), filters=output_filter, strides=1, padding='same')(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)
    res_x = BatchNormalization()(res_x)
    if input_filter == output_filter:
        identity = x
    else: #需要升维或者降维
        identity = Conv2D(kernel_size=(1,1), filters=output_filter, strides=1, padding='same')(x)
    x = keras.layers.add([identity, res_x])
    output = Activation('relu')(x)
    return output
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

1.2 残差网络
残差网络的搭建分为两步:

使用VGG公式搭建Plain VGG网络
在Plain VGG的卷积网络之间插入Identity Mapping,注意需要升维或者降维的时候加入 [公式] 卷积。
在实现过程中,一般是直接stack残差块的方式。

def resnet_v1(x):
    x = Conv2D(kernel_size=(3,3), filters=16, strides=1, padding='same', activation='relu')(x)
    x = res_block_v1(x, 16, 16)
    x = res_block_v1(x, 16, 32)
    x = Flatten()(x)
    outputs = Dense(10, activation='softmax', kernel_initializer='he_normal')(x)
    return outputs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

1.3 为什么叫残差网络
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过分析残差网络的正向和反向两个过程,我们发现,当残差块满足上面两个假设时,信息可以非常畅通的在高层和低层之间相互传导,说明这两个假设是让残差网络可以训练深度模型的充分条件。那么这两个假设是必要条件吗?
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
图3:直接映射的变异模型
在这里插入图片描述
图4:变异模型(均为110层)在Cifar10数据集上的表现
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
图5:激活函数在残差网络中的使用
在这里插入图片描述
而实验结果也表明将激活函数移动到残差部分可以提高模型的精度。

该网络一般就在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 output

def 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 outputs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在这里插入图片描述
参考链接:https://zhuanlan.zhihu.com/p/42706477

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/195919
推荐阅读
相关标签
  

闽ICP备14008679号