YOLOv8改进 | 主干篇 | 利用SENetV2改进网络结构 (全网首发改进)

2023-12-25 07:28

本文主要是介绍YOLOv8改进 | 主干篇 | 利用SENetV2改进网络结构 (全网首发改进),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、本文介绍

本文给大家带来的改进机制是SENetV2,其是2023.11月的最新机制(所以大家想要发论文的可以在上面下点功夫),其是一种通过调整卷积网络中的通道关系来提升性能的网络结构。SENet并不是一个独立的网络模型,而是一个可以和现有的任何一个模型相结合的模块(可以看作是一种通道型的注意力机制但是相对于SENetV1来说V2又在全局的角度进行了考虑)。在SENet中,所谓的挤压和激励(Squeeze-and-Excitation)操作是作为一个单元添加到传统的卷积网络结构中,如残差单元中(后面我会把修改好的残差单元给大家大家直接复制粘贴即可使用)亲测大中小三中目标检测上都有一定程度的涨点效果。

推荐指数:⭐⭐⭐⭐⭐

涨点效果:⭐⭐⭐⭐⭐

专栏回顾:YOLOv8改进系列专栏——本专栏持续复习各种顶会内容——科研必备    

训练结果对比图->  

后面我会将这个机制SENetV1和SENetV2添加到多个网络结构中进行融合涨点,同时将其融合到检测头里将模型发布给大家使用。

(我对于SENetV1和SENetV2各提供了两个版本的yaml文件,我分别尝试了其中的两种,这个SENetV2的实验yaml文件可能不如我没实验的yaml文件二大家可以都尝试一下。)

目录

一、本文介绍

 二、SENetV2框架原理

三、SENetV2核心代码

四、手把手教你添加SENetV2模块

 4.1 SENetV2添加步骤

4.1.1 步骤一

4.1.2 步骤二

4.1.3 步骤三

4.2 SENetV2的yaml文件和训练截图

4.2.1 SENetV2的yaml版本一

4.2.2 SENetV2的yaml版本二

4.3 推荐SENetV2可添加的位置 

4.4 SENetV2的训练过程截图 

五、本文总结


 二、SENetV2框架原理

论文地址:官方论文地址点击即可跳转

代码地址:官方代码地址点击即可跳转


SENetV2介绍了一种改进的SENet架构,该架构通过引入一种称为Squeeze aggregated excitation(SaE)的新模块来提升网络的表征能力。这个模块结合了挤压和激励(SENetV1)操作,通过多分支全连接层增强了网络的全局表示学习。在基准数据集上的实验结果证明了SENetV2模型相较于现有模型在分类精度上的显著提升。这一架构尤其强调在仅略微增加模型参数的情况下,如何有效地提高模型的性能。 

挤压和激励模块大家可以看我发的SENetV1文章里面有介绍。

图中展示了三种不同的神经网络模块对比:

a) ResNeXt模块:采用多分支CNN结构,不同分支的特征图通过卷积操作处理后合并(concatenate),再进行额外的卷积操作。

b) SENet模块:标准卷积操作后,利用全局平均池化来挤压特征,然后通过两个尺寸为1x1的全连接层(FC)和Sigmoid激活函数来获取通道权重,最后对卷积特征进行缩放(Scale)。

c) SENetV2模块:结合了ResNeXt和SENet的特点,采用多分支全连接层(FC)来挤压和激励操作,最后进行特征缩放。

其中SENetV2的设计旨在通过多分支结构进一步提升特征表达的精细度和全局信息的整合能力。

前面我们提到了SaE,就是SENetV2相对于SENetV1的主要改进机制,下面的图片介绍了其内部工作原理。

SENet V2中所提出的SaE(Squeeze-and-Excitation)模块的内部工作机制。挤压输出后,被输入到多分支的全连接(FC)层,然后进行激励过程。分割的输入在最后被传递以恢复其原始形状。这种设计能够让网络更有效地学习到输入数据的不同特征,并且在进行特征转换时考虑到不同通道之间的相互依赖性。 


三、SENetV2核心代码

下面的代码是MSDA的核心代码,我们将其复制导'ultralytics/nn/modules'目录下,在其中创建一个文件,我这里起名为Dilation然后粘贴进去,其余使用方式看章节四。

import torch
import torch.nn as nn
from .conv import Conv
# 定义SE模块
class SELayer(nn.Module):def __init__(self, channel, reduction=16):super(SELayer, self).__init__()self.avg_pool = nn.AdaptiveAvgPool2d(1)self.fc = nn.Sequential(nn.Linear(channel, channel // reduction, bias=False),nn.ReLU(inplace=True),nn.Linear(channel // reduction, channel, bias=False),nn.Sigmoid())def forward(self, x):b, c, _, _ = x.size()y = self.avg_pool(x).view(b, c)y = self.fc(y).view(b, c, 1, 1)return x * y.expand_as(x)# 定义SaE模块
class SELayerV2(nn.Module):def __init__(self, in_channel, reduction=32):super(SELayerV2, self).__init__()assert in_channel>=reduction and in_channel%reduction==0,'invalid in_channel in SaElayer'self.reduction = reductionself.cardinality=4self.avg_pool = nn.AdaptiveAvgPool2d(1)#cardinality 1self.fc1 = nn.Sequential(nn.Linear(in_channel,in_channel//self.reduction, bias=False),nn.ReLU(inplace=True))# cardinality 2self.fc2 = nn.Sequential(nn.Linear(in_channel, in_channel // self.reduction, bias=False),nn.ReLU(inplace=True))# cardinality 3self.fc3 = nn.Sequential(nn.Linear(in_channel, in_channel // self.reduction, bias=False),nn.ReLU(inplace=True))# cardinality 4self.fc4 = nn.Sequential(nn.Linear(in_channel, in_channel // self.reduction, bias=False),nn.ReLU(inplace=True))self.fc = nn.Sequential(nn.Linear(in_channel//self.reduction*self.cardinality, in_channel, bias=False),nn.Sigmoid())def forward(self, x):b, c, _, _ = x.size()y = self.avg_pool(x).view(b, c)y1 = self.fc1(y)y2 = self.fc2(y)y3 = self.fc3(y)y4 = self.fc4(y)y_concate = torch.cat([y1,y2,y3,y4],dim=1)y_ex_dim = self.fc(y_concate).view(b,c,1,1)return x * y_ex_dim.expand_as(x)class 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.SEV2 = SELayerV2(c2)self.add = shortcut and c1 == c2def forward(self, x):"""'forward()' applies the YOLO FPN to input data."""return x + self.SEV2(self.cv2(self.cv1(x))) if self.add else self.SEV2(self.cv2(self.cv1(x)))class C2f_SENetV2(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(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))# import ipdb
#
# se_v2 = SaELayer(64)
# # 示例输入
# input = torch.randn(3, 64, 224, 224)
# output = se_v2(input)
#
# print(output.shape)#torch.Size([3, 64, 224, 224])


四、手把手教你添加SENetV2模块

 4.1 SENetV2添加步骤

4.1.1 步骤一

首先我们找到如下的目录'ultralytics/nn/modules',然后在这个目录下创建一个py文件,名字为你也可以根据你自己的习惯起即可,然后将核心代码复制进去。

4.1.2 步骤二

之后我们找到'ultralytics/nn/tasks.py'文件,在其中注册我们的模块。

首先我们需要在文件的开头导入我们的模块,如下图所示->

4.1.3 步骤三

我们找到parse_model这个方法,可以用搜索也可以自己手动找,大概在六百多行吧。 我们找到如下的地方,然后将模块按照我的方法添加进去即可,模仿我添加即可,其中另外的模块,你没有删除即可,添加红框的内容即可。

到此我们就注册成功了,可以修改yaml文件使用我们添加的模块了。


4.2 SENetV2的yaml文件和训练截图

下面推荐几个版本的yaml文件给大家,大家可以复制进行训练,但是组合用很多具体那种最有效果都不一定,针对不同的数据集效果也不一样,我不可每一种都做实验,所以我下面推荐了几种我自己认为可能有效果的配合方式,你也可以自己进行组合。


4.2.1 SENetV2的yaml版本一

这个是我尝试的版本,和上一篇SENetV1做了个对比反过来尝试一下。

# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect# 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 GFLOPss: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPsm: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPsl: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPsx: [1.00, 1.25, 512]   # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOP# 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_SENetV2, [256]]  # 15 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]]- [[-1, 12], 1, Concat, [1]]  # cat head P4- [-1, 3, C2f_SENetV2, [512]]  # 18 (P4/16-medium)- [-1, 1, Conv, [512, 3, 2]]- [[-1, 9], 1, Concat, [1]]  # cat head P5- [-1, 3, C2f_SENetV2, [1024]]  # 21 (P5/32-large)- [[11, 14, 17], 1, Detect, [nc]]  # Detect(P3, P4, P5)

4.2.2 SENetV2的yaml版本二

下面的版本我在大中小三个检测层的输出部分添加了SENetV2,大家可以根据自己的需求,减少SENetV2比如你做的小目标检测,那么可以把另外两个去去掉,但是别忘了修改检测通道数,要不然会报错。 

# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect# 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 GFLOPss: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPsm: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPsl: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPsx: [1.00, 1.25, 512]   # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOP# 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, SELayerV2, []]  # 16- [-1, 1, Conv, [256, 3, 2]]- [[-1, 12], 1, Concat, [1]]  # cat head P4- [-1, 3, C2f, [512]]  # 19 (P4/16-medium)- [-1, 1, SELayerV2, []]  # 20- [-1, 1, Conv, [512, 3, 2]]- [[-1, 9], 1, Concat, [1]]  # cat head P5- [-1, 3, C2f, [1024]]  # 23 (P5/32-large)- [-1, 1, SELayerV2, []]  # 24- [[16, 20, 24], 1, Detect, [nc]]  # Detect(P3, P4, P5)

4.3 推荐SENetV2可添加的位置 

SENetV2是一种即插即用的可替换卷积的模块,其可以添加的位置有很多,添加的位置不同效果也不同,所以我下面推荐几个添加的位,置大家可以进行参考,当然不一定要按照我推荐的地方添加。

  1. 残差连接中:在残差网络的残差连接中加入SENetV2

  2. Neck部分:YOLOv8的Neck部分负责特征融合,这里添加SENetV2可以帮助模型更有效地融合不同层次的特征。

  3. 能添加的位置很多:一篇文章很难全部介绍到,后期我会发文件里面集成上百种的改进机制,然后还有许多融合模块,给大家。


4.4 SENetV2的训练过程截图 

下面是添加了SENetV2的训练截图。

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

​​​​​​


五、本文总结

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

专栏回顾:YOLOv8改进系列专栏——本专栏持续复习各种顶会内容——科研必备

​​​

这篇关于YOLOv8改进 | 主干篇 | 利用SENetV2改进网络结构 (全网首发改进)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

(超详细)YOLOV7改进-Soft-NMS(支持多种IoU变种选择)

1.在until/general.py文件最后加上下面代码 2.在general.py里面找到这代码,修改这两个地方 3.之后直接运行即可

YOLOv8改进 | SPPF | 具有多尺度带孔卷积层的ASPP【CVPR2018】

💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 专栏目录 :《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有40+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进——点击即可跳转 Atrous Spatial Pyramid Pooling (ASPP) 是一种在深度学习框架中用于语义分割的网络结构,它旨

【智能优化算法改进策略之局部搜索算子(五)—自适应Rosenbrock坐标轮换法】

1、原理介绍 作为一种有效的直接搜索技术,Rosenbrock坐标轮换法[1,2]是根据Rosenbrock著名的“香蕉函数”的特点量身定制的,该函数的最小值位于曲线狭窄的山谷中。此外,该方法是一种典型的基于自适应搜索方向集的无导数局部搜索技术。此法于1960年由Rosenbrock提出,它与Hooke-Jeeves模式搜索法有些类似,但比模式搜索更为有效。每次迭代运算分为两部分[3]: 1)

智能优化算法改进策略之局部搜索算子(六)--进化梯度搜索

1、原理介绍     进化梯度搜索(Evolutionary Gradient Search, EGS)[1]是兼顾进化计算与梯度搜索的一种混合算法,具有较强的局部搜索能力。在每次迭代过程中,EGS方法首先用受进化启发的形式估计梯度方向,然后以最陡下降的方式执行实际的迭代步骤,其中还包括步长的自适应,这一过程的总体方案如下图所示:     文献[1]

【论文复现|智能算法改进】一种基于多策略改进的鲸鱼算法

目录 1.算法原理2.改进点3.结果展示4.参考文献5.代码获取 1.算法原理 SCI二区|鲸鱼优化算法(WOA)原理及实现【附完整Matlab代码】 2.改进点 混沌反向学习策略 将混沌映射和反向学习策略结合,形成混沌反向学习方法,通过该方 法生成鲸鱼算法的初始种群。混沌序列采用 Tent 混沌映射: x i + 1 = { δ x i 0 < x i < 0.5

智能优化算法改进策略之局部搜索算子(三)—二次插值法

1、原理介绍 多项式是逼近函数的一种常用工具。在寻求函数极小点的区间(即寻查区间)上,我们可以利用在若干点处的函数值来构成低次插值多项式,用它作为求极小点的函数的近似表达式,并用这个多项式的极小点作为原函数极小点的近似。低次多项式的极小点比较容易计算。常用的插值多项式为二次或三次,一般说来三次插值公式的收敛性好一些,但在导数不变计算时,三点二次插值也是一种常用的方法[1]。 3

智能优化算法改进策略之局部搜索算子(四)--梯度搜索法

2、仿真实验 以海洋捕食者算法(MPA)为基本算法。考察基于梯度搜索的改进海洋捕食者算法(命名为GBSMPA) vs. 海洋捕食者算法(MPA)  在Sphere函数上的比较      在Penalized1函数上的比较    在CEC2017-1上的比较    在CEC2017-3上的比较 在CEC2017-4上的比较 代码获取:

智能优化算法改进策略之局部搜索算子(八)--Powell方法

1、原理介绍 Powell方法[1]是一种无约束优化算法,又称为方向加速法,用于寻找多变量函数的极小值。其基本思想是在迭代中逐次产生Q共轭方向组,本质上它属于不需计算导数的共轭方向法。每次迭代后,算法会更新搜索方向,并包含新的方向以改善优化效果。由于Powell方法不需要计算梯度信息,因此适用于目标函数不可导或计算梯度成本较高的情况。它在迭代过程中通过调整方向和步长,逐步缩小搜索范围,以达到目标

智能优化算法改进策略之局部搜索算子(七)--自适应模式搜索法

1、原理介绍     模式搜索法[1]是Hooke与Jeeves提出的一种直接搜索算法,其目的是通过比较目标函数在有限点集中的函数值来优化目标函数。更重要的是,它不仅不使用任何导数知识,而且不需要隐式地建立任何一种导数近似。 在这种直接搜索技术中,将模式移动和探索移动相结合,迭代地寻找最优解。该技术首先沿着每个轴进行探索性移动,以寻找新的基点和有利于函数值下降的方向。然后,为了加快在探索性移动

IDEA 中 Maven 报错 Cannot resolve xxx(全网试完,亲测有效的方法汇总)

问题: pom中已经添加相关依赖,maven刷新也没有用,依旧是疯狂报错。 可能原因: 在IDEA中的pom文件中添加了依赖,并且正确加载了相应依赖,pom文件没有报红,看起来像是把所有依赖库全部加载进来了,但是代码中使用依赖的类库使报红。 在pom中添加了某个依赖,不会直接立刻马上将其下载并且添加到项目的external libraries中。只有在某个子模块的pom文件中也添加了