当前位置:   article > 正文

DeeplabV3+(学习笔记1自用)mobilenetv2模型构成_deeplab v3+mobilenetv2

deeplab v3+mobilenetv2

 1.基本block块

 首先是一个block块

  1. class InvertedResidual(nn.Module): # 继承nn.Module的类,用于定义Inverted Residual模块。
  2. def __init__(self, inp, oup, stride, expand_ratio): # expand_ratio 扩展比例(扩展通道数)
  3. super(InvertedResidual, self).__init__() # 父类初始化
  4. self.stride = stride # 创建类属性-步幅
  5. assert stride in [1, 2] # 断言,若stride不等一1或2,则报错,避免参数不合法
  6. hidden_dim = round(inp * expand_ratio) # 计算隐藏层的通道数 round()四舍五入
  7. self.use_res_connect = self.stride == 1 and inp == oup # 如果当前层的步幅为1,并且输入通道数等于输出通道数,则将 self.use_res_connect 设置为 True,表示使用残差连接。
  8. if expand_ratio == 1: # 若扩展比例为1
  9. self.conv = nn.Sequential( # 定义一个层
  10. #--------------------------------------------#
  11. # 进行3x3的逐层卷积,进行跨特征点的特征提取
  12. #--------------------------------------------#
  13. nn.Conv2d(hidden_dim, hidden_dim, 3, stride, 1, groups=hidden_dim, bias=False), # 分组卷积(在这里分组数等于输入通道数,相当于逐层卷积)
  14. BatchNorm2d(hidden_dim), # 归一化
  15. nn.ReLU6(inplace=True), # 激活函数
  16. #-----------------------------------#
  17. # 利用1x1卷积进行通道数的调整
  18. #-----------------------------------#
  19. nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
  20. BatchNorm2d(oup),
  21. )
  22. else: # 若扩展比例不为1
  23. self.conv = nn.Sequential(
  24. #-----------------------------------#
  25. # 利用1x1卷积进行通道数的上升
  26. #-----------------------------------#
  27. nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False), # 输出通道数为hidden_dim
  28. BatchNorm2d(hidden_dim),
  29. nn.ReLU6(inplace=True),
  30. #--------------------------------------------#
  31. # 进行3x3的逐层卷积,进行跨特征点的特征提取
  32. #--------------------------------------------#
  33. nn.Conv2d(hidden_dim, hidden_dim, 3, stride, 1, groups=hidden_dim, bias=False),
  34. BatchNorm2d(hidden_dim),
  35. nn.ReLU6(inplace=True),
  36. #-----------------------------------#
  37. # 利用1x1卷积进行通道数的下降
  38. #-----------------------------------#
  39. nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
  40. BatchNorm2d(oup),
  41. )
  42. def forward(self, x):
  43. if self.use_res_connect: # 如果使用残差网络
  44. return x + self.conv(x)
  45. else:
  46. return self.conv(x)

 一个block块大致就是对输入图像进行通道升维,卷积,再降维的过程,一个基本的模块,MobilenetV2就是由许多这样的模块构成。

2. MobilenetV2网络

  1. class MobileNetV2(nn.Module): # 定义MobileNetV2类模型
  2. def __init__(self, n_class=1000, input_size=224, width_mult=1.): # n_class:模型输出的类别数;width_mult:宽度倍率,用于调整通道数
  3. super(MobileNetV2, self).__init__()
  4. block = InvertedResidual # block等于上面的类本身
  5. input_channel = 32 # 模型初始输入通道数为32
  6. last_channel = 1280 # 模型的最终输出通道数为 1280

定义了block块,设置了一些参数。

  1. # 定义了模型中不同阶段的网络结构,包括扩展比例(t)、输出通道数(c)、重复次数(n)和步幅(s)(是否进行尺寸压缩)
  2. interverted_residual_setting = [
  3. # t, c, n, s
  4. [1, 16, 1, 1],
  5. [6, 24, 2, 2],
  6. [6, 32, 3, 2],
  7. [6, 64, 4, 2],
  8. [6, 96, 3, 1],
  9. [6, 160, 3, 2],
  10. [6, 320, 1, 1],
  11. ]

定义了一个列表,代表网络结构。

t:(通道的扩展比例)        c:(输出的通道数)        n:(模块被重复的次数)

s:(卷积步幅,控制尺寸,步幅大于 1 时,特征图的尺寸会缩小。)

  1. assert input_size % 32 == 0 # 确保输入尺寸能被32整除,否则报错
  2. input_channel = int(input_channel * width_mult) # 根据指定的宽度倍率 width_mult 调整输入通道数 input_channel
  3. # 如果 width_mult 大于 1.0,则将最终输出通道数 last_channel 乘以 width_mult,并将结果转换为整数类型,以更新最终输出通道数。
  4. # 如果 width_mult 小于等于 1.0,则不对输出通道数进行调整,保持其不变。
  5. self.last_channel = int(last_channel * width_mult) if width_mult > 1.0 else last_channel

通道倍率说明

  1. self.features = [conv_bn(3, input_channel, 2)] # features,其中包含了一个使用了 conv_bn 函数的卷积层序列(小网络1)
  2. for t, c, n, s in interverted_residual_setting:
  3. output_channel = int(c * width_mult)
  4. for i in range(n):
  5. if i == 0:
  6. self.features.append(block(input_channel, output_channel, s, expand_ratio=t))
  7. else:
  8. self.features.append(block(input_channel, output_channel, 1, expand_ratio=t))
  9. input_channel = output_channel

创建features列表来存储网络。第一个网络是conv_bn,如下:

  1. def conv_bn(inp, oup, stride): # 小网路1(输入通道数,输出通道数,卷积步幅)
  2. return nn.Sequential(
  3. nn.Conv2d(inp, oup, 3, stride, 1, bias=False), # 3*3卷积 ,填充1圈
  4. BatchNorm2d(oup), # 归一化
  5. nn.ReLU6(inplace=True) # 激活函数
  6. )

后面利用for循环,以block块为基础构建主体网络。外循环次数为7,每轮的内循环次数为每一个子列表的n的值。内循环每轮第一次都进行设置步长的block块内的卷积,如果步长为2,尺寸会缩小一倍,后续步长都为1,尺寸不变。

 输入尺寸为224*224*32,经过上述操作得到输出尺寸为14*14*320

  1. self.features.append(conv_1x1_bn(input_channel, self.last_channel))# 加一个1*1卷积,输出通道数为1280*width_mult
  2. self.features = nn.Sequential(*self.features) # 将特征提取部分的各个操作序列整合为一个神经网络模块 nn.Sequential
  3. self.classifier = nn.Sequential( # 模型分类部分,包含一个丢弃层和全连接层
  4. nn.Dropout(0.2),
  5. nn.Linear(self.last_channel, n_class),
  6. )
  7. self._initialize_weights() # 调用权重初始化函数
  1. def forward(self, x):
  2. x = self.features(x)
  3. x = x.mean(3).mean(2) # 全局平均池化
  4. x = self.classifier(x)
  5. return x
  1. def _initialize_weights(self):
  2. for m in self.modules(): # 遍历模型所有子模块
  3. if isinstance(m, nn.Conv2d): # m模块是否为nn.Conv2d
  4. n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels # 卷积核的高度*宽度*卷积核个数(输出通道),计算了卷积核的参数量
  5. m.weight.data.normal_(0, math.sqrt(2. / n)) # 对卷积层的权重参数进行初始化
  6. if m.bias is not None:
  7. m.bias.data.zero_() # 卷积层偏置项设置为0
  8. elif isinstance(m, BatchNorm2d): # 批量归一化初始化
  9. m.weight.data.fill_(1)
  10. m.bias.data.zero_()
  11. elif isinstance(m, nn.Linear): # 全连接层初始化设置
  12. n = m.weight.size(1)
  13. m.weight.data.normal_(0, 0.01)
  14. m.bias.data.zero_()

参数初始化函数。

下面打印一下整体的网络结构 

  1. if __name__ == "__main__": # 本模块测试
  2. model = mobilenetv2()
  3. for i, layer in enumerate(model.features): # enumerate 函数返回一个迭代器
  4. print(i, layer)

0 Sequential(
  (0): Conv2d(3, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
  (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (2): ReLU6(inplace=True)
)
1 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=32, bias=False)
    (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(32, 16, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (4): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
2 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(16, 96, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(96, 96, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), groups=96, bias=False)
    (4): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(96, 24, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
3 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(24, 144, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(144, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(144, 144, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=144, bias=False)
    (4): BatchNorm2d(144, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(144, 24, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
4 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(24, 144, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(144, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(144, 144, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), groups=144, bias=False)
    (4): BatchNorm2d(144, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(144, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
5 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(32, 192, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(192, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(192, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=192, bias=False)
    (4): BatchNorm2d(192, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(192, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
6 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(32, 192, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(192, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(192, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=192, bias=False)
    (4): BatchNorm2d(192, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(192, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
7 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(32, 192, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(192, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(192, 192, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), groups=192, bias=False)
    (4): BatchNorm2d(192, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(192, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
8 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(64, 384, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(384, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(384, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=384, bias=False)
    (4): BatchNorm2d(384, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(384, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
9 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(64, 384, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(384, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(384, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=384, bias=False)
    (4): BatchNorm2d(384, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(384, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
10 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(64, 384, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(384, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(384, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=384, bias=False)
    (4): BatchNorm2d(384, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(384, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
11 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(64, 384, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(384, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(384, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=384, bias=False)
    (4): BatchNorm2d(384, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(384, 96, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
12 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(96, 576, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(576, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(576, 576, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=576, bias=False)
    (4): BatchNorm2d(576, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(576, 96, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
13 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(96, 576, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(576, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(576, 576, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=576, bias=False)
    (4): BatchNorm2d(576, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(576, 96, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
14 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(96, 576, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(576, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(576, 576, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), groups=576, bias=False)
    (4): BatchNorm2d(576, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(576, 160, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
15 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(160, 960, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(960, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(960, 960, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=960, bias=False)
    (4): BatchNorm2d(960, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(960, 160, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
16 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(160, 960, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(960, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(960, 960, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=960, bias=False)
    (4): BatchNorm2d(960, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(960, 160, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(160, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
17 InvertedResidual(
  (conv): Sequential(
    (0): Conv2d(160, 960, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (1): BatchNorm2d(960, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU6(inplace=True)
    (3): Conv2d(960, 960, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=960, bias=False)
    (4): BatchNorm2d(960, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU6(inplace=True)
    (6): Conv2d(960, 320, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (7): BatchNorm2d(320, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)
18 Sequential(
  (0): Conv2d(320, 1280, kernel_size=(1, 1), stride=(1, 1), bias=False)
  (1): BatchNorm2d(1280, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (2): ReLU6(inplace=True)
)
 

可见,一共有19个网络,其中block块有17个,是第2个到第18个。


3.网络的一些修改

 在另一个deeplabv3_plus.py文件中,定义了一个同名的类。用于对基础的网络进行一些修改,再输出最终结果。

  1. class MobileNetV2(nn.Module):
  2. def __init__(self, downsample_factor=8, pretrained=True):
  3. super(MobileNetV2, self).__init__()
  4. from functools import partial # functools.partial 函数的作用是创建一个新的函数,通过固定一部分参数来生成一个新的可调用对象。
  5. model = mobilenetv2.mobilenetv2(pretrained) # 导入mobilenetv2文件中的mobilenetv2函数,并进行权重初始化
  6. self.features = model.features[:-1] # 取出mobilenetv2网络中除去最后块的网络)(取出了18块网络)
  7. self.total_idx = len(self.features) # 网络的长度 ,这里是18
  8. self.down_idx = [2, 4, 7, 14] # 定义了一个列表,表示特定网络块的索引,在写网络块中进行了下采样

这里降采样倍数设置为8, downsample_factor=8 

self.features 包含了上面第0到第17个网络块,第1个到第17个为block块,我将每个block块中3*3卷积部分的步长提取出来如下图:

 

 self.down_idx   = [2, 4, 7, 14] 就是步长为2(也就是能使宽高变小(下采样))的网络块下标。

  1. def _nostride_dilate(self, m, dilate): # 修改卷积层参数的函数,m是模型层对象
  2. classname = m.__class__.__name__ # m.__class__.__name__ 返回了对象 m 所属类的类名
  3. if classname.find('Conv') != -1: # 如果能找到类名中包含字符串‘Conv’
  4. if m.stride == (2, 2): #如果步幅为2,则改为1
  5. m.stride = (1, 1)
  6. if m.kernel_size == (3, 3): # 修改膨胀率和填充设置
  7. m.dilation = (dilate//2, dilate//2)
  8. m.padding = (dilate//2, dilate//2)
  9. else:
  10. if m.kernel_size == (3, 3): # 如果卷积核大小为 (3, 3),则将膨胀率和填充都设置为 (dilate, dilate)。这一步如果步幅是1,则输出结果尺寸不变
  11. m.dilation = (dilate, dilate)
  12. m.padding = (dilate, dilate)

        这是修改卷积层参数的函数,如果stride=2,则把stride改为1,同时膨胀率和填充都变为设定值整除2。

        如果stride = 1,膨胀率和填充都更改为设定值。

  1. # 根据给定的膨胀率,修改卷积层的参数
  2. if downsample_factor == 8: # 如果下采样倍数为8
  3. for i in range(self.down_idx[-2], self.down_idx[-1]): # i从7-13
  4. self.features[i].apply(
  5. partial(self._nostride_dilate, dilate=2) # 调用_nostride_dilate函数,参数固定为2
  6. )
  7. for i in range(self.down_idx[-1], self.total_idx): # i从14-17
  8. self.features[i].apply(
  9. partial(self._nostride_dilate, dilate=4)
  10. )
  11. elif downsample_factor == 16:
  12. for i in range(self.down_idx[-1], self.total_idx): # 从14到17
  13. self.features[i].apply(
  14. partial(self._nostride_dilate, dilate=2)
  15. )

         代码对卷积层进行修改:如果降采样倍数设置为8,那么第一步i从7遍历到13,对这些块内的3*3卷积进行修改,设定值dilate=2。

        假设输入特征图的大小是 W × H,卷积核大小是 K × K,padding 是 P,stride 是 S,dilate 是 D,则输出特征图的大小可以计算为:

        输出宽度 = [(W + 2 * P - D * (K - 1) - 1) / S] + 1

        输出高度 = [(H + 2 * P - D * (K - 1) - 1) / S] + 1

那么带入函数可知,修改后的7-13网络块,不会对图片尺寸进行改变。(原来7号块会使图像缩小1倍)。

        第二步,i从14遍历到17,对这些块内的3*3卷积进行修改,设定值dilate=4。计算可知14-17网络仍不会对图像尺寸改变。(ps:不懂为什么要分开弄)

所以只有2,4对图像进行下采样,再加上第0号网络也进行了一次下采样,所以一共进行了3次下采样,每次下采样倍数为2,三次就是8。

        同样downsample_factor=16,会有4次下采样,代码中消除了14号网络的下采样,保留了0、2、4、7号网络进行下采样。

  1. def forward(self, x):
  2. low_level_features = self.features[:4](x) # 低层特征(前四层)
  3. x = self.features[4:](low_level_features) # 深层特征(继续传播)
  4. return low_level_features, x

 最后输出前4块层网络为低级特征,输出所有网络为深层特征,继续进行下一步处理(ASPP)。(但是这里并没有包含去除掉的1*1卷积层,有点疑惑)

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

闽ICP备14008679号