ICNet

一. ICNet网络结构编写

  1. ICNet先将图片分别下采样得到x_sub1, x_sub2, x_sub4三个不同大小的特征图, 再将这三个特征图输入ICHead(包含CFF) 得到四个不同大小的预测结果图。
  2. Cityscapes数据集的dataset和采样器的制作移步:Cityscapes数据集采样器制作

x_sub1 (1/8,channels:64)

三个ConvBNRLU模块,将图片下采样至1/8

self.conv_sub1 = nn.Sequential(
            _ConvBNRLU(3, 32, 3, 2, **kwargs),
            _ConvBNRLU(32, 32, 3,2, **kwargs),
            _ConvBNRLU(32, 64, 3, 2, **kwargs)
)
x_sub1 = self.conv_sub1(x)

x_sub2 ( 1/16,channels:512)

  1. 将原图线性插值至1/2
x_sub2 = F.interpolate(x, scale_factor=0.5, mode='bilinear', align_corners=True)
  1. layer0 + layer1 + layer2 三个模块累计下采样至1/16
x_sub2 = self.resnet.layer0(x_sub2) #1/4
x_sub2 = self.resnet.layer1(x_sub2) 
x_sub2 = self.resnet.layer2(x_sub2) #1/2

x_sub4 ( 1/32,channels:2048)

  1. 将原图线性插值至1/4
x_sub4 = F.interpolate(x, scale_factor=0.25, mode='bilinear', align_corners=True)
  1. layer0 + layer1 + layer2 + layer3 + layer4 五个模块累计下采样至1/32
x_sub4 = self.resnet.layer0(x_sub4)
x_sub4 = self.resnet.layer1(x_sub4)
x_sub4 = self.resnet.layer2(x_sub4) #1/2
x_sub4 = self.resnet.layer3(x_sub4) #1/2
x_sub4 = self.resnet.layer4(x_sub4) #1/2
  1. PPM金字塔池化模块
x_sub4 = self.ppm(x_sub4)

CFF模块(size, channels)

  1. x_sub4(1/32, 2048)插值至(1/16, 2048),再卷积至 A:(1/16, 128)
  2. x_sub2(1/16, 512)卷积至 B:(1/16, 128)
  3. 将上两步的结果A和B叠加得到 x_cff_24:(1/16, 128)
  4. x_cff_24(1/16, 128)插值至(1/8, 128),再卷积至 C:(1/8, 128)
  5. x_sub1(1/8, 64)卷积至 D:(1/8, 128)
  6. 将上两步的C和D叠加得到 x_cff_12

ICHead

1/16 结果图

A(1/16, 128) 卷积至:(1/16, nclass)

1/8结果图

C(1/8, 128) 卷积至:(1/8, nclass)

1/4结果图

x_cff_12插值至:(1/4, 128), 再卷积至 (1/4, nclass)

1结果图

1/4结果图再插值至:(1, nclass)

返回结果

上诉的四张结果图就是ICNet网络返回的预测结果

二. 网络结构细节

layers

  1. 每个layer都由不同数量的block堆叠而成
  2. 每个layer的stride只在第一个block里实现,也就是说:第一个以外的其他block的stride都为1
  3. 每个layer的通道数的转换只在第一个block里实现,也就是说:第一个以外的其他block的in_channels和out_channels是相同的
block_num=[3,4,6,3]
self.layer1 = self._make_layer(64, 256, block_num[0])
self.layer2 = self._make_layer(256, 512, block_num[1], stride=2)
self.layer3 = self._make_layer(512, 1024, block_num[2], stride=2)
self.layer4 = self._make_layer(1024, 2048, block_num[3], stride=2)

block(Bottleneck)

  1. 每个block都由三个卷积层 + 一个残差边 构成
  2. 由layers部分的讲解你会发现,只有每个layers的第一个block的残差边(skip_connection)不是恒等的,既需要改变size(如果该layer的stride !=1),也需要改变channels
  3. 只在第二个卷积层才实现size大小的变化
  4. self.conv1: (in_channels, out_channels/4, 1)
  5. self.conv2: (out_channels/4, out_channels/4, 3, stride)
  6. self.conv3: (out_channels/4, out_channels, 1)
identity = x

out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)

out = self.conv2(out)
out = self.bn2(out)
out = self.relu(out)

out = self.conv3(out)
out = self.bn3(out)

identity = self.skip_connection(x)

out += identity
out = self.relu(out)

return out

PPM金字塔池化

  1. 这是一个简陋的金字塔池化
  2. 只有x_sub4进行了金字塔池化,池化前池化后size和channels都没变
  3. 先将x_sub4 分别平均池化成:1x1, 2x2, 3x3, 6x6 的大小,再线性插值回x_sub4的大小
  4. 将原来的x_sub4 和4份池化再插值后的特征图进行叠加,得到新的x_sub4

三. 实验细节

数据集 Cityscapes
batchsize 16
base_lr 0.01
pl_lr_power 0.9
iter 30k
momentum 0.9
weight_decay 0.0001
\(\lambda_{1,2,3}\) 0.4,0.4,1
posted @ 2022-03-14 19:46  小鸟飞飞11  阅读(380)  评论(0编辑  收藏  举报