YOLOv5改进 | 主干网络 | 用SimRepCSP作为主干网络提取特征【全网独家 + 降本增效】

发布于:2024-06-07 ⋅ 阅读:(344) ⋅ 点赞:(0)

💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡

SimRepCSP 类似于 YOLOv7的主干网络,由卷积模块和重参数化卷积(RepConv)模块组合而成,以 Cross Stage Partial(CSP)网络作为模块之间的连接。通过将 SimRepCSP 作为替代主干纳入 YOLOv5,本文介绍了一种简单而有效的替代模块SimRepCSP 。在本文中,给大家带来的教程是在原来的主干网络修改为SimRepCSP 。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。

专栏地址: YOLOv5改进+入门——持续更新各种有效涨点方法 点击即可跳转

目录

1. 原理

2. SimRepCSP的代码实现

2.1 将SimRepCSP添加到YOLOv5中

SimRepCSP 主要流程:

2.2 新增yaml文件

2.3 注册模块

 2.4 执行程序

3. 完整代码分享

4. GFLOPs

5.总结


1. 原理

官方论文:Modified YOLO Model for Small Platform Application using SimRepCSP Module with Case Study——点击即可跳转

SimRepCSP 是一种针对 YOLO 模型的改进背骨模块,其设计旨在提高训练效率和模型性能,同时降低成本。以下是 SimRepCSP 的主要原理及其应用:

SimRepCSP 主要原理

  1. 模块组合:

    • 卷积模块:SimRepCSP 集成了标准的卷积模块。

    • 重新参数化卷积模块(RepConv):这些是专门设计的卷积层,通过增加模型参数来提高性能,而不会显著增加计算成本。

    • 跨阶段部分网络(CSP):该网络结构连接不同的模块,增强特征传播和网络学习能力。

  2. 结构和效率:

    • SimRepCSP 通过组合三个卷积模块、一个 RepConv 模块和一个连接到 CSP 网络的级联模块构建而成。

    • 这些模块排列的目的是最大化特征提取和重用,从而在减少参数数量的情况下提升性能。

    • 每个卷积模块都包含批量归一化和 SiLU 激活函数。

  3. 与 YOLO 的集成:

    • SimRepCSP 可以作为替代背骨集成到 YOLOv8 模型中,分别称为 SimRepCSPv1 和 SimRepCSPv2。这种集成旨在提升模型性能指标,相较于原始的 YOLOv8 背骨。

    • SimRepCSP 的架构包括一个焦点层、多层 SimRepCSP 模块和一个 SPPF(快速空间金字塔池化)模块,用于多尺度特征聚合。

  4. 实验结果:

    • 在 GlobalWheat2020 数据集上进行的实验表明,带有 SimRepCSP 模块(SimRepCSPv1 和 SimRepCSPv2)的模型在减少训练和应用成本的同时,实现了更高的性能指标。

    • 主要改进包括减少了 FLOPS(每秒浮点运算次数)、GPU 内存使用量和整体模型重量,同时保持或提高了目标检测的准确性。

  5. 目标和优势:

    • 降低计算成本:通过减少所需操作次数,SimRepCSP 旨在使模型更加高效。

    • 增强参数性能:通过微调和优化参数来提高模型的准确性和有效性。

    • 降低 GPU 内存成本:最小化内存需求以允许更大的批处理大小和更高效的训练。

    • 减少模型重量:创建一个轻量级模型,便于部署而不影响性能。

总结

SimRepCSP 通过优化网络架构、减少计算和内存成本以及增强特征提取和参数调优,显著提高了 YOLO 模型的效率和性能。

2. SimRepCSP的代码实现

2.1 将SimRepCSP添加到YOLOv5中

关键步骤一: 将下面代码粘贴到/projects/yolov5-6.1/models/common.py文件中

*注:代码过长,请查看完整代码 

class RepConv(nn.Module):
    # Represented convolution
    # https://arxiv.org/abs/2101.03697

    def __init__(self, c1, c2, k=3, s=1, p=None, g=1, act=True, deploy=False):
        super(RepConv, self).__init__()

        self.deploy = deploy
        self.groups = g
        self.in_channels = c1
        self.out_channels = c2

        assert k == 3
        assert autopad(k, p) == 1

        padding_11 = autopad(k, p) - k // 2

        self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) #

        if deploy:
            self.rbr_reparam = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=True)

        else:
            self.rbr_identity = (nn.BatchNorm2d(num_features=c1) if c2 == c1 and s == 1 else None)

            self.rbr_dense = nn.Sequential(
                nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False),
                nn.BatchNorm2d(num_features=c2),
            )

            self.rbr_1x1 = nn.Sequential(
                nn.Conv2d( c1, c2, 1, s, padding_11, groups=g, bias=False),
                nn.BatchNorm2d(num_features=c2),
            )

    def forward(self, inputs):
        if hasattr(self, "rbr_reparam"):
            return self.act(self.rbr_reparam(inputs))

        if self.rbr_identity is None:
            id_out = 0
        else:
            id_out = self.rbr_identity(inputs)

        return self.act(self.rbr_dense(inputs) + self.rbr_1x1(inputs) + id_out)
    
    def get_equivalent_kernel_bias(self):
        kernel3x3, bias3x3 = self._fuse_bn_tensor(self.rbr_dense)
        kernel1x1, bias1x1 = self._fuse_bn_tensor(self.rbr_1x1)
        kernelid, biasid = self._fuse_bn_tensor(self.rbr_identity)
        return (
            kernel3x3 + self._pad_1x1_to_3x3_tensor(kernel1x1) + kernelid,
            bias3x3 + bias1x1 + biasid,
        )

    def _pad_1x1_to_3x3_tensor(self, kernel1x1):
        if kernel1x1 is None:
            return 0
        else:
            return nn.functional.pad(kernel1x1, [1, 1, 1, 1])

    def _fuse_bn_tensor(self, branch):
        if branch is None:
            return 0, 0
        if isinstance(branch, nn.Sequential):
            kernel = branch[0].weight
            running_mean = branch[1].running_mean
            running_var = branch[1].running_var
            gamma = branch[1].weight
            beta = branch[1].bias
            eps = branch[1].eps
        else:
            assert isinstance(branch, nn.BatchNorm2d)
            if not hasattr(self, "id_tensor"):
                input_dim = self.in_channels // self.groups
                kernel_value = np.zeros(
                    (self.in_channels, input_dim, 3, 3), dtype=np.float32
                )
                for i in range(self.in_channels):
                    kernel_value[i, i % input_dim, 1, 1] = 1

SimRepCSP 主要流程:

  1. 输入图片预处理:

    • 图片读取:从存储介质或摄像头读取输入图片。

    • 图片缩放:将图片缩放到模型所需的输入尺寸(例如,YOLOv8 通常使用 640x640 像素的输入大小)。

    • 归一化处理:将图片像素值归一化到 [0, 1] 区间。

  2. 特征提取(通过 SimRepCSP 模块):

    • 初始卷积和下采样:输入图片首先通过一个初始卷积层和下采样层,这有助于减少图片的空间尺寸并提取基本特征。

    • CSP 模块处理:图片特征进入多个 SimRepCSP 模块,每个模块由标准卷积、RepConv 和 CSP 网络组成。具体流程如下:

      • 标准卷积:标准卷积层提取局部特征。

      • RepConv:重新参数化卷积层在训练期间增强模型的表示能力。

      • CSP 网络:跨阶段部分网络将特征进行跨层传递和整合,进一步丰富特征表示。

  3. 多尺度特征提取:

    • 特征金字塔网络(FPN):SimRepCSP 结合特征金字塔网络,提取不同尺度的特征以应对不同尺寸的目标物体。

    • 空间金字塔池化(SPPF):在 SimRepCSPv1 和 SimRepCSPv2 中引入 SPPF 模块,用于多尺度特征的聚合和增强。

  4. 特征融合与预测:

    • 特征融合:将不同尺度的特征融合,生成最终的特征图。

    • 检测头:最终特征图传递给检测头,进行目标的分类和定位预测。检测头包括一系列的卷积层和激活函数,用于输出目标的类别和边界框坐标。

    2.2 新增yaml文件

    关键步骤二:在下/projects/yolov5-6.1/models下新建文件 yolov5_SimRepCSP.yaml并将下面代码复制进去

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80  # number of classes
depth_multiple: 1  # model depth multiple
width_multiple: 1  # layer channel multiple
anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32


# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2
   [-1, 1, Conv, [128, 3, 2]], #1 1-P2/4
   
   [-1, 1, Conv, [64, 1, 1]], #2

   [-1, 1, RepConv, [64, 3, 1]], #3
   [[-1,-2], 1, Concat, [1]], #4
   [-1, 1, Conv, [128, 1, 1]], #5

   [-1, 1, Conv, [256, 3, 2]],  #6/ 3-P3/8
   
   [-1, 1, Conv, [128, 1, 1]], #7

   [-1, 1, RepConv, [128, 3, 1]], #8
   [[-1,-2], 1, Concat, [1]], #9
   [-1, 1, Conv, [256, 1, 1]],  #10 -P4/16 

   [-1, 1, Conv, [512, 3, 2]], #11
   [-1, 1, Conv, [256, 1, 1]], #12

   [-1, 1, RepConv, [256, 3, 1]], #13
   [[-1,-2], 1, Concat, [1]], #14
   [-1, 1, Conv, [512, 1, 1]], #15

   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32 16

   [-1, 1, Conv, [512, 1, 1]], #17

   [-1, 1, RepConv, [512, 3, 1]], #18
   [[-1,-2], 1, Concat, [1]], #19
   [-1, 1, Conv, [1024, 1, 1]], #20

   [-1, 1, SPPF, [1024, 5]],  # 21
  ]


# YOLOv5 v6.0 head
head:
   [[-1, 1, Conv, [512, 1, 1]], #22
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 11], 1, Concat, [1]],  # cat backbone P4
   [-1, 3, C3, [512, False]],  # 25


   [-1, 1, Conv, [256, 1, 1]], #26
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 6], 1, Concat, [1]],  #28 cat backbone P3
   [-1, 3, C3, [256, False]],  # 29 (P3/8-small)


   [-1, 1, Conv, [256, 3, 2]],
   [[-1,26], 1, Concat, [1]],  # 31 cat head P4
   [-1, 3, C3, [512, False]],  # 32 (P4/16-medium)


   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 22], 1, Concat, [1]],  #34 cat head P5
   [-1, 3, C3, [1024, False]],  #35 (P5/32-large)


   [[29, 32, 35], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

温馨提示:本文只是对yolov5l基础上添加模块,如果要对yolov5n/l/m/x进行添加则只需要指定对应的depth_multiple 和 width_multiple。


# YOLOv5n
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.25  # layer channel multiple
 
# YOLOv5s
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple
 
# YOLOv5l 
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
 
# YOLOv5m
depth_multiple: 0.67  # model depth multiple
width_multiple: 0.75  # layer channel multiple
 
# YOLOv5x
depth_multiple: 1.33  # model depth multiple
width_multiple: 1.25  # layer channel multiple

2.3 注册模块

关键步骤三:在yolo.py中注册, 大概在260行左右添加 ‘RepConv’

 2.4 执行程序

在train.py中,将cfg的参数路径设置为yolov5_SimRepCSP.yaml的路径

建议大家写绝对路径,确保一定能找到

🚀运行程序,如果出现下面的内容则说明添加成功🚀

3. 完整代码分享

https://pan.baidu.com/s/17lq0bRONXbtMRgAalj77gA?pwd=39uq

 提取码: 39uq  

4. GFLOPs

关于GFLOPs的计算方式可以查看:百面算法工程师 | 卷积基础知识——Convolution

未改进的GFLOPs

改进后的GFLOPs

5.总结

SimRepCSP 是一种针对 YOLO 模型的改进backbone模块,其设计旨在提高训练效率和模型性能,同时降低成本。它通过集成标准卷积模块、重新参数化卷积模块(RepConv)和跨阶段部分网络(CSP)来增强特征传播和网络学习能力。SimRepCSP 的结构包括三个卷积模块、一个 RepConv 模块和一个连接到 CSP 网络的级联模块,这些模块的排列旨在最大化特征提取和重用,从而在减少参数数量的情况下提升性能。每个卷积模块都包含批量归一化和 SiLU 激活函数。SimRepCSP 可以作为替代backbone集成到 YOLOv5 模型中,分别称为 SimRepCSPv1 和 SimRepCSPv2,这种集成旨在提升模型性能指标,相较于原始的backbone。SimRepCSP 的架构包括一个焦点层、多层 SimRepCSP 模块和一个 SPPF(快速空间金字塔池化)模块,用于多尺度特征聚合。带有 SimRepCSP 模块的模型在减少训练和应用成本的同时,实现了更高的性能指标,主要改进包括减少了 FLOPS(每秒浮点运算次数)、GPU 内存使用量和整体模型重量,同时保持或提高了目标检测的准确性。SimRepCSP 的目标和优势在于通过减少所需操作次数降低计算成本,通过微调和优化参数增强参数性能,最小化内存需求以允许更大的批处理大小和更高效的训练,并创建一个轻量级模型,便于部署而不影响性能。总体而言,SimRepCSP 通过优化网络架构、减少计算和内存成本以及增强特征提取和参数调优,显著提高了 YOLO 模型的效率和性能。


微信公众号

今日签到

点亮在社区的每一天
去签到