365天深度学习训练营-第J2周:ResNet50V2算法实战与解析

 目录

 一、前言

二、论文解读

1、ResNetV2结构与ResNet结构对比

2、关于残差结构的不同尝试

          3、关于激活的尝试

三、模型复现

1.Residual Block

3、ResNet50V2架构复现

 4.ResNet50V2模型结构大图


 一、前言

● 难度:夯实基础⭐⭐
● 语言:Python3、Pytorch3
● 时间:2月10日-2月17日
🍺要求:

1.根据本文的Tensorflow代码,编写Pytorch代码
2.了解ResnetV2和Resnet的区别
3.改进地方可以迁移到哪里呢

二、论文解读

论文:Identity Mappings in Deep Residual Networks

论文的主要贡献:

分析了残差块的传播公式

提出了一种新的残差单元

从理论上证明为什么残差网络有效(为什么可以让梯度在网络中顺畅传递而不会爆炸和消失)

1、ResNetV2结构与ResNet结构对比

🧲 改进点:

(a)original表示原始的ResNet的残差结构,(b)proposed表示新的ResNet的残差结构。

主要差别就是

(a)结构先卷积后进行BN和激活函数计算,最后执行addition后再进行ReLU计算;(b)结构先进性BN和激活函数计算后卷积,把addition后的ReLU计算放到了残差结构内部。

📌 改进结果:作者使用这两种不同的结构再CIFAR-10数据集上做测试,模型用的是1001层的ResNet模型。从图中的结果我们可以看出,(b)proposed的测试集错误率明显更低一些,达到了4.92%的错误率。(a)original的测试集错误率是7.61%

2、关于残差结构的不同尝试

 (b-f)中的快捷连接被不同的组件阻碍。为了简化插图,我们不显示BN层,这里所有的单位均采用权值层之后的BN层。图中(a-f)都是作者对残差结构的shortcut部分进行的不同尝试,作者对不同shortcut结构的尝试结果如下表所示。

作者用不同的shortcut结构的ResNet-110在CIFAR-10数据集上做测试,发现最原始的(a)original结构是最好的,也就是identity mapping恒等映射是最好的。

 3、关于激活的尝试

 

 最好的结果是(e)full pre-activation,其次是(a)original。

三、模型复现

1.Residual Block

''' 残差块
Arguments:
    x: 输入张量
    filters: integer, filters, of the bottleneck layer.
    kernel_size: default 3, kernel size of the bottleneck layer.
    stride: default 1, stride of the first layer.
    conv_shortcut: default False, use convolution shortcut if True, otherwise identity shortcut.
    name: string, block label.
Returns:
    Output tensor for the residual block.
'''
def block2(x, filters, kernel_size=3, stride=1, conv_shortcut=False, name=None):
    preact = BatchNormalization(name=name+'_preact_bn')(x)
    preact = Activation('relu', name=name+'_preact_relu')(preact)
    
    if conv_shortcut:
        shortcut = Conv2D(4*filters, 1, strides=stride, name=name+'_0_conv')(preact)
    else:
        shortcut = MaxPooling2D(1, strides=stride)(x) if stride>1 else x
    
    x = Conv2D(filters, 1, strides=1, use_bias=False, name=name+'_1_conv')(preact)
    x = BatchNormalization(name=name+'_1_bn')(x)
    x = Activation('relu', name=name+'_1_relu')(x)
    
    x = ZeroPadding2D(padding=((1, 1), (1, 1)), name=name+'_2_pad')(x)
    x = Conv2D(filters, kernel_size, strides=stride, use_bias=False, name=name+'_2_conv')(x)
    x = BatchNormalization(name=name+'_2_bn')(x)
    x = Activation('relu', name=name+'_2_relu')(x)
    
    x = Conv2D(4*filters, 1, name=name+'_3_conv')(x)
    x = layers.Add(name=name+'_out')([shortcut, x])
    return x

2.堆叠Residual Block

def stack2(x, filters, blocks, stride1=2, name=None):
    x = block2(x, filters, conv_shortcut=True, name=name+'_block1')
    for i in range(2, blocks):
        x = block2(x, filters, name=name+'_block'+str(i))
    x = block2(x, filters, stride=stride1, name=name+'_block'+str(blocks))
    return x

3、ResNet50V2架构复现

''' 构建ResNet50V2 '''
def ResNet50V2(include_top=True,  # 是否包含位于网络顶部的全链接层
               preact=True,  # 是否使用预激活
               use_bias=True,  # 是否对卷积层使用偏置
               weights='imagenet',
               input_tensor=None,  # 可选的keras张量,用作模型的图像输入
               input_shape=None,
               pooling=None,
               classes=1000,  # 用于分类图像的可选类数
               classifer_activation='softmax'):  # 分类层激活函数
    img_input = Input(shape=input_shape)
    x = ZeroPadding2D(padding=((3, 3), (3, 3)), name='conv1_pad')(img_input)
    x = Conv2D(64, 7, strides=2, use_bias=use_bias, name='conv1_conv')(x)
    
    if not preact:
        x = BatchNormalization(name='conv1_bn')(x)
        x = Activation('relu', name='conv1_relu')(x)
    
    x = ZeroPadding2D(padding=((1, 1), (1, 1)), name='pool1+pad')(x)
    x = MaxPooling2D(3, strides=2, name='pool1_pool')(x)
    
    x = stack2(x, 64, 3, name='conv2')
    x = stack2(x, 128, 4, name='conv3')
    x = stack2(x, 256, 6, name='conv4')
    x = stack2(x, 512, 3, strides=1, name='conv5')
    
    if preact:
        x = BatchNormalization(name='post_bn')(x)
        x = Activation('relu', name='post_relu')(x)
    if include_top:
        x = GlobalAveragePooling2D(name='avg_pool')(x)
        x = Dense(classes, activation=classifer_activation, name='predictions')(x)
    else:
        if pooling=='avg':
            # GlobalAveragePooling2D就是将每张图片的每个通道值各自加起来再求平均,
            # 最后结果是没有了宽高维度,只剩下个数与平均值两个维度
            # 可以理解成变成了多张单像素图片
            x = GlobalAveragePooling2D(name='avg_pool')(x)
        elif pooling=='max':
            x = GlobalMaxPooling2D(name='max_pool')(x)
    
    model = Model(img_input, x, name='resnet50v2')
    return model

 4.ResNet50V2模型结构大图

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值