1. Mixed Local Channel Attention (MLCA)介绍
MLCA(混合局部通道注意力)是一种轻量级的注意力机制,旨在提高目标检测网络的性能。它结合了局部和全局特征以及通道和空间特征的信息,以增强网络对有用特征的捕捉能力。
具体来说,MLCA首先对输入特征图进行局部和全局平均池化,然后通过1D卷积进行特征转换。局部池化后的特征与原始输入特征相结合,全局池化后的特征则与局部池化特征相结合,最终通过反池化恢复到原始空间维度。这种方法在保持计算效率的同时,显著提高了检测精度 。

原始论文:https://www.sciencedirect.com/science/article/abs/pii/S0952197623006267
原始代码:https://github.com/wandahangFY/MLCA
结构介绍
-
输入处理:MLCA的输入特征向量经过两步池化处理,首先进行局部池化,将输入转换为1 * C * ks * ks的向量,以提取局部空间信息。
-
分支处理:经过初始阶段处理后,使用两个分支将输入转换为一维向量,第一个分支包含全局信息,第二个分支包含局部空间信息。
-
信息融合:经过一维卷积处理后,两个向量的原始分辨率通过反池化恢复,然后融合信息以实现混合注意力。
工作原理
-
局部空间信息提取:通过局部池化和反池化,MLCA能够捕获输入特征向量中的局部空间信息,有助于提高对象检测的准确性。
-
通道交互信息:一维卷积考虑每个通道与其k个相邻通道之间的关系,捕获通道间的局部交互信息,从而增强通道信息的表达能力。
-
全局和局部信息融合:MLCA通过融合全局和局部信息,实现对对象检测任务的综合关注,同时避免通道维度减少导致的精度损失。
2. MLCA代码实现
在ultralytics/nn/路径下创建MLCA.py文件,并复制以下代码:
import torch.nn as nn
import torch
import math
import torch.nn.functional as F
class 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_size
self.gamma = gamma
self.b = b
t = int(abs(math.log(in_size, 2) + self.b) / self.gamma) # eca gamma=2
k = t if t % 2 else t + 1
self.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_weight
self.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.shape
b_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)
# (b,c,1,1) -> (b,c,1) -> (b,1,c)
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)
# (b,1,c) -> (b,c,1) -> (b,c,1,1)
y_global_transpose = y_global.transpose(-1, -2).unsqueeze(-1)
# 反池化
att_local = y_local_transpose.sigmoid()
att_global = F.adaptive_avg_pool2d(y_global_transpose.sigmoid(), [self.local_size, self.local_size])
att_all = F.adaptive_avg_pool2d(att_global * (1 – self.local_weight) + (att_local * self.local_weight), [m, n])
x = x * att_all
return x
3. 具体改进步骤
🍀🍀步骤1:创建MLCA.py文件

🍀🍀步骤2:tasks.py文件修改
先在ultralytics/nn/tasks.py代码最前端from ultralytics.nn.MLCA import MLCA导入一下MLCA模块

然后,tasks.py文件中找到parse_model函数(ctrl+f 可以直接搜索parse_model位置)添加MLCA模块:

🍀🍀步骤3:创建YAML配置文件
以YOLOv11为例,创建yolo11-MLCA.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: 8 # 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
– [-1, 1, MLCA, [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]] # 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, Conv, [256, 3, 2]]
– [[-1, 14], 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)
🍀🍀步骤4:新建train.py文件训练模型
import warnings
warnings.filterwarnings('ignore')
from ultralytics import YOLO
if __name__ == '__main__':
model = YOLO('yolo11-MLCA.yaml')
# model.load('yolo11n.pt') # loading pretrain weights
model.train(data='dataset/data.yaml',
cache=False,
imgsz=640,
epochs=300,
batch=32,
close_mosaic=0,
workers=4, # Windows下出现莫名其妙卡主的情况可以尝试把workers设置为0
# device='0',
optimizer='SGD', # using SGD
# patience=0, # set 0 to close earlystop.
# resume=True, # 断点续训,YOLO初始化时选择last.pt
# amp=False, # close amp
# fraction=0.2,
project='runs/train',
name='exp',
)



