deeplabv3+源码之慢慢解析17 第四章network文件夹(1)backbone文件夹(c1)resnet.py--2个卷积层小函数,BasicBlock类和Bottleneck类

系列文章目录(更新中)

第一章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个类]
总结

文章目录

  • 系列文章目录(更新中)
    • 前期准备和说明
    • resnet.py的导入部分
    • resnet.py的非函数非类代码
    • 两个卷积层小函数
    • 第一种残差类型 BasicBlock类
    • 第二种残差类型 Bottleneck类


前期准备和说明

  1. 还是建议:有足够的耐心看完本章推荐的全部补充链接。
  2. 先看关于ResNet的理论部分。(老规矩,看文后补充链接)。
  3. ResNet是个里程碑,很多概念都是这里提出的。在ResNet提出之前,所有的视觉类神经网络都是通过卷积层和池化层的叠加组成的。当时认为卷积层和池化层的层数越多,学习效果越好。但是出现了两个问题:一是梯度爆炸与梯度消失,二是退化问题(随着层数的增加,预测效果反而越来越差)。
    ResNet亮点有三
    (1)超深的网络结构(超过1000层)。(神经网络刚刚复苏的时候,只要超过7层就算深度了,感叹一下发展之快,现在更复杂的都有哦,卷无上限!)
    (2)提出residual(残差结构)模块。(为了解决退化问题。)
    (3)使用Batch Normalization 加速训练(丢弃dropout)。(为了解决梯度爆炸与梯度消失,现在用dropout的越来越少了。)

resnet.py的导入部分

#还是简简单单,torch的各种基本功能
import torch
import torch.nn as 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

resnet.py的非函数非类代码

提示:提示:resnet.py包含12个函数和3个类。先介绍非函数非类的代码。

__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101',
           'resnet152', 'resnext50_32x4d', 'resnext101_32x8d',
           'wide_resnet50_2', 'wide_resnet101_2']   #可供使用的类和不同结构所用的函数。


model_urls = {   #各预训练模型下载的地址。
    'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
    'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
    'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
    'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
    'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
    'resnext50_32x4d': 'https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth',
    'resnext101_32x8d': 'https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth',
    'wide_resnet50_2': 'https://download.pytorch.org/models/wide_resnet50_2-95faca4d.pth',
    'wide_resnet101_2': 'https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth',
}


两个卷积层小函数

ResNet中两种不同的residual(不同的ResNet层数结构使用不同的residual): BasicBlock(即两个33conv+一个独立的shortcut)和 Bottleneck(即1个(11conv(降维)+33conv+11conv(升维))+一个独立的shortcut)。
而shortcut也分为两种,一是维度不变时,直接使用当前输入作为shortcut和conv块结果相加。二是维度变化时,通过1×1的卷积核进行了维度处理(特征矩阵在长宽方向降采样(常用strdie=2长宽减半),深度方向调整成下一层残差结构所需要的channel)。

def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):
    """3x3 convolution with padding"""   #使用3*3卷积核的卷积层
    return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
                     padding=dilation, groups=groups, bias=False, dilation=dilation)#此处的groups就是分组卷积。

def conv1x1(in_planes, out_planes, stride=1):
    """1x1 convolution"""    #使用1*1卷积核的卷积层
    return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)

第一种残差类型 BasicBlock类

提示:即两个3*3conv+一个独立的shortcut。

class BasicBlock(nn.Module):
    expansion = 1   #扩展倍数。

    def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,
                 base_width=64, dilation=1, norm_layer=None): #base_width是给wide_resnet使用的参数,普通resnet不用。
        super(BasicBlock, self).__init__()
        if norm_layer is None:
            norm_layer = nn.BatchNorm2d
        if groups != 1 or base_width != 64: #BasicBlock有很多不支持。
            raise ValueError('BasicBlock only supports groups=1 and base_width=64')
        if dilation > 1:
            raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
        # Both self.conv1 and self.downsample layers downsample the input when stride != 1
        self.conv1 = conv3x3(inplanes, planes, stride)
        self.bn1 = norm_layer(planes)
        self.relu = nn.ReLU(inplace=True)   #第一个3*3conv。
        self.conv2 = conv3x3(planes, planes)
        self.bn2 = norm_layer(planes)   #第二个3*3conv。
        self.downsample = downsample #传入的shortcut,默认无,即直接使用当前输入数据。
        self.stride = stride

    def forward(self, x):
        identity = x

        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out) #第一个3*3conv。

        out = self.conv2(out)
        out = self.bn2(out)  #第二个3*3conv。

        if self.downsample is not None:
            identity = self.downsample(x) #传入的shortcut,详情在Resnet类中downsample。

        out += identity  #整合两个covnv层的输出和shortcut。
        out = self.relu(out)  #激活函数。

        return out

第二种残差类型 Bottleneck类

提示:即1个(11conv(降维)+33conv+1*1conv(升维))+一个独立的shortcut。

class Bottleneck(nn.Module):
    expansion = 4  #扩展倍数=4

    def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,
                 base_width=64, dilation=1, norm_layer=None): #base_width是给wide_resnet和ResNeXt使用的参数,普通resnet不用。
        super(Bottleneck, self).__init__()
        if norm_layer is None:
            norm_layer = nn.BatchNorm2d
        width = int(planes * (base_width / 64.)) * groups #ResNet中其实就是width=planes。主要是ResNeXt使用的参数,分组卷积groups,这句中就是将通道数扩张了groups倍。base_width对应每个group的卷积核个数,即每个分组中的输出通道数。分母中的64是为了和ResNet类中self.layer1 = self._make_layer(block, 64, layers[0])保持一致。
        # Both self.conv2 and self.downsample layers downsample the input when stride != 1
        self.conv1 = conv1x1(inplanes, width)
        self.bn1 = norm_layer(width)  #第一个部分,1*1conv(降维),注width要比inplanes小才是降维。ResNeXt中不是降维。
        self.conv2 = conv3x3(width, width, stride, groups, dilation) #分组卷积groups
        self.bn2 = norm_layer(width) #第二个部分,3*3conv。
        self.conv3 = conv1x1(width, planes * self.expansion)
        self.bn3 = norm_layer(planes * self.expansion)  #第三个部分,1*1conv(升维),将通道扩大expansion倍。此处为了和shortcut部分相加,通常是升维回到inplanes的大小。
        self.relu = nn.ReLU(inplace=True) #激活函数
        self.downsample = downsample #传入的shortcut,默认无,即直接使用当前输入数据。
        self.stride = stride

    def forward(self, x):
        identity = x

        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out) #第一个部分,1*1conv(降维)。

        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu(out)  #第二个部分,3*3conv。

        out = self.conv3(out)
        out = self.bn3(out) #第三个部分,1*1conv(升维)。

        if self.downsample is not None:
            identity = self.downsample(x) #传入的shortcut,详情在Resnet类中downsample。

        out += identity #整合两个covnv层的输出和shortcut。
        out = self.relu(out) #激活函数。

        return out

Tips

  1. 补充:ResNet详解。
  2. 补充:Wide-ResNet。
  3. 有了前面的章节,这里相对简单。虽然很多概念是resNet提出的,但因前面已讲过,本节就不强调顺序了,理解代码即可。
  4. 下一节是resnet.py剩余的部分,即ResNet类和10个不同结构的调用函数。

你可能感兴趣的:(技术,人工智能,深度学习,deeplab,v3+,语义分割)