一、简介

Coordinate Attention(坐标注意力)是CVPR 2021提出的一种面向移动网络的高效注意力机制。它通过将通道注意力(Channel Attention)巧妙地分解为沿水平与垂直两个空间方向的1D特征编码过程,有效解决了传统通道注意力(如SENet)因使用2D全局池化而丢失位置信息的问题。具体而言,给定输入特征图,Coordinate Attention会分别使用尺寸为 (H,1) 和 (1,W) 的池化核沿垂直与水平方向对每个通道进行编码,得到一对方向感知的特征图。这些特征图经过卷积变换和非线性激活后,被编码成一对方向感知和位置敏感的注意力图。这些注意力图能互补的应用到输入特征图上,使模型在捕获通道间依赖关系和长程空间交互的同时,保留精确的位置信息,从而帮助模型(如MobileNetV2、MobileNeXt和EfficientNet)更准确地关注和定位目标,例如在图像分类、目标检测及语义分割等任务中都观察到了性能提升,且几乎不增加计算开销。

二、Coordinate Attention的实现代码
 

代码源地址:https://github.com/Andrew-Qibin/CoordAttention/blob/main/models/coord_att.py

import torch
import torch.nn as nn
import math
import torch.nn.functional as F


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()
        x_h = self.pool_h(x)
        x_w = self.pool_w(x).permute(0, 1, 3, 2)

        y = torch.cat([x_h, x_w], dim=2)
        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

三、在yolov10中改进


以下改进均在yolov10s.yaml文件中修改

3.1 改进:
改进方法:直接嵌入到骨干网络(backbone)中,将模块放入到C2fCIB模块和SPPF模块之间

四、修改操作:


4.1 模块导入


在yolov10的ultralytics/nn目录中新建一个文件夹AddAttention(名字自定义),在AddAttention中建立CoordinateAttention.py,并将CoordinateAttention的实现的代码放入其中,然后再在AddAttention中再新建_init_.py,并在该文件中写入:

from .CoordinateAttention import *

用于将模块导出,如图:

4.2 修改


对模块进行参数设置,在ultralytics/nn/tasks.py的parse_model函数中添加如下代码在添加代码前,在tasks.py文件中对AddAttention里的模块进行导入,即在task.py文件中写入

from .AddAttention import *


):

  1. ch[f]:代表当前CoordAtt层的输入通道数,它从前一层(索引为f)的输出通道数ch[f]中获取,确保了网络中各层间通道数的连贯性

  2. c2 = args[0]:从配置参数中读取预设的输出通道数,这是模型设计时指定的目标输出维度

  3. 通道数优化:通过make_divisible(min(c2, max_channels) * width, 8)对输出通道数进行三重调整:

    1. min(c2, max_channels):限制最大通道数,防止模型过大

    2. * width:应用宽度乘子,支持不同尺寸的模型变体

    3. make_divisible(..., 8):确保通道数能被8整除,优化硬件计算效率

  4. 参数重构:最终构建的参数列表[c1, c2, *args[1:]]包含了处理后的输入通道数、优化后的输出通道数以及模块的其他配置参数

        elif m in {CoordAtt}:
            c1 = ch[f]
            c2 = args[0]
            c2 = make_divisible(min(c2, max_channels) * width, 8)
            args = [c1, c2, *args[1:]]



位置如图所示:

4.1.3 yaml文件的修改
在ultralytics/cfg/models/v10目录下,将该目录下新建yolov10s_CA.yaml(名字自定义,这里CA为简写),并将yolov10s.yaml文件中的内容复制过来,并对其进行修改,在SPPF模块和C2FCIB模块之间添加CoordinateAttention模块,输出通道设为1024,如图:

五、运行结果


打印网络模型,看到自定义的模块名称出现在网络中即可代表修改成功

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐