YOLOv9改进策略 | Neck篇 | 2024.1最新MFDS-DETR的HS-FPN改进特征融合层(轻量化Neck、全网独家首发)

news/2024/9/24 13:16:28/

  一、本文介绍

本文给大家带来的改进机制是最近这几天最新发布的改进机制MFDS-DETR提出的一种HS-FPN结构,其是一种为白细胞检测设计的网络结构,主要用于解决白细胞数据集中的多尺度挑战。它的基本原理包括两个关键部分:特征选择模块特征融合模块。其可以起到特征选择的作用,非常适合轻量化的读者来使用,其存在二次创新和多次创新的机会,利用该结构参数量下降了约100W,本专栏每周更新3-5篇最新机制,更有包含我所有改进的文件和交流群提供给大家,同时本专栏目前改进基于yolov9.yaml文件,后期如果官方放出轻量化版本,专栏内所有改进也会同步更新,请大家放心。

欢迎大家订阅我的专栏一起学习YOLO 

专栏地址:YOLOv9有效涨点专栏-持续复现各种顶会内容-有效涨点-全网改进最全的专栏 

目录

  一、本文介绍

二、HS-FPN原理

2.1  HS-FPN的基本原理

2.2  SSF模块

三、HS-FPN的核心代码

四、手把手教你添加HS-FPN 

4.1 HS-FPN添加步骤

4.1.1 修改一

4.1.2 修改二

4.1.3 修改三 

4.1.4 修改四

4.2 HS-FPN的yaml文件和训练截图

4.2.1 HS-FPN的yaml版本一(推荐)

4.2.2 HS-FPN的yaml版本二

4.2 HS-FPN的训练过程截图 

五、本文总结


二、HS-FPN原理

dc5fc59fbdae4c919232c28df8009d0f.png

论文地址:论文官方链接

代码地址:代码官方链接

610b78849060477ca986c2d71398cf80.png


2.1  HS-FPN的基本原理

HS-FPN(High-level Screening-feature Fusion Pyramid Networks)是一种为白细胞检测设计的网络结构,主要用于解决白细胞数据集中的多尺度挑战。它的基本原理包括两个关键部分:特征选择模块特征融合模块

HS-FPN的结构如下图所示,包括两个主要组成部分:

2eafc944fb234fc5b384934ecd97a0a8.png

1. 特征选择模块:该模块利用通道注意力(CA)和维度匹配(DM)机制对不同尺度的特征图进行筛选。通过池化操作(如全局平均池化和全局最大池化)和权重计算,该模块有效地提取了每个通道中的重要信息。

2. 特征融合模块:该模块通过选择性特征融合(SFF)机制将筛选后的低级特征和高级特征结合起来。高级特征扩展后,通过双线性插值或转置卷积进行尺度调整,然后与低级特征融合,从而增强模型对白细胞特征的表达能力。

总的来说,HS-FPN通过这两个模块协同工作,有效地解决了白细胞检测中的多尺度问题,提高了检测的准确性和鲁棒性。


2.2  SSF模块

选择性特征融合(Selective Feature Fusion, SFF)是HS-FPN网络中的一个关键组件,它的主要作用是融合不同尺度的特征图。SFF通过使用高级特征作为权重来过滤低尺度特征中的重要信息。在这个过程中,高级特征经过转置卷积和双线性插值操作进行尺度调整,以匹配低尺度特征的尺寸。然后,利用高级特征作为注意力权重,筛选出低尺度特征中有用的信息。这种融合方法能够有效地结合高级特征的语义信息和低尺度特征的细节信息,从而提高模型在处理多尺度问题时的性能。

 下图为大家展示了SFF模块的框架结构:

4ab051fb7d174d31add86d1ac4ad0e7d.png

给定一个输入高级特征eq?f_%7Bhigh%7D%5Cepsilon%20R%5E%7BC*H*W%7D和一个输入低尺度特征eq?f_%7Blow%7D%5Cepsilon%20R%5E%7BC*H*W_%7B1%7D%7D,高级特征首先使用一个大小为2,核大小为3x3的转置卷积(T-Conv)进行扩展,得到特征大小eq?f_%7Bhigh%7D%5Cepsilon%20R%5E%7BC*2H*2W%7D

然后,为了统一高级特征和低尺度特征的维度,作者使用双线性插值来向上或向下采样高级特征,得到特征eq?f_%7Batt%7D%5Cepsilon%20R%5E%7BC*H_%7B1%7D*W_%7B1%7D%7D。接下来,使用CA模块将高级特征转换为相应的注意力权重,以过滤低尺度特征,在获得具有相同维度的特征后。

最后,将过滤后的低尺度特征与高级特征融合,以增强模型的特征表示,并得到eq?f_%7Bout%7D%5Cepsilon%20R%5E%7BC*H_%7B1%7D*W_%7B1%7D%7D。方程(1)和(2)说明了特征选择的融合过程:

65f82ddf139441b29ef26fd1349271af.png


三、HS-FPN的核心代码

这里的CA对应着官方代码中的ChannelAttention,但是在早期的库里面它在官方里面已经集成了,导入过来可能名字重复从而导致使用的时候报错,我这里给改写成CA了,大家看官方代码的时候需要注意下。

python">import torch
import torch.nn as nn
import torch.nn.functional as F__all__ = ['CA', 'multiply', 'Add']class Add(nn.Module):# Concatenate a list of tensors along dimensiondef __init__(self, ch=256):super().__init__()def forward(self, x):input1, input2 = x[0], x[1]x = input1 + input2return xclass multiply(nn.Module):def __init__(self):super().__init__()def forward(self, x):x = x[0] * x[1]return xclass CA(nn.Module):def __init__(self, in_planes, ratio = 4, flag=True):super(CA, self).__init__()self.avg_pool = nn.AdaptiveAvgPool2d(1)self.max_pool = nn.AdaptiveMaxPool2d(1)self.conv1 = nn.Conv2d(in_planes, in_planes // ratio, 1, bias=False)self.relu = nn.ReLU()self.conv2 = nn.Conv2d(in_planes // ratio, in_planes, 1, bias=False)self.flag = flagself.sigmoid = nn.Sigmoid()nn.init.xavier_uniform_(self.conv1.weight)nn.init.xavier_uniform_(self.conv2.weight)def forward(self, x):avg_out = self.conv2(self.relu(self.conv1(self.avg_pool(x))))max_out = self.conv2(self.relu(self.conv1(self.max_pool(x))))out = avg_out + max_outout = self.sigmoid(out) * x if self.flag else self.sigmoid(out)return outclass FeatureSelectionModule(nn.Module):def __init__(self, in_chan, out_chan):super(FeatureSelectionModule, self).__init__()self.conv_atten = nn.Conv2d(in_chan, in_chan, kernel_size=1)self.group_norm1 = nn.GroupNorm(32, in_chan)self.sigmoid = nn.Sigmoid()self.conv = nn.Conv2d(in_chan, out_chan, kernel_size=1)self.group_norm2 = nn.GroupNorm(32, out_chan)nn.init.xavier_uniform_(self.conv_atten.weight)nn.init.xavier_uniform_(self.conv.weight)def forward(self, x):atten = self.sigmoid(self.group_norm1(self.conv_atten(F.avg_pool2d(x, x.size()[2:]))))feat = torch.mul(x, atten)x = x + featfeat = self.group_norm2(self.conv(x))return featif __name__ == "__main__":# Generating Sample imageimage_size = (1, 64, 240, 240)image = torch.rand(*image_size)# Modelmobilenet_v3 = FeatureSelectionModule(64, 64)out = mobilenet_v3(image)print(out.size())


四、手把手教你添加HS-FPN 

4.1 HS-FPN添加步骤

4.1.1 修改一

首先我们找到如下的目录'yolov9-main/models',然后在这个目录下在创建一个新的目录然后这个就是存储改进的仓库,大家可以在这里新建所有的改进的py文件,对应改进的文件名字可以根据你自己的习惯起(不影响任何但是下面导入的时候记住改成你对应的即可),然后将HS-FPN 的核心代码复制进去。


4.1.2 修改二

然后在新建的目录里面我们在新建一个__init__.py文件(此文件大家只需要建立一个即可),然后我们在里面添加导入我们模块的代码。注意标记一个'.'其作用是标记当前目录。


4.1.3 修改三 

然后我们找到如下文件''models/yolo.py''在开头的地方导入我们的模块按照如下修改->

(如果你看了我多个改进机制此处只需要添加一个即可,无需重复添加)

注意的添加位置要放在common的导入上面!!!!!

5af82969538846b0ad386aa4acd733dd.png​​​​


4.1.4 修改四

然后我们找到''models/yolo.py''文件中的parse_model方法,按照如下修改->

3b5e1471ac054f6c8e50ffd57a080b7a.png

        elif m in {'此处添加大家修改的对应机制即可'}:c2 = ch[f]args = [c2, *args]
python">        elif m is multiply:c2 = ch[f[0]]elif m is Add:c2 = ch[f[-1]]

到此就修改完成了,复制下面的ymal文件即可运行。


4.2 HS-FPN的yaml文件和训练截图

4.2.1 HS-FPN的yaml版本一(推荐)

下面的添加HS-FPN是我实验结果的版本,这个版本为官方一比一复现的版本。

python"># YOLOv9# parameters
nc: 80  # number of classes
depth_multiple: 1  # model depth multiple
width_multiple: 1  # 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# conv down[-1, 1, Conv, [256, 3, 2]],  # 4-P3/8# elan-2 block[-1, 1, RepNCSPELAN4, [512, 256, 128, 1]],  # 5# conv down[-1, 1, Conv, [512, 3, 2]],  # 6-P4/16# elan-2 block[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 7# conv down[-1, 1, Conv, [512, 3, 2]],  # 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[ -1, 1, CA, [ ] ], # 11[ -1, 1, nn.Conv2d, [ 256, 1 ] ], # 12[ -1, 1, RepNCSPELAN4, [256, 256, 128, 1] ], # 13 P5[ 7, 1, CA, [ ] ],[ -1, 1, nn.Conv2d, [ 256, 1 ] ],  # 15[ 12, 1, nn.ConvTranspose2d, [ 256, 3, 2, 1, 1 ] ], # 16[ -1, 1, CA, [ 4, False ] ],[ [ -1, 15 ], 1, multiply, [ ] ], # 18[ [ -1, 16 ], 1, Add, [ ] ], # 19[ -1, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 20 P4[ 5, 1, CA, [ ] ], # 21[ -1, 1, nn.Conv2d, [ 256, 1 ] ], # 22[ 16, 1, nn.ConvTranspose2d, [ 256, 3, 2, 1, 1 ] ], # 23[ -1, 1, CA, [ 4, False ] ], # 24[ [ -1, 22 ], 1, multiply, [ ] ], # 25[ [ -1, 23 ], 1, Add, [ ] ], # 26[ -1, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 27 P3# routing + 5[5, 1, CBLinear, [[256]]], # 28[7, 1, CBLinear, [[256, 512]]], # 29[9, 1, CBLinear, [[256, 512, 512]]], # 30# conv down[0, 1, Conv, [64, 3, 2]],  # 31-P1/2# conv down[-1, 1, Conv, [128, 3, 2]],  # 32-P2/4# elan-1 block[-1, 1, RepNCSPELAN4, [256, 128, 64, 1]],  # 33# conv down fuse[-1, 1, Conv, [256, 3, 2]],  # 34-P3/8[[28, 29, 30, -1], 1, CBFuse, [[0, 0, 0]]], # 35# elan-2 block[-1, 1, RepNCSPELAN4, [512, 256, 128, 1]],  # 36# conv down fuse[-1, 1, Conv, [512, 3, 2]],  # 37-P4/16[[29, 30, -1], 1, CBFuse, [[1, 1]]], # 38# elan-2 block[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 39# conv down fuse[-1, 1, Conv, [512, 3, 2]],  # 40-P5/32[[30, -1], 1, CBFuse, [[2]]], # 41# elan-2 block[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 42# detect[[36, 39, 42, 13, 20, 27], 1, DualDDetect, [nc]],  # DualDDetect(A3, A4, A5, P3, P4, P5)]


4.2.2 HS-FPN的yaml版本二

添加的版本二具体那种适合你需要大家自己多做实验来尝试,此版本把通道数改回了YOLOv5的版本。

python"># YOLOv9# parameters
nc: 80  # number of classes
depth_multiple: 1  # model depth multiple
width_multiple: 1  # 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# conv down[-1, 1, Conv, [256, 3, 2]],  # 4-P3/8# elan-2 block[-1, 1, RepNCSPELAN4, [512, 256, 128, 1]],  # 5# conv down[-1, 1, Conv, [512, 3, 2]],  # 6-P4/16# elan-2 block[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 7# conv down[-1, 1, Conv, [512, 3, 2]],  # 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[ -1, 1, CA, [ ] ], # 11[ -1, 1, nn.Conv2d, [ 256, 1 ] ], # 12[ -1, 1, RepNCSPELAN4, [256, 256, 128, 1] ], # 13 P5[ 7, 1, CA, [ ] ],[ -1, 1, nn.Conv2d, [ 256, 1 ] ],  # 15[ 12, 1, nn.ConvTranspose2d, [ 256, 3, 2, 1, 1 ] ], # 16[ -1, 1, CA, [ 4, False ] ],[ [ -1, 15 ], 1, multiply, [ ] ], # 18[ [ -1, 16 ], 1, Add, [ ] ], # 19[ -1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 20 P4[ 5, 1, CA, [ ] ], # 21[ -1, 1, nn.Conv2d, [ 256, 1 ] ], # 22[ 16, 1, nn.ConvTranspose2d, [ 256, 3, 2, 1, 1 ] ], # 23[ -1, 1, CA, [ 4, False ] ], # 24[ [ -1, 22 ], 1, multiply, [ ] ], # 25[ [ -1, 23 ], 1, Add, [ ] ], # 26[ -1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 27 P3# routing + 5[5, 1, CBLinear, [[256]]], # 28[7, 1, CBLinear, [[256, 512]]], # 29[9, 1, CBLinear, [[256, 512, 512]]], # 30# conv down[0, 1, Conv, [64, 3, 2]],  # 31-P1/2# conv down[-1, 1, Conv, [128, 3, 2]],  # 32-P2/4# elan-1 block[-1, 1, RepNCSPELAN4, [256, 128, 64, 1]],  # 33# conv down fuse[-1, 1, Conv, [256, 3, 2]],  # 34-P3/8[[28, 29, 30, -1], 1, CBFuse, [[0, 0, 0]]], # 35# elan-2 block[-1, 1, RepNCSPELAN4, [512, 256, 128, 1]],  # 36# conv down fuse[-1, 1, Conv, [512, 3, 2]],  # 37-P4/16[[29, 30, -1], 1, CBFuse, [[1, 1]]], # 38# elan-2 block[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 39# conv down fuse[-1, 1, Conv, [512, 3, 2]],  # 40-P5/32[[30, -1], 1, CBFuse, [[2]]], # 41# elan-2 block[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 42# detect[[36, 39, 42, 13, 20, 27], 1, DualDDetect, [nc]],  # DualDDetect(A3, A4, A5, P3, P4, P5)]


4.2 HS-FPN的训练过程截图 

大家可以看下面的运行结果和添加的位置所以不存在我发的代码不全或者运行不了的问题大家有问题也可以在评论区评论我看到都会为大家解答(我知道的)。

​​​​​​


五、本文总结

到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv9改进有效涨点专栏,本专栏目前为新开的平均质量分98分,后期我会根据各种最新的前沿顶会进行论文复现,也会对一些老的改进机制进行补充,如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~

希望大家阅读完以后可以给文章点点赞和评论支持一下这样购买专栏的人越多群内人越多大家交流的机会就更多了。  

专栏地址:YOLOv9有效涨点专栏-持续复现各种顶会内容-有效涨点-全网改进最全的专栏 


http://www.ppmy.cn/news/1424924.html

相关文章

【C++】:C++关键字,命名空间,输入输出,缺省参数

目录 一,C关键字(C98)二,命名空间2.1 命名冲突2.2 关键字namespace2.2.1 命名空间中可以定义变量/函数/类型2.2.2 命名空间可以嵌套2.2.3 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。 2.3 命名空间的使用2.3.1 指定…

深入挖掘C语言 ----动态内存分配

开篇备忘录: "自给自足的光, 永远都不会暗" 目录 1. malloc和free1.1 malloc1.2 free 2. calloc和realloc2.1 calloc2.2 realloc 3. 总结C/C中程序内存区域划分 正文开始 1. malloc和free 1.1 malloc C语言提供了一个动态开辟内存的函数; void* malloc (size_t s…

并发学习27--多线程 Tomcat 线程池

Tomcat连接器的线程池 socketProcessor也是个线程 Executor处理线程是按照JDK线程池方法处理,优先选用核心线程,再用救急线程,再去阻塞队列,最后采用拒绝策略。 Tomcat线程池与ThreadExecutorPool的区别 Tomcat中的配置 Tomcat …

10. Spring MVC 程序开发

本文源码位置: Spring-MVC 1. Spring MVC 概要 摘自Spring官方: Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, “Spring Web MVC,” comes …

设计模式-命令模式(Command)

1. 概念 命令模式(Command Pattern)是一种行为型设计模式,也被称为动作模式或事务模式。它的核心思想是将一个请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化。对请求排队或记录,以及支持可撤销的操作…

利用正射影像对斜射图像进行反向投影

在图像投影和映射领域,有两种类型的投影:正向投影和反向投影。正向投影涉及使用内部方向(即校准相机参数)将 3D 点(例如地面上的物体)投影到 2D 图像平面上。另一方面,向后投影是指根据 2D 图像确定地面物体的 3D 坐标的过程。 为了匹配倾斜图像和正射影像并确定相机位置…

【opencv】示例-phase_corr.cpp 捕获视频流并通过计算相位相关性来检测画面中的移动...

// 包含OpenCV库的头文件 #include "opencv2/core.hpp" // 包含OpenCV核心功能 #include "opencv2/videoio.hpp" // 包含视频IO功能 #include "opencv2/highgui.hpp" // 包含高级GUI功能,显示图像 #include "opencv2/imgproc.hp…

SpringBoot整合Nacos

文章目录 nacosnacos下载nacos启动nacos相关配置demo-dev.yamldemo-test.yamluser.yaml 代码pom.xmlUserConfigBeanAutoRefreshConfigExampleValueAnnotationExampleDemoApplicationbootstrap.yml测试结果补充.刷新静态配置 nacos nacos下载 下载地址 一键傻瓜试安装即可,官…