YOLO11改进|注意力机制篇|引入MLCA轻量级注意力机制

news/2024/10/8 17:11:48/

在这里插入图片描述

目录

    • 一、MLCA注意力机制
      • 1.1MLCA注意力介绍
      • 1.2MLCA核心代码
    • 五、添加MLCA注意力机制
      • 5.1STEP1
      • 5.2STEP2
      • 5.3STEP3
      • 5.4STEP4
    • 六、yaml文件与运行
      • 6.1yaml文件
      • 6.2运行成功截图

一、MLCA注意力机制

1.1MLCA注意力介绍

在这里插入图片描述

MLCA(Multi-Level Channel Attention,多级通道注意力)是一种用于提升卷积神经网络(CNN)性能的注意力机制,主要通过在多个层次上捕捉不同通道间的依赖关系,来增强网络对重要特征的关注。MLCA的工作流程:

  • 特征提取: 首先,输入图像经过卷积网络的多层卷积提取出多层次的特征图,这些特征图代表了从不同尺度和不同深度捕捉到的特征信息。
  • 通道权重计算: 在每个层次的特征图上,MLCA 分别计算出每个通道的重要性权重,使用类似 SE 模块的全局池化操作得到全局特征表示,然后通过一系列非线性操作(如全连接、激活函数)生成通道权重。
  • 多级加权: 通过通道权重对各层次的特征图进行加权操作,增强重要特征通道的响应,抑制无关或冗余的特征。
  • 融合与输出: 对不同层次的特征进行融合,形成最终的特征表达,然后将其传递给后续的网络模块(如分类器或检测头)。
    工作流程图如下所示:
  1. 输入
    输入数据的维度为 (𝐶,𝑊,𝐻),其中:𝐶 表示通道数W 表示宽度H 表示高度

  2. 局部区域池化(LAP)和区域池化(AP)
    在这一步,输入数据被分成不同的局部区域块,这些块的大小为 (ks,ks),其中ks=5(kernel size)。通过这一步操作,宽度和高度被缩小为 W/ks 和 H/ks,形成局部特征表示。这一步类似于局部区域的平均池化,帮助提取局部的空间特征。

  3. 全局平均池化(GAP)
    接着进行全局平均池化(GAP),将每个局部区域的特征聚合到通道维度上,形成全局通道特征。这会将每个通道的信息进一步简化,汇总成单个全局特征。

  4. 1D卷积(Conv1d)
    然后通过一个1D卷积操作,对这些全局特征进行进一步处理。1D卷积的目的是在通道维度上提取不同通道之间的相关性,以增强通道注意力机制。这里,卷积核大小 𝑘,k 作用于通道维度,以捕捉更多通道间的依赖关系。

  5. 特征重塑(Reshape)
    卷积后的输出特征经过重塑(Reshape)操作,恢复到原始的特征形状,使其可以与原始特征对齐。

  6. 未池化操作(UNAP)
    为了将池化后的特征与原始输入对齐,这里使用了未池化操作(UNAP),将特征图恢复到原始的分辨率。通过 UNAP 操作,池化缩减的特征图的维度被扩展回去,以保持输入和输出特征在相同维度上的一致性。

  7. 通道加权
    经过上述过程后,MLCA模块生成的局部通道注意力权重会与输入特征进行加权叠加,结合了通道间的相互依赖关系以及局部特征,产生增强的特征表示。

  8. 输出
    最终输出维度与输入维度保持一致,为 (𝐶,𝑊,𝐻)。通过这种通道和局部特征的融合,网络能够更加有效地聚焦在重要的局部特征和通道间的全局依赖关系上,提升模型的表达能力。
    在这里插入图片描述

1.2MLCA核心代码

import torch
import torch.nn as nn
import torch.nn.functional as F
import mathclass MLCA(nn.Module):def __init__(self, in_size, local_size=5, gamma=2, b=1, local_weight=0.5):super(MLCA, self).__init__()# ECA 计算方法self.local_size = local_sizeself.gamma = gammaself.b = bt = int(abs(math.log(in_size, 2) + self.b) / self.gamma)  # eca  gamma=2k = t if t % 2 else t + 1self.conv = nn.Conv1d(1, 1, kernel_size=k, padding=(k - 1) // 2, bias=False)self.conv_local = nn.Conv1d(1, 1, kernel_size=k, padding=(k - 1) // 2, bias=False)self.local_weight = local_weightself.local_arv_pool = nn.AdaptiveAvgPool2d(local_size)self.global_arv_pool = nn.AdaptiveAvgPool2d(1)def forward(self, x):local_arv = self.local_arv_pool(x)global_arv = self.global_arv_pool(local_arv)b, c, m, n = x.shapeb_local, c_local, m_local, n_local = local_arv.shape# (b,c,local_size,local_size) -> (b,c,local_size*local_size)-> (b,local_size*local_size,c)-> (b,1,local_size*local_size*c)temp_local = local_arv.view(b, c_local, -1).transpose(-1, -2).reshape(b, 1, -1)temp_global = global_arv.view(b, c, -1).transpose(-1, -2)y_local = self.conv_local(temp_local)y_global = self.conv(temp_global)# (b,c,local_size,local_size) <- (b,c,local_size*local_size)<-(b,local_size*local_size,c) <- (b,1,local_size*local_size*c)y_local_transpose = y_local.reshape(b, self.local_size * self.local_size, c).transpose(-1, -2).view(b, c,self.local_size,self.local_size)# y_global_transpose = y_global.view(b, -1).transpose(-1, -2).unsqueeze(-1)y_global_transpose = y_global.view(b, -1).unsqueeze(-1).unsqueeze(-1)  # 代码修正# print(y_global_transpose.size())# 反池化att_local = y_local_transpose.sigmoid()att_global = F.adaptive_avg_pool2d(y_global_transpose.sigmoid(), [self.local_size, self.local_size])# print(att_local.size())# print(att_global.size())att_all = F.adaptive_avg_pool2d(att_global * (1 - self.local_weight) + (att_local * self.local_weight), [m, n])# print(att_all.size())x = x * att_allreturn xdef autopad(k, p=None, d=1):  # kernel, padding, dilation"""Pad to 'same' shape outputs."""if d > 1:k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k]  # actual kernel-sizeif p is None:p = k // 2 if isinstance(k, int) else [x // 2 for x in k]  # auto-padreturn pclass Conv(nn.Module):"""Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation)."""default_act = nn.SiLU()  # default activationdef __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True):"""Initialize Conv layer with given arguments including activation."""super().__init__()self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False)self.bn = nn.BatchNorm2d(c2)self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()def forward(self, x):"""Apply convolution, batch normalization and activation to input tensor."""return self.act(self.bn(self.conv(x)))def forward_fuse(self, x):"""Perform transposed convolution of 2D data."""return self.act(self.conv(x))class C2f_MLCA(nn.Module):"""Faster Implementation of CSP Bottleneck with 2 convolutions."""def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):"""Initialize CSP bottleneck layer with two convolutions with arguments ch_in, ch_out, number, shortcut, groups,expansion."""super().__init__()self.c = int(c2 * e)  # hidden channelsself.cv1 = Conv(c1, 2 * self.c, 1, 1)self.cv2 = Conv((2 + n) * self.c, c2, 1)  # optional act=FReLU(c2)self.m = nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n))def forward(self, x):"""Forward pass through C2f layer."""y = list(self.cv1(x).chunk(2, 1))y.extend(m(y[-1]) for m in self.m)return self.cv2(torch.cat(y, 1))def forward_split(self, x):"""Forward pass using split() instead of chunk()."""y = list(self.cv1(x).split((self.c, self.c), 1))y.extend(m(y[-1]) for m in self.m)return self.cv2(torch.cat(y, 1))class Bottleneck(nn.Module):"""Standard bottleneck."""def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5):"""Initializes a bottleneck module with given input/output channels, shortcut option, group, kernels, andexpansion."""super().__init__()c_ = int(c2 * e)  # hidden channelsself.cv1 = Conv(c1, c_, k[0], 1)self.cv2 = Conv(c_, c2, k[1], 1, g=g)self.add = shortcut and c1 == c2self.MLCA = MLCA(c2)def forward(self, x):"""'forward()' applies the YOLO FPN to input data."""return x + self.MLCA(self.cv2(self.cv1(x))) if self.add else self.MLCA(self.cv2(self.cv1(x)))if __name__ == "__main__":attention = MLCA(in_size=64)inputs = torch.randn((2, 55, 16, 16))result = attention(inputs)print(result.shape)

五、添加MLCA注意力机制

5.1STEP1

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

5.2STEP2

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

5.3STEP3

找到ultralytics/nn文件夹中的task.py文件,在其中按照下图添加在这里插入图片描述

5.4STEP4

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

在这里插入图片描述

六、yaml文件与运行

6.1yaml文件

以下是添加MLCA注意力机制在Backbone中的yaml文件,大家可以注释自行调节,效果以自己的数据集结果为准

# 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 GFLOPss: [0.50, 0.50, 1024] # summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPsm: [0.50, 1.00, 512] # summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPsl: [1.00, 1.00, 512] # summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPsx: [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, 1, MLCA, []]- [-1, 2, C2PSA, [1024]] # 11# YOLO11n head
head:- [-1, 1, nn.Upsample, [None, 2, "nearest"]]- [[-1, 6], 1, Concat, [1]] # cat backbone P4- [-1, 2, C3k2, [512, False]] # 14- [-1, 1, nn.Upsample, [None, 2, "nearest"]]- [[-1, 4], 1, Concat, [1]] # cat backbone P3- [-1, 2, C3k2, [256, False]] # 17 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]]- [[-1, 14], 1, Concat, [1]] # cat head P4- [-1, 2, C3k2, [512, False]] # 20 (P4/16-medium)- [-1, 1, Conv, [512, 3, 2]]- [[-1, 11], 1, Concat, [1]] # cat head P5- [-1, 2, C3k2, [1024, True]] # 23 (P5/32-large)- [[17, 20, 23], 1, Detect, [nc]] # Detect(P3, P4, P5)

6.2运行成功截图

在这里插入图片描述

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

在这里插入图片描述


http://www.ppmy.cn/news/1536227.html

相关文章

King3399 SDK(ubuntu文件系统)编译简明教程

该文章仅供参考&#xff0c;编写人不对任务实验设备、人员及测量结果负责&#xff01;&#xff01;&#xff01; 0 引言 文章主要介绍King3399&#xff08;瑞芯微rk3399开发板&#xff0c;荣品&#xff09;官方SDK&#xff08;Ubuntu文件系统&#xff09;编译过程&#xff0c…

【2024保研经验帖】武汉大学测绘遥感国家重点实验室夏令营(计算机向)

前言 先说本人背景&#xff1a;末211&#xff0c;rk前5%&#xff0c;无科研&#xff0c;有几个竞赛(数模、机器人等) 武大的国重是我参加的第二个夏令营&#xff0c;武大国重这次有提前开几个分会场&#xff0c;一个在中南大学&#xff0c;一个在吉林大学&#xff0c;还有在兰…

【Golang】关于Go语言数学计算、随机数生成模块--math

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

RFID学习

24.10.5学习目录 一.简介1.组成2.RFID协议3.RFID卡 一.简介 RFID被称为无线射频识别&#xff0c;其是一种通信技术&#xff0c;通过无线电讯号耦合识别特定目标并读写相关数据&#xff1b; RFID主要位于典型物联网架构中的感知层&#xff0c;其因为具有非接触式特性&#xff…

SpringBoot开发——Spring Security中获取当前登录用户信息的方式

文章目录 1、前言2、实现方法2.1 使用Authentication对象获取当前登录用户信息2.2 使用SecurityContextHolder获取当前登录用户信息1、前言 在Web应用程序开发中,用户认证与授权是确保系统安全性的关键环节。Spring Security作为Spring框架的一部分,提供了一个强大且灵活的身…

弹性分布式数据集RDD详细说明

文章目录 整体介绍一、定义与特性二、操作与转换三、存储级别与持久化四、依赖关系与容错机制五、优化与性能调优 常见操作支持的数据格式1.文本文件 (Text Files)2. CSV 文件3. JSON 文件4. Parquet 文件5. Sequence Files6.Hadoop文件读取A. 读取HDFS上的文本文件B. 使用Hado…

1007B逆序对(二维数点问题 窗口星星)

http://cplusoj.com/d/senior/p/SS241007B 显然这题是一个二维数点问题&#xff0c;我们要求在确定 [ l , r ] [l,r] [l,r] 下 i i i 个数的最大值&#xff1a; l < i < r l<i<r l<i<r a r < i < a l a_r<i<a_l ar​<i<al​ 考场上想了…

浅谈新能源电动汽车充电站建设与运营模式分析

摘要&#xff1a;电动汽车是当前新能源汽车中重要的组成部分&#xff0c;具有广阔的发展前景&#xff0c;能够实现“以电代油”&#xff0c;与传统的燃油汽车相比&#xff0c;电动汽车在噪音及废气排放量方面相对较少&#xff0c;具有节能环保的显著特点。而电动汽车充电站则是…