🍁🍁🍁图像分割实战-系列教程 总目录
有任何问题欢迎在下面留言
本篇文章的代码运行界面均在Pycharm中进行
本篇文章配套的代码资源已经上传
本项目的网络结构在network文件夹中,主要在modeling.py和_deeplab.py中:
modeling.py:指定要用的骨干网络是什么
_deeplab.py:根据modeling.py指定的骨干网络构建实际的网络结构
5、modeling.py的 _segm_resnet函数
def _segm_resnet(name, backbone_name, num_classes, output_stride, pretrained_backbone):
if output_stride==8:
replace_stride_with_dilation=[False, True, True]
aspp_dilate = [12, 24, 36]
else:
replace_stride_with_dilation=[False, False, True]
aspp_dilate = [6, 12, 18]
- 如果输出步长为8,则
- 替换步长用膨胀率,如果为None,设置默认值为[False, False, False],表示不使用空洞卷积,通过使用空洞卷积替代增加步长的标准卷积
- 膨胀率为[12, 24, 36],用于调整空洞卷积
- 如果输出步长不是8,则设置另外的参数
backbone = resnet.__dict__[backbone_name](
pretrained=pretrained_backbone, replace_stride_with_dilation=replace_stride_with_dilation)
inplanes = 2048
low_level_planes = 256
- 使用指定的ResNet版本构建backbone
- resnet.__dict__是一个指向不同ResNet模型的字典
- pretrained=pretrained_backbone指定是否加载预训练权重
- replace_stride_with_dilation用于控制网络中卷积层的步长和膨胀
- inplanes = 2048:设置网络最后一层的通道数
- low_level_planes = 256:设置低层特征的通道数
if name=='deeplabv3plus':
return_layers = {'layer4': 'out', 'layer1': 'low_level'}#
classifier = DeepLabHeadV3Plus(inplanes, low_level_planes, num_classes, aspp_dilate)
elif name=='deeplabv3':
return_layers = {'layer4': 'out'}
classifier = DeepLabHead(inplanes , num_classes, aspp_dilate)
# 提取网络的第几层输出结果并给一个别名
backbone = IntermediateLayerGetter(backbone, return_layers=return_layers)
model = DeepLabV3(backbone, classifier)
return model
return_layers
是一个字典,定义返回层,这个键值不用管,out对应的是带有高维度特征的输出对应的是比较大的物体的分割,low_level即小物体classifier
初始化分类器,inplanes
传入分类器的特征通道数,low_level_planes
是低层特征的通道数,num_classes
是目标分类的类别数,aspp_dilate
是ASPP模块中使用的膨胀率IntermediateLayerGetter(backbone, return_layers=return_layers)
,这里的backbone是之前定义的基础网络如resnet,return_layers定义了要从哪些层输出,IntermediateLayerGetter
使得我们可以在后续的网络部分中使用这些特定层的输出进行进一步的处理和特征融合,最后得到修改后的backbonemodel = DeepLabV3(backbone, classifier)
使用修改后的backbone 和定义好的classifier构建DeepLabHeadV3Plus模型
6、_deeplab.py的 DeepLabHeadV3Plus类
在前面的_segm_resnet函数我们调用了DeepLabHeadV3Plus类来构建我们的网络,这部分介绍一下DeepLabHeadV3Plus类
6.1 构造函数
class DeepLabHeadV3Plus(nn.Module):
def __init__(self, in_channels, low_level_channels, num_classes, aspp_dilate=[12, 24, 36]):
super(DeepLabHeadV3Plus, self).__init__()
self.project = nn.Sequential(
nn.Conv2d(low_level_channels, 48, 1, bias=False),
nn.BatchNorm2d(48),
nn.ReLU(inplace=True),
)
self.aspp = ASPP(in_channels, aspp_dilate)
self.classifier = nn.Sequential(
nn.Conv2d(304, 256, 3, padding=1, bias=False),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.Conv2d(256, num_classes, 1)
)
self._init_weight()
- self.project,定义一个执行序列,包含一个二维卷积、一个批归一化、一个ReLU激活
- self.aspp,调用ASPP类初始化一个对象
- self.classifier,定义一个执行序列包含一个二维卷积、一个批归一化、一个ReLU激活、一个二维卷积
- self._init_weight(),调用此类中一个函数,这个函数主要用于初始化权重
6.2 前向传播函数
def forward(self, feature):
#print(feature.shape)
low_level_feature = self.project( feature['low_level'] )#return_layers = {'layer4': 'out', 'layer1': 'low_level'}
#print(low_level_feature.shape)
output_feature = self.aspp(feature['out'])
#print(output_feature.shape)
output_feature = F.interpolate(output_feature, size=low_level_feature.shape[2:], mode='bilinear', align_corners=False)
#print(output_feature.shape)
return self.classifier( torch.cat( [ low_level_feature, output_feature ], dim=1 ) )
6.3 def _init_weight(self):函数
def _init_weight(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight)
elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)