第一章deeplabv3+源码之慢慢解析 根目录(1)main.py–get_argparser函数
第一章deeplabv3+源码之慢慢解析 根目录(2)main.py–get_dataset函数
第一章deeplabv3+源码之慢慢解析 根目录(3)main.py–validate函数
第一章deeplabv3+源码之慢慢解析 根目录(4)main.py–main函数
第一章deeplabv3+源码之慢慢解析 根目录(5)predict.py–get_argparser函数和main函数
第二章deeplabv3+源码之慢慢解析 datasets文件夹(1)voc.py–voc_cmap函数和download_extract函数
第二章deeplabv3+源码之慢慢解析 datasets文件夹(2)voc.py–VOCSegmentation类
第二章deeplabv3+源码之慢慢解析 datasets文件夹(3)cityscapes.py–Cityscapes类
第二章deeplabv3+源码之慢慢解析 datasets文件夹(4)utils.py–6个小函数
第三章deeplabv3+源码之慢慢解析 metrics文件夹stream_metrics.py–StreamSegMetrics类和AverageMeter类
第四章deeplabv3+源码之慢慢解析 network文件夹(1)backbone文件夹(a1)hrnetv2.py–4个函数和可执行代码
第四章deeplabv3+源码之慢慢解析 network文件夹(1)backbone文件夹(a2)hrnetv2.py–Bottleneck类和BasicBlock类
第四章deeplabv3+源码之慢慢解析 network文件夹(1)backbone文件夹(a3)hrnetv2.py–StageModule类
第四章deeplabv3+源码之慢慢解析 network文件夹(1)backbone文件夹(a4)hrnetv2.py–HRNet类
第四章deeplabv3+源码之慢慢解析 network文件夹(1)backbone文件夹(b1)mobilenetv2.py–2个类和2个函数
第四章deeplabv3+源码之慢慢解析 network文件夹(1)backbone文件夹(b2)mobilenetv2.py–MobileNetV2类和mobilenet_v2函数
第四章deeplabv3+源码之慢慢解析 network文件夹(1)backbone文件夹(c1)resnet.py–2个基础函数,BasicBlock类和Bottleneck类
第四章deeplabv3+源码之慢慢解析 network文件夹(1)backbone文件夹(c2)resnet.py–ResNet类和10个不同结构的调用函数
第四章deeplabv3+源码之慢慢解析 network文件夹(1)backbone文件夹(d1)xception.py–SeparableConv2d类和Block类
第四章deeplabv3+源码之慢慢解析 network文件夹(1)backbone文件夹(d2)xception.py–Xception类和xception函数
第四章deeplabv3+源码之慢慢解析 network文件夹(2)_deeplab.py–ASPP相关的4个类和1个函数
第四章deeplabv3+源码之慢慢解析 network文件夹(3)_deeplab.py–DeepLabV3类,DeepLabHeadV3Plus类和DeepLabHead类
第四章deeplabv3+源码之慢慢解析 network文件夹(4)modeling.py–5个私有函数(4个骨干网,1个模型载入)
第四章deeplabv3+源码之慢慢解析 network文件夹(5)modeling.py–12个调用函数
第四章deeplabv3+源码之慢慢解析 network文件夹(6)utils.py–_SimpleSegmentationModel类和IntermediateLayerGetter类
第五章deeplabv3+源码之慢慢解析 utils文件夹(1)ext_transforms.py.py–[17个类]
第五章deeplabv3+源码之慢慢解析 utils文件夹(2)loss.py–[1个类]
第五章deeplabv3+源码之慢慢解析 utils文件夹(3)scheduler.py–[1个类]
第五章deeplabv3+源码之慢慢解析 utils文件夹(4)utils.py–[1个类,4个函数]
第五章deeplabv3+源码之慢慢解析 utils文件夹(5)visualizer.py–[1个类]
总结
#以下是torch的常用功能
import torch
from torch import nn
from torch.nn import functional as F
#以下是从本文件夹下utils.py导入的部分,就是骨干网选择。详见后面utils.py这一节。
from .utils import _SimpleSegmentationModel
__all__ = ["DeepLabV3"] #DeepLabV3类,简单明了的一句。
提示:#可以对比backbone文件夹中xception.py中SeparableConv2d类的写法。
class AtrousSeparableConvolution(nn.Module): #convert_to_separable_conv函数使用,就是论文中输入数据的第一个处理环节。但本代码中没有实际用到。
""" Atrous Separable Convolution #空洞可分离卷积,相对与之前的深度可分离卷积(DW+PW)的区别,就是把DW的dilation换成1以外的值,即使用空洞卷积。
"""
def __init__(self, in_channels, out_channels, kernel_size,
stride=1, padding=0, dilation=1, bias=True):
super(AtrousSeparableConvolution, self).__init__()
self.body = nn.Sequential(
# Separable Conv #和DW没有什么变化,主要是输入的dilation不同罢了。
nn.Conv2d( in_channels, in_channels, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, bias=bias, groups=in_channels ),
# PointWise Conv #PW部分还是kernel_size=1,stride=1没什么变化。
nn.Conv2d( in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=bias),
)
self._init_weight() #初始化权重
def forward(self, x): #返回Separable Conv+PW,没有复杂内容。
return self.body(x)
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)
class ASPPConv(nn.Sequential): #ASPP第(2)-(4)部分。
def __init__(self, in_channels, out_channels, dilation): #此处的主要参数为:空洞dilation。
modules = [
nn.Conv2d(in_channels, out_channels, 3, padding=dilation, dilation=dilation, bias=False), #论文中kernel=3。padding=dilation保证不同卷积核,获得的结果尺寸相同,以便整合。
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True)
]
super(ASPPConv, self).__init__(*modules)
class ASPPPooling(nn.Sequential): #ASPP第(5)部分。池化。
def __init__(self, in_channels, out_channels):
super(ASPPPooling, self).__init__(
nn.AdaptiveAvgPool2d(1),
nn.Conv2d(in_channels, out_channels, 1, bias=False),
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True))
def forward(self, x):
size = x.shape[-2:] #输入x的shape取最后2项,长宽尺寸即h和w。
x = super(ASPPPooling, self).forward(x)
return F.interpolate(x, size=size, mode='bilinear', align_corners=False)#为接下来的数据整合,池化后进行插值数据采样,改变数据的尺寸。 F.interpolate后补链接。
提示:ASPP类就是整个之前的内容,在DeepLabHeadV3Plus类和DeepLabHead类倍调用。
class ASPP(nn.Module): #空洞卷积。论文中的Encoder部分主要就是ASPP。
def __init__(self, in_channels, atrous_rates):
super(ASPP, self).__init__()
out_channels = 256
modules = [] #论文中ASPP的5个部分
modules.append(nn.Sequential( #此处是ASPP第1个部分:卷积核为1。
nn.Conv2d(in_channels, out_channels, 1, bias=False),
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True)))
rate1, rate2, rate3 = tuple(atrous_rates) #此处调取不同的rate,对应论文中的不同卷积核,DeepLabHead类中aspp_dilate。
modules.append(ASPPConv(in_channels, out_channels, rate1)) #此处是ASPP第2个部分:卷积核为3(固定),dilation=rate1(参数传入)
modules.append(ASPPConv(in_channels, out_channels, rate2)) #此处是ASPP第3个部分:卷积核为3(固定),dilation=rate2(参数传入)
modules.append(ASPPConv(in_channels, out_channels, rate3)) #此处是ASPP第4个部分:卷积核为3(固定),dilation=rate3(参数传入)
modules.append(ASPPPooling(in_channels, out_channels)) #此处是ASPP第5个部分:,Image_pooling
self.convs = nn.ModuleList(modules) #ASPP各部分统一为self.convs。
self.project = nn.Sequential( #需要将ASPP的5个部分整合输出,因此整个部分输入为5倍,输出为原来的输出数量。之后按卷积核1输出。
nn.Conv2d(5 * out_channels, out_channels, 1, bias=False), #卷积核1。
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True),
nn.Dropout(0.1),)
def forward(self, x):
res = []
for conv in self.convs:
res.append(conv(x)) #每一层数据走一遍输入数据,注意5个部分在最后汇总前,都是独立并行的,因此都是单独输入x,而不是前者输出为后后者输入。
res = torch.cat(res, dim=1) #torch.cat() 的dim=1拼接,是指将两个2*3,变成一个4*3。对应前面将5个部分的结果进行拼接(5 * out_channels)。
return self.project(res)
提示:就是个转化函数,这段代码中没用到。
def convert_to_separable_conv(module):
new_module = module
if isinstance(module, nn.Conv2d) and module.kernel_size[0]>1: #对于参数传入模型中的nn.Conv2d层(卷积层),只要kernel>1,则转为空洞可分卷积层。
new_module = AtrousSeparableConvolution(module.in_channels,
module.out_channels,
module.kernel_size,
module.stride,
module.padding,
module.dilation,
module.bias)
for name, child in module.named_children():
new_module.add_module(name, convert_to_separable_conv(child)) #递归转换。
return new_module
Tips