YOLOv5改进 | 主干网络 | 用repvgg模块替换Conv【教程+代码 】

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

尽管Ultralytics 推出了最新版本的 YOLOv8 模型。但YOLOv5作为一个anchor base的目标检测的算法,YOLOv5可能比YOLOv8的效果更好。注意力机制是提高模型性能最热门的方法之一,本文给大家带来的教程是将YOLOv5的backbone的Conv用repvgg模块替换来提取特征。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行小白也可轻松上手实践此外还增加了进阶模块,来提高学有能力的同学进一步增长知识。帮助您更好地学习深度学习目标检测YOLO系列的挑战。

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

目录

1.原理

2. RepVGG代码实现

2.1 将RepVGG添加到YOLOv5中

2.2 新增yaml文件

 2.3 注册模块

2.4 执行程序

3. 完整代码分享

4. 进阶

5. 总结


1.原理

论文地址:RepVGG: Making VGG-style ConvNets Great Again点击即可跳转

官方代码:官方代码仓库点击即可跳转

RepVGG 是一种卷积神经网络架构,它通过对经典的VGG网络进行改进,提高了其在推理过程中的性能和效率。RepVGG的名称来自“Re-parameterizable VGG”,意指它在训练和推理阶段采用了不同的参数化方法。以下是对RepVGG的详细介绍:

  • 设计思想

  1. Re-parameterization:RepVGG的核心思想是在训练和推理阶段使用不同的网络结构。在训练阶段,RepVGG使用多分支结构,以增强模型的表示能力;而在推理阶段,这些多分支结构会被合并为单一分支,以提高计算效率。

  2. 简化的推理结构:在推理阶段,RepVGG变成了一个由普通卷积层和激活函数组成的简单网络。这种设计大大减少了计算量和内存占用,使得推理速度显著提升。

  • 架构

RepVGG的架构主要基于VGG,但在每个卷积层前后引入了1x1卷积层。这些1x1卷积层在训练时有助于提升网络的表示能力,而在推理时可以通过数学转换将其与主分支的卷积层合并,从而简化网络。

具体来说,RepVGG在训练阶段使用了三种卷积操作:

  1. 3x3卷积:这是VGG架构的主要卷积操作。

  2. 1x1卷积:增加非线性和特征组合能力。

  3. Identity mapping:保持特征的一致性。

在推理阶段,这三种操作会被重新参数化为一个等效的3x3卷积层,从而简化计算。

2. RepVGG代码实现

2.1 将RepVGG添加到YOLOv5中

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

img

def conv_bn(in_channels, out_channels, kernel_size, stride, padding, groups=1):
    result = nn.Sequential()
    result.add_module('conv', nn.Conv2d(in_channels=in_channels, out_channels=out_channels,
                                        kernel_size=kernel_size, stride=stride, padding=padding, groups=groups,
                                        bias=False))
    result.add_module('bn', nn.BatchNorm2d(num_features=out_channels))
​
    return result
​
​
class RepVGGBlock(nn.Module):
    '''RepVGGBlock is a basic rep-style block, including training and deploy status
    This code is based on https://github.com/DingXiaoH/RepVGG/blob/main/repvgg.py
    '''
    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(RepVGGBlock, self).__init__()
        """ Initialization of the class.
        Args:
            in_channels (int): Number of channels in the input image
            out_channels (int): Number of channels produced by the convolution
            kernel_size (int or tuple): Size of the convolving kernel
            stride (int or tuple, optional): Stride of the convolution. Default: 1
            padding (int or tuple, optional): Zero-padding added to both sides of
                the input. Default: 1
            dilation (int or tuple, optional): Spacing between kernel elements. Default: 1
            groups (int, optional): Number of blocked connections from input
                channels to output channels. Default: 1
            padding_mode (string, optional): Default: 'zeros'
            deploy: Whether to be deploy status or training status. Default: False
            use_se: Whether to use se. Default: False
        """
        self.deploy = deploy
        self.groups = groups
        self.in_channels = in_channels
        self.out_channels = out_channels
​
        assert kernel_size == 3
        assert padding == 1
​
        padding_11 = padding - kernel_size // 2
​
        self.nonlinearity = nn.ReLU()
​
        if use_se:
            raise NotImplementedError("se block not supported yet")
        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)
​
    def forward(self, inputs):
        '''Forward process'''
        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 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 switch_to_deploy(self):
        if hasattr(self, 'rbr_reparam'):
            return
        kernel, bias = self.get_equivalent_kernel_bias()
        self.rbr_reparam = nn.Conv2d(in_channels=self.rbr_dense.conv.in_channels, out_channels=self.rbr_dense.conv.out_channels,
                                     kernel_size=self.rbr_dense.conv.kernel_size, stride=self.rbr_dense.conv.stride,
                                     padding=self.rbr_dense.conv.padding, dilation=self.rbr_dense.conv.dilation, groups=self.rbr_dense.conv.groups, bias=True)
        self.rbr_reparam.weight.data = kernel
        self.rbr_reparam.bias.data = bias
        for para in self.parameters():
            para.detach_()
        self.__delattr__('rbr_dense')
        self.__delattr__('rbr_1x1')
        if hasattr(self, 'rbr_identity'):
            self.__delattr__('rbr_identity')
        if hasattr(self, 'id_tensor'):
            self.__delattr__('id_tensor')
        self.deploy = True
​
​
class RepBlock(nn.Module):
    '''
        RepBlock is a stage block with rep-style basic block
    '''
    def __init__(self, in_channels, out_channels, n=1):
        super().__init__()
        self.conv1 = RepVGGBlock(in_channels, out_channels)
        # 和yolov6官方的区别是这里没有用一个RepVGGBlock
        self.block = nn.Sequential(*(RepVGGBlock(out_channels, out_channels) for _ in range(n - 1))) if n > 1 else None
        # self.block = nn.Sequential(*[RepVGGBlock(out_channels, out_channels) for _ in range(n)])
​
    def forward(self, x):
        x = self.conv1(x)
        if self.block is not None:
            x = self.block(x)
        return x

RepVGG 的主要流程可以分为训练阶段和推理阶段两个部分。这两个阶段使用不同的网络结构,具体如下:

  • 训练阶段

在训练阶段,RepVGG 采用多分支的复杂网络结构,目的是增强模型的表示能力和学习能力。其主要流程如下:

  1. 输入图像:输入一个图像到网络中进行处理。

  2. 卷积层

    • 3x3 卷积:每个卷积层的核心操作,用于提取图像的局部特征。

    • 1x1 卷积:用于增加特征的非线性组合和特征混合。

    • Identity Mapping:保留原始特征,帮助网络学习更深层次的特征。

  3. 激活函数:在每个卷积层后应用非线性激活函数(如ReLU),增加网络的非线性表达能力。

  4. 池化层:在某些位置插入池化层(如最大池化层),降低特征图的分辨率,减少计算量并增加感受野。

  5. 全连接层:将卷积层输出的特征图展平,传递到全连接层,进行最终的分类或回归任务。

  6. 损失函数和反向传播:计算损失函数(如交叉熵损失),并通过反向传播算法调整网络的权重,使其逐渐优化。

  • 推理阶段

在推理阶段,RepVGG 会将训练阶段的多分支结构重新参数化为单一分支的简单结构,以提高计算效率。其主要流程如下:

  1. 重新参数化

    • 将训练阶段的 3x3 卷积、1x1 卷积 和 Identity Mapping 合并为一个等效的 3x3 卷积。

    • 这种合并可以通过数学推导和权重转换实现,确保推理阶段的网络结构更加简洁和高效。

  2. 简化网络结构:推理阶段的 RepVGG 只包含简单的卷积层和激活函数,没有额外的分支和复杂的运算。

  3. 输入图像:输入图像到简化后的网络结构中。

  4. 卷积层和激活函数:使用简化后的卷积层和激活函数进行特征提取和处理。

  5. 池化层:如训练阶段一样,插入必要的池化层,降低特征图的分辨率。

  6. 全连接层:将卷积层输出的特征图展平,传递到全连接层,进行最终的分类或回归任务。

  7. 输出结果:最终得到分类结果或其他推理任务的输出。

2.2 新增yaml文件

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

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license

# Parameters
nc: 80  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # 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, RepVGGBlock, [128, 3, 2]],  # 1-P2/4
   [-1, 3, C3, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 6, C3, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 9, C3, [512]],
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 3, C3, [1024]],
   [-1, 1, SPPF, [1024, 5]],  # 9
  ]

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

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

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

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

   [[17, 20, 23], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

温馨提示:本文只是对yolov5l基础上添加swin模块,如果要对yolov8n/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行左右添加 ‘RepVGGBlock’

2.4 执行程序

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

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

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

3. 完整代码分享

https://pan.baidu.com/s/1TAOAYPwSfssTbQw2iJ1pHw?pwd=yppx

提取码: yppx 

4. 进阶

你能将整个backbone部分换成RepVGG吗?这样会大幅度降低整个网络的GFLOPs[大约能降低一半]

5. 总结

RepVGG 是一种新的卷积神经网络(CNN)架构,旨在结合 VGG 模型的简单性与复杂网络的性能优势。其关键创新在于训练和推理架构的分离,通过一种称为结构重参数化(structural re-parameterization)的技术实现。在训练阶段,RepVGG 使用包含身份映射和 1×1 卷积的多分支架构,以增强模型的表示能力;在推理阶段,这些分支被合并为单一的 3×3 卷积层,从而简化网络结构并提高计算效率。RepVGG 在 ImageNet 数据集上取得了超过 80% 的 top-1 准确率,且相比 ResNet-50 和 ResNet-101 等模型,具有更快的推理速度和更高的准确性。其简单的架构不仅提高了内存利用率,还易于实施诸如通道剪枝等技术,表现出极高的灵活性和内存效率。RepVGG 在图像分类和语义分割任务中均表现出色,展示了其在各类应用中的广泛适用性和高效性能。这使得 RepVGG 成为学术界和工业界中非常实际且强大的选择。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IC617 虚拟机下载 RHEL6_ic617_hspice2015_spectre15

下载地址: 链接:https://pan.baidu.com/s/1kFEkq-SVkpSXcSS49THkiA?pwdtpm8 提取码:tpm8

tomcat学习--部署java项目

主流开发项目,springboot框架下,jar部署java传统的tomcat发布war包 一 什么是tomcat? 是一个用于运行java程序的软件,发布的时候:开发将源码使用maven打包,生产war包 二 安装tomcat tomcat是java写的&a…

磁带存储:“不老的传说”依然在继续

现在是一个数据指数增长的时代,根据IDC数据预测,2025年全世界将产生175ZB的数据。 这里面大部分数据是不需要存储的,在2025预计每年需要存储11ZB的数据。换算个容易理解的说法,1ZB是10^18Bytes, 相当于要写5556万块容量18TB的硬盘…

【介绍下运维开发】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…

【1.文件和目录相关(上)】

一、Linux的文件系统结构 1、Linux文件系统就是一个树形的分层组织结构。 2、文件系统层次结构标准FHS:用于规范文件目录命名和存放标准。 (1)/bin:是二进制英文缩写。 (2)/boot:存放的是系统启动时要用到的程序。 …

个股期权开户的准入条件

今天带你了解个股期权开户的准入条件。个股期权是一种金融行生品,投资者可以通过购买期权来获得在未来某个时间点以约定价格买入或卖出某只股票的权利,但不承担义务。 个股期权开户的准入条件 场外个股期权(OTC股票期权)相对于交…

【后端开发】服务开发场景之分布式(CAP,Raft,Gossip | API网关,分布式ID与锁 | RPC,Dubbo,Zookeeper)

【后端开发】服务开发场景之分布式(CAP,Raft,Gossip | API网关,分布式ID与锁 | RPC,Dubbo,Zookeeper) 文章目录 1、如何设计一个分布式系统?(底层原理)理论&a…

服务器感染了. rmallox勒索病毒,如何确保数据文件完整恢复?

导言: 近年来,随着信息技术的飞速发展,网络安全问题日益凸显。其中,勒索病毒作为一种严重的网络威胁,对个人和企业数据造成了巨大的威胁。本文将重点介绍.rmallox勒索病毒的特点、传播途径以及应对策略,旨…

MySQL的安全性

给root用户设置密码 点击用户--下面三个账号双击--进行编辑 修改密码--修改完进行保存 关闭数据库后连接不上 重新编辑,设置密码 新建账号 填入信息--保存(主机哪里要选择%) 连接这个新的账号 点击连接--填写连接的名称,地址&…

如何编写高效的单片机代码?

单片机的程序比软开少一些,真正想编写出高效的代码,还是要积累很多年的。 在做研发工程师的10年里,我经历过几个公司,看过很多工程师写的代码,但真正能让我跪着看完的,极少。哪怕是大厂工程师,也…

【深度好文】AI企业融合联盟营销,做的好就是最大赢家!

AI工具市场正在迅速发展,现仍有不少企业陆续涌出,那么如何让你的工具受到目标群体的关注呢?这相比是AI工具营销人员一直在思考的问题。 即使这个市场正蓬勃发展,也无法保证营销就能轻易成功。AI工具虽然被越来越多人认可和接受&a…

短视频矩阵系统源码---开发BS架构B/S(Browser/Server Architecture)架构

短视频矩阵系统源头开发------- 第一款叫做筷子科技,这个筷子科技剪辑和发布都是没有问题的,但是前一段时间他的剪辑发个公告,每个账号只能发两条,另外它的唯一缺点就是它成本比较高的,入门门槛应该在12800左右&#…

Linux学习笔记(epoll,IO多路复用)

Linux learning note 1、epoll的使用场景2、epoll的使用方法和内部原理2.1、创建epoll2.2、使用epoll监听和处理事件 3、示例 1、epoll的使用场景 epoll的英文全称是extend poll,顾名思义是poll的升级版。常见的IO复用技术有select,poll,epo…

HaloDB 的 Oracle 兼容模式

↑ 关注“少安事务所”公众号,欢迎⭐收藏,不错过精彩内容~ 前倾回顾 前面介绍了“光环”数据库的基本情况和安装办法。 哈喽,国产数据库!Halo DB! 三步走,Halo DB 安装指引 ★ HaloDB是基于原生PG打造的新一代高性能安…

海医大三院使用先进血管外科微创技术成功救治危重主动脉夹层患者

近日,上海东方肝胆外科医院血管外科周建教授团队采用主动脉弓分支型一体化移植物联合体外开窗技术,成功救治复杂危重主动脉夹层患者,为上海嘉定首例,彰显了上海东方肝胆外科医院血管外科的优势与特色。 患者谢先生,72岁,两周前突发剧烈胸背部撕裂样疼痛,休息后症状未能得到缓解…

MyBatis的坑(动态SQL会把0和空串比较相等为true)

文章目录 前言一、场景如下二、原因分析1. 源码分析2. 写代码验证 三、解决办法代码及执行结果如下 总结 前言 在开发过程中遇到MyBatis的动态SQL的if条件不生效的情况,但经过debuger发现并不是参数问题,已经拿到了参数并传给了MyBatis,且从表…

APP逆向之调试的开启

很基础的一个功能设置,大佬轻喷。 背景 在开始进行对APP逆向分析的时候,需要对APP打开调试模式。 打开调试的模式有多种方式可以通过直接改包方式也可以通过借助第三方工具进行打开调试模式。 下面就整理下这个打开调试模式的一些方式。 改包修改模…

计算机网络学习笔记——应用层

一、应用层概述 二、客户/服务器方式(C/S方式)和对等方式(P2P方式) 客户/服务器(Client/Server,C/S)方式 服务器总是处于运行状态,并等待客户的服务请求。服务器具有固定端口号(例如HTTP服务器的默认端口号为80),而运行服务器的主机也具有固…

四川汇聚荣聚荣科技有限公司是正规的吗?

在当今社会,随着科技的飞速发展,越来越多的科技公司如雨后春笋般涌现。然而,在这个信息爆炸的时代,如何判断一家公司是否正规成为了许多人关注的焦点。本文将围绕“四川汇聚荣聚荣科技有限公司是否正规”这一问题展开讨论&#xf…

社区供稿丨GPT-4o 对实时互动与 RTC 的影响

以下文章来源于共识粉碎机 ,作者AI芋圆子 前面的话: GPT-4o 发布当周,我们的社区伙伴「共识粉碎机」就主办了一场主题为「GPT-4o 对实时互动与 RTC 的影响」讨论会。涉及的话题包括: GPT-4o 如何降低延迟(VAD 模块可…