【6-1】YOLOv10添加【CBAM】【SE】【CA】【ECA】【BAM】注意力机制 【超30种先进模块随心选】【注意力机制篇】

本文主要介绍如何在YOLOv10中添加注意力机制,全系文章提供了超30种经典注意力机制模块供大家学习,使用时可据自己的实际情况进行选择🛩️🛩️



提示:喜欢本专栏的小伙伴,请多多点赞关注支持。本文仅供学习交流使用,创作不易,未经作者允许,不得搬运或转载!!!


前言🛩️🛩️

注意力机制(Attention Mechanism)是深度学习中的一种技术,旨在模拟人类注意力的特点,即在处理复杂信息时,能够聚焦于其中的关键部分,从而提高处理效率和效果。它最初在自然语言处理(NLP)领域中被提出,但现已广泛应用于各种深度学习任务,如计算机视觉、语音识别等。


一、注意力机制基础知识🛩️🛩️

1、注意力机制的核心思想🌱🌱

注意力机制的核心思想是根据输入的特征分配不同的权重,聚焦于重要的信息。具体来说,注意力机制通过计算一组权重(注意力权重),这些权重决定了每个输入特征的重要程度,然后根据这些权重对输入特征进行加权求和,从而得到一个聚合的表示。

2、注意力机制的主要类型🌱🌱

  • Soft Attention(软注意力):
    在软注意力中,所有的输入特征都会参与加权求和。权重通过一个可微分的函数(如softmax)进行计算,使得模型可以通过反向传播来学习这些权重。
  • Hard Attention(硬注意力):
    硬注意力则是选择一个或多个输入特征直接作为输出,而非对所有特征进行加权求和。由于这种选择是离散的,通常需要通过强化学习等技术进行训练,因为传统的反向传播算法无法直接应用。

二、注意力机制模块介绍🛩️🛩️

1、CBAM(Convolutional Block Attention Module)🌱🌱

CBAM于2018年在论文《CBAM: Convolutional Block Attention Module》中提出,该模块通过通道注意力和空间注意力两个子模块依次处理特征图,分别在通道和空间两个维度上进行特征增强。这种机制使得网络能够更加关注重要的特征,提高了模型的表现能力。通道注意力模块通过全局池化和共享的全连接层自适应地重新校准每个通道的特征,而空间注意力模块通过池化和卷积操作来增强特定的空间位置。最终的输出特征图结合了这两种注意力机制的优势,显著提升了特征表示的效果。
在这里插入图片描述
在这里插入图片描述

import torch
import torch.nn as nn


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
        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):
        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、SE(Squeeze-and-Excitation Networks)🌱🌱

SE于2019年在论文《Squeeze-and-Excitation Networks》中提出,SE模块能够自适应地重新调整每个通道的特征权重,从而提升卷积神经网络对重要特征的关注能力,提高整体的性能。这种机制增强了网络对有用信息的敏感度,抑制了不重要的信息噪声,使得模型在各种任务上的表现都有显著提升。其核心思想是通过三个主要步骤:Squeeze(压缩)、Excitation(激励)和Scale(缩放)来调整每个通道的重要性。

在这里插入图片描述

# SE
class SE(nn.Module):
    def __init__(self, c1, ratio=16):
        super(SE, self).__init__()
        self.avgpool = nn.AdaptiveAvgPool2d(1)
        self.l1 = nn.Linear(c1, c1 // ratio, bias=False)
        self.relu = nn.ReLU(inplace=True)
        self.l2 = nn.Linear(c1 // ratio, c1, bias=False)
        self.sig = nn.Sigmoid()

    def forward(self, x):
        b, c, _, _ = x.size()
        y = self.avgpool(x).view(b, c)
        y = self.l1(y)
        y = self.relu(y)
        y = self.l2(y)
        y = self.sig(y)
        y = y.view(b, c, 1, 1)
        return x * y.expand_as(x)




3、CA(Coordinate Attention)🌱🌱

Coordinate Attention(CA)是一种用于高效移动网络设计的注意力机制,在论文《Coordinate Attention for Efficient Mobile Network Design》中被提出。CA注意力机制通过引入坐标信息,有效地捕捉了长距离依赖关系,同时保持计算效率,非常适合应用在资源受限的设备上,如移动设备。
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


4、ECA-Net(Efficient Channel Attention Network)🌱🌱

ECA-Net(Efficient Channel Attention Network)是在论文《ECA-Net: Efficient Channel Attention for Deep Convolutional Neural Networks》中提出的一种高效通道注意力机制。ECA注意力机制旨在通过一种高效的方式增强卷积神经网络(CNN)的特征表示能力,主要通过调整通道间的关系而无需增加太多的计算成本。
ECA注意力机制的核心思想是利用一个简单但有效的方式来建模通道间的交互关系,而不是通过复杂的全连接层。这种方法能够显著减少参数量和计算开销,同时提升模型性能。

在这里插入图片描述

import torch
import torch.nn as nn
class ECA(nn.Module):
    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):
        y = self.avg_pool(x)
        y = self.conv(y.squeeze(-1).transpose(-1, -2)).transpose(-1, -2).unsqueeze(-1)
        y = self.sigmoid(y)
        return x * y.expand_as(x)

5、BAM(Bottleneck Attention Module)🌱🌱

论文地址:https://arxiv.org/pdf/1807.06514

BAM于2018年提出,是一种轻量级的注意力机制,用于提高卷积神经网络的性能。它通过在网络中加入注意力模块来增强网络对重要特征的关注,忽略不重要的信息,从而提升整体表现。

BAM的优点

  • 轻量级:BAM模块在计算上非常高效,不会显著增加模型的计算复杂度和参数量。
  • 兼容性好:BAM可以很容易地嵌入到现有的各种卷积神经网络架构中,提升它们的性能。
  • 显著的性能提升:通过强调重要的特征和抑制不相关的特征,BAM能够显著提升模型的分类、检测等任务的表现。
    在这里插入图片描述
import numpy as np
import torch
from torch import nn
from torch.nn import init


class Flatten(nn.Module):
    def forward(self, x):
        return x.view(x.shape[0], -1)


class ChannelAttention(nn.Module):
    def __init__(self, channel, reduction=16, num_layers=3):
        super().__init__()
        self.avgpool = nn.AdaptiveAvgPool2d(1)
        gate_channels = [channel]
        gate_channels += [channel // reduction] * num_layers
        gate_channels += [channel]

        self.ca = nn.Sequential()
        self.ca.add_module('flatten', Flatten())
        for i in range(len(gate_channels) - 2):
            self.ca.add_module('fc%d' % i, nn.Linear(gate_channels[i], gate_channels[i + 1]))
            self.ca.add_module('bn%d' % i, nn.BatchNorm1d(gate_channels[i + 1]))
            self.ca.add_module('relu%d' % i, nn.ReLU())
        self.ca.add_module('last_fc', nn.Linear(gate_channels[-2], gate_channels[-1]))

    def forward(self, x):
        res = self.avgpool(x)
        res = self.ca(res)
        res = res.unsqueeze(-1).unsqueeze(-1).expand_as(x)
        return res


class SpatialAttention(nn.Module):
    def __init__(self, channel, reduction=16, num_layers=3, dia_val=2):
        super().__init__()
        self.sa = nn.Sequential()
        self.sa.add_module('conv_reduce1',
                           nn.Conv2d(kernel_size=1, in_channels=channel, out_channels=channel // reduction))
        self.sa.add_module('bn_reduce1', nn.BatchNorm2d(channel // reduction))
        self.sa.add_module('relu_reduce1', nn.ReLU())
        for i in range(num_layers):
            self.sa.add_module('conv_%d' % i, nn.Conv2d(kernel_size=3, in_channels=channel // reduction,
                                                        out_channels=channel // reduction, padding=1, dilation=dia_val))
            self.sa.add_module('bn_%d' % i, nn.BatchNorm2d(channel // reduction))
            self.sa.add_module('relu_%d' % i, nn.ReLU())
        self.sa.add_module('last_conv', nn.Conv2d(channel // reduction, 1, kernel_size=1))

    def forward(self, x):
        res = self.sa(x)
        res = res.expand_as(x)
        return res


class BAMBlock(nn.Module):
    def __init__(self, channel=512, reduction=16, dia_val=2):
        super().__init__()
        self.ca = ChannelAttention(channel=channel, reduction=reduction)
        self.sa = SpatialAttention(channel=channel, reduction=reduction, dia_val=dia_val)
        self.sigmoid = nn.Sigmoid()

    def init_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                init.kaiming_normal_(m.weight, mode='fan_out')
                if m.bias is not None:
                    init.constant_(m.bias, 0)
            elif isinstance(m, nn.BatchNorm2d):
                init.constant_(m.weight, 1)
                init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                init.normal_(m.weight, std=0.001)
                if m.bias is not None:
                    init.constant_(m.bias, 0)

    def forward(self, x):
        b, c, _, _ = x.size()
        sa_out = self.sa(x)
        ca_out = self.ca(x)
        weight = self.sigmoid(sa_out + ca_out)
        out = (1 + weight) * x
        return out



三、添加步骤🛩️🛩️

以SE注意力机制为例,其余添加方式类似:

  1. 打开…/ultralytics/nn/modules/block.py文件,在文开头置添加各模块类名称,并在文末空白位置添加各模块代码。

  2. 打开…/nn/modules/init.py文件,在相应位置添加各模块类名称。

  3. 打开…/ultralytics/nn/tasks.py文件,中相应位置添加各模块类名称。

from ultralytics.nn.modules import (
    AIFI,
 ...
    SE
    )
...
def parse_model(d, ch, verbose=True):  # model_dict, input_channels(3)
    """Parse a YOLO model.yaml dictionary into a PyTorch model."""
    import ast
...
        n = n_ = max(round(n * depth), 1) if n > 1 else n  # depth gain
        if m in {
            Classify,
            ...
            SE
        }:

  1. 在…/ultralytics/cfg/models/v10路径中新建yolov10_se.yaml文件,文件做如下更改:
    (注意修改红色边框理的参数,否则网络的架构将会发生改变)
    在这里插入图片描述
    yolov10_se.yaml文件内容示例:
#仅供学习交流
# Parameters
nc: 8 # 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] 

# 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, SCDown, [512, 3, 2]] # 5-P4/16
  - [-1, 6, C2f, [512, True]]
  - [-1, 1, SCDown, [1024, 3, 2]] # 7-P5/32
  - [-1, 3, C2f, [1024, True]]
  - [-1, 1, SE, [1024]] # 9
  - [-1, 1, SPPF, [1024, 5]] # 10
  - [-1, 1, PSA, [1024]] # 11

# YOLOv8.0n head
head:
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 6], 1, Concat, [1]] # cat backbone P4
  - [-1, 3, C2f, [512]] # 14

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 4], 1, Concat, [1]] # cat backbone P3
  - [-1, 3, C2f, [256]] # 17 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 14], 1, Concat, [1]] # cat head P4
  - [-1, 3, C2f, [512]] # 20 (P4/16-medium)

  - [-1, 1, SCDown, [512, 3, 2]]
  - [[-1, 11], 1, Concat, [1]] # cat head P5
  - [-1, 3, C2fCIB, [1024, True, True]] # 23 (P5/32-large)

  - [[17, 18, 23], 1, v10Detect, [nc]] # Detect(P3, P4, P5)
  1. 使用python命令或CIL命令即可训练添加注意力机制的模型,可参照本系列第四篇文章,使用时注意修改相关文件路径。

  2. 显示以下打印内容时,说明注意力机制已成功添加到YOLOv10网络中了。
    在这里插入图片描述

注:注意力机制的添加位置和方式并不固定,可根据自己的需求灵活调整。由于本文篇幅过长,其他添加方式后续会持续更新,感谢大家的关注❤❤


本文至此结束,文章持续更新中,敬请期待!!!
请添加图片描述
喜欢的本文的话,请不吝点赞+收藏,感谢各位伙伴的支持🍵🍵
下一篇:【6-2】YOLOv10添加【BAM】【CoTAttention】等注意力机制 【超30种先进模块随心选】【中篇】🥤🥤


  • 14
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
手把手带你在Yolov5 (v6.1)的C3模块添加注意力机制。 首先,为了在C3模块中加入注意力机制,我们需要在yolov5/models模块中的common.py文件中进行修改。 1. 打开common.py文件,找到C3模块的定义代码。 C3模块的定义通常如下所示: ```python class C3(nn.Module): # ... def __init__(self, c1, c2, c3, c4, c5, shortcut, g): # ... def forward(self, x): # ... ``` 2. 在C3类的初始化函数中添加注意力机制所需的参数。注意力机制通常通过使用Squeeze-and-Excitation(SE模块来实现,该模块包括一个全局平均池化层和两个全连接层。 ```python class C3(nn.Module): # ... def __init__(self, c1, c2, c3, c4, c5, shortcut, g): super(C3, self).__init__() # 添加注意力机制参数,g代表SE模块中的通道缩放比例 self.se = nn.Sequential( nn.AdaptiveAvgPool2d(1), nn.Conv2d(c3, c3 // g, kernel_size=1, stride=1, padding=0), nn.ReLU(inplace=True), nn.Conv2d(c3 // g, c3, kernel_size=1, stride=1, padding=0), nn.Sigmoid() ) # ... ``` 3. 在C3类的前向传播函数中应用注意力机制。首先,计算注意力权重,并将其应用于C3模块的输入特征图上。 ```python class C3(nn.Module): # ... def forward(self, x): # ... # 计算注意力权重 attentions = self.se(x) # 注意力加权 x = x * attentions # ... return x ``` 4. 保存文件并退出编辑器。 现在,C3模块中已经加入了注意力机制。这将使得模型能够更加关注重要的特征图区域,提升目标检测的性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值