YOLOv5改进 | 模块融合 | C3融合 ghost + DynamicConv 【两次融合 + 独家改进】

2024-08-29 17:04

本文主要是介绍YOLOv5改进 | 模块融合 | C3融合 ghost + DynamicConv 【两次融合 + 独家改进】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转


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


专栏目录: 《YOLOv5入门 + 改进涨点》专栏介绍 & 专栏目录 |目前已有70+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进


本文介绍了一种C3_GhostDynamicConv模块融合GhostModule和DynamicConv,通过在GhostModule结构中使用DynamicConv替换传统卷积,实现了在保持计算效率的同时增强特征表达能力的目的。然后再用GhostModule替换C3的Bottleneck实现改进。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。  

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

目录

1. 原理 

2. 将C3_GhostDynamicConv添加到yolov5网络中

2.1 C3_GhostDynamicConv 代码实现

2.2 C3_GhostDynamicConv的神经网络模块代码解析

2.3 新增yaml文件

2.4 注册模块

2.5 执行程序

3. 完整代码分享

4. GFLOPs

5. 进阶

6. 总结


1. 原理 

论文地址:Dynamic Convolution: Attention over Convolution Kernels——点击即可跳转

代码实现: 非官方代码仓库——点击即可跳转

动态卷积是一种旨在提高卷积神经网络 (CNN) 的表示能力而不会显著增加计算成本的技术。动态卷积背后的主要原理如下:

  1. 多个卷积核:动态卷积不是每层使用单个卷积核,而是采用一组 (K) 个并行卷积核。对于每个输入,这些内核使用输入相关的注意权重进行动态聚合。这允许网络根据输入数据调整卷积操作,从而增强其灵活性和表达能力。

  2. 注意机制:每个内核的注意权重\pi_k(x) 都是根据输入 ( x ) 动态计算的。这些权重决定了每个内核在最终聚合的卷积内核中应该有多大的影响。聚合按如下方式执行: W(x) = \sum{k=1}^{K} \pi_k(x) W_k, \quad b(x) = \sum{k=1}^{K} \pi_k(x) b_k , 其中 W_kb_k分别是各个内核权重和偏差。

  3. 效率:尽管使用多个内核会增加模型复杂度,但动态卷积在计算上是高效的。额外的计算主要是由于计算注意力权重和聚合内核,与卷积操作本身相比,这只增加了很小的开销。这使得动态卷积特别适合轻量级 CNN,因为增加深度或宽度(即更多层或通道)的成本太高。

  4. 非线性聚合:通过注意力机制以非线性方式聚合内核,动态卷积可以对数据中更复杂的关系进行建模,而传统的静态卷积则不然。

  5. 训练注意事项:动态卷积网络 (DY-CNN) 更难训练,因为它们需要跨层联合优化所有内核和注意力权重。建议采用两种关键策略来促进训练:

  • 和为一约束:强制约束 \sum_{k=1}^{K} \pi_k(x) = 1 有助于更有效地学习注意力模型。

  • 早期训练中的扁平注意力:在早期训练阶段使用 softmax 函数中的高温可产生更均匀的注意力权重,从而帮助网络更好地学习。

动态卷积已被证明可以显著提高 MobileNetV2 和 MobileNetV3 等模型在 ImageNet 分类等任务上的性能,而计算成本仅略有增加。

2. 将C3_GhostDynamicConv添加到yolov5网络中

2.1 C3_GhostDynamicConv 代码实现

关键步骤一将下面的代码粘贴到\yolov5\models\common.py中

import math
from timm.layers import CondConv2dclass DynamicConv_Single(nn.Module):""" Dynamic Conv layer"""def __init__(self, in_features, out_features, kernel_size=1, stride=1, padding='', dilation=1,groups=1, bias=False, num_experts=4):super().__init__()self.routing = nn.Linear(in_features, num_experts)self.cond_conv = CondConv2d(in_features, out_features, kernel_size, stride, padding, dilation,groups, bias, num_experts)def forward(self, x):pooled_inputs = F.adaptive_avg_pool2d(x, 1).flatten(1)  # CondConv routingrouting_weights = torch.sigmoid(self.routing(pooled_inputs))x = self.cond_conv(x, routing_weights)return xclass DynamicConv(nn.Module):default_act = nn.SiLU()  # default activationdef __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True, num_experts=4):super().__init__()self.conv = nn.Sequential(DynamicConv_Single(c1, c2, kernel_size=k, stride=s, padding=autopad(k, p, d), dilation=d, groups=g, num_experts=num_experts),nn.BatchNorm2d(c2),self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity())def forward(self, x):return self.conv(x)class GhostModule(nn.Module):def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, act_layer=nn.SiLU, num_experts=4):super(GhostModule, self).__init__()self.oup = oupinit_channels = math.ceil(oup / ratio)new_channels = init_channels * (ratio - 1)self.primary_conv = DynamicConv(inp, init_channels, kernel_size, stride, num_experts=num_experts)self.cheap_operation = DynamicConv(init_channels, new_channels, dw_size, 1, g=init_channels, num_experts=num_experts)def forward(self, x):x1 = self.primary_conv(x)x2 = self.cheap_operation(x1)out = torch.cat([x1, x2], dim=1)return out[:, :self.oup, :, :]class Bottleneck_DynamicConv(Bottleneck):def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5):super().__init__(c1, c2, shortcut, g, k, e)c_ = int(c2 * e)  # hidden channelsself.cv2 = DynamicConv(c2, c2, 3)class C3_DynamicConv(C3):def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):super().__init__(c1, c2, n, shortcut, g, e)c_ = int(c2 * e)  # hidden channelsself.m = nn.Sequential(*(Bottleneck_DynamicConv(c_, c_, shortcut, g, k=(1, 3), e=1.0) for _ in range(n)))class C3_GhostDynamicConv(C3):def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):super().__init__(c1, c2, n, shortcut, g, e)c_ = int(c2 * e)  # hidden channelsself.m = nn.Sequential(*(GhostModule(c_, c_) for _ in range(n)))

2.2 C3_GhostDynamicConv的神经网络模块代码解析

C3_GhostDynamicConv 是一个基于C3 模块的自定义神经网络模块,结合了 GhostModule 和 Dynamic Convolution 的特性。让我们逐步讲解它的组成和功能:

1. 继承 C2f 模块

  • C3_GhostDynamicConv 继承自 C3 类,因此它保留了 C3 的结构和功能。这意味着它是一个层级结构,通常用于构建包含多个子层的模块。

2. GhostModule 的引入

  • C3_GhostDynamicConv 通过 nn.ModuleList 创建了多个 GhostModule 实例,这些实例被存储在模块列表中 self.m。这里的 GhostModule 是一个轻量级的卷积模块,它使用了 Dynamic Convolution 来增强表示能力。

3. GhostModule 的细节

  • primary_conv:这是第一个卷积操作,使用 Dynamic Convolution 在输入通道和 init_channels 之间进行卷积。Dynamic Convolution 是一种基于输入数据动态聚合多个卷积核的技术,它使卷积操作更加灵活和自适应。

  • cheap_operation:这是第二个卷积操作,同样使用了 Dynamic Convolution,但在通道数增加的情况下,它通过更小的深度卷积(dw_size)来减少计算成本。

  • 输出GhostModule 的输出是通过 torch.catprimary_convcheap_operation 的结果在通道维度上拼接,并裁剪到所需的输出通道数。

4. 模块的调用

  • C3_GhostDynamicConv 被调用时,它将依次执行 self.m 中所有 GhostModule 实例的 forward 函数,并根据 C3的定义将这些模块的输出聚合。

C3_GhostDynamicConv 通过整合 Dynamic Convolution 和 GhostModule 的特性,在保持计算高效的前提下,增强了模型的灵活性和表达能力,非常适合用于资源受限的深度学习应用。

2.3 新增yaml文件

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

  • 目标检测yaml文件 
# Ultralytics YOLOv5 🚀, AGPL-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, Conv, [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_GhostDynamicConv, [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_GhostDynamicConv, [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)]
  • 语义分割yaml文件
# Ultralytics YOLOv5 🚀, AGPL-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, Conv, [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_GhostDynamicConv, [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_GhostDynamicConv, [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, Segment, [nc, anchors, 32, 256]], # Segment (P3, P4, P5)]

温馨提示:本文只是对yolov5基础上添加模块,如果要对yolov5n/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.4 注册模块

关键步骤三在yolo.py的parse_model函数替换添加C3_GhostDynamicConv

2.5 执行程序

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

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

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

                 from  n    params  module                                  arguments0                -1  1      7040  models.common.Conv                      [3, 64, 6, 2, 2]1                -1  1     73984  models.common.Conv                      [64, 128, 3, 2]2                -1  3    156928  models.common.C3                        [128, 128, 3]3                -1  1    295424  models.common.Conv                      [128, 256, 3, 2]4                -1  6   1118208  models.common.C3                        [256, 256, 6]5                -1  1   1180672  models.common.Conv                      [256, 512, 3, 2]6                -1  9   6433792  models.common.C3                        [512, 512, 9]7                -1  1   4720640  models.common.Conv                      [512, 1024, 3, 2]8                -1  3   3714072  models.common.C3_GhostDynamicConv       [1024, 1024, 3]9                -1  1   2624512  models.common.SPPF                      [1024, 1024, 5]10                -1  1    525312  models.common.Conv                      [1024, 512, 1, 1]11                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']12           [-1, 6]  1         0  models.common.Concat                    [1]13                -1  3   1201688  models.common.C3_GhostDynamicConv       [1024, 512, 3, False]14                -1  1    131584  models.common.Conv                      [512, 256, 1, 1]15                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']16           [-1, 4]  1         0  models.common.Concat                    [1]17                -1  3    690688  models.common.C3                        [512, 256, 3, False]18                -1  1    590336  models.common.Conv                      [256, 256, 3, 2]19          [-1, 14]  1         0  models.common.Concat                    [1]20                -1  3   2495488  models.common.C3                        [512, 512, 3, False]21                -1  1   2360320  models.common.Conv                      [512, 512, 3, 2]22          [-1, 10]  1         0  models.common.Concat                    [1]23                -1  3   9971712  models.common.C3                        [1024, 1024, 3, False]        24      [17, 20, 23]  1    457725  Detect                                  [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [256, 512, 1024]]
YOLOv5_C3_GhostDynamicConv summary: 405 layers, 38750125 parameters, 38750125 gradients, 97.0 GFLOPs

3. 完整代码分享

https://pan.baidu.com/s/1RGXTGrAArSK_M_58bMAHVw?pwd=gt9h

提取码: gt9h 

4. GFLOPs

关于GFLOPs的计算方式可以查看百面算法工程师 | 卷积基础知识——Convolution

未改进的GFLOPs

img

改进后的GFLOPs

5. 进阶

可以结合损失函数或者卷积模块进行多重改进

YOLOv5改进 | 损失函数 | EIoU、SIoU、WIoU、DIoU、FocuSIoU等多种损失函数——点击即可跳转

6. 总结

Dynamic Convolution通过在每一层使用多组并行卷积核,并根据输入数据动态地聚合这些卷积核来增强卷积神经网络的表示能力。通过引入基于输入数据的注意力机制,网络能够自适应地调整每个卷积核的影响力,实现对输入的非线性响应。这种方法在保持网络深度和宽度不变的情况下,提高了模型的复杂度和表达能力。尽管模型中增加了多个卷积核,计算成本的增加主要集中在注意力权重的计算和卷积核的聚合上,相对于卷积操作本身,这些额外的计算量可以忽略不计。因此,Dynamic Convolution特别适用于轻量级神经网络。在训练过程中,使用动态卷积的网络需要同时优化所有卷积核和跨层的注意力权重,这使得训练更加困难。为此,采用了两个关键策略来改善训练效果:一是对注意力输出施加求和为1的约束,以简化注意力模型的学习;二是在训练初期使用高温度的softmax函数,使注意力权重趋于均匀,从而促进卷积核的学习。总体而言,Dynamic Convolution在不显著增加计算量的情况下,显著提升了模型在检测等任务中的表现。

这篇关于YOLOv5改进 | 模块融合 | C3融合 ghost + DynamicConv 【两次融合 + 独家改进】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

hdu1254(嵌套bfs,两次bfs)

/*第一次做这种题感觉很有压力,思路还是有点混乱,总是wa,改了好多次才ac的思路:把箱子的移动当做第一层bfs,队列节点要用到当前箱子坐标(x,y),走的次数step,当前人的weizhi(man_x,man_y),要判断人能否将箱子推到某点时要嵌套第二层bfs(人的移动);代码如下:

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

韦季李输入法_输入法和鼠标的深度融合

在数字化输入的新纪元,传统键盘输入方式正悄然进化。以往,面对实体键盘,我们常需目光游离于屏幕与键盘之间,以确认指尖下的精准位置。而屏幕键盘虽直观可见,却常因占据屏幕空间,迫使我们在操作与视野间做出妥协,频繁调整布局以兼顾输入与界面浏览。 幸而,韦季李输入法的横空出世,彻底颠覆了这一现状。它不仅对输入界面进行了革命性的重构,更巧妙地将鼠标这一传统外设融入其中,开创了一种前所未有的交互体验。 想象

基于 YOLOv5 的积水检测系统:打造高效智能的智慧城市应用

在城市发展中,积水问题日益严重,特别是在大雨过后,积水往往会影响交通甚至威胁人们的安全。通过现代计算机视觉技术,我们能够智能化地检测和识别积水区域,减少潜在危险。本文将介绍如何使用 YOLOv5 和 PyQt5 搭建一个积水检测系统,结合深度学习和直观的图形界面,为用户提供高效的解决方案。 源码地址: PyQt5+YoloV5 实现积水检测系统 预览: 项目背景

Jenkins构建Maven聚合工程,指定构建子模块

一、设置单独编译构建子模块 配置: 1、Root POM指向父pom.xml 2、Goals and options指定构建模块的参数: mvn -pl project1/project1-son -am clean package 单独构建project1-son项目以及它所依赖的其它项目。 说明: mvn clean package -pl 父级模块名/子模块名 -am参数

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类

一种改进的red5集群方案的应用、基于Red5服务器集群负载均衡调度算法研究

转自: 一种改进的red5集群方案的应用: http://wenku.baidu.com/link?url=jYQ1wNwHVBqJ-5XCYq0PRligp6Y5q6BYXyISUsF56My8DP8dc9CZ4pZvpPz1abxJn8fojMrL0IyfmMHStpvkotqC1RWlRMGnzVL1X4IPOa_  基于Red5服务器集群负载均衡调度算法研究 http://ww

python内置模块datetime.time类详细介绍

​​​​​​​Python的datetime模块是一个强大的日期和时间处理库,它提供了多个类来处理日期和时间。主要包括几个功能类datetime.date、datetime.time、datetime.datetime、datetime.timedelta,datetime.timezone等。 ----------动动小手,非常感谢各位的点赞收藏和关注。----------- 使用datet

[yolov5] --- yolov5入门实战「土堆视频」

1 项目介绍及环境配置 下载yolov5 tags 5.0源码,https://github.com/ultralytics/yolov5/tree/v5.0,解压 Pycharm 中创建conda虚拟环境 激活conda虚拟环境 根据作者提供的requirements.txt文件,pip install -r requirements.txt 如果作者没有提供requirement.txt文件