YOLOv5算法改进(3)— 添加CBAM注意力机制

前言:Hello大家好,我是小哥谈。注意力机制是近年来深度学习领域内的研究热点,可以帮助模型更好地关注重要的特征,从而提高模型的性能。CBAM(Convolutional Block Attention Module) 是一种用于前馈卷积神经网络的简单而有效的注意力模块,它是一种结合了通道(channel)和空间(spatial)的注意力机制模块,相比于SE-Net只关注通道注意力机制可以取得更好的结果。🌈 

 前期回顾:

            YOLOv5算法改进(1)— 如何去改进YOLOv5算法

            YOLOv5算法改进(2)— 添加SE注意力机制

            目录

🚀1.注意力机制原理 

🚀2.CBAM论文

🚀3.CBAM方法介绍

🚀4.添加CBAM注意力机制的方法

💥💥步骤1:在common.py中添加CBAM模块

💥💥步骤2:在yolo.py文件中加入类名 

💥💥步骤3:创建自定义yaml文件

💥💥步骤4:修改yolov5s_CBAM.yaml文件 

💥💥步骤5:验证是否加入成功

💥💥步骤6:修改train.py中的'--cfg'默认参数

🚀5.添加C3_CBAM注意力机制的方法(在C3模块中添加)

💥💥步骤1:在common.py中添加CBAMBottleneck和C3_CBAM模块

💥💥步骤2:在yolo.py文件里parse_model函数中加入类名

💥💥步骤3:创建自定义yaml文件

💥💥步骤4:验证是否加入成功

💥💥步骤5:修改train.py中的'--cfg'默认参数 

🚀1.注意力机制原理 

神经网络中的注意力机制(Attention Mechanism)是在计算能力有限的情况下,将计算资源分配给更重要的任务,同时解决信息超载问题的一种资源分配方案。在神经网络学习中,一般而言,模型的参数越多则模型的表达能力越强,模型所存储的信息量也越大,但这会带来信息过载的问题。那么通过引入注意力机制,在众多的输入信息中聚焦于对当前任务更为关键的信息,降低对其他信息的关注度,甚至过滤掉无关信息,就可以解决信息过载问题,并提高任务处理的效率和准确性。 🍃

这就类似于人类的视觉注意力机制,通过扫描全局图像,获取需要重点关注的目标区域,而后对这一区域投入更多的注意力资源,获取更多与目标有关的细节信息,而忽视其他无关信息。通过这种机制可以利用有限的注意力资源从大量信息中快速筛选出高价值的信息。🍃

一般而言,注意力机制可以分为:通道注意力机制空间注意力机制二者的结合

空间注意力机制(关注每个通道的比重),通道注意力机制(关注每个像素点的比重),比较典型的如SENet,而CBAM则是二者的结合。🌱


🚀2.CBAM论文

论文题目:《CBAM:Convolutional Block Attention Module》
论文地址:  https://arxiv.org/pdf/1807.06521.pdf

代码实现:  https://github.com/luuuyi/CBAM.PyTorch

论文(2018年)提出了一种轻量的注意力模块( CBAM,Convolutional Block Attention Module ),可以在通道和空间维度上进行 Attention 。论文在 ResNet 和 MobileNet 等经典结构上添加了 CBAM 模块并进行对比分析,同时也进行了可视化,发现 CBAM 更关注识别目标物体,这也使得 CBAM 具有更好的解释性。🌾

由论文可知,CBAM的网络结构包括通道注意力机制和空间注意力机制。作者将二者串联搭建,且通道注意力模块在前,空间注意力模块在后。

经过实验,作者发现:串联搭建比并联搭建效果好,先进行通道注意力比先空间注意力效果好。🌾


🚀3.CBAM方法介绍

卷积神经网络(CNN)在计算机视觉任务中取得了显著的成功。为了进一步提高CNN的性能,研究人员提出了一种名为“卷积神经网络注意力模块”(Convolutional Block Attention Module, CBAM)的注意力机制。CBAM旨在自动学习输入特征图的空间和通道注意力权重,从而更好地捕捉图像中的局部信息和全局上下文。🌟

CBAM包括两个主要组成部分: 空间注意力模块通道注意力模块。它们可以作为插件,轻松地集成到现有的 CNN 架构中,以提高性能。

空间注意力模块 (Spatial Attention Module) : 空间注意力模块的目的是为输入特征图的每个位置分配一个注意力权重。这些权重可帮助网络集中注意力于感兴趣的区域。

空间注意力模块主要包括以下步骤:👇

  • a.对输入特征图进行全局平均池化和全局最大池化操作。
  • b.将池化后的特征图按通道相加,得到两个1维向量。
  • c.对这两个向量进行点积,形成一个注意力权重矩阵。
  • d.将注意力权重矩阵应用于输入特征图,得到空间注意力调整后的特征图。

通道注意力模块 (ChannelAttention Module) : 通道注意力模块旨在为输入特征图的每个通道分配一个权重,从而强调重要的通道并抑制不太重要的通道。

通道注意力模块主要包括以下步骤:👇

  • a.对输入特征图进行全局平均池化和全局最大池化操作。
  • b.使用全连接层 (MLP) 学习每个通道的权重。
  • c.将学到的权重应用于输入特征图,得到通道注意力调整后的特征图。

最后,将空间注意力模块和通道注意力模块的输出相加,形成CBAM调整后的特征图。这个特征图可以继续传递到CNN的下一层。
实验证明,CBAM在各种计算机视觉任务上都能显著提高性能,如图像分类、目标检测和语义分割等。它是一种通用的注意力机制,可以与任何卷积神经网络架构相结合。🌾

说明:♨️♨️♨️

CBAM的核心:

应用了Channel Attention Module(通道注意模块)Spatial Attention Module(空间注意模块)的结合,对输入进来的特征层分别进行通道注意力模块和空间注意力模块的处理。

其中,通道注意力用于处理特征图通道的分配关系,而空间注意力可使神经网络更加关注图像中对分类起决定作用的像素区域而忽略无关紧要的区域。同时对这两个维度进行注意力的分配增强了注意力机制对模型性能的提升效果。


🚀4.添加CBAM注意力机制的方法

💥💥步骤1:在common.py中添加CBAM模块

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

# CBAM
class ChannelAttention(nn.Module):
    def __init__(self, in_planes, ratio=16):
        super(ChannelAttention, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.max_pool = nn.AdaptiveMaxPool2d(1)
        self.f1 = nn.Conv2d(in_planes, in_planes // ratio, 1, bias=False)
        self.relu = nn.ReLU()
        self.f2 = nn.Conv2d(in_planes // ratio, in_planes, 1, bias=False)
        self.sigmoid = nn.Sigmoid()
    def forward(self, x):
        avg_out = self.f2(self.relu(self.f1(self.avg_pool(x))))
        max_out = self.f2(self.relu(self.f1(self.max_pool(x))))
        out = self.sigmoid(avg_out + max_out)
        return out
    
class SpatialAttention(nn.Module):
    def __init__(self, kernel_size=7):
        super(SpatialAttention, self).__init__()
        assert kernel_size in (3, 7), 'kernel size must be 3 or 7'
        padding = 3 if kernel_size == 7 else 1
        # (特征图的大小-算子的size+2*padding)/步长+1
        self.conv = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
        self.sigmoid = nn.Sigmoid()
    def forward(self, x):
        # 1*h*w
        avg_out = torch.mean(x, dim=1, keepdim=True)
        max_out, _ = torch.max(x, dim=1, keepdim=True)
        x = torch.cat([avg_out, max_out], dim=1)
        #2*h*w
        x = self.conv(x)
        #1*h*w
        return self.sigmoid(x)
    
class CBAM(nn.Module):
    def __init__(self, c1, c2, ratio=16, kernel_size=7):  # ch_in, ch_out, number, shortcut, groups, expansion
        super(CBAM, self).__init__()
        self.channel_attention = ChannelAttention(c1, ratio)
        self.spatial_attention = SpatialAttention(kernel_size)
    def forward(self, x):
        out = self.channel_attention(x) * x
        # c*h*w
        # c*h*w * 1*h*w
        out = self.spatial_attention(out) * out
        return out
 

 具体如下图所示:

💥💥步骤2:在yolo.py文件中加入类名 

首先在yolo.py文件中找到parse_model函数,然后将CBAM添加到这个注册表里。

💥💥步骤3:创建自定义yaml文件

models文件夹中复制yolov5s.yaml,粘贴并命名为yolov5s_CBAM.yaml

💥💥步骤4:修改yolov5s_CBAM.yaml文件 

本步骤是修改yolov5s_CBAM.yaml,将CBAM添加到我们想添加的位置。在这里,我将[-1,1,CBAM,[1024]]添加到SPPF的上一层,即下图中所示位置。

说明:♨️♨️♨️

注意力机制可以加在Backbone、Neck、Head等部分,常见的有两种:一种是在主干的SPPF前面添加一层;二是将Backbone中的C3全部替换。不同的位置效果可能不同,需要我们去反复测试。

这里需要注意一个问题,当在网络中添加新的层之后,那么该层网络后面的层的编号会发生变化。原本Detect指定的是[17,20,23]层,所以,我们在添加了CBAM模块之后,也要对这里进行修改,即原来的17层,变成18层,原来的20层,变成21层,原来的23层,变成24层;所以这里需要改为[18,21,24]。同样的,Concat的系数也要修改,这样才能保持原来的网络结构不会发生特别大的改变,我们刚才把CBAM加到了第9层,所以第9层之后的编号都需要加1,这里我们把后面两个Concat的系数分别由[-1,14][-1,10]改为[-1,15][-1,11]🌻

具体如下图所示。

💥💥步骤5:验证是否加入成功

yolo.py文件里,将配置改为我们刚才自定义的yolov5s_CBAM.yaml

 然后运行yolo.py,得到结果。

找到了CBAM模块说明我们添加成功了。🎉🎉🎉

💥💥步骤6:修改train.py中的'--cfg'默认参数

 在train.py文件中找到 parse_opt函数,然后将第二行'--cfg'的default改为 'models/yolov5s_CBAM.yaml',然后就可以开始进行训练了。🎈🎈🎈


🚀5.添加C3_CBAM注意力机制的方法(在C3模块中添加)

上面是单独添加注意力层,接下来的方法是在C3模块中加入注意力层。这个策略是将CBAM注意力机制添加到Bottleneck,替换Backbone中所有的C3模块。

💥💥步骤1:在common.py中添加CBAMBottleneck和C3_CBAM模块

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

# CBAM
class ChannelAttention(nn.Module):
    def __init__(self, in_planes, ratio=16):
        super(ChannelAttention, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.max_pool = nn.AdaptiveMaxPool2d(1)
        self.f1 = nn.Conv2d(in_planes, in_planes // ratio, 1, bias=False)
        self.relu = nn.ReLU()
        self.f2 = nn.Conv2d(in_planes // ratio, in_planes, 1, bias=False)
        self.sigmoid = nn.Sigmoid()
    def forward(self, x):
        avg_out = self.f2(self.relu(self.f1(self.avg_pool(x))))
        max_out = self.f2(self.relu(self.f1(self.max_pool(x))))
        out = self.sigmoid(avg_out + max_out)
        return out
    
class SpatialAttention(nn.Module):
    def __init__(self, kernel_size=7):
        super(SpatialAttention, self).__init__()
        assert kernel_size in (3, 7), 'kernel size must be 3 or 7'
        padding = 3 if kernel_size == 7 else 1
        # (特征图的大小-算子的size+2*padding)/步长+1
        self.conv = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
        self.sigmoid = nn.Sigmoid()
    def forward(self, x):
        # 1*h*w
        avg_out = torch.mean(x, dim=1, keepdim=True)
        max_out, _ = torch.max(x, dim=1, keepdim=True)
        x = torch.cat([avg_out, max_out], dim=1)
        #2*h*w
        x = self.conv(x)
        #1*h*w
        return self.sigmoid(x)
 
class CBAMBottleneck(nn.Module):
    # ch_in, ch_out, shortcut, groups, expansion, ratio, kernel_size
    def __init__(self, c1, c2, shortcut=True, g=1, e=0.5, ratio=16, kernel_size=7):
        super(CBAMBottleneck, self).__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
        # 加入CBAM模块
        self.channel_attention = ChannelAttention(c2, ratio)
        self.spatial_attention = SpatialAttention(kernel_size)
    
    def forward(self, x):
        # 考虑加入CBAM模块的位置:bottleneck模块刚开始时、bottleneck模块中shortcut之前,这里选择在shortcut之前
        x2 = self.cv2(self.cv1(x))  # x和x2的channel数相同
        # 在bottleneck模块中shortcut之前加入CBAM模块
        out = self.channel_attention(x2) * x2
        # print('outchannels:{}'.format(out.shape))
        out = self.spatial_attention(out) * out
        return x + out if self.add else out
 
 
class C3_CBAM(C3):
    # C3 module with CBAMBottleneck()
    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(*(CBAMBottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))
 

💥💥步骤2:在yolo.py文件里parse_model函数中加入类名

yolo.py文件 parse_model函数中,加入CBAMBottleneckC3_CBAM这两个模块。

💥💥步骤3:创建自定义yaml文件

按照上面的步骤创建yolov5s_C3_CBAM.yaml文件,替换4个C3模块。

💥💥步骤4:验证是否加入成功

yolo.py文件里配置刚才我们自定义的yolov5s_C3_CBAM.yaml,然后运行。

💥💥步骤5:修改train.py中的'--cfg'默认参数 

train.py文件中找到parse_opt函数,然后将第二行'--cfg'的default改为 'models/yolov5s_C3_CBAM.yaml',然后就可以开始进行训练了。🎈🎈🎈



http://www.niftyadmin.cn/n/4964076.html

相关文章

更换阿里云的yum源

更换阿里云的yum源 yum源存储的位置在: etc/yum.repos.d记住这个名字 CentOS-Base.repo对它进行备份,防止下载的yum源有问题 mv CentOS-Base.repo Back_up然后找到阿里云的yum源 如果没有wget 可以使用yum -y install wget 下载 wget http://mirrors…

电动汽车电机铁芯市场研究,未来汽车电机铁芯行业将迎来较大增长

电动汽车电机铁芯是电动汽车中用于支撑和固定电动机线圈的主要部件。它通常由高性能硅钢片制成,具有特殊的磁导性和磁导率,以优化电机的效率和性能。 电动汽车电机铁芯的主要功能是提供一个稳定的磁路,使电能能够有效地转化为机械能。当电流…

Ensp+Wireshark+VirtualBox+WinPcap

软件下载 [名称]:Ensp及辅助程序 [大小]:830.65MB [语言]:Chinese [安装环境]:Win7/Win8/Win10 [下载链接]: 链接:https://pan.baidu.com/s/1KbypgxAGQy07ijSAj3SvsQ 提取码:ly88 软件介…

sql server 如何设置主键

开始之前 限制和局限 一个表只能包含一个 PRIMARY KEY 约束。 在 PRIMARY KEY 约束中定义的所有列都必须定义为 NOT NULL。 如果没有指定为 Null 性,则加入 PRIMARY KEY 约束的所有列的为 Null 性都将设置为 NOT NULL。 创建主键会自动创建相应的唯一群集索引、…

mysql、oracle、sqlserver常见方法区分

整理了包括字符串与日期互转、字符串与数字互转、多行合并为一行、拼接字段等一些常用的函数,当然有些功能实现的方法不止一种,这里列举了部分常用的,后续会持续补充。 MySQLOracleSQL Server字符串转数字 CAST(123 as SIGNED) 或 CONVERT(12…

怎么检测UI卡顿?(线上及线下)

什么是UI卡顿? 在Android系统中,我们知道UI线程负责我们所有视图的布局,渲染工作,UI在更新期间,如果UI线程的执行时间超过16ms,则会产生丢帧的现象,而大量的丢帧就会造成卡顿,影响用…

Element Plus按需引入配置

由于使用中太多坑&#xff0c;本人暂时放弃使用 碰见的坑 例如 #图标要加上 i-ep<i-ep-House/># 在axios中使用加载和弹窗无效 开始使用配置正题 组件配置官网&#xff1a;快速开始 | Element Plus (gitee.io) 图标配置官网&#xff1a;Icon 图标 | Element Plus (g…

KUKA机器人零点标定的具体方法

KUKA机器人零点标定的具体方法 在进行机器人校正时,先将各轴置于一个定义好的机械位置,即所谓的机械零点。这个机械零点位置表明了同轴的驱动角度之间的对应关系,它用一个测量刻槽表示。 为了精确地确定机器人某根轴的机械零点位置,一般应先找到其预校正位置,然后去掉测量…