`
第一章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的各种基本功能
from torch import nn
try: # for torchvision<0.4
from torchvision.models.utils import load_state_dict_from_url
except: # for torchvision>=0.4
from torch.hub import load_state_dict_from_url
import torch.nn.functional as F
提示:提示:mobilenetv2.py包含3个函数和3个类。先介绍非函数非类的代码。
__all__ = ['MobileNetV2', 'mobilenet_v2'] #MobileNetV2类, mobilenet_v2函数。
model_urls = {
'mobilenet_v2': 'https://download.pytorch.org/models/mobilenet_v2-b0353104.pth', #预训练模型下载地址。
}
def _make_divisible(v, divisor, min_value=None):
"""
This function is taken from the original tf repo.
It ensures that all layers have a channel number that is divisible by 8
It can be seen here:
https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py
:param v:
:param divisor:
:param min_value: #此函数中要注意,如果保证结果是divisor的整数倍,则min_value最好用默认值,否则可能出现意外,如_make_divisible(5,8,31)==31。
:return:
"""
if min_value is None:
min_value = divisor
new_v = max(min_value, int(v + divisor / 2) // divisor * divisor) #//是商取整数部分的运算符,此处即int(v + divisor / 2) // divisor再* divisor,得到的就是divisor的整数倍。divisor==8就是8的整数倍。
# Make sure that round down does not go down by more than 10%.
if new_v < 0.9 * v: #如果小于v的90%,则加一个divisor,相当于加了1倍。
new_v += divisor
return new_v
提示:基本结构块Conv2d+BatchNorm2d+ReLU6,在InvertedResidual类和MobileNetV2类中使用。
class ConvBNReLU(nn.Sequential):
def __init__(self, in_planes, out_planes, kernel_size=3, stride=1, dilation=1, groups=1):
#padding = (kernel_size - 1) // 2
super(ConvBNReLU, self).__init__(
nn.Conv2d(in_planes, out_planes, kernel_size, stride, 0, dilation=dilation, groups=groups, bias=False),
nn.BatchNorm2d(out_planes),
nn.ReLU6(inplace=True) #基本序列Conv2d+BatchNorm2d+ReLU6。
)
def fixed_padding(kernel_size, dilation): #特别注意:在Pytorch中,空洞卷积(膨胀卷积)dilation = 1等同于没有dilation的标准卷积。dilation = 2才是间隔1个,扩大感受野。
kernel_size_effective = kernel_size + (kernel_size - 1) * (dilation - 1) #插入空洞后,新的卷积核尺寸。
pad_total = kernel_size_effective - 1 #在保持高和宽不变的情况下,卷积减少的尺寸为k-1,有padding填充的为2p,即k-1=2p。则p=(k-1)//2。
pad_beg = pad_total // 2
pad_end = pad_total - pad_beg
return (pad_beg, pad_end, pad_beg, pad_end)
class InvertedResidual(nn.Module): #论文中把这个整体叫做bottleneck。
def __init__(self, inp, oup, stride, dilation, expand_ratio):
super(InvertedResidual, self).__init__()
self.stride = stride
assert stride in [1, 2] #测试用,stride=1则分辨率不变,stride=2则分辨率降一半。
hidden_dim = int(round(inp * expand_ratio)) #输入*扩展系数=hidden_dim ,即中间的输出数量。
self.use_res_connect = self.stride == 1 and inp == oup #stride==1且输入输出数量相等,则use_res_connect=True。
layers = []
if expand_ratio != 1:#如果扩展系数不为1,即需要扩大中间的输出通道数,则进行kernel=1的升维。即论文中的前期的pw升维部分。
# pw
layers.append(ConvBNReLU(inp, hidden_dim, kernel_size=1))
layers.extend([
# dw
ConvBNReLU(hidden_dim, hidden_dim, stride=stride, dilation=dilation, groups=hidden_dim),#正常的DW部分。
# pw-linear #pw线性降维部分,不用激活函数。
nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup),
])
self.conv = nn.Sequential(*layers) #整合网络各层,即pw+dw+pw-linear,论文中把这个整体叫做bottleneck,本代码没有单独写出这个名字。
self.input_padding = fixed_padding( 3, dilation )#计算填充的尺寸。
def forward(self, x):
x_pad = F.pad(x, self.input_padding) #把输入x按填充尺寸填充。
if self.use_res_connect: #特别的,针对stride=1 和stride=2,在block上有稍微不同,主要是为了与shortcut的维度匹配,因此,stride=2时,不采用shortcut。
return x + self.conv(x_pad) #stride==1且输入输出数量相等时,输入x与输出结果整合。
else:
return self.conv(x_pad)
Tips