`
第一章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个类]
总结
class Bottleneck(nn.Module): #Bottleneck结构为4部分:(1)卷积(核1)+标准化+relu;(2)卷积(核3)+标准化+relu;(3)卷积(核1)*expansion+标准化*expansion;(4)从输入直接或计算得到的downsample与(3)的结果一起+relu=output。
expansion = 4 #expansion是对输出通道数的倍乘。
def __init__(self, inplanes, planes, stride=1, downsample=None): #卷积参数stride:指的是窗口从当前位置到下一个位置,跳过的中间数据个数。
super(Bottleneck, self).__init__()
self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) #卷积(核1)
self.bn1 = nn.BatchNorm2d(planes) #标准化
self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) #卷积(核3)
self.bn2 = nn.BatchNorm2d(planes) #标准化
self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False) #卷积(核1),输出通道扩大expansion倍。
self.bn3 = nn.BatchNorm2d(planes * self.expansion) #标准化同样扩大扩大expansion倍。
self.relu = nn.ReLU(inplace=True) #激活函数。
self.downsample = downsample #实际上downsample就是经过卷积核标准化之后得到的残差,详见HRNet类。
def forward(self, x):
identity = x #x就是传入的输入inplanes。
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out) #完成过程(1):卷积(核1)+标准化+relu。
out = self.conv2(out)
out = self.bn2(out)
out = self.relu(out) #完成过程(2):卷积(核3)+标准化+relu。
out = self.conv3(out)
out = self.bn3(out) #完成过程(3):卷积(核1)*expansion+标准化*expansion。
if self.downsample is not None:
identity = self.downsample(x)
out += identity #实际上identity就是传入的输入inplanes或者残差downsample,与(3)中的out叠加,成为新的out。
out = self.relu(out) #完成过程(4):过程(3)的out+identity,之后+relu=最终out。
return out
1.新手同学请注意,现阶段,一个块结构就是一个主干网的核心所在。
2.一个主干网往往是由多个块组成,就像小时候玩积木一样。很多时候,不同厂家的积木都有类似的或者完全相同的积木,主干网络也是如此。
3.残差其实就是Resnet系列里面用到的残差卷积,主要用在Resnet50、Resnet101里面。在这里又用到了,还换了名字,这个不是奇怪的事情。至于是不是创新,个人观点,了解本质最重要,好的组合有新的效果就是创新,不抬杠不钻牛角尖。
4.个人观点:工科是用来解决问题的,效果至上。这也许就是目前神经网络系列火爆的原因吧。如果一定要问why?抱歉,目前我还不知道答案;恭喜,你发现了一个金矿,希望能早日找到答案,带领大家一起进步!
class BasicBlock(nn.Module): #BasicBlock结构为3部分:(1)卷积(核3)+标准化+relu;(2)卷积(核3)+标准化;(3)从输入直接或计算得到的downsample与(2)的结果一起+relu=output。
expansion = 1
def __init__(self, inplanes, planes, stride=1, downsample=None):
super(BasicBlock, self).__init__()
self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=3, stride=stride, padding=1, bias=False) #卷积(核3)
self.bn1 = nn.BatchNorm2d(planes) #标准化
self.relu = nn.ReLU(inplace=True) #激活函数
self.conv2 = nn.Conv2d(inplanes, planes, kernel_size=3, stride=1, padding=1, bias=False) #卷积(核3)
self.bn2 = nn.BatchNorm2d(planes) #标准化
self.downsample = downsample #实际上downsample就是经过卷积核标准化之后得到的残差,详见HRNet类。
def forward(self, x):
identity = x #x就是传入的输入inplanes。
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out) #完成过程(1):卷积(核3)+标准化+relu。
out = self.conv2(out)
out = self.bn2(out) #完成过程(2):卷积(核3)+标准化。
if self.downsample is not None:
identity = self.downsample(x)
out += identity
out = self.relu(out) #完成过程(3):过程(2)的out+identity,之后+relu=最终out。
return out
1.BasicBlock类对比Bottleneck类代码要相对简单,看懂Bottleneck类再看BasicBlock类,这样比较容易。
2.此处仅仅是块结构不同,好好体会。
Tips
补充,很喜欢这位大佬的风格,个人推荐HRNetV2详解。
补充HRNet的一个学习笔记。
本节介绍了最重要的两个块,是基础中最重要的东西。下一个节介绍hrnetv2.py中的阶段过程StageModule类。