YOLOv3中的残差网络

本文详细介绍了YOLOv3中引入的Darknet-53网络,这是一个结合了Darknet-19和ResNet思想的深度学习模型,用于图像特征提取。Darknet-53由53个卷积层构成,其中包含5组残差结构,每组残差结构的块数分别为1、2、8、8、4。通过引入残差块,网络能够更有效地学习深层特征,避免梯度消失问题。网络的构建通过`_make_layer()`函数实现,该函数根据给定的参数动态生成相应数量的残差块。每个残差块由两次卷积操作和一次残差累加组成,以保持特征映射的尺寸。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

YOLOv3中设计了Darknet-53网络,对图像进行特征提取,是之前YOLOv2中使用的Darknet-19网络中添加了残差块。原文:

We use a new network for performing feature extraction. Our new network is a hybrid approach between the network used in YOLOv2, Darknet-19, and that newfangled residual network stuff. Our network uses successive 3×3 and 1×1 convolutional layers but now has some shortcut connections as well and is significantly larger. It has 53 convolutional layers so we call it… wait for it… Darknet-53!
最后一句真有意思,哈哈。

Darknet-53网络结构是这样的:
在这里插入图片描述
这个网络中一共添加了5组残差结构。粉色标注中的是×1,表示添加了一个残差块。×2,表示使用了两个残差块的累加。具体说下这么多的残差结构是怎么嵌入到网络中的。

Darknet-53构建

def darknet53(pretrained, **kwargs):
    model = DarkNet([1, 2, 8, 8, 4]) 

在最开始的Darknet-53网络的实例化中,给了一组参数[1, 2, 8, 8, 4],这表示构建5组残差结构,其中每一个残差结构包含的残差块分别为1个,2个,8个,8个,4个。这正好对应网络的所有残差。

调用实例化的残差网络

输入x的维度为(416,416,32),经过一次残差网络的结果为(208,208,64)

class DarkNet(nn.Module):
    def __init__(self, layers):  # layers = [1 2  8 8 4]
        super(DarkNet, self).__init__()
        self.inplanes = 32  # 卷积核个数
        # (416,416,3) -> (416,416,32)
        self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=3, stride=1, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(self.inplanes)
        self.relu1 = nn.LeakyReLU(0.1)

        # 416,416,32 -> 208,208,64
        self.layer1 = self._make_layer([32, 64], layers[0]) 

    def forward(self, x):  # 网络的残差块结构
        # (416,416,3) -> (416,416,32)
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu1(x)

        # (416,416,32) -> (208,208,64)
        x = self.layer1(x)

残差网络实例化

self.layer1 = self._make_layer([32, 64], layers[0])

定义一个残差块为_make_layer()函数,其中[32, 64]是输出的通道数,layers[0]是残差的块数

残差网络函数定义

def _make_layer(self, planes, blocks):
        layers = [] # 初始化一个列表,里面存放定义好的CBAPD模块
     	# 经历一个CBA,卷积核大小为3*3,stride=2,即进行了下采样,
        layers.append(("ds_conv", nn.Conv2d(self.inplanes, planes[1], kernel_size=3,stride=2, padding=1, bias=False)))
        layers.append(("ds_bn", nn.BatchNorm2d(planes[1])))
        layers.append(("ds_relu", nn.LeakyReLU(0.1)))
       
        # 利用for循环构建残差块
        self.inplanes = planes[1]
        for i in range(0, blocks):
            layers.append(("residual_{}".format(i), BasicBlock(self.inplanes, planes)))
        return nn.Sequential(OrderedDict(layers))   # layers是一个列表,包含卷积过程
  • 利用layers.append()函数,不断在列表中添加卷积模块。
  • "residual_{}".format(i) 是一种输出方式,如果i = 1,则输出residual_1,对残差块进行了命名。
  • BasicBlock()是基础残差块,利用i的数量构建叠加在一起的残差块的数量。
  • 这里的for循环就可以根据之前的[1,2,8,8,4]自动快速生成对应数量的残差块。

基础残差块——BasicBlock()

基础残差块的模型如下:
在这里插入图片描述

class BasicBlock(nn.Module):  
    def __init__(self, inplanes, planes):
        super(BasicBlock, self).__init__()
        
        # 首先进行一次卷积,通道数变成32
        self.conv1 = nn.Conv2d(inplanes, planes[0], kernel_size=1, stride=1, padding=0, bias=False)
        self.bn1 = nn.BatchNorm2d(planes[0])
        self.relu1 = nn.LeakyReLU(0.1)
        
        # 再进行一次卷积,通道数又变成64
        self.conv2 = nn.Conv2d(planes[0], planes[1], kernel_size=3,
                               stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(planes[1])
        self.relu2 = nn.LeakyReLU(0.1)

    def forward(self, x):  # 残差块
        # 备份残差块的输入X
        # (208,208,64) -> (208,208,32)
        residual = x 

        # (208,208,32) -> (208,208,32) 
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu1(out)

        # (208,208,32) -> (208,208,64)
        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu2(out)
        
        # 残差累加
        # (208,208,64) + (208,208,64) -> (208,208,64)
        out += residual
        # 返回经历一个残差块的结果
        return out

参考文章:【链接

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值