【YOLOv5改进系列(7)】高效涨点----使用yolov8中的C2F模块替换yolov5中的C3模块

2024-03-30 15:20

本文主要是介绍【YOLOv5改进系列(7)】高效涨点----使用yolov8中的C2F模块替换yolov5中的C3模块,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述


文章目录

  • 🚀🚀🚀前言
  • 一、1️⃣ C3模块和C2F模块详解
    • 1.1 🎓 C3模块
    • 1.2 ✨BottleNeck模块
    • 1.3 ⭐️C2F模块
  • 二、2️⃣添加C2f和C2F_Bottleneck模块代码
  • 三、3️⃣新建yolov5s_C2F.yaml文件
  • 四、4️⃣修改yolo.py中的parse_model函数
  • 五、5️⃣实验部分


在这里插入图片描述

👀🎉📜系列文章目录

【YOLOv5改进系列(1)】高效涨点----使用EIoU、Alpha-IoU、SIoU、Focal-EIOU替换CIou
【YOLOv5改进系列(2)】高效涨点----Wise-IoU详细解读及使用Wise-IoU(WIOU)替换CIOU
【YOLOv5改进系列(3)】高效涨点----Optimal Transport Assignment:OTA最优传输方法
【YOLOv5改进系列(4)】高效涨点----添加可变形卷积DCNv2
【YOLOv5改进系列(5)】高效涨点----添加密集小目标检测NWD方法
【YOLOv5改进系列(6)】高效涨点----使用DAMO-YOLO中的Efficient RepGFPN模块替换yolov5中的Neck部分

🚀🚀🚀前言

🚀这里解释一下为什么要使用yolov8中的C2F模块替换yolov5中的C3模块,可能在大家印象当中最新的模型要比旧的模型性能要好,其实博主在训练不同数据集的时候会发现yolov5的检测性能可能会优于v7甚至v8,因为目前大部分的目标检测模型都是在coco数据集上进行训练,然后再与旧的模型进行比较,如果只看在coco数据集上的表现确实v7、v8是要优于v5的,但是在自己数据集上面训练可能就是另外一种结果,所以可以尝试将不同模型的不同模块进行融合,试一试训练效果。我在钢轨疵点数据集上进行实验,添加了c2f模块之后的yolov5要比基准模型的map@50提高了2个百分点


一、1️⃣ C3模块和C2F模块详解

1.1 🎓 C3模块

这里解释一下为什么叫C3模块,因为是由三个CBS模块,也就是三个卷积层,再加上若干个BottleNeck模块构成,输入进来的特征,分为两个部分,一部分特征是只经过CBS模块处理,一部分经过CBS+BottleNeck处理,最后通过concat将两部分特征进行拼接,再经过一个CBS层将特征维度进行恢复。
在这里插入图片描述
YOLOv5-v6.0版本中使用了C3模块,替代了早期的BottleneckCSP模块。这两者结构作用基本相同,均为CSP架构,只是在修正单元的选择上有所不同,C3模块包含了3个标准卷积层以及多个Bottleneck模块,与BottleneckCSP模块所不同的是,经过Bottleneck模块输出后的Conv模块被去掉了。旧版本的yolov5的CSP模块如下:
在这里插入图片描述

1.2 ✨BottleNeck模块

在上面解释C3模块的时候,其中是有一个BottleNeck模块,该模块是类似与resnet残差结构,该模块其实存在两种形式,也就是BottleNeck1和BottleNeck2,BottleNeck1是以resnet残差结构连接的,该残差结构是由两条路构成,其中一路先进行1×1卷积将特征图的通道数减小一半,从而减少计算量,再通过3×3卷积提取特征,并且将通道数加倍,其输入与输出的通道数是不发生改变的,而另外一路通过shortcut进行残差连接,与第一路的输出特征图相加,从而实现特征融合;BottleNeck2只是经过一次1x1卷积的CBS和一次3x3卷积的CBS。
在这里插入图片描述

1.3 ⭐️C2F模块

在理解C2F模块模块的时候建议是先看第一幅图,通过CBS处理之后的特征首先进行Split分割成两部分特征一部分特征保留不做任何处理,一部分经过若干个BottleNeck进行处理其中每个BottleNeck又会分出两条通道,一条是将处理过的特征传递给下一个BottleNeck,一条则是保留下来用作后面的concat连接。最后经过n个BottleNeck之后将所有的特征进行融合。

📜有意思的是Split分出的这条线路和连接方式比较像残差连接结构(不知道这样解释对不对) ,n个BottleNeck的特征融合方式很像FPN特征金字塔自顶向下融合,将深层特征与浅层特征进行融合

在这里插入图片描述

✨✨✨详细的特征处理可以看下面这个结构图,输入的特征经过Split之后通道数变为原来的一半( h ∗ w ∗ 0.5 c o u t h*w*0.5 cout hw0.5cout),一半的特征图不做处理,另外一半则是传入到BottleNeck模块中做特征融合操作。
在这里插入图片描述

二、2️⃣添加C2f和C2F_Bottleneck模块代码

🔥🔥🔥🔥温馨提示:这里的C2f和C2F_Bottleneck其实是我直接从github上的yolov8源码拷贝下来的,修改了部分参数命名,在一开始我是打算直接使用yolov5中的Bottleneck模块,但是仔细阅读v5和v8中的Bottleneck模块发现还是有部分内容不一定,像卷积核大小设置,为了保证代码能够正常运行,所以在拷贝C2f的同时连同v8中的Bottleneck一块拷贝到yolov5中间。

📌首先找到models文件夹下common.py文件,在该文件的最后一行添加如下代码;分别是`C2f和C2F_Bottleneck``模块。

class C2f(nn.Module):"""Faster Implementation of CSP Bottleneck with 2 convolutions."""def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):"""Initialize CSP bottleneck layer with two convolutions with arguments ch_in, ch_out, number, shortcut, groups,expansion."""super().__init__()self.c = int(c2 * e)  # hidden channelsself.cv1 = Conv(c1, 2 * self.c, 1, 1)self.cv2 = Conv((2 + n) * self.c, c2, 1)  # optional act=FReLU(c2)self.m = nn.ModuleList(C2F_Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n))def forward(self, x):"""Forward pass through C2f layer."""y = list(self.cv1(x).chunk(2, 1))y.extend(m(y[-1]) for m in self.m)return self.cv2(torch.cat(y, 1))def forward_split(self, x):"""Forward pass using split() instead of chunk()."""y = list(self.cv1(x).split((self.c, self.c), 1))y.extend(m(y[-1]) for m in self.m)return self.cv2(torch.cat(y, 1))class C2F_Bottleneck(nn.Module):"""Standard bottleneck."""def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5):"""Initializes a bottleneck module with given input/output channels, shortcut option, group, kernels, andexpansion."""super().__init__()c_ = int(c2 * e)  # hidden channelsself.cv1 = Conv(c1, c_, k[0], 1)self.cv2 = Conv(c_, c2, k[1], 1, g=g)self.add = shortcut and c1 == c2def forward(self, x):"""'forward()' applies the YOLO FPN to input data."""return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))

三、3️⃣新建yolov5s_C2F.yaml文件

🔥在models文件夹新建一个yolov5s_C2F.yaml文件,因为我使用的yolov5s权重进行训练,然后将如下代码都拷贝到yolov5s_C2F.yaml文件当中,这里我将所有的C3模块都换成了C2f模块。

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license# Parameters
nc: 6  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # 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] 输出640*640[ [ -1, 1, Conv, [ 64, 6, 2, 2 ] ],  # 0-P1/2 320*320    64表示输出的channel,但是需要乘以width_multiple,6表示卷积核的大小,2表示padding大小,2表示stride大小[ -1, 1, Conv, [ 128, 3, 2 ] ],  # 1-P2/4   160*160*128      2表示stride大小[ -1, 3, C2f, [ 128 ] ],[ -1, 1, Conv, [ 256, 3, 2 ] ],  # 3-P3/8   80*80*256[ -1, 6, C2f, [ 256 ] ],[ -1, 1, Conv, [ 512, 3, 2 ] ],  # 5-P4/16   40*40*512[ -1, 9, C2f, [ 512 ] ],[ -1, 1, Conv, [ 1024, 3, 2 ] ],  # 7-P5/32   20*20[ -1, 3, C2f, [ 1024 ] ],[ -1, 1, SPPF, [ 1024, 5 ] ],  # 9]# YOLOv5 v6.0 head
head:#  ================ 自下向上融合FPN =====================[ [ -1, 1, Conv, [ 512, 1, 1 ] ], # 降维 20*20*1024->20*20*512[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], #上采样 20*20*512->40*40*512[ [ -1, 6 ], 1, Concat, [ 1 ] ],  # cat backbone P4 40*40*(512+512)[ -1, 3, C2f, [ 512, False ] ],  # 13             40*40*1024->40*40*512[ -1, 1, Conv, [ 256, 1, 1 ] ],         #40*40*512->40*40*256[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],   # 40*40*256->80*80*256[ [ -1, 4 ], 1, Concat, [ 1 ] ],  # cat backbone P3 80*80*(256+256)[ -1, 3, C2f, [ 256, False ] ],  # 17 (P3/8-small) 80*80*512->80*80*256# ================ 自上向下融合PAN ==================[ -1, 1, Conv, [ 256, 3, 2 ] ],  # 80*80*256->40*40*256[ [ -1, 14 ], 1, Concat, [ 1 ] ],  # cat head P4  40*40*(256+256)[ -1, 3, C2f, [ 512, False ] ],  # 20 (P4/16-medium)[ -1, 1, Conv, [ 512, 3, 2 ] ],   #40*40*(256+256)-> 20*20*512[ [ -1, 10 ], 1, Concat, [ 1 ] ],  # cat head P5  20*20*(512+512)[ -1, 3, C2f, [ 1024, False ] ],  # 23 (P5/32-large)[ [ 17, 20, 23 ], 1, Detect, [ nc, anchors ] ],  # Detect(P3, P4, P5)]

四、4️⃣修改yolo.py中的parse_model函数

models文件夹下面找到yolo.py文件,在该文件找到parse_model网络解析函数,然后添加C2f,添加内容如下:

在这里插入图片描述

五、5️⃣实验部分

yolov5基准模型训练结果:F1置信度分数为0.71、map@0.5=0.779;
在这里插入图片描述

使用C2F模块替换之后训练结果F1置信度分数为0.73、map@0.5=0.794
在这里插入图片描述
总结:使用yolov8中的C2F模块替换yolov5中的C3模块之后,F1置信分数和map@0.5都上涨了将近2个百分点。


在这里插入图片描述

这篇关于【YOLOv5改进系列(7)】高效涨点----使用yolov8中的C2F模块替换yolov5中的C3模块的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/861840

相关文章

Java docx4j高效处理Word文档的实战指南

《Javadocx4j高效处理Word文档的实战指南》对于需要在Java应用程序中生成、修改或处理Word文档的开发者来说,docx4j是一个强大而专业的选择,下面我们就来看看docx4j的具体使用... 目录引言一、环境准备与基础配置1.1 Maven依赖配置1.2 初始化测试类二、增强版文档操作示例2.

一文详解如何使用Java获取PDF页面信息

《一文详解如何使用Java获取PDF页面信息》了解PDF页面属性是我们在处理文档、内容提取、打印设置或页面重组等任务时不可或缺的一环,下面我们就来看看如何使用Java语言获取这些信息吧... 目录引言一、安装和引入PDF处理库引入依赖二、获取 PDF 页数三、获取页面尺寸(宽高)四、获取页面旋转角度五、判断

C++中assign函数的使用

《C++中assign函数的使用》在C++标准模板库中,std::list等容器都提供了assign成员函数,它比操作符更灵活,支持多种初始化方式,下面就来介绍一下assign的用法,具有一定的参考价... 目录​1.assign的基本功能​​语法​2. 具体用法示例​​​(1) 填充n个相同值​​(2)

Spring StateMachine实现状态机使用示例详解

《SpringStateMachine实现状态机使用示例详解》本文介绍SpringStateMachine实现状态机的步骤,包括依赖导入、枚举定义、状态转移规则配置、上下文管理及服务调用示例,重点解... 目录什么是状态机使用示例什么是状态机状态机是计算机科学中的​​核心建模工具​​,用于描述对象在其生命

使用Python删除Excel中的行列和单元格示例详解

《使用Python删除Excel中的行列和单元格示例详解》在处理Excel数据时,删除不需要的行、列或单元格是一项常见且必要的操作,本文将使用Python脚本实现对Excel表格的高效自动化处理,感兴... 目录开发环境准备使用 python 删除 Excphpel 表格中的行删除特定行删除空白行删除含指定

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

prometheus如何使用pushgateway监控网路丢包

《prometheus如何使用pushgateway监控网路丢包》:本文主要介绍prometheus如何使用pushgateway监控网路丢包问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录监控网路丢包脚本数据图表总结监控网路丢包脚本[root@gtcq-gt-monitor-prome

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

SpringBoot中如何使用Assert进行断言校验

《SpringBoot中如何使用Assert进行断言校验》Java提供了内置的assert机制,而Spring框架也提供了更强大的Assert工具类来帮助开发者进行参数校验和状态检查,下... 目录前言一、Java 原生assert简介1.1 使用方式1.2 示例代码1.3 优缺点分析二、Spring Fr

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期