目录
一、引言
二、注意力优势、结构图、代码
2.1 CA注意力
2.2 ECA注意力
2.3 GAM注意力
2.4 CAA注意力
1. CAA(Context Anchor Attention)的优势特点
2. 在本文中的突出贡献
三、逐步手把手添加CA/ECA/GAM/CAA注意力
3.1 第一步
3.2 第二步
3.3 第三步
3.4 第四步
四 完整yaml
4.1 YOLO11-MM前期(early)加入CA、ECA、GAM、CAA
4.2 YOLO11-MM中期(middle)加入CA、ECA、GAM、CAA
4.3 YOLO11-MM后期(late)加入CA、ECA、GAM、CAA
五 训练代码和结果
5.1 模型训练代码
5.2 模型训练结果
六 总结
一、引言
本文主要围绕 YOLO11-MM 多模态目标检测 展开,重点探讨在网络中引入 CA/ECA/GAM/CAA等注意力机制的核心思路与具体实践。我们将 CA/ECA/GAM/CAA分别置于模态融合路径的前期、中期和后期,对不同插入位置进行改进与性能对比,系统分析在不同阶段引入注意力,对特征表达能力和最终检测效果带来的影响。
需要强调的是,YOLO11-MM 多模态目标检测与 RTDETR-MM 多模态目标检测在设计取向上存在明显差异:
YOLO11-MM 更偏向轻量化与工程友好,结构更易于改进和融合各类增强模块,在推理速度、部署体验,以及训练稳定性与收敛性方面具有更明显的优势。
在实验过程中,我们一方面通过合理选择注意力模块的插入位置,尽可能增强模型的特征表示能力;另一方面也尽量控制额外参数量,在较低计算与存储开销的前提下,获得尽可能高的检测精度。近期我们已完成大量实验并对结果进行了系统整理,希望能在多模态目标检测方向的研究与工程实践中,为大家节省一定的调参与反复验证成本。
需要特别说明的是:本文所使用的数据集为 FLIR 数据集的一个子集,而非完整 FLIR 数据集,后续在复现或扩展实验时请务必留意这一点。也希望这篇文章能为正在攻关多模态目标检测的同学提供一些有价值的参考。
二、注意力优势、结构图、代码
2.1 CA注意力
优势特点:
将通道注意力和坐标信息显式结合,沿 H、W 两个方向做聚合,既建模长程依赖,又保留精确位置信息;
对细粒度空间位置信息更敏感,更利于小目标、远距离目标的定位;
计算开销适中,相比复杂自注意力更轻量,易于插入现有网络。
在本文中的突出贡献:
将 CA 布置在模态融合前期,可以在刚开始对齐可见光与红外特征时,就引导网络关注“在哪儿更重要”;
有助于在复杂场景下压制无关区域、突出多模态一致的目标区域,为后续特征融合打下更好的空间对齐基础。
重要意义:
说明在多模态检测中,显式编码坐标信息的注意力对跨模态对齐和目标定位尤为关键;
为后续设计多模态骨干和融合模块提供了一个清晰的思路:在早期特征阶段应优先考虑带有空间先验的注意力形式。
CA核心代码:
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, reduction=32):
super(CoordAtt, self).__init__()
oup = inp
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
2.2 ECA注意力
优势特点:
不做通道压缩,通过一维卷积实现局部跨通道交互,结构极其简洁;
额外参数和计算量极小,几乎不影响模型推理速度,非常适合部署场景;
在保持轻量的同时,能够有效突出关键通道、抑制冗余通道。
在本文中的突出贡献:
将 ECA 布置在模态融合中期,用于在已经对齐的多模态特征上进一步筛选“哪几类通道更有用”;
在几乎不增加开销的前提下,提升了特征表达的判别性,实现了精度–复杂度的更优折中。

重要意义:
证明了在多模态检测中,轻量级通道注意力足以带来可观收益,非常适合实际工程部署;
为后续在边缘设备、实时系统中引入注意力机制提供了可行范例:优先考虑类似 ECA 这类低成本模块。
ECA核心代码
import torch
from torch import nn
from torch.nn.parameter import Parameter
class ECA(nn.Module):
"""Constructs a ECA module.
Args:
channel: Number of channels of the input feature map
k_size: Adaptive selection of kernel size
"""
def __init__(self, channel, k_size=3):
super(ECA, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.conv = nn.Conv1d(1, 1, kernel_size=k_size, padding=(k_size - 1) // 2, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
# feature descriptor on the global spatial information
y = self.avg_pool(x)
# Two different branches of ECA module
y = self.conv(y.squeeze(-1).transpose(-1, -2)).transpose(-1, -2).unsqueeze(-1)
# Multi-scale information fusion
y = self.sigmoid(y)
return x * y.expand_as(x)
2.3 GAM注意力
优势特点:
同时建模全局通道依赖与空间分布,实现更充分的通道–空间交互;
感受野更大,对复杂背景、长距离依赖建模能力强;
相比单纯的 SE/CBAM 等模块,对全局上下文的利用更加充分。=


在本文中的突出贡献:
将 GAM 布置在模态融合后期/检测头前,在高层语义特征上做一次“全局重整”;
有助于在最终检测阶段进一步压制伪目标和背景干扰,提升对难例、拥挤场景的鲁棒性。
重要意义:
展示了在多模态检测框架中,在后期引入更强的全局注意力,可以显著提升上限性能;
为后续工作提供启示:在靠近检测头的高语义阶段,适当使用稍“重”的全局注意力模块,是提升检测质量的有效途径。
核心代码:
import torch
import torch.nn as nn
'''
https://arxiv.org/abs/2112.05561
'''
class GAM(nn.Module):
def __init__(self, in_channels, rate=4):
super().__init__()
out_channels = in_channels
in_channels = int(in_channels)
out_channels = int(out_channels)
inchannel_rate = int(in_channels / rate)
self.linear1 = nn.Linear(in_channels, inchannel_rate)
self.relu = nn.ReLU(inplace=True)
self.linear2 = nn.Linear(inchannel_rate, in_channels)
self.conv1 = nn.Conv2d(in_channels, inchannel_rate, kernel_size=7, padding=3, padding_mode='replicate')
self.conv2 = nn.Conv2d(inchannel_rate, out_channels, kernel_size=7, padding=3, padding_mode='replicate')
self.norm1 = nn.BatchNorm2d(inchannel_rate)
self.norm2 = nn.BatchNorm2d(out_channels)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
b, c, h, w = x.shape
# B,C,H,W ==> B,H*W,C
x_permute = x.permute(0, 2, 3, 1).view(b, -1, c)
# B,H*W,C ==> B,H,W,C
x_att_permute = self.linear2(self.relu(self.linear1(x_permute))).view(b, h, w, c)
# B,H,W,C ==> B,C,H,W
x_channel_att = x_att_permute.permute(0, 3, 1, 2)
x = x * x_channel_att
x_spatial_att = self.relu(self.norm1(self.conv1(x)))
x_spatial_att = self.sigmoid(self.norm2(self.conv2(x_spatial_att)))
out = x * x_spatial_att
return out
if __name__ == '__main__':
img = torch.rand(1, 64, 32, 48)
b, c, h, w = img.shape
net = GAM(in_channels=c, out_channels=c)
output = net(img)
print(output.shape)
2.4 CAA注意力
1. CAA(Context Anchor Attention)的优势特点
显式建模“上下文锚点”
通过 先对特征做局部上下文聚合,相当于为每个位置构造一个带有周围语义信息的“上下文锚点”,有助于在复杂背景中稳定目标响应。
AvgPool(7×7)
水平方向 + 垂直方向的长程依赖建模
利用 与
(1, k) 的深度可分离卷积分别沿宽、高两个方向建模长程依赖,比 2D 大卷积或自注意力更便宜,却能有效捕获细长目标、行人队列、车道等具有强方向性的结构信息。
(k, 1)
通道与空间同时重标定
先用 1×1 卷积在通道维度上做非线性变换,再通过大核 DWConv 和最后的 1×1+Sigmoid 输出完整的 2D 注意力图,实现对“哪些通道、哪些空间位置”同时加权,比单纯通道注意力更细致。
轻量且易插拔
关键计算都在深度可分离卷积上完成,参数量和计算量相对较低,可以无缝嵌入 YOLO11-MM 这类轻量框架,对整体推理速度和部署影响较小。

2. 在本文中的突出贡献
提升多模态特征的上下文感知能力
将 CAA 插入多模态融合路径后,能够在融合前后充分利用局部与长程上下文,对红外与可见光的互补信息进行“带锚点”的增强,使得目标区域响应更集中、背景区域更受抑制。
兼顾精度提升与轻量化需求
相比更重的全局注意力结构,CAA 在增加极少参数的前提下,就能带来稳定的检测性能提升,与 YOLO11-MM 的轻量化设计目标高度契合。
可视化与代码双重支撑
文中同时给出了 CAA 的注意力热力图与 PyTorch 实现代码(如上 ),一方面直观展示了其在空间上的关注模式,另一方面也方便读者直接复现与二次开发。
class CAA(nn.Module)
核心代码:
class CAA(nn.Module):
"""Context Anchor Attention"""
def __init__(
self,
channels: int,
h_kernel_size: int = 11,
v_kernel_size: int = 11,
norm_cfg: Optional[dict] = dict(type='BN', momentum=0.03, eps=0.001),
act_cfg: Optional[dict] = dict(type='SiLU'),
):
super().__init__()
self.avg_pool = nn.AvgPool2d(7, 1, 3)
self.conv1 = ConvModule(channels, channels, 1, 1, 0,
norm_cfg=norm_cfg, act_cfg=act_cfg)
self.h_conv = ConvModule(channels, channels, (1, h_kernel_size), 1,
(0, h_kernel_size // 2), groups=channels,
norm_cfg=None, act_cfg=None)
self.v_conv = ConvModule(channels, channels, (v_kernel_size, 1), 1,
(v_kernel_size // 2, 0), groups=channels,
norm_cfg=None, act_cfg=None)
self.conv2 = ConvModule(channels, channels, 1, 1, 0,
norm_cfg=norm_cfg, act_cfg=act_cfg)
self.act = nn.Sigmoid()
def forward(self, x):
attn_factor = self.act(self.conv2(self.v_conv(self.h_conv(self.conv1(self.avg_pool(x))))))
return attn_factor
三、逐步手把手添加CA/ECA/GAM/CAA注意力
3.1 第一步
在 ultralytics/nn 目录下面,新建一个叫 attention 的文件夹,然后在里面分别新建一个.py 文件,把注意力模块的“核心代码”粘进去。
注意🔸 如果你使用我完整的项目代码,这个 attention 文件夹已经有了、里面的模块也是有的,直接使用进行训练和测试,如果没有你只需要在里面新建一个 py 文件或直接修改已有的即可,如下图所示。

3.2 第二步
第二步:在该目录下新建一个名为 的 Python 文件(如果使用的是我项目提供的工程,该文件一般已经存在,无需重复创建),然后在该文件中导入我们自定义的注意力CA、ECA和GAM CAA,具体写法如下图所示。
__init__.py

3.3 第三步
第三步:找到 文件,在其中完成我们模块 CA、ECA和GAM 、CAA的导入和注册(如果使用的是我提供的项目工程,该文件已自带,无需新建)。具体书写方式如下图所示
ultralytics/nn/tasks.py

3.4 第四步
第四步:找到 文件,在
ultralytics/nn/tasks.py 方法中加入对应配置即可,具体书写方式如下图所示。
parse_model
elif m in {CBAM,CA,CAA,ECA,GAM}: # 所有注意力机制模块
c2 = ch[f]
args = [c2, *args]

四 完整yaml
4.1 YOLO11-MM前期(early)加入CA、ECA、GAM、CAA
ECA训练信息:summary: 184 layers, 2,590,665 parameters, 2,590,649 gradients, 6.5 GFLOPs
CA训练信息:summary: 187 layers, 2,590,790 parameters, 2,590,774 gradients, 6.5 GFLOPs
GAM训练信息:summary: 189 layers, 2,597,142 parameters, 2,597,126 gradients, 7.9 GFLOPs
CAA训练信息:summary: 191 layers, 2,591,622 parameters, 2,591,606 gradients, 6.7 GFLOPs
# Ultralytics YOLO11 🚀 MultiModal Early Fusion Configuration
# 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] # YOLO11n summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
s: [0.50, 0.50, 1024] # YOLO11s summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
m: [0.50, 1.00, 512] # YOLO11m summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
l: [1.00, 1.00, 512] # YOLO11l summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs
x: [1.00, 1.50, 512] # YOLO11x summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.4 GFLOPs
backbone:
# P1/2 - 早期融合层:直接处理6通道输入(RGB+X)
- [-1, 1, Conv, [64, 3, 2], 'Dual'] # 0-P1/2 (6ch->64ch early fusion)
# - [-1, 1, CA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, ECA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, GAM, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
- [-1, 1, CAA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 2, C3k2, [256, False, 0.25]] # 2
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 2, C3k2, [512, False, 0.25]] # 4
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 2, C3k2, [512, True]] # 6
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 2, C3k2, [1024, True]] # 8
- [-1, 1, SPPF, [1024, 5]] # 9
- [-1, 2, C2PSA, [1024]] # 10
# 检测头 - 标准YOLO11检测头结构
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 11
- [[-1, 7], 1, Concat, [1]] # 12 cat backbone P4
- [-1, 2, C3k2, [512, False]] # 13
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 14
- [[-1, 5], 1, Concat, [1]] # 15 cat backbone P3
- [-1, 2, C3k2, [256, False]] # 16 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]] # 17
- [[-1, 14], 1, Concat, [1]] # 18 cat head P4
- [-1, 2, C3k2, [512, False]] # 19 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]] # 20
- [[-1, 11], 1, Concat, [1]] # 21 cat backbone P5
- [-1, 2, C3k2, [1024, True]] # 22 (P5/32-large)
- [[17, 20, 23], 1, Detect, [nc]] # 23 Detect(P3, P4, P5)

4.2 YOLO11-MM中期(middle)加入CA、ECA、GAM、CAA
ECA训练信息:summary: 328 layers, 4,979,580 parameters, 4,979,564 gradients, 11.3 GFLOPs
CA训练信息:summary: 334 layers, 5,045,110 parameters, 5,045,094 gradients, 11.4 GFLOPs
GAM训练信息:summary: 338 layers, 8,258,934 parameters, 8,258,918 gradients, 17.8 GFLOPs
CAA训练信息:summary: 342 layers, 5,256,054 parameters, 5,256,038 gradients, 11.8 GFLOPs
# Ultralytics YOLOMM 🚀 Standard Mid-Fusion Paradigm
# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants
# [depth, width, max_channels]
n: [0.50, 0.25, 1024]
s: [0.50, 0.50, 1024]
m: [0.50, 1.00, 512]
l: [1.00, 1.00, 512]
x: [1.00, 1.50, 512]
# P4/P5双层融合架构
backbone:
# ========== RGB路径 (层0-10) - 完整骨干网到P5 ==========
- [-1, 1, Conv, [64, 3, 2], 'RGB'] # 0-P1/2 RGB路径起始
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 2, C3k2, [256, False, 0.25]] # 2
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8 (RGB_P3)
- [-1, 2, C3k2, [512, False, 0.25]] # 4
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 2, C3k2, [512, True]] # 6 (RGB_P4)
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 2, C3k2, [1024, True]] # 8
- [-1, 1, SPPF, [1024, 5]] # 9
- [-1, 2, C2PSA, [1024]] # 10 (RGB_P5)
# ========== X路径 (层11-21) - 完整骨干网到P5 ==========
- [-1, 1, Conv, [64, 3, 2], 'X'] # 11-P1/2 X路径起始
- [-1, 1, Conv, [128, 3, 2]] # 12-P2/4
- [-1, 2, C3k2, [256, False, 0.25]] # 13
- [-1, 1, Conv, [256, 3, 2]] # 14-P3/8 (X_P3)
- [-1, 2, C3k2, [512, False, 0.25]] # 15
- [-1, 1, Conv, [512, 3, 2]] # 16-P4/16
- [-1, 2, C3k2, [512, True]] # 17 (X_P4)
- [-1, 1, Conv, [1024, 3, 2]] # 18-P5/32
- [-1, 2, C3k2, [1024, True]] # 19
- [-1, 1, SPPF, [1024, 5]] # 20
- [-1, 2, C2PSA, [1024]] # 21 (X_P5)
# ========== P4和P5层级融合 ==========
# P4级融合
- [[6, 17], 1, Concat, [1]] # 22 P4融合: RGB_P4(6) + X_P4(17)
- [-1, 2, C3k2, [1024, True]] # 23 (Fused_P4)
- [-1, 1, CA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, ECA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, GAM, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, CAA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# P5级融合
- [[10, 21], 1, Concat, [1]] # 24 P5融合: RGB_P5(10) + X_P5(21)
- [-1, 2, C3k2, [1024, True]] # 25
- [-1, 1, C2PSA, [1024]] # 26 (Fused_P5)
- [-1, 1, CA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, ECA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, GAM, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, CAA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# 标准YOLOv11检测头 (Neck + Head)
head:
# 自顶向下路径 (FPN)
- [28, 1, nn.Upsample, [None, 2, "nearest"]] # 27 Fused_P5上采样
- [[-1, 24], 1, Concat, [1]] # 28 连接Fused_P4
- [-1, 2, C3k2, [512, False]] # 29
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 30
- [[-1, 4], 1, Concat, [1]] # 31 连接RGB_P3(4)
- [-1, 2, C3k2, [256, False]] # 32 (P3/8-small)
# 自底向上路径 (PAN)
- [-1, 1, Conv, [256, 3, 2]] # 33
- [[-1, 31], 1, Concat, [1]] # 34
- [-1, 2, C3k2, [512, False]] # 35 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]] # 36
- [[-1, 28], 1, Concat, [1]] # 37
- [-1, 2, C3k2, [1024, True]] # 38 (P5/32-large)
- [[34, 37, 40], 1, Detect, [nc]] # 39 Detect(P3, P4, P5)

4.3 YOLO11-MM后期(late)加入CA、ECA、GAM、CAA
ECA训练信息:summary: 330 layers, 5,138,527 parameters, 5,138,511 gradients, 12.5 GFLOPs
CA训练信息:summary: 339 layers, 5,310,550 parameters, 5,310,534 gradients, 12.8 GFLOPs
GAM训练信息:summary: 345 layers, 13,744,598 parameters, 13,744,582 gradients, 28.2 GFLOPs
CAA训练信息:summary: 351 layers, 5,851,734 parameters, 5,851,718 gradients, 13.9 GFLOPs
# Ultralytics YOLO11 🚀 MultiModal Late Fusion Reference
# 说明:该“late-ref”版本遵循 YOLOMM 设计范式与分支书写规范,使用第5字段进行模态路由标注。
# 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] # YOLO11n summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
s: [0.50, 0.50, 1024] # YOLO11s summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
m: [0.50, 1.00, 512] # YOLO11m summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
l: [1.00, 1.00, 512] # YOLO11l summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs
x: [1.00, 1.50, 512] # YOLO11x summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.4 GFLOPs
backbone:
# RGB路径 (层0-10) - 完整的RGB特征提取
- [-1, 1, Conv, [64, 3, 2], 'RGB'] # 0-P1/2 RGB路径起始
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 2, C3k2, [256, False, 0.25]] # 2
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 2, C3k2, [512, False, 0.25]] # 4
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 2, C3k2, [512, True]] # 6
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 2, C3k2, [1024, True]] # 8
- [-1, 1, SPPF, [1024, 5]] # 9
- [-1, 2, C2PSA, [1024]] # 10 RGB路径结束
# X路径 (层11-21) - 完整的X模态特征提取
- [-1, 1, Conv, [64, 3, 2], 'X'] # 11-P1/2 X路径起始(from=-1但实际从X模态输入)
- [-1, 1, Conv, [128, 3, 2]] # 12-P2/4
- [-1, 2, C3k2, [256, False, 0.25]] # 13
- [-1, 1, Conv, [256, 3, 2]] # 14-P3/8
- [-1, 2, C3k2, [512, False, 0.25]] # 15
- [-1, 1, Conv, [512, 3, 2]] # 16-P4/16
- [-1, 2, C3k2, [512, True]] # 17
- [-1, 1, Conv, [1024, 3, 2]] # 18-P5/32
- [-1, 2, C3k2, [1024, True]] # 19
- [-1, 1, SPPF, [1024, 5]] # 20
- [-1, 2, C2PSA, [1024]] # 21 X路径结束
# 独立检测头 - RGB和X模态各自独立检测,最后融合决策
head:
# RGB检测分支 (层22-33)
- [10, 1, nn.Upsample, [None, 2, "nearest"]] # 22 从RGB backbone
- [[-1, 6], 1, Concat, [1]] # 23 cat RGB backbone P4
- [-1, 2, C3k2, [512, False]] # 24
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 25
- [[-1, 4], 1, Concat, [1]] # 26 cat RGB backbone P3
- [-1, 2, C3k2, [256, False]] # 27 (RGB P3/8-small)
- [-1, 1, Conv, [256, 3, 2]] # 28
- [[-1, 24], 1, Concat, [1]] # 29 cat RGB head P4
- [-1, 2, C3k2, [512, False]] # 30 (RGB P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]] # 31
- [[-1, 10], 1, Concat, [1]] # 32 cat RGB backbone P5
- [-1, 2, C3k2, [1024, True]] # 33 (RGB P5/32-large)
# X模态检测分支 (层34-45)
- [21, 1, nn.Upsample, [None, 2, "nearest"]] # 34 从X backbone
- [[-1, 17], 1, Concat, [1]] # 35 cat X backbone P4
- [-1, 2, C3k2, [512, False]] # 36
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 37
- [[-1, 15], 1, Concat, [1]] # 38 cat X backbone P3
- [-1, 2, C3k2, [256, False]] # 39 (X P3/8-small)
- [-1, 1, Conv, [256, 3, 2]] # 40
- [[-1, 36], 1, Concat, [1]] # 41 cat X head P4
- [-1, 2, C3k2, [512, False]] # 42 (X P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]] # 43
- [[-1, 21], 1, Concat, [1]] # 44 cat X backbone P5
- [-1, 2, C3k2, [1024, True]] # 45 (X P5/32-large)
- [[27, 39], 1, Concat, [1]] # 46 融合P3
# - [-1, 1, CA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, ECA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, GAM, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
- [-1, 1, CAA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
- [[30, 42], 1, Concat, [1]] # 47 融合P4
# - [-1, 1, CA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, ECA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, GAM, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
- [-1, 1, CAA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
- [[33, 45], 1, Concat, [1]] # 48 融合P5
# - [-1, 1, CA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, ECA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
# - [-1, 1, GAM, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
- [-1, 1, CAA, []] # 0-P1/2 6-channel input ######### 加入注意力 ,同时也可以替换为其他的注意力
- [[47, 49, 51], 1, Detect, [nc]] # 49 Detect(P3, P4, P5)

五 训练代码和结果
5.1 模型训练代码
import warnings
from ultralytics import YOLOMM
# 1. 可选:屏蔽 timm 的未来弃用警告(不影响训练,仅减少控制台噪音)
warnings.filterwarnings(
"ignore",
category=FutureWarning,
message="Importing from timm.models.layers is deprecated, please import via timm.layers"
)
if __name__ == "__main__":
# 2. 加载多模态模型配置(RGB + IR)
# 这里使用官方提供的 yolo11n-mm-mid 配置,你也可以换成自己的 yaml
model = YOLOMM("ultralytics/cfg/models/attention/yolo11-mm-late_attention.yaml")
# 3. 启动训练
model.train(
data="FLIR3C/data.yaml", # 多模态数据集配置(上一节已经编写)
epochs=10, # 训练轮数,实际实验中建议 100+ 起步
batch=4, # batch size,可根据显存大小调整
imgsz=640, # 输入分辨率(默认 640),可与数据集分辨率统一
device=0, # 指定 GPU id,CPU 训练可写 "cpu"
workers=4, # dataloader 线程数(Windows 一般 0~4 比较稳)
project="runs/mm_exp", # 训练结果保存根目录
name="rtdetrmm_flir3c", # 当前实验名,对应子目录名
# resume=True, # 如需从中断的训练继续,可打开此项
# patience=30, # 早停策略,连降若干轮 mAP 不提升则停止
# modality="X", # 模态消融参数(默认由 data.yaml 中的 modality_used 决定)
# cache=True, # 启用图片缓存,加快 IO(内存足够时可打开)
)

5.2 模型训练结果


六 总结
到这里,本文的正式内容就告一段落啦。
最后也想郑重向大家推荐我的专栏 「YOLO11-MM 多模态目标检测」。目前专栏整体以实战为主,每一篇都是我亲自上手验证后的经验沉淀。后续我也会持续跟进最新顶会的前沿工作进行论文复现,并对一些经典方法及改进机制做系统梳理和补充。
✨如果这篇文章对你哪怕只有一丝帮助,欢迎订阅本专栏、关注我,并私信联系,我会拉你进入 「YOLO11-MM 多模态目标检测」技术交流群 QQ 群~
你的支持,就是我持续输出的最大动力!✨



