YOLO11改进|注意力机制篇|引入矩形自校准模块RCM

目录

一、【RCM】注意力机制

1.1【RCM】注意力介绍

下图是【RCM】的结构图,让我们简单分析一下运行过程和优势

  • RCA 模块(Residual Cross-Attention):
    目的: RCA 模块实现了一种空间注意力机制,能够捕获特征图中高度和宽度两个维度的信息交互。这可以增强网络对空间区域的关注,提升它对局部上下文的理解。
    处理步骤:
  • 空间卷积: 模块首先使用深度可分离卷积(dwconv_hw)在输入张量的高度和宽度上进行处理,这有助于捕捉局部的空间信息。
  • 自适应池化: 模块分别对高度(pool_h)和宽度(pool_w)方向进行全局平均池化,以获得每个通道的高度和宽度的信息聚合结果。高度池化会生成形状为 [N, C, H, 1] 的张量,而宽度池化会生成形状为 [N, C, 1, W] 的张量。
  • Excite模块: 将高度和宽度的信息相加(x_gather = x_h + x_w),然后通过一系列卷积、归一化和激活操作(ReLU + Sigmoid)生成注意力权重。这个注意力机制学习到了高度和宽度的相关性,并将其用于调整输入特征。
  • 残差连接: 最后,将经过注意力权重调整的特征与原始卷积结果进行逐元素乘法相结合,输出最终的增强特征。这种操作可以强化重要的空间区域。
    优势:RCA 模块引入了全局高度和宽度的池化操作,使得模型能够捕捉长距离依赖关系。使用深度可分离卷积减少了计算成本,同时保持了良好的特征提取能力。注意力机制可以动态地调整特征图中不同空间位置的权重,从而提高模型对重要局部信息的捕捉能力。
  • RCM 模块(Residual Cross Mixer):
    目的: RCM 模块整合了多种模块化操作(包括RCA 和 MLP)用于特征的混合与增强,同时通过残差连接确保信息不会丢失。

处理步骤:

  • Token Mixer (RCA): RCM 模块首先调用 RCA 模块,使用其自带的注意力机制对输入特征图进行初步处理。这个步骤能够捕捉特征图的空间关系,并输出加权后的特征图。
  • 归一化: 对经过RCA处理后的输出应用批归一化层,稳定模型的训练并改善收敛性。
  • MLP层: 调用 ConvMlp 模块,将输入的特征图通过两个1x1卷积进行通道间的线性变换,进一步提取特征。这相当于一个在卷积上下文中使用的多层感知机。
  • Layer Scale (Gamma): RCM 模块使用一个可学习的参数 gamma,其初始值非常小(1e-6),在更新过程中逐步优化。这种机制允许模型在残差连接上进行适度的权重调节,使得模型能够更加灵活地融合新旧信息。
  • 残差连接: 将经过 DropPath 操作后的输出与初始输入进行相加,实现残差连接。这确保了信息流不会因过多的非线性变换而丢失,增强了模型的训练效果。
    优势 :RCM 模块通过结合 RCA 和 MLP 操作,既能捕捉全局的空间关系,又能实现通道间的特征交互。Layer Scale 使得模型可以平衡新旧特征之间的融合,增加了模型的鲁棒性。DropPath 操作引入了随机深度的正则化,帮助模型在训练时进行更好的泛化。

1.2【RCM】核心代码

python 复制代码
from functools import partial

import torch
import torch.nn as nn

from timm.models.layers import DropPath
from timm.models.layers.helpers import to_2tuple


class ConvMlp(nn.Module):
    """ MLP using 1x1 convs that keeps spatial dims
    copied from timm: https://github.com/huggingface/pytorch-image-models/blob/v0.6.11/timm/models/layers/mlp.py
    """

    def __init__(
            self, in_features, hidden_features=None, out_features=None, act_layer=nn.ReLU,
            norm_layer=None, bias=True, drop=0.):
        super().__init__()
        out_features = out_features or in_features
        hidden_features = hidden_features or in_features
        bias = to_2tuple(bias)

        self.fc1 = nn.Conv2d(in_features, hidden_features, kernel_size=1, bias=bias[0])
        self.norm = norm_layer(hidden_features) if norm_layer else nn.Identity()
        self.act = act_layer()
        self.drop = nn.Dropout(drop)
        self.fc2 = nn.Conv2d(hidden_features, out_features, kernel_size=1, bias=bias[1])

    def forward(self, x):
        x = self.fc1(x)
        x = self.norm(x)
        x = self.act(x)
        x = self.drop(x)
        x = self.fc2(x)
        return x


class RCA(nn.Module):
    def __init__(self, inp, kernel_size=1, ratio=1, band_kernel_size=11, dw_size=(1, 1), padding=(0, 0), stride=1,
                 square_kernel_size=2, relu=True):
        super(RCA, self).__init__()
        self.dwconv_hw = nn.Conv2d(inp, inp, square_kernel_size, padding=square_kernel_size // 2, groups=inp)
        self.pool_h = nn.AdaptiveAvgPool2d((None, 1))
        self.pool_w = nn.AdaptiveAvgPool2d((1, None))

        gc = inp // ratio
        self.excite = nn.Sequential(
            nn.Conv2d(inp, gc, kernel_size=(1, band_kernel_size), padding=(0, band_kernel_size // 2), groups=gc),
            nn.BatchNorm2d(gc),
            nn.ReLU(inplace=True),
            nn.Conv2d(gc, inp, kernel_size=(band_kernel_size, 1), padding=(band_kernel_size // 2, 0), groups=gc),
            nn.Sigmoid()
        )

    def sge(self, x):
        # [N, D, C, 1]
        x_h = self.pool_h(x)
        x_w = self.pool_w(x)
        x_gather = x_h + x_w  # .repeat(1,1,1,x_w.shape[-1])
        ge = self.excite(x_gather)  # [N, 1, C, 1]

        return ge

    def forward(self, x):
        loc = self.dwconv_hw(x)
        att = self.sge(x)
        out = att * loc
        return out


class RCM(nn.Module):
    """ MetaNeXtBlock Block
    Args:
        dim (int): Number of input channels.
        drop_path (float): Stochastic depth rate. Default: 0.0
        ls_init_value (float): Init value for Layer Scale. Default: 1e-6.
    """

    def __init__(
            self,
            dim,
            token_mixer=RCA,
            norm_layer=nn.BatchNorm2d,
            mlp_layer=ConvMlp,
            mlp_ratio=2,
            act_layer=nn.GELU,
            ls_init_value=1e-6,
            drop_path=0.,
            dw_size=11,
            square_kernel_size=3,
            ratio=1,
    ):
        super().__init__()
        self.token_mixer = token_mixer(dim, band_kernel_size=dw_size, square_kernel_size=square_kernel_size,
                                       ratio=ratio)
        self.norm = norm_layer(dim)
        self.mlp = mlp_layer(dim, int(mlp_ratio * dim), act_layer=act_layer)
        self.gamma = nn.Parameter(ls_init_value * torch.ones(dim)) if ls_init_value else None
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()

    def forward(self, x):
        shortcut = x
        x = self.token_mixer(x)
        x = self.norm(x)
        x = self.mlp(x)
        if self.gamma is not None:
            x = x.mul(self.gamma.reshape(1, -1, 1, 1))
        x = self.drop_path(x) + shortcut
        return x


if __name__ == "__main__":
    # 创建随机输入张量 (batch_size, channels, height, width)
    x = torch.randn(8, 64, 32, 32)  # 假设输入是8个样本,64个通道,32x32大小

    # 实例化 ConvMlp 模块
    conv_mlp = ConvMlp(in_features=64, hidden_features=128, out_features=64, act_layer=nn.ReLU)

    # 实例化 RCA 模块
    rca = RCA(inp=64, kernel_size=1, ratio=1, band_kernel_size=11, square_kernel_size=3)

    # 实例化 RCM 模块
    rcm = RCM(dim=64, dw_size=11, square_kernel_size=3, ratio=1, drop_path=0.1)

    # 测试 ConvMlp 模块
    print("Testing ConvMlp module:")
    output_mlp = conv_mlp(x)
    print(f"Output shape of ConvMlp: {output_mlp.shape}")

    # 测试 RCA 模块
    print("\nTesting RCA module:")
    output_rca = rca(x)
    print(f"Output shape of RCA: {output_rca.shape}")

    # 测试 RCM 模块
    print("\nTesting RCM module:")
    output_rcm = rcm(x)
    print(f"Output shape of RCM: {output_rcm.shape}")

二、添加【RCM】注意力机制

2.1STEP1

首先找到ultralytics/nn文件路径下新建一个Add-module的python文件包【这里注意一定是python文件包,新建后会自动生成_init_.py】,如果已经跟着我的教程建立过一次了可以省略此步骤 ,随后新建一个RCM.py文件并将上文中提到的注意力机制的代码全部粘贴到此文件中,如下图所示

2.2STEP2

在STEP1中新建的_init_.py文件中导入增加改进模块的代码包如下图所示

2.3STEP3

找到ultralytics/nn文件夹中的task.py文件,在其中按照下图添加

2.4STEP4

定位到ultralytics/nn文件夹中的task.py文件中的def parse_model(d, ch, verbose=True): # model_dict, input_channels(3)函数添加如图代码,【如果不好定位可以直接ctrl+f搜索定位】

三、yaml文件与运行

3.1yaml文件

以下是添加【RCM】注意力机制在小目标检测层后的yaml文件,大家可以注释自行调节,效果以自己的数据集结果为准

python 复制代码
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLO11 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolo11n.yaml' will call yolo11.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.50, 0.25, 1024] # summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
  s: [0.50, 0.50, 1024] # summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
  m: [0.50, 1.00, 512] # summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
  l: [1.00, 1.00, 512] # summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs
  x: [1.00, 1.50, 512] # summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs

# YOLO11n 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, 2, C3k2, [256, False, 0.25]]
  - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
  - [-1, 2, C3k2, [512, False, 0.25]]
  - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
  - [-1, 2, C3k2, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
  - [-1, 2, C3k2, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]] # 9
  - [-1, 2, C2PSA, [1024]] # 10

# YOLO11n head
head:
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 6], 1, Concat, [1]] # cat backbone P4
  - [-1, 2, C3k2, [512, False]] # 13

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 4], 1, Concat, [1]] # cat backbone P3
  - [-1, 2, C3k2, [256, False]] # 16 (P3/8-small)
  - [-1, 1, RCM,  []]

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 13], 1, Concat, [1]] # cat head P4
  - [-1, 2, C3k2, [512, False]] # 19 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 10], 1, Concat, [1]] # cat head P5
  - [-1, 2, C3k2, [1024, True]] # 22 (P5/32-large)

  - [[17, 20, 23], 1, Detect, [nc]] # Detect(P3, P4, P5)

以上添加位置仅供参考,具体添加位置以及模块效果以自己的数据集结果为准

3.2运行成功截图

OK 以上就是添加【RCM】注意力机制的全部过程了,后续将持续更新尽情期待

相关推荐
智驱力人工智能9 小时前
小区高空抛物AI实时预警方案 筑牢社区头顶安全的实践 高空抛物检测 高空抛物监控安装教程 高空抛物误报率优化方案 高空抛物监控案例分享
人工智能·深度学习·opencv·算法·安全·yolo·边缘计算
工程师老罗9 小时前
YOLOv1 核心结构解析
yolo
Lun3866buzha9 小时前
YOLOv10-BiFPN融合:危险物体检测与识别的革新方案,从模型架构到实战部署全解析
yolo
Katecat9966310 小时前
YOLOv8-MambaOut在电子元器件缺陷检测中的应用与实践_1
yolo
工程师老罗11 小时前
YOLOv1 核心知识点笔记
笔记·yolo
工程师老罗16 小时前
基于Pytorch的YOLOv1 的网络结构代码
人工智能·pytorch·yolo
学习3人组19 小时前
YOLO模型集成到Label Studio的MODEL服务
yolo
孤狼warrior19 小时前
YOLO目标检测 一千字解析yolo最初的摸样 模型下载,数据集构建及模型训练代码
人工智能·python·深度学习·算法·yolo·目标检测·目标跟踪
水中加点糖21 小时前
小白都能看懂的——车牌检测与识别(最新版YOLO26快速入门)
人工智能·yolo·目标检测·计算机视觉·ai·车牌识别·lprnet
前端摸鱼匠1 天前
YOLOv8 环境配置全攻略:Python、PyTorch 与 CUDA 的和谐共生
人工智能·pytorch·python·yolo·目标检测