经典主干DarkNet53&网络搭建

1. DarkNet53网络介绍

YOLOv3中的backbone,DarkNet53。不同于YOLOv2中的DarkNet19,它由大量的残差组成,DarkNet53在ImageNet上面的表现也证明了该网络的有效行。DarkNet53的网络结构如下。
经典主干DarkNet53&网络搭建_第1张图片
YOLO版本的如下:
经典主干DarkNet53&网络搭建_第2张图片
Darknet-53中总共有6个单独的卷积层和23个Residual,每个Residual包含2个卷积层(一个1×1,一个3×3),所以Darknet-53中共有52层卷积,可为什么叫做Darknet-53呢?因为Darknet-53在YOLO v3中,前52层只用作特征提取,最后一层是用于输出预测值的,故加上输出那一层称为Darknet-53。

如上图所示,DarkNet53主要由基本的卷积块(ConvBlock = Conv2d + BN +LeakyRelu)、残差块等组成。残差结构如下,它由1x1卷积、3x3卷积组成。
经典主干DarkNet53&网络搭建_第3张图片
残差块的输入首先经过一个1×1的卷积层Conv(1×1,stride=1)将通道数降为原来的一半,接着通过3x3卷积将通道数恢复为In_channels。最后3×3卷积的输出与经过Shorcut传递过来的输入Input相加得到最终的Output(此时3×3卷积的输出与Input的形状(In_channels,h,w)相同,可以直接相加)。我们看到,经过Residual运算之后,输入的特征图形状保持不变。

2. DarkNet53网络搭建(YOLO版本)

Step1: 封装基本的卷积块CBL
在这里插入图片描述

#封装CBL
class Conv(nn.Module):
    def __init__(self, c_in, c_out, k, s, p, bias=True):
        '''
        自定义卷积块,一次性完成卷积+归一化+池化
        :param c_in: 输入通道数
        :param c_in: 输出通道数
        :param k:    卷积核大小
        :param s:    步长
        :param p:    填充
        :param bias: 偏置
        '''
        super(Conv, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(c_in, c_out, k, s, p, bias=bias),
            nn.BatchNorm2d(c_out),
            nn.LeakyReLU(0.1),
        )

    def forward(self, x):
        return self.conv(x)

Step2: 封装残差单元
经典主干DarkNet53&网络搭建_第4张图片

class ConvResidual(nn.Module):
    def __init__(self, c_in):
        '''
        自定义残差单元,只需给出通道数,该单元完成两次卷积,并进行加残差后返回相同维度的特征图
        '''
        super(ConvResidual, self).__init__()
        c = c_in/2
        # 采用1*1 + 3*3 的形式加深网络深度,加强特征抽取
        self.conv = nn.Sequential(
            Conv(c_in, c, 1, 1, 0), #1x1卷积降通道
            Conv(c, c_in, 3, 1, 1), #3x3拉回通道
        )
    def forward(self, x):
        return x + self.conv(x) #残差

Step3:根据DarkNet53网络图将卷积块与残差块进行组合,以搭建最终的网络。

class DarkNet53(nn.Module):
    def __init__(self):
        super(DarkNet53, self).__init__()
        self.conv1 = Conv(3, 32, 3, 1, 1)  # 一个卷积块 = 1层卷积
        self.conv2 = Conv(32, 64, 3, 2, 1)
        self.conv3_4 = ConvResidual(64) # 一个残差块 = 2层卷积   1
        self.conv5 = Conv(64, 128, 3, 2, 1)
        self.conv6_9 = nn.Sequential(    #4层卷积               2
            ConvResidual(128),
            ConvResidual(128),
        )
        self.conv10 = Conv(128, 256, 3, 2, 1)
        self.conv11_26 = nn.Sequential(*[ConvResidual(256) for i in range(8)])  # 8
        self.conv27 = Conv(256, 512, 3, 2, 1)
        self.conv28_43 = nn.Sequential(*[ConvResidual(512) for i in range(8)])  # 8
        self.conv44 = Conv(512, 1024, 3, 2, 1)
        self.conv45_52 = nn.Sequential(*[ConvResidual(1024) for i in range(4)]) # 4

    def forward(self, x):
        conv1 = self.conv1(x)
        conv2 = self.conv2(conv1)
        conv3_4 = self.conv3_4(conv2)
        conv5 = self.conv5(conv3_4)
        conv6_9 = self.conv6_9(conv5)
        conv10 = self.conv10(conv6_9)
        conv11_26 = self.conv11_26(conv10)
        conv27 = self.conv27(conv11_26)
        conv28_43 = self.conv28_43(conv27)
        conv44 = self.conv44(conv28_43)
        conv45_52 = self.conv45_52(conv44)
        return conv45_52, conv28_43, conv11_26  # YOLOv3用,所以输出了3次特征

你可能感兴趣的:(#,深度学习&源码分析,深度学习,计算机视觉)