YOLOv8不同位置引入RepVGG重参数化

news2025/2/23 7:34:10

一、原理解析:
复杂的卷积网络大都具有如下缺点:

  1. 复杂的多分支设计(如ResNet中的残差相加和Inception中的分支连接)使模型难以实现和自定义,降低了推理速度和降低了内存利用率。
  2. 一些组件(例如Xception和MobileNets中的depth conv和ShuffleNets中的channel shuffle)增加了内存访问成本,缺乏各种设备的支持。

RepVGG具有以下优点。
•该模型具有类似VGG的无分支(即前馈)拓扑,这意味着每一层都将其唯一前一层的输出作为输入,并将输出馈送到其唯一后一层。
•该模型的主体仅使用3×3 conv和ReLU。
•具体的架构(包括特定的深度和层宽度)实例化时不需要自动搜索、手动细化、复合缩放,也不需要其他繁重的设计。

由于多分支结构的优点都是训练的,而缺点是不利于推理的,我们提出了通过结构重新参数化将训练时多分支结构和推理时平面结构解耦,即通过变换结构参数将结构从一个结构转换到另一个结构。具体地说,网络结构与一组参数相耦合,例如:

卷积层由四阶核张量表示。如果某一结构的参数可以转换为另一结构耦合的另一组参数,我们可以等效地用后者替代前者,从而改变整个网络架构。

具体来说,我们使用identity和1×1分支构造了训练时的RepVGG,这是受ResNet的启发,但采用了不同的方式,可以通过结构重新参数化来删除分支(图2、4)。经过训练后,我们用简单代数进行变换,将一个identity分支看作是一个降级的1×1 conv,后者可以进一步看作是一个降级的3×3 conv,这样我们就可以用原3×3 kernel、identity和1×1分支以及批归一化(BN)层的训练参数构造一个3×3 kernel。因此,转换后的模型有一堆3×3的 conv层,保存用于测试和部署。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

源代码:

源代码
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 SEBlock(nn.Module):

    def __init__(self, input_channels, internal_neurons):
        super(SEBlock, self).__init__()
        self.down = nn.Conv2d(in_channels=input_channels, out_channels=internal_neurons, kernel_size=1, stride=1,
                              bias=True)
        self.up = nn.Conv2d(in_channels=internal_neurons, out_channels=input_channels, kernel_size=1, stride=1,
                            bias=True)
        self.input_channels = input_channels

    def forward(self, inputs):
        x = F.avg_pool2d(inputs, kernel_size=inputs.size(3))
        x = self.down(x)
        x = F.relu(x)
        x = self.up(x)
        x = torch.sigmoid(x)
        x = x.view(-1, self.input_channels, 1, 1)
        return inputs * x


class RepVGGBlock(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(RepVGGBlock, 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)

    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))


二、YOLOv8更换方式
整体的修改思路式如下:
在 YOLOv8 中添加模块可分为如下 5 步:
1.在ultralytics/models/v8文件夹下新建一个 yolov8-RepVGG.yaml ;
2.将本文上面提供的 RepVGG 代码添加到 ultralytics/nn/modules/block.py 文件末尾;
3.将 RepVGGBlock 这个类的名字加入到 ultralytics/nn/tasks.py 中;
4.修改 yolov8-RepVGG.yaml ,使用RepVGGBlock构建网络 ;
5.开始训练。

下面详细介绍:
**第二步、**将本文上面提供的代码添加到 ultralytics/nn/modules/block.py 文件末尾,随后在 ultralytics/nn/modules/block.py 文件最上方添加如下代码,
在这里插入图片描述
随后在 ultralytics/nn/modules/init.py 文件中的两处位置分别添加如下代码,
在这里插入图片描述
最后我们需要在 ultralytics/nn/tasks.py 上方导入类名;
在这里插入图片描述
第 3 步的详细方式如下:

task.py的parse_model函数中添加:

       elif m is RepVGGBlock:
            c1, c2 = ch[f], args[0]
            if c2 != nc:
                c2 = make_divisible(min(c2, max_channels) * width, 8)
            args = [c1, c2, *args[1:]]

随后依然在 ultralytics/nn/tasks.py 中 搜索 for m in self.model.modules(): ,定位到如下位置,在如下位置继续添加代码:
在这里插入图片描述

                if type(m) is RepVGGBlock:
                    if hasattr(m, 'rbr_1x1'):
                        kernel, bias = m.get_equivalent_kernel_bias()
                        rbr_reparam = nn.Conv2d(in_channels=m.rbr_dense.conv.in_channels,
                                                out_channels=m.rbr_dense.conv.out_channels,
                                                kernel_size=m.rbr_dense.conv.kernel_size,
                                                stride=m.rbr_dense.conv.stride,
                                                padding=m.rbr_dense.conv.padding, dilation=m.rbr_dense.conv.dilation,
                                                groups=m.rbr_dense.conv.groups, bias=True)
                        rbr_reparam.weight.data = kernel
                        rbr_reparam.bias.data = bias
                        for para in self.parameters():
                            para.detach_()
                        m.rbr_dense = rbr_reparam
                        m.__delattr__('rbr_1x1')
                        if hasattr(m, 'rbr_identity'):
                            m.__delattr__('rbr_identity')
                        if hasattr(m, 'id_tensor'):
                            m.__delattr__('id_tensor')
                        m.deploy = True
                        delattr(m, 'se')
                        m.forward = m.fusevggforward  # update forward

第 4 步:yaml文件
主要分两种,第一种,主干添加:yolov8-RepVGG.yaml

# Parameters
nc: 80  # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.33, 0.25, 1024]  # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPs
  s: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPs
  m: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPs
  l: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
  x: [1.00, 1.25, 512]   # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs

# YOLOv8.0n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, Conv, [64, 3, 2]]  # 0-P1/2
  - [-1, 1, RepVGGBlock, [128, 3, 2]]  # 1-P2/4
  - [-1, 3, C2f, [128, True]]
  - [-1, 1, RepVGGBlock, [256, 3, 2]]  # 3-P3/8
  - [-1, 6, C2f, [256, True]]
  - [-1, 1, RepVGGBlock, [512, 3, 2]]  # 5-P4/16
  - [-1, 6, C2f, [512, True]]
  - [-1, 1, RepVGGBlock, [1024, 3, 2]]  # 7-P5/32
  - [-1, 3, C2f, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]]  # 9

# YOLOv8.0n head
head:
  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [[-1, 6], 1, Concat, [1]]  # cat backbone P4
  - [-1, 3, C2f, [512]]  # 12

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

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 12], 1, Concat, [1]]  # cat head P4
  - [-1, 3, C2f, [512]]  # 18 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 9], 1, Concat, [1]]  # cat head P5
  - [-1, 3, C2f, [1024]]  # 21 (P5/32-large)

  - [[15, 18, 21], 1, Detect, [nc]]  # Detect(P3, P4, P5)



第二种,任务头添加:yolov8-RepVGG-Head.yaml

# Parameters
nc: 80  # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.33, 0.25, 1024]  # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPs
  s: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPs
  m: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPs
  l: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
  x: [1.00, 1.25, 512]   # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs

# YOLOv8.0n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, Conv, [64, 3, 2]]  # 0-P1/2
  - [-1, 1, Conv, [128, 3, 2]]  # 1-P2/4
  - [-1, 3, C2f, [128, True]]
  - [-1, 1, Conv, [256, 3, 2]]  # 3-P3/8
  - [-1, 6, C2f, [256, True]]
  - [-1, 1, Conv, [512, 3, 2]]  # 5-P4/16
  - [-1, 6, C2f, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]]  # 7-P5/32
  - [-1, 3, C2f, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]]  # 9

# YOLOv8.0n head
head:
  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [[-1, 6], 1, Concat, [1]]  # cat backbone P4
  - [-1, 3, C2f, [512]]  # 12

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

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 12], 1, Concat, [1]]  # cat head P4
  - [-1, 3, C2f, [512]]  # 18 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 9], 1, Concat, [1]]  # cat head P5
  - [-1, 3, C2f, [1024]]  # 21 (P5/32-large)

  - [-1, -7, RepVGGBlock, [256 , 3, 1]]  # (P3/8-small)
  - [-1, -5, RepVGGBlock, [512 , 3, 1]]  # (P4/16-medium)
  - [-1, -3, RepVGGBlock, [1024, 3, 1]]  # (P5/32-large)

  - [[22, 23, 24], 1, Detect, [nc]]  # Detect(P3, P4, P5)


当然,还有第三种,都添加,至于效果,可以自行尝试。

然后即可训练。

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

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

相关文章

嵌入式linux系统中压力测试的方法

在Linux环境下,确保系统各项资源充分且稳定地运行对任何系统管理员来说都至关重要。特别是在生产环境中,理解如何对系统资源进行基准测试和压力测试可以帮助预防未来的问题,同时也能够优化现有系统的性能。 在本文中,我们将探讨如何使用命令行工具来对Linux系统的CPU、内存…

开发环境搭建——Node.js

在启动前端项目的时候我们通常会用到Node.js,下面是对Node.js的下载安装以及配置的讲解 一、Node.js的安装 1.1、通过Node.js官网下载:Node.js — Run JavaScript Everywhere 下载后双击.msi安装文件后一直点击下一步即可 1.2、配置node 1.2.1、查看…

MT2140 供水管线(最小生成树Kruskal)

思路&#xff1a;Kruskal模板题 代码&#xff1a; #include<iostream> #include<stdio.h> #include<string.h> #include<vector> #include<algorithm> using namespace std;#define LL long long intconst int MAXN1e22;struct edge{int u,v,w;…

try-catch-finally 捕获异常不在catch里抛出;循环遍历对象生成任务,捕获异常对象不抛出,不影响其他正常对象生成任务

场景&#xff1a;一个模板绑定多个对象&#xff0c;要对每个对象生成任务。捕获生成任务过程中的异常&#xff0c;但是不抛出&#xff0c;只是用日志记录。这样做目的&#xff1a;循环遍历对象生成任务时&#xff0c;异常对象数据生成任务时发生异常只是导致自己生成任务失败&a…

29 列表元素访问

创建列表之后&#xff0c;可以使用整数作为下标来访问其中的元素&#xff1b;列表还支持使用负整数作为下标。 x list(hello world) print(x) print(x[0]) # 下标为0的元素&#xff0c;第一个元素 print(x[-1]) # 下标为-1的元素&#xff0c;最后一个元素x[5] print(x)

RedHat9 | Ansible 角色

环境版本说明 RedHat9 [Red Hat Enterprise Linux release 9.0]Ansible [core 2.13.3]Python [3.9.10]jinja [3.1.2] 描述角色结构 Playbook可能比较冗长且负载&#xff0c;也可能存在大量的重复代码。而角色&#xff08;roles&#xff09;可以用于层次性结构化的组织playbo…

【python】python生活管理费系统(源码+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

Python爬虫入门01:在Chrome浏览器轻松抓包

文章目录 爬虫基本概念爬虫定义爬虫工作原理爬虫流程爬虫类型爬虫面临的挑战 使用Chrome浏览器抓包查看网页HTML代码查看HTTP请求请求头&#xff08;Request Header&#xff09;服务器响应抓包的意义 爬虫基本概念 爬虫定义 爬虫&#xff08;Web Crawler 或 Spider&#xff0…

【JavaEE初阶】线程安全(重点)

目录 &#x1f4d5; 线程安全的概念 &#x1f384; 观察线程不安全 &#x1f333; 线程不安全的原因 &#x1f6a9; 原因&#xff1a; &#x1f332;解决之前的线程不安全问题 &#x1f6a9; synchronized 关键字 &#x1f4d5; 线程安全的概念 如果多线程环境下…

前端面经1

1、js是单线程还是多线程&#xff1f; 单线程执行。一次只能执行一个任务&#xff0c;处理任务的方式是通过一个任务队列&#xff08;也称为消息队列&#xff09;来实现的。如果某个操作&#xff08;如网络请求或定时器&#xff09;需要花费较长时间才能完成&#xff0c;它不会…

Flink SQL 的工作机制

前言 Flink SQL 引擎的工作流总结如图所示。 从图中可以看出&#xff0c;一段查询 SQL / 使用TableAPI 编写的程序&#xff08;以下简称 TableAPI 代码&#xff09;从输入到编译为可执行的 JobGraph 主要经历如下几个阶段&#xff1a; 将 SQL文本 / TableAPI 代码转化为逻辑执…

如何保证前后端交互信息不被篡改。

先说说前后端有哪些认证方式来保证&#xff1a; 基于 session 的认证方式&#xff1a;前端在用户登录成功后&#xff0c;后端会在服务器端生成一个唯一的 session ID&#xff0c;并将该 session ID 返回给前端&#xff0c;在后续的请求中&#xff0c;前端需要带上该 session ID…

【漏洞复现】蓝凌OA——远程命令执行

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现 漏洞描述 蓝凌OA平台&#xff0c;数字化向纵深发展&#xff0c;正加速构建产业互联…

图解分布式事务中的2PC与Seata方案

文章目录 文章导图什么是2PC解决传统2PC方案XA方案DTP模型举例&#xff1a;新用户注册送积分总结&#xff1a; Seata方案设计思想执行流程举例&#xff1a;新用户注册送积分 Seata实现2PC事务&#xff08;AT模式&#xff09;前提整体机制写隔离读隔离实际案例理解要点说明核心代…

自动驾驶-机器人-slam-定位面经和面试知识系列06之C++STL面试题(02)

这个博客系列会分为C STL-面经、常考公式推导和SLAM面经面试题等三个系列进行更新&#xff0c;基本涵盖了自己秋招历程被问过的面试内容&#xff08;除了实习和学校项目相关的具体细节&#xff09;。在知乎和牛客&#xff08;某些文章上会附上内推码&#xff09;也会同步更新&a…

锅总详解开源组织之ASF

ASF是什么&#xff1f;ASF孵化的顶级项目有哪些&#xff1f;ASF顶级项目商用化有哪些&#xff1f;涉及的版权是什么&#xff1f;应用案例有哪些&#xff1f;衍生项目及其关联是什么&#xff1f;希望本文能帮您解答这些疑惑&#xff01; 一、ASF简介 Apache Software Foundati…

Java从入门到精通 (十一) ~ 操作系统、进程和线程

无论做什么&#xff0c;请记住都是为你自己而做&#xff0c;这样就毫无怨言&#xff01;今天&#xff0c;我为自己而活&#xff01;今天&#xff0c;又是美丽的一天&#xff01;早安&#xff0c;朋友&#xff01; 目录 前言 一、操作系统 1. 概念 2. 操作系统的基本功能 3…

Mindspore框架循环神经网络RNN模型实现情感分类|(五)模型训练

Mindspore框架循环神经网络RNN模型实现情感分类 Mindspore框架循环神经网络RNN模型实现情感分类|&#xff08;一&#xff09;IMDB影评数据集准备 Mindspore框架循环神经网络RNN模型实现情感分类|&#xff08;二&#xff09;预训练词向量 Mindspore框架循环神经网络RNN模型实现…

Ubuntu上编译多个版本的frida

准备工作 Ubuntu20(WSL) 略 安装依赖 sudo apt update sudo apt-get install build-essential git lib32stdc-9-dev libc6-dev-i386 -y nodejs 去官网[1]下载nodejs&#xff0c;版本的话我就选的20.15.1&#xff1a; tar -xf node-v20.15.1-linux-x64.tar.xz 下载源码 …