Hippogriff's Blog
首页
C++
  • 算法
  • 数据结构
  • Leetcode
  • 操作系统
  • 计算机网络
  • MySQL
  • 深度学习
  • 网络
收藏
  • 醍醐灌顶
  • 句读
个人书单 (opens new window)
GitHub (opens new window)

Absm

什么也不会
首页
C++
  • 算法
  • 数据结构
  • Leetcode
  • 操作系统
  • 计算机网络
  • MySQL
  • 深度学习
  • 网络
收藏
  • 醍醐灌顶
  • 句读
个人书单 (opens new window)
GitHub (opens new window)
  • 网络

  • 深度学习

    • 常见的图像处理操作函数与功能
    • 关于BN(batch normalization)层
    • 一文读懂神经网络训练中的Batch Size,Epoch,Iteration
    • LSTM与GRU
    • MMDetection文档笔记
    • ResNet笔记
      • 总体
      • input阶段
      • stage层
        • BasicBlock
        • Bottleneck结构
        • 1*1卷积
      • 图片尺寸变化
        • 如何让输入输出保持不变
        • 如何让输出尺寸变成输入尺寸的一半
        • resnet代码中的操作
    • RNN基础
  • 技术
  • 深度学习
Absm
2021-03-14
目录

ResNet笔记

# 总体

整体结构如下:

这里面主要有左侧六个阶段组成,包括input,output在内,还有4个stage。下面分别描述一下各个部分的组成。

# input阶段

输入阶段包括四步,分别为:

        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)
        self.bn1 = nn.BatchNorm2d(64)
        self.relu = nn.ReLU(inplace=True)
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
1
2
3
4

把图片从224*224降成了56*56的大小,简化了后续的计算。

# stage层

这里首先要注意的是,18层和34层使用的是BasicBlock而后面50层以上则使用的是BottleNeck结构,下面分别描述两种结构存在的不同之处。

# BasicBlock

def forward(self, x):
1

这里面forward( )函数规定了网络数据的流向。

# Bottleneck结构

# 1*1卷积

# 图片尺寸变化

# 如何让输入输出保持不变

设

  • 填充$padding = P$

  • 卷积核大小$kernel_size = K$

  • 步长$stride = S$

则经过卷积的输入输出关系为:$output_size = \frac{input_size + 2 \times P - K}{S} + 1$(这里的相除,其实是求商,舍掉小数)

如果想让图片输入输出不发生变化,设S=1,则只需满足$K = 2P+1$即可。

例如$K = 3, P =1, S = 1$,这种设计在resnet中已经被广泛使用。

# 如何让输出尺寸变成输入尺寸的一半

继续利用上面的关系式,只要取$K=3, P=1, S=2$,就可以了,这样算出来的结果为:

$output_size = \frac{input_size + 1}{2}$,因为这个除法实际上是取商,所以得到的最终结果为:

$output_size = \frac{input_size}{2}$

# resnet代码中的操作

为了完成上述的操作,resnet在代码中用_make_layer函数完成,核心代码如下:

  def _make_layer(self, block, planes, blocks, stride=1, dilate=False):

      ……

      layers = []
      layers.append(block(self.inplanes, planes, stride, downsample, self.groups,
                          self.base_width, previous_dilation, norm_layer))
      self.inplanes = planes * block.expansion
      for _ in range(1, blocks):
          layers.append(block(self.inplanes, planes, groups=self.groups,
                              base_width=self.base_width, dilation=self.dilation,
                              norm_layer=norm_layer))
1
2
3
4
5
6
7
8
9
10
11
12

调用时:

self.layer1 = self._make_layer(block, 64, layers[0])
self.layer2 = self._make_layer(block, 128, layers[1], stride=2,
                                       dilate=replace_stride_with_dilation[0])
self.layer3 = self._make_layer(block, 256, layers[2], stride=2,
                                       dilate=replace_stride_with_dilation[1])
self.layer4 = self._make_layer(block, 512, layers[3], stride=2,
                                       dilate=replace_stride_with_dilation[2])
1
2
3
4
5
6
7

可以发现实际上在layer2-4中传递了stride = 2的情况,而在make_layer函数中,只有第一层用了stride,后面统一使用了默认值1,进而保证了尺度保持不变。

参考

[1] https://zhuanlan.zhihu.com/p/54289848

编辑 (opens new window)
上次更新: 2023/03/02, 12:43:17
MMDetection文档笔记
RNN基础

← MMDetection文档笔记 RNN基础→

最近更新
01
少年游·长安古道马迟迟
11-30
02
CMake基础命令
11-08
03
由浅入深剖析OAuth2.0的授权码模式
07-07
更多文章>
Theme by Vdoing | Copyright © 2019-2023 Murray Li | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×