YOLOv5改进系列(3)——添加CA注意力机制

简介: YOLOv5改进系列(3)——添加CA注意力机制

【YOLOv5改进系列】前期回顾:

YOLOv5改进系列(0)——重要性能指标与训练结果评价及分析

YOLOv5改进系列(1)——添加SE注意力机制

YOLOv5改进系列(2)——添加CBAM注意力机制



🚀一、CA注意力机制原理

论文题目:《Coordinate Attention for Efficient Mobile Network Design》

论文地址:https://arxiv.org/abs/2103.02907

代码实现: https://github.com/Andrew- Qibin/CoordAttention

1.1 SE和CBAM方法的不足

  • SE(Squeeze-and-Excitation):SE注意力机制在编码过程中只考虑编码通道间信息而忽略了位置信息的重要性
  • CBAM(CBAM: Convolutional Block Attention Module):使用卷积计算空间注意力来利用位置信息,但卷积只能捕获局部关系,而无法捕捉的长距离依赖关系。

1.2 Coordinate Attention Block

Coordinate Attention通过精确的位置信息对通道关系和长期依赖性进行编码,具体操作分为 Coordinate信息嵌入 Coordinate Attention生成 2个步骤。


1.2.1 Coordinate Information Embedding:Coordinate信息嵌入

CxHxW形状的输入特征图逐通道进行平均池化,使用(H,1)(1,W)的池化核分别按XY轴方向进行池化,产生 CxHx1Cx1xW 形状的特征图。

通过这种方式所产生的一对方法感知特征图,可以使 CA 注意力能够在一个通道内捕获长距离的依赖关系,并且还有助于保留精确的位置信息,使网络能够更加准确的定位对象。


1.2.2 Coordinate Attention Generation :Coordinate Attention生成

(1)将上述所提取到的特征图按空间维度进行拼接,拼接成 Cr��x1x(W+H) 形状的特征图,其中 r 用于控制块的减小率和SE中的作用相同。

(2)再将特征图经过F1卷积变换函数(1x1卷积)和非线性激活函数产生 f 中间特征图。然后将 f 按空间维度拆分成两个张量 fhfw ,形状分别为Cr��xH Cr��xW,接着分别进行 FhFw 卷积变换函数(1x1卷积)和 Sigmoid 激活函数,得到 gh 和 gw 坐标注意力

(3)最后将gh gw 与原输入进行相乘,得到与输入相同形状的输出


1.3 CA的优势

  • 不仅考虑了通道信息,还考虑了方向相关的位置信息。
  • 足够的灵活和轻量,能够简单的插入到轻量级网络的核心模块中。
  • 可以作为预训练模型用于多种任务中,如检测和分割,均有不错的性能提升。

🚀二、添加CA注意力机制方法(单独加)

2.1 添加顺序

(1)models/common.py    --> 加入新增的网络结构

(2)     models/yolo.py       -->  设定网络结构的传参细节,将CA(CoordAtt

)类名加入其中。(当新的自定义模块中存在输入输出维度时,要使用qw调整输出维度)

(3) models/yolov5*.yaml  --> 新建一个文件夹,如yolov5s_CA.yaml,修改现有模型结构配置文件。(当引入新的层时,要修改后续的结构中的from参数)

(4)         train.py                --> 修改‘--cfg’默认参数,训练时指定模型结构配置文件


2.2 具体添加步骤

第①步:在common.py中添加CA模块

将下面的CA代码复制粘贴到common.py文件的末尾

# CA
class h_sigmoid(nn.Module):
    def __init__(self, inplace=True):
        super(h_sigmoid, self).__init__()
        self.relu = nn.ReLU6(inplace=inplace)
    def forward(self, x):
        return self.relu(x + 3) / 6
class h_swish(nn.Module):
    def __init__(self, inplace=True):
        super(h_swish, self).__init__()
        self.sigmoid = h_sigmoid(inplace=inplace)
    def forward(self, x):
        return x * self.sigmoid(x)
class CoordAtt(nn.Module):
    def __init__(self, inp, oup, reduction=32):
        super(CoordAtt, self).__init__()
        self.pool_h = nn.AdaptiveAvgPool2d((None, 1))
        self.pool_w = nn.AdaptiveAvgPool2d((1, None))
        mip = max(8, inp // reduction)
        self.conv1 = nn.Conv2d(inp, mip, kernel_size=1, stride=1, padding=0)
        self.bn1 = nn.BatchNorm2d(mip)
        self.act = h_swish()
        self.conv_h = nn.Conv2d(mip, oup, kernel_size=1, stride=1, padding=0)
        self.conv_w = nn.Conv2d(mip, oup, kernel_size=1, stride=1, padding=0)
    def forward(self, x):
        identity = x
        n, c, h, w = x.size()
        #c*1*W
        x_h = self.pool_h(x)
        #c*H*1
        #C*1*h
        x_w = self.pool_w(x).permute(0, 1, 3, 2)
        y = torch.cat([x_h, x_w], dim=2)
        #C*1*(h+w)
        y = self.conv1(y)
        y = self.bn1(y)
        y = self.act(y)
        x_h, x_w = torch.split(y, [h, w], dim=2)
        x_w = x_w.permute(0, 1, 3, 2)
        a_h = self.conv_h(x_h).sigmoid()
        a_w = self.conv_w(x_w).sigmoid()
        out = identity * a_w * a_h
        return out

如下图所示:


第②步:在yolo.py文件里的parse_model函数加入类名

首先找到yolo.py里面parse_model函数的这一行

然后把刚才加入的类CoordAtt添加到这个注册表里面


第③步:创建自定义的yaml文件 

首先在models文件夹下复制yolov5s.yaml 文件,粘贴并重命名为yolov5s_CA.yaml

接着修改  yolov5s_CA.yaml  ,将CA模块加到我们想添加的位置。

注意力机制可以添加在backbone,Neck,Head等部分, 常见的有两种:一是在主干的 SPPF 前添加一层二是将Backbone中的C3全部替换

在这里我是用第一种:将 [-1,1,CA,[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_CA.yaml

 然后运行yolo.py

  找到CA这一层,就说明我们添加成功啦!


第⑤步:修改train.py中 ‘--cfg’默认参数

我们先找到train.py 文件的parse_opt函数,然后将第二行‘--cfg’default改为'models/yolov5s_CA.yaml',然后就可以开始训练啦~


🚀三、添加C3_CA注意力机制方法(在C3模块中添加)

上面是单独加注意力层,接下来的方法是在C3模块中加入注意力层

刚才也提到了,这个策略是将CA注意力机制添加到Bottleneck,替换Backbone中的所有C3模块

(因为步骤和上面相同,所以接下来只放重要步骤噢~)

第①步:在common.py中添加CABottleneck和C3_CA模块

将下面的代码复制粘贴到common.py文件的末尾

# CA
class h_sigmoid(nn.Module):
    def __init__(self, inplace=True):
        super(h_sigmoid, self).__init__()
        self.relu = nn.ReLU6(inplace=inplace)
    def forward(self, x):
        return self.relu(x + 3) / 6
class h_swish(nn.Module):
    def __init__(self, inplace=True):
        super(h_swish, self).__init__()
        self.sigmoid = h_sigmoid(inplace=inplace)
    def forward(self, x):
        return x * self.sigmoid(x)
class CABottleneck(nn.Module):
    # Standard bottleneck
    def __init__(self, c1, c2, shortcut=True, g=1, e=0.5, ratio=32):  # 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.ca=CoordAtt(c1,c2,ratio)
        self.pool_h = nn.AdaptiveAvgPool2d((None, 1))
        self.pool_w = nn.AdaptiveAvgPool2d((1, None))
        mip = max(8, c1 // ratio)
        self.conv1 = nn.Conv2d(c1, mip, kernel_size=1, stride=1, padding=0)
        self.bn1 = nn.BatchNorm2d(mip)
        self.act = h_swish()
        self.conv_h = nn.Conv2d(mip, c2, kernel_size=1, stride=1, padding=0)
        self.conv_w = nn.Conv2d(mip, c2, kernel_size=1, stride=1, padding=0)
    def forward(self, x):
        x1 = self.cv2(self.cv1(x))
        n, c, h, w = x.size()
        # c*1*W
        x_h = self.pool_h(x1)
        # c*H*1
        # C*1*h
        x_w = self.pool_w(x1).permute(0, 1, 3, 2)
        y = torch.cat([x_h, x_w], dim=2)
        # C*1*(h+w)
        y = self.conv1(y)
        y = self.bn1(y)
        y = self.act(y)
        x_h, x_w = torch.split(y, [h, w], dim=2)
        x_w = x_w.permute(0, 1, 3, 2)
        a_h = self.conv_h(x_h).sigmoid()
        a_w = self.conv_w(x_w).sigmoid()
        out = x1 * a_w * a_h
        # out=self.ca(x1)*x1
        return x + out if self.add else out
class C3_CA(C3):
    # C3 module with CABottleneck()
    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(*(CABottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))

第②步:在yolo.py文件里的parse_model函数加入类名

yolo.pyparse_model函数中,加入CABottleneckC3_CA两个模块


第③步:创建自定义的yaml文件 

按照上面的步骤创建yolov5s_C3_CA.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_CA, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 6, C3_CA, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 3, C3_CA, [512]],
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 3, C3_CA, [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_CA.yaml,然后运行

这样就OK啦~


第⑤步:修改train.py中 ‘--cfg’默认参数

接下来的训练就和上面一样,不再叙述啦~

完结~撒花✿✿ヽ(°▽°)ノ✿


PS:今天训练的结果和比昨天CBAM的mAP增长了1.1,说明CA效果还是很不错的~


🌟本人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入门实践(1)——手把手带你环境配置搭建

YOLOv5入门实践(2)——手把手教你利用labelimg标注数据集

YOLOv5入门实践(3)——手把手教你划分自己的数据集

YOLOv5入门实践(4)——手把手教你训练自己的数据集

YOLOv5入门实践(5)——从零开始,手把手教你训练自己的目标检测模型(包含pyqt5界面)


本文参考(感谢大佬们):

b站:【YOLOv5 v6.1添加SE,CA,CBAM,ECA注意力机制教学,即插即用】

CSDN: CVPR 2021 | 即插即用! CA:新注意力机制,助力分类/检测/分割涨点!_Amusi(CVer)的博客-CSDN博客

手把手带你YOLOv5 (v6.1)添加注意力机制(二)(在C3模块中加入注意力机制)_迪菲赫尔曼的博客-CSDN博客

相关文章
|
4天前
|
机器学习/深度学习 网络架构 计算机视觉
YOLOv5改进有效涨点系列->适合多种检测场景的BiFormer注意力机制(Bi-level Routing Attention)
YOLOv5改进有效涨点系列->适合多种检测场景的BiFormer注意力机制(Bi-level Routing Attention)
144 0
|
4天前
|
机器学习/深度学习 计算机视觉
YOLOv8改进 | 2023注意力篇 | EMAttention注意力机制(附多个可添加位置)
YOLOv8改进 | 2023注意力篇 | EMAttention注意力机制(附多个可添加位置)
325 0
|
4天前
|
机器学习/深度学习 自然语言处理 数据处理
Transformer模型中的Attention机制是什么?
Google研究团队为解决机器翻译准确性问题,推出了Transformer模型,核心是Attention机制。Transformer摒弃RNN和CNN,利用Attention处理全局依赖,提高长文本处理效率。模型包含编码器-解码器与自Attention,多头Attention增强信息捕获,位置编码处理顺序信息。虽在翻译质量和速度上有显著提升,但面临泛化能力、长距离依赖处理和计算复杂度等问题,仍有优化空间。
18 0
Transformer模型中的Attention机制是什么?
|
4天前
|
机器学习/深度学习 测试技术 计算机视觉
注意力机制汇总,包括SE、CBAM、ECA等
注意力机制汇总,包括SE、CBAM、ECA等
143 0
|
4天前
|
机器学习/深度学习 算法
YOLOv8改进算法之添加CA注意力机制
CA(Coordinate Attention)注意力机制是一种用于加强深度学习模型对输入数据的空间结构理解的注意力机制。CA 注意力机制的核心思想是引入坐标信息,以便模型可以更好地理解不同位置之间的关系
294 0
|
4天前
|
机器学习/深度学习 算法
YOLOv5改进算法之添加CA注意力机制模块
CA(Coordinate Attention)注意力机制是一种用于加强深度学习模型对输入数据的空间结构理解的注意力机制。CA 注意力机制的核心思想是引入坐标信息,以便模型可以更好地理解不同位置之间的关系。
242 0
|
4天前
|
机器学习/深度学习 计算机视觉
YOLOv5改进 | 2023注意力篇 | EMAttention注意力机制(附多个可添加位置)
YOLOv5改进 | 2023注意力篇 | EMAttention注意力机制(附多个可添加位置)
270 0
|
4天前
|
机器学习/深度学习 网络架构 计算机视觉
YOLOv8改进有效涨点系列->适合多种检测场景的BiFormer注意力机制(Bi-level Routing Attention)
YOLOv8改进有效涨点系列->适合多种检测场景的BiFormer注意力机制(Bi-level Routing Attention)
186 0
|
4天前
|
机器学习/深度学习 数据处理 计算机视觉
YOLOv5改进 | 2023 | 将RT-DETR模型AIFI模块和Conv模块结合替换SPPF(全网独家改进)
YOLOv5改进 | 2023 | 将RT-DETR模型AIFI模块和Conv模块结合替换SPPF(全网独家改进)
121 0
|
4天前
|
机器学习/深度学习 数据处理 计算机视觉
YOLOv8改进 | 2023 | 将RT-DETR模型AIFI模块和Conv模块结合替换SPPF(全网独家改进)
YOLOv8改进 | 2023 | 将RT-DETR模型AIFI模块和Conv模块结合替换SPPF(全网独家改进)
71 0