系列文章目录(共五章33节已完结)
第一章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–
2个翻转类和ExtCompose类
第五章deeplabv3+源码之慢慢解析 utils文件夹(2)ext_transforms.py.py–
2个裁剪类和2个缩放类
第五章deeplabv3+源码之慢慢解析 utils文件夹(3)ext_transforms.py.py–
旋转类,填充类,张量转化类和标准化类
第五章deeplabv3+源码之慢慢解析 utils文件夹(4)ext_transforms.py.py–
ExtResize类,ExtColorJitter类,Lambda类和Compose类
第五章deeplabv3+源码之慢慢解析 utils文件夹(5)loss.py–
FocalLoss类
第五章deeplabv3+源码之慢慢解析 utils文件夹(6)scheduler.py–
PolyLR类
第五章deeplabv3+源码之慢慢解析 utils文件夹(7)utils.py–
去标准化,momentum设定,标准化层锁定和路径创建
第五章deeplabv3+源码之慢慢解析 utils文件夹(8)visualizer.py–
Visualizer类(完结)
阶段过程 StageModule类
提示:hrnetv2的理论部分一定先看看,要不然很难理解。这里的关键是,第n个Stage会有n个branch分支。如hrnetv2理论部分分为4个stage,第一部分1个分支,第二部分2个,第三部分3个,第四部分4个。每个分支为4个块+1个整合输出。
class StageModule(nn.Module):
def __init__(self, stage, output_branches, c):
super(StageModule, self).__init__()
self.number_of_branches = stage # number of branches is equivalent to the stage configuration.#第n个Stage会有n个branch分支。
self.output_branches = output_branches #在HRNet类中,output_branches参数都设置==number_of_branches(即stage)。
self.branches = nn.ModuleList() #初始化branches。后补链接。nn.ModuleList自动将每个 module 的 parameters 添加到网络之中的容器。可以把任意nn.Module的子类 (比如 nn.Conv2d, nn.Linear 之类的) 加到这个 list 里面,加入到 nn.ModuleList里面的module是会自动注册到整个网络上的,同时module的parameters也会自动添加到整个网络中。
# Note: Resolution + Number of channels maintains the same throughout respective branch. #分辨率+通道数在各个分支保持不变。如长和宽都缩小为1/2,则channels数量就扩大2倍。
for i in range(self.number_of_branches): # Stage scales with the number of branches. Ex: Stage 2 -> 2 branch
channels = c * (2 ** i) # Scale channels by 2x for branch with lower resolution, #每一个分支的channel数在不断翻倍,如第一个32,则第二个64.
# Paper does x4 basic block for each forward sequence in each branch (x4 basic block considered as a block)
branch = nn.Sequential(*[BasicBlock(channels, channels) for _ in range(4)]) #每个分支有4个BasicBlock组成。
self.branches.append(branch) # list containing all forward sequence of individual branches.
# For each branch requires repeated fusion with all other branches after passing through x4 basic blocks.#在4个BasicBlock之后,每个分支都和其他分支进行融合。
self.fuse_layers = nn.ModuleList() #初始化融合层。
for branch_output_number in range(self.output_branches): #输出所在的分支branch_output_number
self.fuse_layers.append(nn.ModuleList())
for branch_number in range(self.number_of_branches): #输入所在的分支branch_number
if branch_number == branch_output_number: #当前循环的分支和上一层循环的分支是同一个分支的话,则不做处理。
self.fuse_layers[-1].append(nn.Sequential()) # Used in place of "None" because it is callable
elif branch_number > branch_output_number: #上采样(图像长宽变大,channel变少)
self.fuse_layers[-1].append(nn.Sequential(
nn.Conv2d(c * (2 ** branch_number), c * (2 ** branch_output_number), kernel_size=1, stride=1,
bias=False),#先改变channel,即从c * (2 ** branch_number)减小为c * (2 ** branch_output_number)。c是第一个分支的通道数,所以对应不同的分支需要乘以对应的倍数。
nn.BatchNorm2d(c * (2 ** branch_output_number), eps=1e-05, momentum=0.1, affine=True,
track_running_stats=True),
nn.Upsample(scale_factor=(2.0 ** (branch_number - branch_output_number)), mode='nearest'), #再改变长宽。Upsample把长和宽扩大相对应的2倍数差。
))
elif branch_number < branch_output_number: #下采样(图像有大变小,channel变多)
downsampling_fusion = []
for _ in range(branch_output_number - branch_number - 1): #下采样比上采样复杂一点,如是相邻,则跳过此过程。按下面直接变化即可。但不相邻的,则需要先改变到适合的尺寸(详见下一条注释)。
downsampling_fusion.append(nn.Sequential(
nn.Conv2d(c * (2 ** branch_number), c * (2 ** branch_number), kernel_size=3, stride=2,
padding=1,
bias=False), #stride=2使得长宽减半。(正好跳过每两个中的一个。)此处是先通过循环,将长宽减到合适的尺寸(差2倍达到要求),以便和后面的缩减2倍达成一致目的。
nn.BatchNorm2d(c * (2 ** branch_number), eps=1e-05, momentum=0.1, affine=True,
track_running_stats=True),
nn.ReLU(inplace=True),
))
downsampling_fusion.append(nn.Sequential(
nn.Conv2d(c * (2 ** branch_number), c * (2 ** branch_output_number), kernel_size=3,
stride=2, padding=1,
bias=False), #长宽减半,并直接变大channel到所需的数量。
nn.BatchNorm2d(c * (2 ** branch_output_number), eps=1e-05, momentum=0.1, affine=True,
track_running_stats=True),
))
self.fuse_layers[-1].append(nn.Sequential(*downsampling_fusion)) #downsampling_fusion是list,需要*解包转化,如果它是nn.Sequential,则可以没有这个过程。后补链接。
self.relu = nn.ReLU(inplace=True)
def forward(self, x):
# input to each stage is a list of inputs for each branch
x = [branch(branch_input) for branch, branch_input in zip(self.branches, x)] #输入x和分支branches对应组队。
x_fused = []
for branch_output_index in range(
self.output_branches): # Amount of output branches == total length of fusion layers#即每个分支都有融合层。此处取输出层branch_output_index。
for input_index in range(self.number_of_branches): # The inputs of other branches to be fused.#此处取输入层input_index。
if input_index == 0: #列表为空,先计算每层的第0个,然后再累加,以免数组越界报错。
x_fused.append(self.fuse_layers[branch_output_index][input_index](x[input_index]))
else:
x_fused[branch_output_index] = x_fused[branch_output_index] + self.fuse_layers[branch_output_index][
input_index](x[input_index])#此处累加计算。
# After fusing all streams together, you will need to pass the fused layers
for i in range(self.output_branches):
x_fused[i] = self.relu(x_fused[i]) #逐个添加激励函数。
return x_fused # returning a list of fused outputs
Tips
-
补充
nn.ModuleList()
。 -
下一个节介绍hrnetv2.py中的HRNet类。