YOLO算法改进指南:8.添加SimAM注意力机制 |无参数注意力模块

本文介绍了中山大学基于神经科学理论提出的SimAM注意力机制,这是一种无参数的3D注意力模块,适用于YOLOv5的改进。通过在ImageNet和COCO任务上的验证,展示了其灵活性和有效性。SimAM无需额外参数,通过能量函数计算注意力权重,简化了注意力模块的设计。文章详细阐述了SimAM的理论基础和YOLOv5的整合步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

image.png

本文是中山大学在注意力机制方面的尝试,从神经科学理论出发,构建了一种能量函数挖掘神经元重要性,并对此推导出了解析解以加速计算。通过ImageNet分类、COCO检测与分割等任务验证了所提SimAM的灵活性与有效性。值得一提的是,所提SimAM是一种无参数注意力模块

一、SimAM详解

1. 概述

本文提出一种概念简单且非常有效的注意力模块。不同于现有的通道/空域注意力模块,该模块无需额外参数为特征图推导出3D注意力权值。具体来说,本文基于著名的神经科学理论提出优化能量函数以挖掘神经元的重要性。本文进一步针对该能量函数推导出一种快速解析解并表明:该解析解仅需不超过10行代码即可实现。该模块的另一个优势在于:大部分操作均基于所定义的能量函数选择,避免了过多的结构调整。最后,本文在不同的任务上对所提注意力模块的有效性、灵活性进行验证。

本文主要贡献包含以下几点:

  • 受启发于人脑注意力机制,本文提出一种3D注意力模块并设计了一种能量函数用于计算注意力权值;
  • 本文推导出了能量函数的解析解加速了注意力权值的计算并得到了一种轻量型注意力模块;
  • 将所提注意力嵌入到现有ConvNet中在不同任务上进行了灵活性与有效性的验证。

2. 理论

在正式介绍本文所提注意力模块之前,我们先对现有代表性注意力模块(比如SE、CBAM、GC)进行简要总结;然后,我们再引出本文所提完全不同架构的注意力模块。

SimAM注意力机制原理图:

image.png

上图a与b列出了现有两种类型的注意力模块:

  • 通道注意力:1D注意力,它对不同通道区别对待,对所有位置同等对待;
  • 空域注意力:2D注意力,它对不同位置区别对待,对所有通道同等对待。

以下图为例,SE缺失了关于"grey_whale"的某些重要成分。我们认为3D注意力比1D和2D更佳,进而提出了上图c的3D注意力模块。

现有注意力模块的另一个重要影响因素:权值生成方法。现有注意力往往采用额外的子网络生成注意力权值,比如SE的GAP+FC+ReLU+FC+Sigmoid。更多注意力模块的操作、参数量可参考下表。总而言之,现有注意力的结构设计需要大量的工程性实验。我们认为:注意力机制的实现应当通过神经科学中的某些统一原则引导设计

📌 本文亮点总结:

  1. 现有注意力模块的另一个重要影响因素:权值生成方法。现有注意力往往采用额外的子网络生成注意力权值,比如SE的GAP+FC+ReLU+FC+Sigmoid。
  2. 在神经科学中,信息丰富的神经元通常表现出与周围神经元不同的放电模式。而且,激活神经元通常会抑制周围神经元,即空域抑制。换句话说,具有空域抑制效应的神经元应当赋予更高的重要性。最简单的寻找重要神经元的方法:度量神经元之间的线性可分性。

二、YOLOv5改进

1. 增加SimAM.yaml文件

# 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, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 6, C3, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 9, C3, [512]],
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 3, C3, [1024]],
   [-1, 1, SPPF, [1024, 5]],  # 9
  ]

# YOLOAir 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)
   [-1, 1, SimAM, [1024]], #修改

   [[17, 20, 24], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

2. common.py配置

./models/common.py文件中增加以下内容

import torch
import torch.nn as nn

class SimAM(torch.nn.Module):
    def __init__(self, channels=None, e_lambda=1e-4):
        super(SimAM, self).__init__()

        self.activaton = nn.Sigmoid()  # Sigmoid 激活函数的实例
        self.e_lambda = e_lambda  # 正则化项的参数 lambda

    def __repr__(self):
        s = self.__class__.__name__ + '('
        s += ('lambda=%f)' % self.e_lambda)  # 返回表示模型的字符串,包括 lambda 参数的值
        return s

    @staticmethod
    def get_module_name():
        return "simam"  # 返回模块的名称,为 "simam"

    def forward(self, x):
        # 前向传播函数,对输入 x 进行处理并返回结果

        b, c, h, w = x.size()    # 获取输入张量的形状信息
        n          = w * h - 1   # 计算总像素数减1

        x_minus_mu_square = (x - x.mean(dim=[2, 3], keepdim=True)).pow(2)  # 计算每个像素与均值的差的平方
        y = x_minus_mu_square / (4 * (x_minus_mu_square.sum(dim=[2, 3], keepdim=True) / n + self.e_lambda)) + 0.5
        # 计算激活函数的输入 y,使用 SimAM 公式:x_minus_mu_square / (4 * (均值方差 + 正则化项)) + 0.5

        return x * self.activaton(y)  # 返回经过激活函数后的结果与输入张量 x 的乘积

3. yolo.py配置

找到models/yolo.py文件中parse_model()函数的for i, (f, n, m, args) in enumerate(d['backbone'] + d['head'])(258行上下)并其循环内添加如下代码。

elif m is SimAM:
    c1, c2 = ch[f], args[0]
    if c2 != no:
        c2 = make_divisible(c2 * gw, 8)

4. 训练模型

python train.py --cfg yolov5_SimAM.yaml
### SimAM注意力机制概述 SimAM是一种轻量级的注意力机制,在深度学习领域被广泛应用于图像分类、目标检测以及语义分割等任务中。它通过简单而高效的计算方式,增强了模型对重要特征的关注能力,同时减少了额外参数的数量和计算开销。 SimAM的核心思想在于利用局部区域内的相似性来衡量像素的重要性。具体而言,对于输入特征图中的每一个位置 \(i\),其对应的响应值可以通过比较该位置与其他所有位置之间的差异得到。这种设计使得SimAM能够捕捉到全局上下文信息并增强显著特征的表现力[^1]。 以下是SimAM的具体实现方法: ### 实现细节 #### 数学表达 给定一个大小为\(H \times W \times C\) 的特征图 \(X\) ,SimAM定义如下公式用于计算每个通道上的权重矩阵: \[ E_{ij} = 1 - \exp(-\lVert X_i - M_j\rVert_2^2), \] 其中, - \(M_j=\frac{1}{N}\sum_k^{N}(X_k)\),表示第j个窗口内所有元素均值; - \(E_{ij}\in[0,1]\), 表达的是当前点相对于邻域平均值偏离程度;当某一点越接近于周围邻居,则它的能量值会更趋近于零,反之则越大。 最终输出可以写成: \[ Y=X\times (1-E). \] #### PyTorch代码示例 下面提供了一个基于PyTorch框架下的SimAM模块实现版本: ```python import torch import torch.nn as nn class SimAM(nn.Module): def __init__(self, lambda_param=0.01): super(SimAM, self).__init__() self.lambda_param = lambda_param def forward(self, x): b, c, h, w = x.size() n = w * h - 1 # 计算空间维度上每一点与其余点的距离平方和 distance = (x.view(b,c,-1).unsqueeze(3) - x.view(b,c,-1).unsqueeze(2)).pow(2) # 排除自身距离项 mask = (torch.ones((h*w,h*w)) - torch.eye(h*w)).cuda().bool() distance = distance[:,:,:,mask].view(b,c,n) exp_distance = (-distance / (n ** .5 + 1e-8)).exp() norm_exp_dis = exp_distance.sum(dim=-1).clamp(min=self.lambda_param)**-.5 output = x * norm_exp_dis.unsqueeze(-1).unsqueeze(-1) return output ``` 此段代码实现了上述提到的能量函数及其后续操作过程,并将其封装成了可调用形式以便集成至其他神经网络结构当中去使用。 ### 性能优势 相比传统复杂的SENet或者CBAM等多分支架构的设计方案来说,SimAM仅需极少新增运算成本即可达到相近甚至超越的效果表现。因此非常适合资源受限环境下的移动端部署场景应用需求.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

K同学啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值