残差神经网络ResNet介绍

简介

  • 神经网络层数比较高时,就很难被训练,容易出现梯度爆炸、梯度消失等问题。残差网络就是一种跳跃连接的网络,它通过将前面的激活值跳过中间的网络层而直接传到更后面的网络中,来避免梯度爆炸和梯度消失,训练更深的网络。

残差块

  • 普通的神经网络层

残差神经网络ResNet介绍_第1张图片
一个神经网络在准确率已经达到饱和的情况下,增加网络层数可能会导致梯度爆炸和梯度消失的情况,导致准确率突然下降。
梯度爆炸:激活值会越来越大
梯度消失:激活值会越来越小

  • 残差块

    残差神经网络ResNet介绍_第2张图片
    残差神经网络ResNet介绍_第3张图片
    期望结果H(x)从F(x)变为F(x)+x

  • 通过“shortcut connections(捷径连接)”的方式,直接把输入x传到输出作为初始结果,输出结果为H(x)=F(x)+x,当F(x)=0时,那么H(x)=x,也就是恒等映射。于是,ResNet相当于将学习目标改变了,不再是学习一个完整的输出,而是目标值H(X)和x的差值,

也就是所谓的残差F(x) := H(x)-x,因此,后面的训练目标就是要将残差结果逼近于0,使到随着网络加深,准确率不下降。

  • 若F(x)与x维度相同,则直接相加,若维度不相同,可以使H(x)=F(x)+Wx,通过一层卷积来调整x的维度,使得能与F(x)相加

好处

  • 缓解梯度爆炸

  • 缓解梯度消失(梯度弥散)

    残差神经网络ResNet介绍_第4张图片
    在反向传播时,梯度由两部分组成,其中对x的直接映射梯度为1,另一部分是多层普通神经网络映射的梯度
    反向传播
    这样即使普通神经网络的梯度已经为0,仍然还有一个1的存在,有效地缓解了梯度弥散的情况。
    残差神经网络ResNet介绍_第5张图片

    代码实现

    当F(x)与x维度相同时

    残差神经网络ResNet介绍_第6张图片

    # 维度相同时的残差块
    def identity_block(X, f, filters, stage, block):
        """
        实现了上图中展示的残差块
    
        参数:
        X -- 要跳跃的激活值矩阵
        f -- 整型。指示卷积层的窗口大小
        filters -- 整型数组,指示残差块中的卷积层的过滤器的个数
        stage -- 整型。用来辅助给网络层取名。
        block -- 字符串。用来辅助给网络层取名。
    
        返回:
        X -- 残差块的最终输出矩阵
        """
    
        # 取一些名字而已,无关紧要
        conv_name_base = 'res' + str(stage) + block + '_branch'
        bn_name_base = 'bn' + str(stage) + block + '_branch'
    
        # 获取每一个卷积层对应的过滤器的个数
        F1, F2, F3 = filters
    
        # 保存输入的激活值,以便后面跳插入到后面的网络层中
        X_shortcut = X
    
        # 主路中的第一组网络层,就是图4的第一组绿橙黄小方块
        X = Conv2D(filters=F1, kernel_size=(1, 1), strides=(1, 1), padding='valid', name=conv_name_base + '2a', kernel_initializer=glorot_uniform(seed=0))(X)
        X = BatchNormalization(axis=3, name=bn_name_base + '2a')(X)
        X = Activation('relu')(X)
    
    
        # 主路中的第二组网络层,就是上图的第二组绿橙黄小方块
        X = Conv2D(filters=F2, kernel_size=(f, f), strides=(1, 1), padding='same', name=conv_name_base + '2b', kernel_initializer=glorot_uniform(seed=0))(X)
        X = BatchNormalization(axis=3, name=bn_name_base + '2b')(X)
        X = Activation('relu')(X)
    
        # 主路中的第三组网络层,图4的第三组绿橙小方块
        X = Conv2D(filters=F3, kernel_size=(1, 1), strides=(1, 1), padding='valid', name=conv_name_base + '2c', kernel_initializer=glorot_uniform(seed=0))(X)
        X = BatchNormalization(axis=3, name=bn_name_base + '2c')(X)
    
        # 这一步就是实现小路的地方。其实就是简单的将前面层的激活值X_shortcut与第三组网络层的输出激活值合并在一起
        # 然后将合并的激活值向下传入到激活函数中,进入到后面的神经网络中去
        X = Add()([X, X_shortcut])
        X = Activation('relu')(X)
    
        return X
    

    当F(x)与x维度不同时

    残差神经网络ResNet介绍_第7张图片

    # 实现上图中的残差块
    def convolutional_block(X, f, filters, stage, block, s=2):
        
        conv_name_base = 'res' + str(stage) + block + '_branch'
        bn_name_base = 'bn' + str(stage) + block + '_branch'
    
        F1, F2, F3 = filters
    
        X_shortcut = X
    
        X = Conv2D(filters=F1, kernel_size=(1, 1), strides=(s, s), padding='valid', name=conv_name_base + '2a', kernel_initializer=glorot_uniform(seed=0))(X)
        X = BatchNormalization(axis=3, name=bn_name_base + '2a')(X)
        X = Activation('relu')(X)
    
    
        X = Conv2D(filters=F2, kernel_size=(f, f), strides=(1, 1), padding='same', name=conv_name_base + '2b', kernel_initializer=glorot_uniform(seed=0))(X)
        X = BatchNormalization(axis=3, name=bn_name_base + '2b')(X)
        X = Activation('relu')(X)
    
        X = Conv2D(filters=F3, kernel_size=(1, 1), strides=(1, 1), padding='valid', name=conv_name_base + '2c', kernel_initializer=glorot_uniform(seed=0))(X)
        X = BatchNormalization(axis=3, name=bn_name_base + '2c')(X)
    
        # 在小路上面加上一个卷积层和一个BatchNormalization
        # 卷积层会改变X_shortcut的维度,这样一来,就能与X矩阵合并在一起了
        X_shortcut = Conv2D(filters=F3, kernel_size=(1, 1), strides=(s, s), padding='valid', name=conv_name_base + '1', kernel_initializer=glorot_uniform(seed=0))(X_shortcut)
        X_shortcut = BatchNormalization(axis=3, name=bn_name_base + '1')(X_shortcut)
    
        # 将变维后的X_shortcut与X合并在一起
        X = Add()([X, X_shortcut])
        X = Activation('relu')(X)
    
        return X
    
    

你可能感兴趣的:(Python,人工智能,神经网络,卷积,resnet,tensorflow,深度学习)