本文件其实和msra_resnet.py类似,进入博文,这里只把两者的不同说下,不同的部分有以下几处,总体感觉作者在这里添加DCN模块很牵强(仅个人吐槽),其实就是把ResNet的输出先经过可变形卷积,然后再经过反卷积,这样迭代了三次,最终得到分类和回归的特征图,通道个数为64,没有用到类似于FPN的特征图融合。加入可变形卷积,可能对反卷积有帮助吧:
# 反卷积操作的通道不同
# used for deconv layers
self.deconv_layers = self._make_deconv_layer(
3,
[256, 128, 64],
[4, 4, 4],
)
# 网络的头部设置不同
for head in self.heads:
classes = self.heads[head]# 获取头部操作
if head_conv > 0:# head_conv=64
# 经过一个 3*3卷积 然后经过 1*1卷积进行调整维度
fc = nn.Sequential(
nn.Conv2d(64, head_conv,
kernel_size=3, padding=1, bias=True),
nn.ReLU(inplace=True),
nn.Conv2d(head_conv, classes,
kernel_size=1, stride=1,
padding=0, bias=True))
if 'hm' in head:# 热图部分偏置置为-2.19
fc[-1].bias.data.fill_(-2.19)
else:
fill_fc_weights(fc)
else:
fc = nn.Conv2d(64, classes,
kernel_size=1, stride=1,
padding=0, bias=True)
if 'hm' in head:
fc.bias.data.fill_(-2.19)
else:
fill_fc_weights(fc)
self.__setattr__(head, fc)
# 反卷积层的设置的时候,在该函数中相当于在反卷积操作前,设置了 一层可变形卷积
def _make_deconv_layer(self, num_layers, num_filters, num_kernels):
assert num_layers == len(num_filters), \
'ERROR: num_deconv_layers is different len(num_deconv_filters)'
assert num_layers == len(num_kernels), \
'ERROR: num_deconv_layers is different len(num_deconv_filters)'
layers = []
for i in range(num_layers):
kernel, padding, output_padding = \
self._get_deconv_cfg(num_kernels[i], i)
planes = num_filters[i]# 256,128,64
# 使用可变形卷积 V2
#256 2048*3*3 ,128 256*3*3, 64 128*3*3
# 可变形模块初始化 权重 和 偏置 均置为 0
# 其实可以直接用 fill_fc_weights 初始化。
fc = DCN(self.inplanes, planes,
kernel_size=(3,3), stride=1,
padding=1, dilation=1, deformable_groups=1)
# fc = nn.Conv2d(self.inplanes, planes,
# kernel_size=3, stride=1,
# padding=1, dilation=1, bias=False)
# fill_fc_weights(fc)
# 反卷积
up = nn.ConvTranspose2d(
in_channels=planes,
out_channels=planes,
kernel_size=kernel,
stride=2,
padding=padding,
output_padding=output_padding,
bias=self.deconv_with_bias)
fill_up_weights(up)
layers.append(fc)
layers.append(nn.BatchNorm2d(planes, momentum=BN_MOMENTUM))
layers.append(nn.ReLU(inplace=True))
layers.append(up)
layers.append(nn.BatchNorm2d(planes, momentum=BN_MOMENTUM))
layers.append(nn.ReLU(inplace=True))
self.inplanes = planes
return nn.Sequential(*layers)
另外 添加了两个初始化函数
# 初始化 上采样层
def fill_up_weights(up):
w = up.weight.data
f = math.ceil(w.size(2) / 2)
c = (2 * f - 1 - f % 2) / (2. * f)
for i in range(w.size(2)):
for j in range(w.size(3)):
w[0, 0, i, j] = \
(1 - math.fabs(i / f - c)) * (1 - math.fabs(j / f - c))
for c in range(1, w.size(0)):
w[c, 0, :, :] = w[0, 0, :, :]
# 初始化卷积参数 其实用 kaiming xavier 两种初始化 应该是更好的
def fill_fc_weights(layers):
for m in layers.modules():
if isinstance(m, nn.Conv2d):
nn.init.normal_(m.weight, std=0.001)
# torch.nn.init.kaiming_normal_(m.weight.data, nonlinearity='relu')
# torch.nn.init.xavier_normal_(m.weight.data)
if m.bias is not None:
nn.init.constant_(m.bias, 0)
其实,原生的 msra_resnet 换为 resnet_dcn 并没有好的提升,更像是作者强行添加的, 当然也可能是我的数据集的原因。