【YOLOv5改进系列】前期回顾:
YOLOv5改进系列(0)——重要性能指标与训练结果评价及分析
🚀一、ECA注意力机制原理
论文题目:《ECA-Net: Efficient Channel Attention for Deep Convolutional Neural Networks》
原文地址:ECA-Net
代码实现:ECA-Net: Efficient Channel Attention for Deep Convolutional Neural Networks 开源代码GitHub - BangguWu/ECANet: Code for ECA-Net: Efficient Channel Attention for Deep Convolutional Neural NetworksECA-Net: Efficient Channel Attention for Deep Convolutional Neural Networks 开源代码
1.1 ECA方法介绍
ECA是通道注意力机制的一种实现形式,是基于SE的扩展。
作者认为SE block的两个FC层之间的降维是不利于channel attention的权重学习的,并且捕获所有通道之间的依存关系是效率不高且是不必要的。权重学习的过程应该直接一一对应。
ECA 注意力机制模块直接在全局平均池化层之后使用1x1卷积层,去除了全连接层。该模块避免了维度缩减,并有效捕获了跨通道交互。并且ECA只涉及少数参数就能达到很好的效果。
ECA通过一维卷积 layers.Conv1D来完成跨通道间的信息交互,卷积核的大小通过一个函数来自适应变化,使得通道数较大的层可以更多地进行跨通道交互。
自适应函数为: ,其中
1.2 SE和ECA网络结构的对比
SEblock网络结构 | ECA模块网络结构 |
(1)global avg pooling产生1 ∗ 1 ∗ C 大小的feature maps | (1)global avg pooling产生1 ∗ 1 ∗ C 大小的feature maps |
(2)两个fc层(中间有维度缩减)来产生每个channel的weight | (2)计算得到自适应的kernel_size |
(3)应用kernel_size于一维卷积中,得到每个channel的weight |
1.3 ECA实现过程
(1)将输入特征图经过全局平均池化,特征图从 [h,w,c] 的矩阵变成 [1,1,c] 的向量
(2)根据特征图的通道数计算得到自适应的一维卷积核大小 kernel_size
(3)将 kernel_size 用于一维卷积中,得到对于特征图的每个通道的权重
(4)将归一化权重和原输入特征图逐通道相乘,生成加权后的特征图
🚀二、添加ECA注意力机制方法(单独加)
2.1 添加顺序
(1)models/common.py --> 加入新增的网络结构
(2) models/yolo.py --> 设定网络结构的传参细节,将ECA类名加入其中。(当新的自定义模块中存在输入输出维度时,要使用qw调整输出维度)
(3) models/yolov5*.yaml --> 新建一个文件夹,如yolov5s_ECA.yaml,修改现有模型结构配置文件。(当引入新的层时,要修改后续的结构中的from参数)
(4) train.py --> 修改‘--cfg’默认参数,训练时指定模型结构配置文件
2.2 具体添加步骤
第①步:在common.py中添加ECA模块
将下面的ECA代码复制粘贴到common.py文件的末尾
class ECA(nn.Module): """Constructs a ECA module. Args: channel: Number of channels of the input feature map k_size: Adaptive selection of kernel size """ def __init__(self, c1,c2, k_size=3): super(ECA, self).__init__() self.avg_pool = nn.AdaptiveAvgPool2d(1) self.conv = nn.Conv1d(1, 1, kernel_size=k_size, padding=(k_size - 1) // 2, bias=False) self.sigmoid = nn.Sigmoid() def forward(self, x): # feature descriptor on the global spatial information y = self.avg_pool(x) y = self.conv(y.squeeze(-1).transpose(-1, -2)).transpose(-1, -2).unsqueeze(-1) # Multi-scale information fusion y = self.sigmoid(y) return x * y.expand_as(x)
如下图所示:
第②步:在yolo.py文件里的parse_model函数加入类名
首先找到yolo.py里面parse_model函数的这一行
然后把刚才加入的类ECA添加到这个注册表里面
第③步:创建自定义的yaml文件
首先在models文件夹下复制yolov5s.yaml文件,粘贴并重命名为 yolov5s_ECA.yaml
接着修改 yolov5s_ECA.yaml ,将ECA模块加到我们想添加的位置。
注意力机制可以添加在backbone,Neck,Head等部分,常见的有两种:一是在主干的 SPPF 前添加一层;二是将Backbone中的C3全部替换。
在这里我是用第一种:将 [-1,1,ECA,[1024]]添加到 SPPF 的上一层,下一节使用第二种。即下图中所示位置:
同样的下面的head也得修改,p4,p5以及最后detect的总层数都得+1
这里我们要把后面两个Concat的from系数分别由[ − 1 , 14 ] ,[ − 1 , 10 ]改为[ − 1 , 15 ],[ − 1 , 11 ]。然后将Detect原始的from系数[ 17 , 20 , 23 ]要改为[ 18 , 21 , 24 ] 。
第④步:验证是否加入成功
在yolo.py 文件里面配置改为我们刚才自定义的yolov5s_ECA.yaml
然后运行yolo.py
找到ECA这一层,就说明我们添加成功啦!
可以看到params参数这里只有3,说明参数量真的很少呀。
第⑤步:修改train.py中 ‘--cfg’默认参数
我们先找到 train.py 文件的parse_opt函数,然后将第二行‘--cfg’的 default改为'models/yolov5s_ECA.yaml',然后就可以开始训练啦~
🚀三、添加C3_CA注意力机制方法(在C3模块中添加)
上面是单独加注意力层,接下来的方法是在C3模块中加入注意力层。
刚才也提到了,这个策略是将CA注意力机制添加到Bottleneck,替换Backbone中的所有C3模块。
(因为步骤和上面相同,所以接下来只放重要步骤噢~)
第①步:在common.py中添加ECABottleneck和C3_ECA模块
将下面的代码复制粘贴到common.py文件的末尾
class ECABottleneck(nn.Module): # Standard bottleneck def __init__(self, c1, c2, shortcut=True, g=1, e=0.5, ratio=16, k_size=3): # ch_in, ch_out, shortcut, groups, expansion super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, 1, 1) self.cv2 = Conv(c_, c2, 3, 1, g=g) self.add = shortcut and c1 == c2 # self.eca=ECA(c1,c2) self.avg_pool = nn.AdaptiveAvgPool2d(1) self.conv = nn.Conv1d(1, 1, kernel_size=k_size, padding=(k_size - 1) // 2, bias=False) self.sigmoid = nn.Sigmoid() def forward(self, x): x1 = self.cv2(self.cv1(x)) # out=self.eca(x1)*x1 y = self.avg_pool(x1) y = self.conv(y.squeeze(-1).transpose(-1, -2)).transpose(-1, -2).unsqueeze(-1) y = self.sigmoid(y) out = x1 * y.expand_as(x1) return x + out if self.add else out class C3_ECA(C3): # C3 module with ECABottleneck() def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): super().__init__(c1, c2, n, shortcut, g, e) c_ = int(c2 * e) # hidden channels self.m = nn.Sequential(*(ECABottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))
第②步:在yolo.py文件里的parse_model函数加入类名
在yolo.py的parse_model
函数中,加入ECABottleneck,C3_ECA这两个模块
第③步:创建自定义的yaml文件
按照上面的步骤创建yolov5s_C3_ECA.yaml文件
替换4个C3模块,如下图所示
代码如下:
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license # Parameters nc: 80 # 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] [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 3, C3_ECA, [128]], [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 6, C3_ECA, [256]], [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 3, C3_ECA, [512]], [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 3, C3_ECA, [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, [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) ]
第④步:验证是否加入成功
在yolo.py 文件里面配置改为我们刚才自定义的yolov5s_C3_ECA.yaml,然后运行
这样就OK啦~
第⑤步:修改train.py中 ‘--cfg’默认参数
接下来的训练就和上面一样,不再叙述啦~
完结~撒花✿✿ヽ(°▽°)ノ✿
PS:今天训练了一下,我的评价是,ECA不如昨天的CA,mAP降了0.3
🌟本人YOLOv5系列导航
🍀YOLOv5源码详解系列:
YOLOv5源码逐行超详细注释与解读(1)——项目目录结构解析
YOLOv5源码逐行超详细注释与解读(2)——推理部分detect.py
YOLOv5源码逐行超详细注释与解读(3)——训练部分train.py
YOLOv5源码逐行超详细注释与解读(4)——验证部分val(test).py
YOLOv5源码逐行超详细注释与解读(5)——配置文件yolov5s.yaml
YOLOv5源码逐行超详细注释与解读(6)——网络结构(1)yolo.py
YOLOv5源码逐行超详细注释与解读(7)——网络结构(2)common.py
🍀YOLOv5入门实践系列:
YOLOv5入门实践(2)——手把手教你利用labelimg标注数据集
YOLOv5入门实践(5)——从零开始,手把手教你训练自己的目标检测模型(包含pyqt5界面)
本文参考(感谢大佬们):
b站:【YOLOv5 v6.1添加SE,CA,CBAM,ECA注意力机制教学,即插即用】
CSDN: 【深度学习】(1) CNN中的注意力机制(SE、ECA、CBAM)
手把手带你YOLOv5 (v6.1)添加注意力机制(二)(在C3模块中加入注意力机制)_yolov5添加注意力机制_迪菲赫尔曼的博客-CSDN博客手把手带你YOLOv5/v7 添加注意力机制(并附上30多种顶会Attention原理图)2023/2/11更新_yolov5添加注意力机制_迪菲赫尔曼的博客-CSDN博客