飞道的博客

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

505人阅读  评论(0)

 目录

 一、前言

二、论文解读

1、ResNetV2结构与ResNet结构对比

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

          3、关于激活的尝试

三、模型复现

1.Residual Block

3、ResNet50V2架构复现

 4.ResNet50V2模型结构大图


 一、前言


  
  1. ● 难度:夯实基础⭐⭐
  2. ● 语言:Python 3、Pytorch 3
  3. ● 时间: 210日- 217
  4. 🍺要求:
  5. 1.根据本文的Tensorflow代码,编写Pytorch代码
  6. 2.了解ResnetV 2和Resnet的区别
  7. 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


  
  1. ''' 残差块
  2. Arguments:
  3. x: 输入张量
  4. filters: integer, filters, of the bottleneck layer.
  5. kernel_size: default 3, kernel size of the bottleneck layer.
  6. stride: default 1, stride of the first layer.
  7. conv_shortcut: default False, use convolution shortcut if True, otherwise identity shortcut.
  8. name: string, block label.
  9. Returns:
  10. Output tensor for the residual block.
  11. '''
  12. def block2( x, filters, kernel_size=3, stride=1, conv_shortcut=False, name=None):
  13. preact = BatchNormalization(name=name+ '_preact_bn')(x)
  14. preact = Activation( 'relu', name=name+ '_preact_relu')(preact)
  15. if conv_shortcut:
  16. shortcut = Conv2D( 4*filters, 1, strides=stride, name=name+ '_0_conv')(preact)
  17. else:
  18. shortcut = MaxPooling2D( 1, strides=stride)(x) if stride> 1 else x
  19. x = Conv2D(filters, 1, strides= 1, use_bias= False, name=name+ '_1_conv')(preact)
  20. x = BatchNormalization(name=name+ '_1_bn')(x)
  21. x = Activation( 'relu', name=name+ '_1_relu')(x)
  22. x = ZeroPadding2D(padding=(( 1, 1), ( 1, 1)), name=name+ '_2_pad')(x)
  23. x = Conv2D(filters, kernel_size, strides=stride, use_bias= False, name=name+ '_2_conv')(x)
  24. x = BatchNormalization(name=name+ '_2_bn')(x)
  25. x = Activation( 'relu', name=name+ '_2_relu')(x)
  26. x = Conv2D( 4*filters, 1, name=name+ '_3_conv')(x)
  27. x = layers.Add(name=name+ '_out')([shortcut, x])
  28. return x

2.堆叠Residual Block


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

3、ResNet50V2架构复现


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

 4.ResNet50V2模型结构大图

 


转载:https://blog.csdn.net/m0_58585940/article/details/129078152
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场