系列文章目录(更新中)
第一章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文件夹(3)modeling.py--[15个函数]
第四章deeplabv3+源码之慢慢解析 network文件夹(4)utils.py--[2个类]
第五章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个类]
总结
文章目录
- 系列文章目录(更新中)
-
- 前期准备和说明
- 导入部分
- 非函数非类代码
- [空洞可分离卷积 AtrousSeparableConvolution类](#空洞可分离卷积 AtrousSeparableConvolution类)
- ASPPConv类
- ASPPPooling类
- ASPP类
- convert_to_separable_conv函数
前期准备和说明
- 空洞卷积(atrous convolutions)又称扩张卷积(dilated convolutions),dilation参数设定忘记的同学务必先看看前面的章节。
- deeplab家族的事情,大家先要了解一下。(老规矩,看文后补充链接)。
- Xception是的deeplab v3+文章的骨干网络,但大家可以多试试玩玩其他的。
- ASPP:Atrous Spatial Pyramid Pooling,空洞空间卷积池化金字塔。就是多个不同dilation的空洞卷积,然后合起来。(老规矩,看文后补充链接)。
- 提示:ASPP,主要有5个部分:
(1)1x1卷积
(2)膨胀率(dilation)为6的3x3卷积 (ASPPConv类)
(3)膨胀率为12的3x3卷积 (ASPPConv类)
(4)膨胀率为18的3x3卷积 (ASPPConv类)
(5)对输入进去的特征层进行池化 (ASPPPooling类) - _deeplab.py包含7个类和1个函数,本节介绍其中ASPP相关内容,即AtrousSeparableConvolution类,ASPPConv类,ASPPPooling类,ASPP类和convert_to_separable_conv函数。
导入部分
python
#以下是torch的常用功能
import torch
from torch import nn
from torch.nn import functional as F
#以下是从本文件夹下utils.py导入的部分,就是骨干网选择。详见后面utils.py这一节。
from .utils import _SimpleSegmentationModel
非函数非类代码
python
__all__ = ["DeepLabV3"] #DeepLabV3类,简单明了的一句。
空洞可分离卷积 AtrousSeparableConvolution类
提示:#可以对比backbone文件夹中xception.py中SeparableConv2d类的写法。
python
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)
ASPPConv类
python
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)
ASPPPooling类
python
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类
提示:ASPP类就是整个之前的内容,在DeepLabHeadV3Plus类和DeepLabHead类倍调用。
python
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)
convert_to_separable_conv函数
提示:就是个转化函数,这段代码中没用到。
python
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
- 补充:Deeplab家族。
- 补充:Deeplabv3+理论。
- 补充:ASPP。
- 补充:F.interpolate插值数据采样。
- 下一节是_deeplab.py剩余的部分,即DeepLabV3类,DeepLabHeadV3Plus类和DeepLabHead类。