RCS-YOLO:检测头和网络结构的改进

news2025/2/27 11:19:39

目录

摘要

原理

总体结构图

 RCS模块原理

代码实现

RCS-Based One-Shot Aggregation

代码实现 

检测头改进

手动计算anchor代码

yaml文件

已详细修改的代码

程序启动命令

可论文指导  +V ------------> jiabei-545

往期推荐 


摘要

凭借速度和准确性之间的出色平衡,尖端的 YOLO 框架已成为最有效的目标检测算法之一。然而, YOLO 网络的性能还有提升的空间。我们提出了 RCS 和 RCS 的一次聚合(RCS-OSA),它将特征级联和计算效率联系起来,以提取更丰富的信息并减少时间消耗。所提出的模型在速度和准确性上超越了YOLOv6、YOLOv7和YOLOv8。值得注意的是,与YOLOv7相比,RCS-YOLO的精度提高了1%,推理速度提高了60%,每秒检测到114.8张图像(FPS)。

原理

1、首先通过将 RepVGG/RepConv 与 ShuffleNet 相结合来开发 RepVGG/RepConv ShuffleNet (RCS),它受益于重新参数化,可以在训练阶段提供更多特征信息并减少推理时间。然后,我们构建了一个基于 RCS 的一次性聚合(RCSOSA)模块,该模块不仅允许低成本的内存消耗,而且还允许语义信息提取。 

2、通过将开发的 RCS-OSA 和 RepVGG/RepConv 与路径聚合相结合,设计了 YOLO 架构的新骨干和颈部网络,以缩短特征预测层之间的信息路径。这促进了准确的定位信息快速传播到骨干网络和颈部网络中的特征层次结构。

总体结构图
 RCS -YOLO的架构主要由RCS -OSA(蓝色)和RepVGG(橙色)模块组成。 n表示堆叠的RCS模块的数量。 ncls 表示检测到的对象中的类数。
 RCS模块原理

受ShuffleNet的启发,设计了一种基于通道shuffle的结构重参数化卷积。下图为RCS的结构示意图。

RCS的结构:左边是训练阶段的 RepVGG。 右边是模型推理(或部署)期间的 RepConv。

假设输入张量的特征维度为 C×H×W ,在通道分割算子之后,它被分为两个不同的通道张量,其维度相同C×H×W 。对于其中一个张量,我们使用恒等分支、1×1 卷积和 3×3 卷积来构造训练时 RCS。在推理阶段,使用结构重参数化将恒等分支、1×1 卷积和3×3 卷积转换为3×3 RepConv。多分支拓扑架构可以在训练时学习丰富的特征信息,简化的单分支架构可以节省推理时的内存消耗,实现快速推理。对其中一个张量进行多分支训练后,它以通道方式连接到另一个张量。通道混洗算子还用于增强两个张量之间的信息融合,从而可以以较低的计算复杂度实现输入的不同通道特征之间的深度测量。

代码实现
class RepVGG(nn.Module):

    def __init__(self, in_channels, out_channels, kernel_size=3,
                 stride=1, padding=1, dilation=1, groups=1, padding_mode='zeros', deploy=False, use_se=False):
        super(RepVGG, self).__init__()
        self.deploy = deploy
        self.groups = groups
        self.in_channels = in_channels

        padding_11 = padding - kernel_size // 2

        self.nonlinearity = nn.SiLU()
        # self.nonlinearity = nn.ReLU()

        if use_se:
            self.se = SEBlock(out_channels, internal_neurons=out_channels // 16)
        else:
            self.se = nn.Identity()

        if deploy:
            self.rbr_reparam = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size,
                                         stride=stride,
                                         padding=padding, dilation=dilation, groups=groups, bias=True,
                                         padding_mode=padding_mode)

        else:
            self.rbr_identity = nn.BatchNorm2d(
                num_features=in_channels) if out_channels == in_channels and stride == 1 else None
            self.rbr_dense = conv_bn(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size,
                                     stride=stride, padding=padding, groups=groups)
            self.rbr_1x1 = conv_bn(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=stride,
                                   padding=padding_11, groups=groups)
            # print('RepVGG Block, identity = ', self.rbr_identity)

    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 torch.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.conv.weight
            running_mean = branch.bn.running_mean
            running_var = branch.bn.running_var
            gamma = branch.bn.weight
            beta = branch.bn.bias
            eps = branch.bn.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
                self.id_tensor = torch.from_numpy(kernel_value).to(branch.weight.device)
            kernel = self.id_tensor
            running_mean = branch.running_mean
            running_var = branch.running_var
            gamma = branch.weight
            beta = branch.bias
            eps = branch.eps
        std = (running_var + eps).sqrt()
        t = (gamma / std).reshape(-1, 1, 1, 1)
        return kernel * t, beta - running_mean * gamma / std

    def forward(self, inputs):
        if hasattr(self, 'rbr_reparam'):
            return self.nonlinearity(self.se(self.rbr_reparam(inputs)))

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

        return self.nonlinearity(self.se(self.rbr_dense(inputs) + self.rbr_1x1(inputs) + id_out))

    def fusevggforward(self, x):
        return self.nonlinearity(self.rbr_dense(x))
RCS-Based One-Shot Aggregation

此外,还设计了单次聚合(OSA)模块来克服 DenseNet 中密集连接的低效率,通过用多感受野表示多样化特征并在最后的特征图中仅聚合所有特征一次。 VoVNet V1 [14 ] 和 V2 [15 ] 在其架构中使用 OSA 模块来构建轻量级和大规模目标检测器,其性能优于广泛使用的 ResNet 主干网络,具有更快的速度和更好的能源效率。

RCS-OSA的结构。 n表示堆叠的RCS模块的数量。
代码实现 
class RCSOSA(nn.Module):
    # VoVNet with Res Shuffle RepVGG
    def __init__(self, c1, c2, n=1, se=False, e=0.5, stackrep=True):
        super().__init__()
        n_ = n // 2
        c_ = make_divisible(int(c1 * e), 8)
        # self.conv1 = Conv(c1, c_)
        self.conv1 = RepVGG(c1, c_)
        self.conv3 = RepVGG(int(c_ * 3), c2)
        self.sr1 = nn.Sequential(*[SR(c_, c_) for _ in range(n_)])
        self.sr2 = nn.Sequential(*[SR(c_, c_) for _ in range(n_)])

        self.se = None
        if se:
            self.se = SEBlock(c2)

    def forward(self, x):
        x1 = self.conv1(x)
        x2 = self.sr1(x1)
        x3 = self.sr2(x2)
        x = torch.cat((x1, x2, x3), 1)
        return self.conv3(x) if self.se is None else self.se(self.conv3(x))

检测头改进

为了进一步减少推理时间,我们将 RepVGG 和 Detect 组成的检测头数量从 3 个减少到 2 个。YOLOv5、YOLOv6、YOLOv7 和 YOLOv8 有 3 个检测头。然而,我们只使用两个特征层进行预测,将原来九个不同尺度的anchor数量减少到四个,并使用K-means无监督聚类方法重新生成不同尺度的anchor。这不仅减少了RCS-YOLO的卷积层数和计算复杂度,而且减少了推理阶段网络的整体计算要求和后处理非极大值抑制的计算时间。

Yolov5的检测目标分别从检测输出17,20,23

YOLOv5结构图
手动计算anchor代码

YOLO 手动计算anchor的值-CSDN博客不需要运行 kmeans.py,运行 clauculate_anchors.py 即可。创建程序两个程序 kmeans.py 以及 clauculate_anchors.py。会调用 kmeans.py 聚类生成新anchors的文件。kmeans.py 程序如下:这不需要运行,也不需要更改。如果报错,可以查看第 13 行内容。会生成anchors文件。https://blog.csdn.net/m0_67647321/article/details/136315355?spm=1001.2014.3001.5501

yaml文件
# RCS-YOLO v1.0  (Two heads)

# Parameters
nc: 1  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 0.75  # layer channel multiple
anchors:
  - [87,90,  127,139]  # P4/16
  - [154,171,  191,240]  # P5/32

# backbone
backbone: # 12462
  # [from, number, module, args]
  [[-1, 1, RepVGG, [64, 3, 2]],  # 0-P1/2
   [-1, 1, RepVGG, [128, 3, 2]],  # 1-P2/4
   [-1, 2, RCSOSA, [128]],
   [-1, 1, RepVGG, [256, 3, 2]],  # 3-P3/8
   [-1, 2, RCSOSA, [256]],
   [-1, 1, RepVGG, [512, 3, 2]],  # 5-P4/16
   [-1, 4, RCSOSA, [512, True]],
   [-1, 1, RepVGG, [1024, 3, 2]],  # 7-P5/32
   [-1, 2, RCSOSA, [1024, True]],
   [-1, 1, SPPF, [1024, 5]],  # 9
  ]

# head
head:
  [[-1, 1, Conv, [512, 1, 1]], # 10
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [-1, 2, RCSOSA, [512]],  # 12

   [[-1, 6], 1, Concat, [1]],  # cat backbone P4
   [-1, 2, RCSOSA, [512]],  # 14

   [-1, 1, RepVGG, [512, 3, 2]],
   [[-1, 10], 1, Concat, [1]],  # cat head P5
   [-1, 2, RCSOSA, [768]],  # 17

   [14, 1, RepVGG, [512, 3, 1]],
   [17, 1, RepVGG, [768, 3, 1]],

   [[18, 19], 1, IDetect, [nc, anchors]],  # Detect(P4, P5)
  ]
已详细修改的代码

链接: https://pan.baidu.com/s/1EOeZP5kJ92tVjZgFtM0Wdg?pwd=zk88 提取码: zk88 

程序启动命令

单GPU

python train.py --workers 8 --device 0 --batch-size 32 --data data/br35h.yaml --img 640 640 --cfg cfg/training/rcs-yolo.yaml --weights '' --name rcs-yolo --hyp data/hyp_training.yaml

多GPU

python -m torch.distributed.launch --nproc_per_node 4 --master_port 9527 train.py --workers 8 --device 0,1,2,3 --sync-bn --batch-size 128 --data data/br35h.yaml --img 640 640 --cfg cfg/training/rcs-yolo.yaml --weights '' --name rcs-yolo --hyp data/hyp_training.yaml
可论文指导  +V ------------> jiabei-545
往期推荐 

Yolov8有效涨点:YOLOv8-AM,添加多种注意力模块提高检测精度,含代码,超详细-CSDN博客

有效涨点,增强型 YOLOV8 与多尺度注意力特征融合,附代码,详细步骤-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1473499.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学习笔记-李沐动手学深度学习(七)(19-21,卷积层、填充padding、步幅stride、多输入多输出通道)

总结 19-卷积层 【补充】看评论区建议的卷积动画视频 数学中的卷积 【链接】https://www.bilibili.com/video/BV1VV411478E/?fromsearch&seid1725700777641154181&vd_sourcee81e116c4ffe5e79d4bc44738263eda4 【可判断是否为卷积的典型标志】两个函数中自变量相加…

瑞_Redis_Redis客户端

文章目录 1 Redis客户端1.1 Redis命令行客户端1.2 图形化桌面客户端1.2.1 资源准备1.2.2 安装1.2.3 建立连接 🙊 前言:本文章为瑞_系列专栏之《Redis》的基础篇的Redis客户端章节。由于博主是从B站黑马程序员的《Redis》学习其相关知识,所以本…

导轨安装式称重传感器信号变送器差分信号隔离转换0-10mV/0-20mV/0-±10mV/0-±20mV转0-5V/0-10V/4-20mA

主要特性 DIN11 IPO 压力应变桥信号处理系列隔离放大器是一种将差分输入信号隔离放大、转换成按比例输出的直流信号导轨安装变送模块。产品广泛应用在电力、远程监控、仪器仪表、医疗设备、工业自控等行业。此系列模块内部嵌入了一个高效微功率的电源,向输入端和输…

图像处理ASIC设计方法 笔记4 异步FIFO

P66 异步FIFO 这段对FIFO的描述很精彩: 理解了水位信号的含义(相当于通常所说的满/空标志,注意读时钟域的空信号,写时钟域的满信号,只能在它各自的时钟域直接使用,如果要在另一时钟域用,需要使…

顺丰科技2024届春季校园招聘常见问题解答及SHL测评题库

顺丰科技2024届春季校园招聘常见问题解答及SHL测评题库 Q:顺丰科技2024届校园招聘面向对象是? A:2024届应届毕业生,毕业时间段为2023年10月1日至2024年9月30日(不满足以上毕业时间的同学可以关注顺丰科技社会招聘或…

【无标题】vite配置代理--loadEnv

环境变量的定义是:会根据当前那代码环境产生值的变化的变量 在 Vite 项目中,使用环境变量提供了一种在不同环境下定制化应用行为的方式。通过读取环境变量,我们可以设置不同的配置信息。 开发中常见的场景有: 区分开发和生产环境 …

<网络安全>《54 概念讲解<第一课 IT和OT>》

1 基本概念 IT:Information Technology的缩写,指信息技术;主要指的是企业中的各个应用系统,包括ERP、MES、EAM、OA等,分布部署在不同的网络层级。除了应用系统,还有计算机,服务器等等&#xff…

Qt介绍以及qt_creater的安装和C++项目工程创建

最近天气严寒,同学们要注意保暖哦!学习的同时别忘了照顾好自己呀!o(* ̄▽ ̄*)ブ 目录 一、Qt 1、Qt概念 2、常见的GUI 二、安装qt_creater 方法一: 方法二: 三、Qt_creater 中C项目的创建 …

【BUG 记录】MyBatis-Plus 处理枚举字段和 JSON 字段

【BUG 记录】MyBatis-Plus 处理枚举字段和JSON字段 一、枚举字段(mysql环境已测、postgresql环境已测)1.1 场景1.2 定义枚举常量1.3 配置枚举处理器1.4 测试 二、JSON字段(mysql环境已测)2.1 导包2.2 使用对象接受2.3 测试 三、JS…

SpringBoot快速入门(黑马学习笔记)

需求 需求:基于SpringBoot的方式开发一个Web应用,浏览器发起请求/hello后,给浏览器返回字符串"Hello World~"。 开发步骤 第一步:创建SpringBoot工程项目 第二步:定义HelloController类,添加方…

【惠友小课堂】骨质疏松≠老年人“专利”,年轻人也不能忽视(文末附自我测试)

虽说现在大家对于骨质疏松并不陌生,许多中老年人甚至年轻人都开始认识到“维护骨骼要趁早”,但依旧有人对骨质疏松存在一些“误解”,今天就来一一解开。(PS:文末有骨质疏松自我测试哦~) 某在读大学生 “我这…

学成在线_课程计划查询_前端页面无法跳转

问题描述 在进行课程计划查询的接口开发时通过了http-client测试但点开课程修改界面后点击保存并进行下一步时无法跳转到修改课程计划查询的页面。 问题原因 课程信息修改的Controller层没有实现 QAQ(可能是老师在讲这一块的时候没有提这一点(我也记…

Netty权威指南——基础篇2(NIO编程)备份

1 概述 与Socket类和ServerSocket,NIO也提供了SocketChannel和ServerSocketChannel两种不同的套接字通道实现。这两种新增的通道都支持阻塞和非阻塞两种模式。阻塞模式使用简单,但性能和可靠性都不好,非阻塞模式则正好相反。一般来说&#xf…

论文阅读:《High-Resolution Image Synthesis with Latent Diffusion Models》

High-Resolution Image Synthesis with Latent Diffusion Models 论文链接 代码链接 What’s the problem addressed in the paper?(这篇文章究竟讲了什么问题?比方说一个算法,它的 input 和 output 是什么?问题的条件是什么) 这篇文章提…

蚓链数字化生态系统, 高效的分钱体验!

​2024年2月24日,农历正月十五是个团圆的好日子,开利网络推出更强体验的“数据分析功能”---【订单分析】:给各位运营用户更加直接、直观的“分钱体验”! 该功能使得运营者掌握更加强有力的数字化工具!可以更高效的服务…

Qt网络编程——UDP

UDP UDP(User Datagram Protocol,用户数据报协议)是一个轻量级的、不提供可靠性保证的、面向数据报的无连接协议,用于可靠性不是非常重要的情况。例如,传感器数据传输:一些传感器数据,如温度、…

Spring6学习技术|事务

学习材料 尚硅谷Spring零基础入门到进阶,一套搞定spring6全套视频教程(源码级讲解) 事务 什么是事务?好像是数据库部分的词,我自己的理解是对数据库进行的操作序列,要么一起完成,要么都不完成…

./configure配置说明

./configure是用来检测你的安装平台的目标特征的。configure根据给定的参数和系统环境会生成Makefile。 在一次configure报错后记得删除生成的config.cache的相关文件再重新configure。(make distclean类似make clean,但同时会将configure生成的文件全部删除掉&…

thinkphp6定时任务

这里主要是教没有用过定时任务没有头绪的朋友, 定时任务可以处理一些定时备份数据库等一系列操作, 具体根据自己的业务逻辑进行更改 直接上代码 首先, 是先在 tp 中的 command 方法中声明, 如果没有就自己新建一个, 代码如下 然后就是写你的业务逻辑 执行定时任务 方法写好了…

代码随想录算法训练营day28

题目:78_子集(没看题解) 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 说明:解集不能包含重复的子集。 示例: 输入: nums [1,2,3] 输出: [ [3], [1], [2], …