YOLOv9改进策略【Neck】| 使用CARAFE轻量级通用上采样算子
一、本文介绍
本文记录的是利用CARAFE上采样对YOLOv9的颈部网络进行改进的方法研究。YOLOv9
采用传统的最近邻插值的方法,仅考虑子像素邻域,无法捕获密集预测任务所需的丰富语义信息,从而影响模型在密集预测任务中的性能。CARAFE
通过在大感受野内聚合信息、能够实时适应实例特定内容且保持计算效率。
文章目录
- 一、本文介绍
- 二、CARAFE介绍
- 2.1、CARAFE原理
- 2.2、优势
- 三、CARAFE的实现代码
- 四、添加步骤
- 4.1 修改common.py
- 4.2 修改yolo.py
- 五、yaml模型文件
- 5.1 模型改进
- 六、成功运行结果
二、CARAFE介绍
CARAFE
: 内容感知的特征重新组合
CARAFE(Content - Aware ReAssembly of FEatures)
是一种用于特征上采样的操作符,其设计原理和优势如下:
2.1、CARAFE原理
- 总体框架:
CARAFE
由两个关键组件组成,即核预测模块和内容感知重组模块。给定大小为 C × H × W C×H×W C×H×W的特征图 x x x和上采样比例 σ \sigma σ(假设 σ \sigma σ是整数),CARAFE
将产生大小为 C × σ H × σ W C×\sigma H×\sigma W C×σH×σW的新特征图 X ′ X' X′。 - 核预测模块:负责以内容感知的方式生成重组核。每个源位置 x x x上对应 σ 2 \sigma^{2} σ2个目标位置 X ′ X' X′上,每个目标位置需要一个 k u p × k u p k_{u p}×k_{u p} kup×kup的重组核,因此该模块将输出大小为 C u p × H × W C_{u p}×H×W Cup×H×W的重组核,其中 C u p = σ 2 k u p 2 C_{u p} = \sigma^{2}k_{u p}^{2} Cup=σ2kup2。该模块由三个子模块组成,分别是通道压缩器、内容编码器和核归一化器。
- 通道压缩器:采用 1 × 1 1×1 1×1卷积层将输入特征通道从 C C C压缩到 C m C_{m} Cm,减少特征图的通道数,从而减少后续步骤的参数和计算成本,使CARAFE更高效。
- 内容编码器:使用核大小为 k e n c o d e r k_{encoder} kencoder的卷积层根据输入特征的内容生成重组核,编码器的参数为 k e n c o d e r × k e n c o d e r × C m × C u p k_{encoder}×k_{encoder}×C_{m}×C_{u p} kencoder×kencoder×Cm×Cup。增大 k e n c o d e r k_{encoder} kencoder可以扩大编码器的感受野,利用更大区域内的上下文信息,但计算复杂度也会随之增加。通过研究, k e n c o d e r = k u p − 2 k_{encoder} = k_{u p} - 2 kencoder=kup−2是性能和效率之间的良好平衡。
- 核归一化器:在将每个 k u p × k u p k_{u p}×k_{u p} kup×kup重组核应用于输入特征图之前,使用softmax函数对其进行空间归一化,使核值之和为 1 1 1,这是对局部区域的软选择。
- 内容感知重组模块:对于目标位置 l ′ l' l′和以 l = ( i , j ) l = (i, j) l=(i,j)为中心的相应方形区域 N ( X l , k u p ) N(X_{l}, k_{u p}) N(Xl,kup),重组过程如公式 X l ′ ′ = ∑ n = − r r ∑ m = − r r W l ′ ( n , m ) ⋅ X ( i + n , j + m ) \mathcal{X}_{l'}' = \sum_{n = -r}^{r}\sum_{m = -r}^{r}\mathcal{W}_{l'(n, m)}·\mathcal{X}_{(i + n, j + m)} Xl′′=∑n=−rr∑m=−rrWl′(n,m)⋅X(i+n,j+m)所示,其中 r = ⌊ k u p / 2 ⌋ r = \lfloor k_{u p} / 2\rfloor r=⌊kup/2⌋。通过重组核,区域 N ( X l , k u p ) N(X_{l}, k_{u p}) N(Xl,kup)中的每个像素根据特征的内容而不是位置的距离对上采样像素 l ′ l' l′的贡献不同,使得重组后的特征图的语义比原始特征图更强。
2.2、优势
- 大视野:与之前仅利用子像素邻域的工作不同,
CARAFE
可以在大感受野内聚合上下文信息。 - 内容感知处理:
CARAFE
能够根据实例特定的内容进行实时处理,为每个样本生成自适应的内核,而不是使用固定的内核。 - 轻量且计算快速:
CARAFE
引入的计算开销很小,可以很容易地集成到现代网络架构中。 - 通用性和有效性:在对象检测、实例分割、语义分割、图像修复等广泛的密集预测任务中,CARAFE都能显著提升性能。
论文:https://arxiv.org/abs/1905.02188
源码:https://github.com/tiny-smart/dysample
三、CARAFE的实现代码
CARAFE模块
的实现代码如下:
class CARAFE(nn.Module):def __init__(self, c, k_enc=3, k_up=5, c_mid=64, scale=2):""" The unofficial implementation of the CARAFE module.The details are in "https://arxiv.org/abs/1905.02188".Args:c: The channel number of the input and the output.c_mid: The channel number after compression.scale: The expected upsample scale.k_up: The size of the reassembly kernel.k_enc: The kernel size of the encoder.Returns:X: The upsampled feature map."""super(CARAFE, self).__init__()self.scale = scaleself.comp = Conv(c, c_mid)self.enc = Conv(c_mid, (scale * k_up) ** 2, k=k_enc, act=False)self.pix_shf = nn.PixelShuffle(scale)self.upsmp = nn.Upsample(scale_factor=scale, mode='nearest')self.unfold = nn.Unfold(kernel_size=k_up, dilation=scale,padding=k_up // 2 * scale)def forward(self, X):b, c, h, w = X.size()h_, w_ = h * self.scale, w * self.scaleW = self.comp(X) # b * m * h * wW = self.enc(W) # b * 100 * h * wW = self.pix_shf(W) # b * 25 * h_ * w_W = torch.softmax(W, dim=1) # b * 25 * h_ * w_X = self.upsmp(X) # b * c * h_ * w_X = self.unfold(X) # b * 25c * h_ * w_X = X.view(b, c, -1, h_, w_) # b * 25 * c * h_ * w_X = torch.einsum('bkhw,bckhw->bchw', [W, X]) # b * c * h_ * w_return X
四、添加步骤
4.1 修改common.py
此处需要修改的文件是models/common.py
common.py中定义了网络结构的通用模块
,我们想要加入新的模块就只需要将模块代码放到这个文件内即可。
CARAFE模块
添加后如下:
注意❗:在4.2小节
中的yolo.py
文件中需要声明的模块名称为:CARAFE
。
4.2 修改yolo.py
此处需要修改的文件是models/yolo.py
yolo.py用于函数调用
,我们只需要将common.py
中定义的新的模块名添加到parse_model函数
下即可。
在def parse_model(d, ch)
中将CARAFE模块
添加后如下:
elif m in [CARAFE]:args = [ch[f], *args[0:]]
五、yaml模型文件
5.1 模型改进
在代码配置完成后,配置模型的YAML文件。
此处以models/detect/yolov9-c.yaml
为例,在同目录下创建一个用于自己数据集训练的模型文件yolov9-c-CARAFE.yaml
。
将yolov9-c.yaml
中的内容复制到yolov9-c-CARAFE.yaml
文件下,修改nc
数量等于自己数据中目标的数量。
📌 修改方法是将CARAFE模块
替换YOLOv9
颈部网络中的上采样模块nn.Upsample
。
# YOLOv9# parameters
nc: 1 # number of classes
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
#activation: nn.LeakyReLU(0.1)
#activation: nn.ReLU()# anchors
anchors: 3# YOLOv9 backbone
backbone:[[-1, 1, Silence, []], # conv down[-1, 1, Conv, [64, 3, 2]], # 1-P1/2# conv down[-1, 1, Conv, [128, 3, 2]], # 2-P2/4# elan-1 block[-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 3# avg-conv down[-1, 1, ADown, [256]], # 4-P3/8# elan-2 block[-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 5# avg-conv down[-1, 1, ADown, [512]], # 6-P4/16# elan-2 block[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 7(可替换)# avg-conv down[-1, 1, ADown, [512]], # 8-P5/32# elan-2 block[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 9(可替换)]# YOLOv9 head
head:[# elan-spp block[-1, 1, SPPELAN, [512, 256]], # 10# up-concat merge[-1, 1, CARAFE, []],[[-1, 7], 1, Concat, [1]], # cat backbone P4# elan-2 block[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 13# up-concat merge[-1, 1, CARAFE, []],[[-1, 5], 1, Concat, [1]], # cat backbone P3# elan-2 block[-1, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 16 (P3/8-small)# avg-conv-down merge[-1, 1, ADown, [256]],[[-1, 13], 1, Concat, [1]], # cat head P4# elan-2 block[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 19 (P4/16-medium)# avg-conv-down merge[-1, 1, ADown, [512]],[[-1, 10], 1, Concat, [1]], # cat head P5# elan-2 block[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 22 (P5/32-large)# multi-level reversible auxiliary branch# routing[5, 1, CBLinear, [[256]]], # 23[7, 1, CBLinear, [[256, 512]]], # 24[9, 1, CBLinear, [[256, 512, 512]]], # 25# conv down[0, 1, Conv, [64, 3, 2]], # 26-P1/2# conv down[-1, 1, Conv, [128, 3, 2]], # 27-P2/4# elan-1 block[-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 28# avg-conv down fuse[-1, 1, ADown, [256]], # 29-P3/8[[23, 24, 25, -1], 1, CBFuse, [[0, 0, 0]]], # 30 # elan-2 block[-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 31# avg-conv down fuse[-1, 1, ADown, [512]], # 32-P4/16[[24, 25, -1], 1, CBFuse, [[1, 1]]], # 33 # elan-2 block[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 34# avg-conv down fuse[-1, 1, ADown, [512]], # 35-P5/32[[25, -1], 1, CBFuse, [[2]]], # 36# elan-2 block[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 37# detection head# detect[[31, 34, 37, 16, 19, 22], 1, DualDDetect, [nc]], # DualDDetect(A3, A4, A5, P3, P4, P5)]
六、成功运行结果
分别打印网络模型可以看到CARAFE模块
已经加入到模型中,并可以进行训练了。
yolov9-c-CARAFE:
from n params module arguments 0 -1 1 0 models.common.Silence [] 1 -1 1 1856 models.common.Conv [3, 64, 3, 2] 2 -1 1 73984 models.common.Conv [64, 128, 3, 2] 3 -1 1 212864 models.common.RepNCSPELAN4 [128, 256, 128, 64, 1] 4 -1 1 164352 models.common.ADown [256, 256] 5 -1 1 847616 models.common.RepNCSPELAN4 [256, 512, 256, 128, 1] 6 -1 1 656384 models.common.ADown [512, 512] 7 -1 1 2857472 models.common.RepNCSPELAN4 [512, 512, 512, 256, 1] 8 -1 1 656384 models.common.ADown [512, 512] 9 -1 1 2857472 models.common.RepNCSPELAN4 [512, 512, 512, 256, 1] 10 -1 1 656896 models.common.SPPELAN [512, 512, 256] 11 -1 1 90696 models.common.CARAFE [512] 12 [-1, 7] 1 0 models.common.Concat [1] 13 -1 1 3119616 models.common.RepNCSPELAN4 [1024, 512, 512, 256, 1] 14 -1 1 90696 models.common.CARAFE [512] 15 [-1, 5] 1 0 models.common.Concat [1] 16 -1 1 912640 models.common.RepNCSPELAN4 [1024, 256, 256, 128, 1] 17 -1 1 164352 models.common.ADown [256, 256] 18 [-1, 13] 1 0 models.common.Concat [1] 19 -1 1 2988544 models.common.RepNCSPELAN4 [768, 512, 512, 256, 1] 20 -1 1 656384 models.common.ADown [512, 512] 21 [-1, 10] 1 0 models.common.Concat [1] 22 -1 1 3119616 models.common.RepNCSPELAN4 [1024, 512, 512, 256, 1] 23 5 1 131328 models.common.CBLinear [512, [256]] 24 7 1 393984 models.common.CBLinear [512, [256, 512]] 25 9 1 656640 models.common.CBLinear [512, [256, 512, 512]] 26 0 1 1856 models.common.Conv [3, 64, 3, 2] 27 -1 1 73984 models.common.Conv [64, 128, 3, 2] 28 -1 1 212864 models.common.RepNCSPELAN4 [128, 256, 128, 64, 1] 29 -1 1 164352 models.common.ADown [256, 256] 30 [23, 24, 25, -1] 1 0 models.common.CBFuse [[0, 0, 0]] 31 -1 1 847616 models.common.RepNCSPELAN4 [256, 512, 256, 128, 1] 32 -1 1 656384 models.common.ADown [512, 512] 33 [24, 25, -1] 1 0 models.common.CBFuse [[1, 1]] 34 -1 1 2857472 models.common.RepNCSPELAN4 [512, 512, 512, 256, 1] 35 -1 1 656384 models.common.ADown [512, 512] 36 [25, -1] 1 0 models.common.CBFuse [[2]] 37 -1 1 2857472 models.common.RepNCSPELAN4 [512, 512, 512, 256, 1] 38[31, 34, 37, 16, 19, 22] 1 21542822 DualDDetect [1, [512, 512, 512, 256, 512, 512]]
yolov9-c-CARAFE summary: 982 layers, 51180982 parameters, 51180950 gradients, 239.2 GFLOPs
相关文章:

YOLOv9改进策略【Neck】| 使用CARAFE轻量级通用上采样算子
一、本文介绍 本文记录的是利用CARAFE上采样对YOLOv9的颈部网络进行改进的方法研究。YOLOv9采用传统的最近邻插值的方法,仅考虑子像素邻域,无法捕获密集预测任务所需的丰富语义信息,从而影响模型在密集预测任务中的性能。CARAFE通过在大感受…...

SpringMVC上
SpringMVC介绍 MVC模型 MVC全称Model View Controller,是一种设计创建Web应用程序的模式。这三个单词分别代表Web应用程序的三个部分: Model(模型):指数据模型。用于存储数据以及处理用户请求的业务逻辑。在Web应用…...

嵌入式软件--51单片机 DAY 2
一、数码管 1.数码管概况 2.设计 (1)硬件设计 我们可以通过阴极控制显示的位置,通过阳极控制显示的内容。两个数码管共有8个阴极引脚和16个阳极引脚,如果所有引脚都直接接入MCU,会造成MCU引脚的极大浪费。 为了节省…...

高精度加法,减法,乘法,除法
加法: 大整数该如何储存? 用数组储存: 把个位放在数下标为0的位置,十位放在数组下标为1的位置(也就是高位放在数组的后面) 因为这样,如果需要增加一位最高位,那我们就可以直接在…...

学习计划(大三上)
第二周 总结Java并发编程的艺术 学习JVM(博客文章) 第三周 学习JVM(博客文章) 图解TCP/IP 4章 第四周 完成简历项目 学习JVM(博客文章) 图解TCP/IP 4章 第五周 完成简历项目 深入学习RocketMQ底层…...

【第0006页 · 数组】寻找重复数
【前言】本文以及之后的一些题解都会陆续整理到目录中,若想了解全部题解整理,请看这里: 第0006页 寻找重复数 今天想讨论的一道题在 LeetCode 上评论也是颇为“不错”。有一说一,是道好题,不过我们还是得先理解了它才…...

移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——10.继承
1.继承的概念及定义 1.1继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保 持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象 程序设计的层…...

uniapp+vue3实现双通道透明MP4播放支持小程序和h5
双通道透明MP4视频播放的截图 以下是合成后结果,二个合并在一起进行播放 下载资源,打开运行直接使用看到效果 https://download.csdn.net/download/qq_40039641/89715780...

汇编:嵌入式软件架构学习资源
成为嵌入式软件架构设计师需要掌握多方面的知识,包括嵌入式系统、实时操作系统、硬件接口、软件设计模式等。 以下是一些推荐的博客和网站,可以帮助你深入学习嵌入式软件架构设计: ### 1. **Embedded.com** - **网址**: [Embedded.com](htt…...

python编程知识(实现数据加密和解密)
👨💻个人主页:开发者-曼亿点 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 曼亿点 原创 👨💻 收录于专栏:…...

如何使div居中?CSS居中终极指南
前言 长期以来,如何在父元素中居中对齐一个元素,一直是一个让人头疼的问题,随着 CSS 的发展,越来越多的工具可以用来解决这个难题,五花八门的招式一大堆,这篇博客,旨在帮助你理解不同的居中方法…...

Redis 篇-深入了解分布式锁 Redisson 原理(可重入原理、可重试原理、主从一致性原理、解决超时锁失效)
🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 本章目录 1.0 基于 Redis 实现的分布式锁存在的问题 2.0 Redisson 功能概述 3.0 Redisson 具体使用 4.0 Redisson 可重入锁原理 5.0 Redisson 锁重试原理 6.0 Redisson WatchDo…...

PostgreSQL中的多版本并发控制(MVCC)深入解析
引言 PostgreSQL作为一款强大的开源关系数据库管理系统,以其高性能、高可靠性和丰富的功能特性而广受欢迎。在并发控制方面,PostgreSQL采用了多版本并发控制(MVCC)机制,该机制为数据库提供了高效的数据访问和更新能力…...

SpringBoot项目-实现简单的CRUD功能和分页查询
背景 本博文主要是创建了一个新的SpringBoot项目,实现基本的增删改查,分页查询,带条件的分页查询功能。是方便初学者学习后端项目的一个比较清晰明了的实践代码,读者可根据博文,从自己动手创建一个新的SpringBoot项目…...

CCF编程能力等级认证GESP—C++2级—20240907
CCF编程能力等级认证GESP—C2级—20240907 单选题(每题 2 分,共 30 分)判断题(每题 2 分,共 20 分)编程题 (每题 25 分,共 50 分)数位之和小杨的矩阵 单选题(每题 2 分,共…...

C语言手撕实战代码_二叉排序树(二叉搜索树)_构建_删除_插入操作详解
二叉排序树习题1.设计算法构建一棵二叉排序树(又称二叉搜索树BST)2.查找二叉排序树中结点为x的结点所在的层数3.删除二叉排序树T中值为x的结点4.查找二叉排序树中所有小于key的关键字5.编写算法,将一棵二叉树t分解成两棵二叉排序树t1和t2,使得t1中的所有…...

YC教父的创始人模式VS职业经理人模式:AI时代的独立开发者崛起
近年来,由风投资助的创始人模式因其相对较低的入门门槛而在创业圈内广受欢迎。然而,真正的挑战在于独立开发者(一人商业)模式。随着AI技术的飞速发展,一人商业模式有望成为未来的主流。本文将探讨独立开发者的工作范围…...

[SUCTF 2019]Pythonginx
给了源码 app.route(/getUrl, methods[GET, POST]) def getUrl():url request.args.get("url")host parse.urlparse(url).hostnameif host suctf.cc:return "我扌 your problem? 111"parts list(urlsplit(url))host parts[1]if host suctf.cc:retu…...

省市县相关校验sql随笔
1.层级校验 要判断一个给定的省、市、区(县)名字是否符合正确的层级关系,假设你的表结构如下: CREATE TABLE regions (id INT PRIMARY KEY,name VARCHAR(255),parent_id INT, -- 指向上一级区域的id,例如市的parent_id指向省的…...

uniapp ios sticky定位,内部 u-tabs(包含scroll-view)消失问题
uniapp中用sticky定位时,元素内部如果有scroll-view,ios在触发bounce机制时,scroll-view的元素会消失,解决方法是页面上包一层高度为100vh的scroll-view <scroll-view style"height: 100vh;" scroll-y scrolltolowe…...

web群集--nginx配置文件location匹配符的优先级顺序详解及验证
文章目录 前言优先级顺序优先级顺序(详解)1. 精确匹配(Exact Match)2. 正则表达式匹配(Regex Match)3. 前缀匹配(Prefix Match) 匹配规则的综合应用验证优先级 前言 location的作用 在 NGINX 中࿰…...

Vivado编译报错黑盒子问题
1 问题描述 “Black Box Instances: Cell **** of type ** has undefined contents and is considered a back box. The contents of this cell must be defined for opt_design to complete successfully.” 检查工程代码提示的模块,该模块为纯手写的Veril…...

【建造者模式】
建造者模式 Builder Pattern 属于创建型模式是将一个复杂对象的构建与它的标识分离,使得同样的构建过程可以创建不同的表示关键点:用户只需要指定需要建造的类型就可以获得对象,建造过程及细节不需要了解 实现 demo 需要构建的对象 Data pu…...

自动化表格处理的革命:智能文档系统技术解析
在当今数据驱动的商业环境中,表格数据的自动化处理成为了企业提高效率、降低成本的关键。企业智能文档系统在智能表格识别方面展现出卓越的性能,通过精准识别和处理各种通用表格,显著提升了企业文档管理的智能化水平。本文将深入探讨该系统在…...

【Hot100】LeetCode—394. 字符串解码
目录 1- 思路栈实现四种情况处理 2- 实现⭐394. 字符串解码——题解思路 3- ACM 实现 原题链接:394. 字符串解码 1- 思路 栈实现四种情况处理 ① 遇到数字,进行倍数相加 、②遇到左括号,压栈之前的元素、③遇到右括号弹出,栈进行…...

12. 如何在MyBatis中进行分页查询?常见的分页实现方式有哪些?
在MyBatis中,分页查询是一种常见的需求,尤其是在处理大数据量的情况下。MyBatis本身不直接提供分页功能,但可以通过以下几种常见的实现方式来实现分页查询。 1. 手动分页 这是最基本的分页方式,直接在SQL语句中添加分页参数。不同…...

@[TOC](力扣题目-滑动窗口-qsort排序-二分法查找)
通信 LCR 009. 乘积小于 K 的子数组268. 丢失的数字287. 寻找重复数 LCR 009. 乘积小于 K 的子数组 已解答 滑动窗口 给定一个正整数数组 nums和整数 k ,请找出该数组内乘积小于 k 的连续的子数组的个数。 示例 1: 输入: nums [10,5,2,6], k 100 输出: 8 解释…...

Docker容器相关命令
Docker是一种容器化技术,可以帮助用户更轻松地创建、部署和管理容器。下面是一些常见的Docker容器管理任务: 创建容器:使用Docker镜像创建一个新的容器。 docker run image_name列出容器:查看当前运行的容器列表。 docker ps启动容…...

【老课推荐】基于LangChain和知识图谱的大模型医疗问答机器人项目
在当今数据驱动和人工智能主导的时代,大模型和知识图谱的结合是一个重要的研究和应用方向。大模型实战课程通过48课时,分为六个主要章节,涵盖了从基本概念到高级应用的多方面内容。学员将通过本课程学习如何使用LangChain和OpenAI进行开发&am…...

Adobe Sensei——自动化视频编辑、特效应用和素材增强,通过AI技术快速优化视频内容,自动修复视频质量、自动添加背景音乐或字幕
一、Adobe Sensei介绍 Adobe Sensei 是 Adobe 公司开发的一款基于人工智能和机器学习技术的平台,旨在增强其各种创意、文档和体验管理工具。Adobe Sensei 通过深度学习、计算机视觉、自然语言处理(NLP)等先进技术,帮助用户在 Ado…...