深入浅出之Bottleneck层、Res unit和ResX模块(YOLO)

一、Bottleneck层,Res unit和ResX模块概念

Bottleneck层、Res unit(残差单元)和ResX模块是深度学习中,特别是在残差网络(ResNet)及其变体,以及目标检测网络YOLO系列中的重要组件。以下是对这三者的详细解析:

1.1 Bottleneck层

  1. 定义
    Bottleneck层,又称瓶颈层,是一种在深度残差网络(ResNet)中引入的结构,旨在降低模型的计算复杂度并提升特征提取能力。

  2. 结构
    Bottleneck层通常由三个卷积层组成:

    • 第一个1×1卷积层:用于降低输入的通道数(维度),以减少后续卷积层的计算量。
    • 第二个3×3卷积层:在降维后的特征图上进行卷积操作,提取特征。
    • 第三个1×1卷积层:将通道数恢复到原始维度,以供下一层使用。

上图右侧图所示结构即为Bottleneck结构。 

  1. 作用

    • 显著降低计算复杂度,加快模型训练和推理速度。
    • 保持或提升特征提取能力,提高模型性能。

1.2 Res unit(残差单元)

  1. 定义
    Res unit是借鉴了ResNet中的残差结构,旨在解决深层网络训练中的梯度消失或梯度爆炸问题,使网络能够构建得更深。

  2. 结构
    Res unit通常由输入层、卷积层(或多个卷积层组成的子块)、批归一化层(BN)、激活函数以及跳跃连接(shortcut connection)组成。

    • 输入层:接收来自上一层的特征图。
    • 卷积层:对输入特征图进行卷积操作,提取特征。
    • 批归一化层:对卷积层的输出进行归一化处理,加速训练过程并稳定模型性能。
    • 激活函数:增加网络的非线性表达能力。
    • 跳跃连接:将输入层的输出直接加到卷积层(或子块)的输出上,形成残差学习的形式。

  1. 作用

    • 解决深层网络训练中的梯度消失或梯度爆炸问题。
    • 提高网络的表达能力和泛化能力。

1.3 ResX模块

  1. 定义
    ResX模块是YOLO系列网络中的一个重要组件,它结合了CBL(Conv+Bn+Leaky_relu)和多个Res unit,形成了一个具有强大特征提取能力的结构单元。

  2. 结构
    ResX模块通常由一个CBL层和多个Res unit组成。

    • CBL层:由卷积层、批归一化层和Leaky_relu激活函数组成,对输入特征图进行初步处理。
    • Res unit:多个残差单元串联而成,对CBL层的输出进行进一步处理,提取更深层次的特征。

  1. 作用

    • 通过组合CBL和多个Res unit,形成一个具有强大特征提取能力的结构单元。
    • 堆叠多个ResX模块,可以提取多尺度的特征信息,有助于网络更好地检测不同大小的目标。

综上所述,Bottleneck层、Res unit和ResX模块在深度学习中发挥着重要作用。它们共同构成了深度残差网络(ResNet)及其变体,以及目标检测网络YOLO系列的基本构建块,为解决深层神经网络训练中的难题提供了有效方法,并提高了模型的性能和泛化能力。

在YOLO系列算法中,Res unit(残差单元)和ResX是两个重要的组件,它们在网络结构中扮演着关键角色。

二、三者区别与联系

2.1 区别

  1. Bottleneck层
    • 主要用于ResNet网络中,特别是较深的ResNet变体(如ResNet-50、ResNet-101等)。
    • 通过使用1×1卷积降低维度,3×3卷积进行特征提取,再使用1×1卷积升高维度,显著减少了模型的计算复杂度。
    • 结构上,Bottleneck层是一个三卷积层的组合,中间层通常具有较少的通道数。
  2. Res unit(残差单元)
    • 是残差网络的基本构建块,旨在解决深层网络训练中的梯度消失或梯度爆炸问题。
    • 包含一个或多个卷积层、批归一化层、激活函数以及一个跳跃连接(shortcut connection)。
    • 跳跃连接将输入直接加到输出上,形成残差学习的形式,有助于梯度在网络中的传播。
  3. ResX模块
    • 主要用于YOLO系列网络,特别是YOLOv3及以后的版本。
    • 由一个CBL(Conv+Bn+Leaky_relu)和多个Res unit组成,形成了一个具有强大特征提取能力的结构单元。
    • 通过堆叠多个ResX模块,YOLO系列网络能够提取多尺度的特征信息,有助于更好地检测不同大小的目标。

2.2 联系

  1. 结构上的联系
    • Bottleneck层和Res unit都可以看作是残差学习的实现方式,它们都包含了跳跃连接。
    • ResX模块则结合了CBL和多个Res unit,形成了一个更复杂的结构单元。
  2. 功能上的联系
    • 三者都旨在提高网络的表达能力和泛化能力。
    • 通过引入残差学习的概念,它们都能够解决深层网络训练中的梯度消失或梯度爆炸问题。

三. 不同网络中的Bottleneck结构参数

2.1 ResNet网络中Bottleneck结构

        下图结构是在ResNet网络中的结构。先通过1x1进行降维,使用3x3进行卷积操作,最后使用1x1升维。

2.2 YOLOV5网络中的Bottleneck结构

        下图为YOLO V5中的结构,与ResNet网络中的Bottleneck结构相比,最大不同是只有2层卷积,最后一层不再使用1x1卷积升维,而是直接输出。

该结构的第一个卷积核为1x1进行降维,然后3x3进行卷积计算后直接输出,在该过程直接设置最终需要的输出Channel数,不再经过1x1卷积进行升维操作。

 YOLOV5 Bottleneck Pytorch实现

 YOLOV5 Bottleneck TensorRT部署 

2.3 YOLOV8网络中Bottleneck结构 


        YOLOV8中的Bottleneck结构和YOLOV5的一致,但是需要注意的是第一个瓶颈操作YOLOV8中使用的卷积核大小是3x3,而不是YOLOV5中使用的1x1,YOLOV8是通过使channel减半,来实现降低参数的目的。

        yoloV8 Bottleneck  pytorch实现

        YOLOV8 Bottleneck TensorRT部署

四、pytorch实现 

4.1 Bottleneck层的PyTorch实现

import torch  
import torch.nn as nn  
  
class Bottleneck(nn.Module):  
    def __init__(self, in_channels, out_channels, stride=1):  
        super(Bottleneck, self).__init__()  
        self.conv1 = nn.Conv2d(in_channels, out_channels // 4, kernel_size=1, stride=stride, bias=False)  
        self.bn1 = nn.BatchNorm2d(out_channels // 4)  
        self.conv2 = nn.Conv2d(out_channels // 4, out_channels // 4, kernel_size=3, stride=1, padding=1, bias=False)  
        self.bn2 = nn.BatchNorm2d(out_channels // 4)  
        self.conv3 = nn.Conv2d(out_channels // 4, out_channels, kernel_size=1, stride=1, bias=False)  
        self.bn3 = nn.BatchNorm2d(out_channels)  
        self.shortcut = nn.Sequential()  
        if stride != 1 or in_channels != out_channels:  
            self.shortcut = nn.Sequential(  
                nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),  
                nn.BatchNorm2d(out_channels),  
            )  
  
    def forward(self, x):  
        identity = x  
        out = self.conv1(x)  
        out = self.bn1(out)  
        out = nn.ReLU(inplace=True)(out)  
        out = self.conv2(out)  
        out = self.bn2(out)  
        out = nn.ReLU(inplace=True)(out)  
        out = self.conv3(out)  
        out = self.bn3(out)  
        out += self.shortcut(identity)  
        out = nn.ReLU(inplace=True)(out)  
        return out

4.2 Res Unit(残差单元)的PyTorch实现

在YOLO中,Res unit通常包含多个卷积层、批归一化层和激活层,以及一个残差连接(跳跃连接)。以下是一个简化的Res unit实现:

class ResUnit(nn.Module):  
    def __init__(self, in_channels, out_channels, stride=1):  
        super(ResUnit, self).__init__()  
        self.conv1 = nn.Conv2d(in_channels, out_channels // 2, kernel_size=1, stride=stride, bias=False)  
        self.bn1 = nn.BatchNorm2d(out_channels // 2)  
        self.conv2 = nn.Conv2d(out_channels // 2, out_channels // 2, kernel_size=3, stride=1, padding=1, bias=False)  
        self.bn2 = nn.BatchNorm2d(out_channels // 2)  
        self.conv3 = nn.Conv2d(out_channels // 2, out_channels, kernel_size=1, stride=1, bias=False)  
        self.bn3 = nn.BatchNorm2d(out_channels)  
        self.downsample = None  
        if stride != 1 or in_channels != out_channels:  
            self.downsample = nn.Sequential(  
                nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),  
                nn.BatchNorm2d(out_channels),  
            )  
  
    def forward(self, x):  
        identity = x  
        out = self.conv1(x)  
        out = self.bn1(out)  
        out = nn.LeakyReLU(inplace=True)(out, negative_slope=0.1)  
        out = self.conv2(out)  
        out = self.bn2(out)  
        out = nn.LeakyReLU(inplace=True)(out, negative_slope=0.1)  
        out = self.conv3(out)  
        out = self.bn3(out)  
        if self.downsample is not None:  
            identity = self.downsample(x)  
        out += identity  
        out = nn.LeakyReLU(inplace=True)(out, negative_slope=0.1)  
        return out

4.3 ResX模块的PyTorch实现

ResX模块通常包含多个Res unit和可能的下采样层。以下是一个简化的ResX模块实现,假设它包含两个Res unit和一个可选的下采样层:

class ResX(nn.Module):  
    def __init__(self, in_channels, out_channels, num_blocks=2, stride=1):  
        super(ResX, self).__init__()  
        self.cbl = nn.Sequential(  
            nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),  
            nn.BatchNorm2d(out_channels),  
            nn.LeakyReLU(inplace=True),  
        )  
        self.blocks = nn.ModuleList([  
            ResUnit(out_channels if i == 0 else out_channels, out_channels, stride if i == 0 else 1)  
            for i in range(num_blocks)  
        ])  
  
    def forward(self, x):  
        out = self.cbl(x)  
        for block in self.blocks:  
            out = block(out)  
        return out
  
# 示例用法  
# 假设in_channels=64, out_channels=128, 需要两个Res unit  
resx_module = ResX(64, 128, num_blocks=2, stride=2)  # 这里stride=2表示该ResX模块包含下采样

 请注意,上面的ResX实现假设所有Res unit的步长除了第一个之外都是1。如果需要在下采样后继续下采样,则需要在网络架构中显式地处理这一点(例如,在ResX模块之间添加额外的下采样层)。此外,YOLO的实际实现可能包含更多的细节和特定的设计选择,因此建议参考具体的YOLO版本和源代码以获取最准确的实现。

打印结果:

ResX(
  (blocks): ModuleList(
    (0): ResUnit(
      (conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(2, 2), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(64, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (downsample): Sequential(
        (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      )
    )
    (1): ResUnit(
      (conv1): Conv2d(128, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (conv3): Conv2d(64, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
      (bn3): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
)

五、总结

Bottleneck层、Res unit和ResX是YOLO系列算法中非常重要的组件,它们通过引入残差学习和多尺度特征提取机制,显著提升了网络的性能和效果。在YOLOv3、YOLOv4等版本中,这些组件被广泛应用并不断优化,为目标检测领域的发展做出了重要贡献。

需要注意的是,随着YOLO系列算法的不断发展,新的版本可能会引入更多的创新和改进。因此,在具体应用时,建议参考最新的官方文档和研究成果。

参考:

  1. yolo组件之Bottleneck层总结_yolo的bottleneck-CSDN博客
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浩瀚之水_csdn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值