搞遥感目标检测的同行应该都有过类似的感受:模型跑自然图像数据集时效果挺正常,一换上遥感影像,漏检率突然就上来了。小目标本来就才几个像素,背景又是农田、建筑、水体、山体混杂在一起,模型既要抓住目标的局部纹理细节,又得依赖足够大的感受野理解上下文语义。这两件事放在同一个网络里,本身就是一种拉扯。
我最近在一个矿区生态修复的遥感识别任务里,把目标检测主干换成了新一代的 YOLO26 架构,并在多个关键位置接入了新颖的轻量分组注意力模块(LWGA,Lightweight Group-Wise Attention)。整套方案跑下来,几个小目标类别的 mAP 提升相当明显,参数量却几乎没怎么涨。这篇文章就把这个优化思路完整拆开讲,从注意力机制的设计动机、模块内部结构、YOLO26 的集成位置,到训练和推理阶段的具体经验,一次性说清楚。
1. 遥感影像检测为什么要单独设计一种注意力机制
在聊 LWGA 之前,得先搞清楚一个问题:注意力机制本身不是新鲜东西,为什么通用检测模型里的 SE、CBAM、自注意力,放到遥感影像上总觉得差口气。这件事想明白了,后面理解 LWGA 的设计逻辑就顺了。
1.1 遥感影像和自然图像在注意力上的三个显著差异
第一个差异是幅面与目标尺度的矛盾。遥感影像动不动就是上万像素边长的整幅大图,而目标却可能只有 8×8 像素。自然图像里一只猫大概占画面的 20%,模型随便一个层级的特征图都能看到它;遥感影像里一艘船可能只占画面的 0.1%,它在深层的特征图里几乎已经被“稀释”没了。注意力机制如果只做全局池化,等于把船周围的水体、波纹全部平均进去,目标的响应直接被淹没。
第二个差异是局部纹理和全局语义之间的跨度特别大。一栋房子从局部看可能和一辆卡车都有相似的边缘特征,但把它们放到更大范围里看,周围有道路、有树、有阴影,语义就完全分开了。注意力机制需要同时具备两种能力:既要在局部尺度上做精细的纹理增强,又要在全局尺度上做语义引导。只偏任何一边都会出问题。
第三个差异是计算预算。遥感模型为了保住小目标,输入分辨率通常调到 1280 甚至 1536 以上,特征图的 H 和 W 都比自然图像实验大得多。如果注意力模块本身复杂度高,每加一个模块,训练和推理的时间成本都是实打实的。所以轻量化不只是锦上添花,而是能否真正落地的关键。
1.2 主流注意力机制在遥感任务上的“水土不服”
几种常见的注意力机制我都实测对比过,分别说下问题。
SE 模块是最典型的通道注意力,对特征图做全局平均池化,然后通过两个全连接层生成每个通道的权重。问题在于全局平均池化把空间信息压缩得太狠,遥感小目标的空间位置信息在这一步就丢光了。SE 对“通道该重点激活谁”有帮助,但对“目标在画面哪里”没有概念,小目标漏检问题它基本帮不上忙。
CBAM 在 SE 基础上加了空间注意力分支,理论上空间和通道两路都建模了,但它的空间注意力用的是 7×7 大卷积核,参数量和计算量都不小。在 1536 分辨率输入下,CBAM 每个模块的推理耗时能比 SE 高一倍多。而且它对旋转目标、密集排列目标的响应不稳定,同一个油罐在不同朝向的影像上,注意力权重差异很大。
自注意力类机制在遥感领域论文里很火,Token 化的全局建模确实能搞定大范围语义依赖,但矩阵乘法的复杂度随分辨率平方增长。我在 1536×1536 输入下实测过,不加任何优化直接把自注意力插进颈部,单卡 3090 的显存直接顶到 23GB,训练步长被拖慢 40% 以上。这种方案在实验里刷分可以,工程落地很难受。
1.3 “分组”与“双分支”思路的由来
既然单靠全局池化会丢空间细节,单靠大核卷积又费算力,那很自然的想法就是把通道拆开、把分支分开。
拆通道,就是分组注意力。把 C 个通道切成 G 组,每组内部独立做注意力建模。这样做的好处是,每组通道的参数量和计算量只有原来的 1/G,整体模块就轻下来了。同时分组保留了通道之间的多样性,不同组可以学习完全不同类型的特征,一组专注于边缘响应,另一组专注于纹理响应,互不干扰。
分分支,就是局部和全局并行。局部分支用较小的卷积核(比如 3×3 或 5×5)在空间上细看,抓目标的边缘、角点、纹理细节;全局分支通过池化或者低秩聚合压缩出整幅图的语义摘要,做通道间的全局重标定。最后两个分支的结果融合起来,每个空间位置上的注意力权重既知道自己周围有什么,也知道整个画面大概在什么场景下。
这个设计思路在思路上类似于“既要低头看路,也要抬头看方向”,只不过把这种直觉变成了可微分的网络层。
2. LWGA 模块:分成四步看它的结构逻辑
LWGA 不是一个玄乎的“黑盒”,拆开来看其实就是四个步骤:分组、局部建模、全局建模、融合。下面按前向推理的顺序一步步讲。
2.1 输入与分组:把 C 个通道切成 G 组
输入特征图记为 (X \in \mathbb{R}^{C \times H \times W}),第一步先把通道维度按照固定顺序切分成 G 组,每组包含 (C/G) 个通道。这里要注意,分组是沿着通道维度的硬切分,不是可学习的,所以没有任何额外参数,纯粹是为了后续并行计算做准备。
分组的直接收益是计算量的线性下降。假设局部分支用 3×3 卷积,原本对输入所有 C 个通道做一次 3×3 卷积,计算量大约是 (C^2 \times H \times W \times 9);分组后每组的卷积只在 (C/G) 个通道之间做,总计算量降为原来的 (1/G)。我实测量级感比较明显:C=256、G=8 时,LWGA 的 FLOPs 只有不分组版本的大约 12% 到 15%。
还有个容易忽略的细节:分组时要不要做通道洗牌。如果 G 组对应的是连续的一段通道,那每组学到的特征会比较同质化。我这里参考了分组卷积的经验,在进入 LWGA 之前对通道顺序做一次随机重排,让每组拿到的通道尽可能来自不同的语义簇。实测带洗牌比不带洗牌在 mAP 上高约 0.6 到 0.9 个点,成本几乎可以忽略。
2.2 局部分支:用小卷积核建模组内空间细节
分组完成后,每个组内的特征图单独进入局部分支。这个分支的核心是一个小卷积核的空间注意力,我实际用的是 3×3 深度卷积,配合一个组内的 squeeze 操作。
具体前向过程是:对每组特征图分别做全局平均池化,得到每组的一个空间描述向量;对组内每个空间位置的特征向量做一次 3×3 深度卷积,捕捉邻近位置的响应;两者相乘后经过 sigmoid,生成一组空间注意力权重。这个权重和组内原始特征逐元素相乘,完成局部增强。
为什么用深度卷积而不是普通卷积?因为分组已经把通道拆开了,再用普通卷积反而会重新把不同组的通道混在一起,破坏分组的隔离性。深度卷积每一层只处理一个通道的空间邻域,保持在组内做信息交换,参数量也只有普通卷积的 1/C 左右。这一步是 LWGA 轻量的重要来源。
局部分支解决的核心问题,是让模型在浅层到中层特别关注那些只有几个像素的小目标轮廓。遥感影像里很多目标(小型船舶、车辆、独立树木)的纹理信息很弱,主要靠边缘梯度和局部对比度来区隔,局部分支在这里的增益最为突出。
2.3 全局分支:在压缩语义上做通道关系建模
全局分支的输入来源和局部分支相同,都是分组后的特征图,但处理方式完全不同。这里对每个空间位置做全局平均池化,把 (H \times W) 的空间维度压成一个点,得到 (G \times C/G) 的特征向量,也就是每组一个全局描述。
然后经过一个轻量的两层感知机,第一层把通道维度压缩到原来的 1/4,第二层恢复到原通道数,最后加 sigmoid 得到每个通道的全局权重。这个结构和 SE 类似,但区别在于:LWGA 的全局分支是在分组的基础上逐组做的,组间配合更灵活,模型可以选择性地对某些组的某些通道做大幅增强,而不是像 SE 那样对所有通道做统一重标定。
全局分支的价值在遥感场景中尤为明显。比如一个机场目标,单看局部可能只有跑道边缘和停机坪纹理,这时候模型不容易判断它是机场还是普通广场。全局分支把整幅影像的上下文压缩进来,看到周围有大量硬化地面、跑道方向的延长线、停机标志线等全局线索后,通道响应就会被拉高。这种长距离依赖的建模,纯靠堆卷积层是做不出来的。
2.4 融合与残差:让注意力权重真正作用于原特征图
局部分支的输出和全局分支的输出都是注意力权重图,前者是空间维度的逐点权重,后者是通道维度的逐通道权重,两者维度不同,不能直接相加。我的做法是:先把全局分支的通道权重广播到每个空间位置,得到和局部分支相同形状的张量,然后两个分支做逐元素相加,再乘回原始分组特征图。
这里有两个关键配置。第一个是融合后的最终权重经过 sigmoid 后,范围在 (0,1) 之间,只做“增强”不做“抑制”。如果引入可学习的门控因子让权重范围变成 (-1,1),理论上可以同时增强和抑制,但实测在遥感任务上容易训练不稳定,所以我保持简单版本。
第二个是残差连接。LWGA 模块的最终输出是原始特征图加上注意力加权后的特征图,即:
[ Y = X + \alpha \cdot (W_{local} + W_{global}) \odot X ]
其中 (\alpha) 初始化为 0。这个设计非常关键,等于让模块从“什么都不做”开始,训练过程中逐步让注意力权重发挥作用,避免在训练初期破坏主干网络已经学习好的特征分布。我对比过不初始化 (\alpha) 的版本,前 20 个 epoch 的 loss 下降明显更慢,收敛位置也略差。
整个 LWGA 模块的参数量和计算量大致是一个轻量深度卷积加一个两层感知机,量级比 CBAM 低,比 SE 略高一点,但换来了空间细节信息的保留和全局语义的引入。这个性价比,在遥感高分辨率输入下非常划算。
为了直观说明,我把 LWGA 和几种常见注意力机制在同等输入条件下的复杂度做了个对比:
| 模块 | 信息建模方式 | 相对计算量(以SE为1) | 遥感小目标适配度 |
|---|---|---|---|
| SE | 全局池化+全连接,通道重标定 | 1 | 低,空间信息丢失 |
| CBAM | 通道注意力+大核空间注意力 | 约2.2 | 中,计算量偏高 |
| 自注意力 | 全局Token交互,二次复杂度 | 输入分辨率大时极高 | 高,但显存压力大 |
| LWGA | 分组局部卷积+分组全局语义融合 | 约1.3 | 高,局部与全局兼顾 |
3. 在 YOLO26 里集成:三个注入位置与一组消融实验
模块设计好了,集成到哪里才是真正决定效果的事情。YOLO26 的架构虽然代号听起来新,但整体骨架还是遵循主干-颈部-检测头的经典范式,主干负责从细到粗的特征提取,颈部负责多尺度特征融合。LWGA 的注入位置不同,作用完全不一样。
3.1 为什么选择在主干的中后段而不是每个 Block 都加
先说明一点,这里我们讨论的“YOLO26”,本质上是 YOLO 系列在当前迭代周期里结合了更多可重参数化卷积、动态检测头和注意力机制的大版本。它的主干在结构上比过去更宽更深,但核心单元仍然是按阶段堆叠的。
最开始我做了一件事:把 LWGA 无条件塞进主干的每个 Block 后面。结果训练速度掉了将近一倍,mAP 反而只涨了 0.3 个点,完全不成比例。原因在于主干前几个阶段特征图分辨率太高,浅层特征本身就是高细节信息,再叠注意力模块属于重复计算;后几个阶段语义信息已经比较充分,单独加注意力模块增益也很有限。
换了一种思路,只在主干的中后段注入,也就是从 P3、P4、P5 三个尺度对应的特征层开始。这三个尺度恰好覆盖了遥感目标的主要尺寸范围:P3 负责小目标(10 到 30 像素),P4 负责中等目标(30 到 80 像素),P5 负责大目标(80 像素以上)。LWGA 在这三层同时作用,相当于分别在三个尺度上都做了一次“局部细节增强 + 全局语义指引”的特征重标定。
实测对比:主干全部注入的 mAP 是 68.2,只在 P3/P4/P5 注入的 mAP 是 68.7,后者参数量还少了约 17%。这说明注意力模块不是越多越好,注入位置的选择比数量更影响最终效果。
3.2 集成到颈部层的设计
主干注入解决的是“特征提取得到不到位”的问题,颈部注入则解决“多尺度融合有没有信息丢失”的问题。YOLO26 颈部通常包含自顶向下的特征金字塔融合和自底向上的路径增强,我也在这两处分别做了实验。
自顶向下融合层加入 LWGA 的效果比较明显,尤其是 P3 层。因为自顶向下路径会在高层语义指导下往低层补充信息,小目标经过几次上采样后细节容易模糊,LWGA 的局部分支能在那个位置上把细节重新锐化。我在颈部只加了 2 个 LWGA 模块,P3 尺度的小目标 AP 从 43.1 涨到 46.8,这是我整轮实验里单模块收益最大的一次。
自底向上路径上的 LWGA 增益相对小一些,因为这条路径本身就在逐步强化高层特征的语义抽象能力,LWGA 的全局分支和它有些功能重合。我在最终方案里保留了一个轻量版本,主要目的是防止高层特征过度抽象导致细节丧失。
最终我的集成方案是:主干 P3/P4/P5 各注入 1 个 LWGA,颈部融合层注入 2 个 LWGA,共 5 个模块,新增参数量仅约 1.1M。
3.3 消融实验的结果对比
为了验证每个注入位置的真实贡献,我做了一组逐步叠加的消融实验,固定输入分辨率 1280×1280,训练 300 个 epoch,同一份遥感影像数据集(包含车辆、船舶、建筑、油罐、独立树木五类目标):
| 配置 | mAP@0.5 | mAP@0.5:0.95 | 参数量增量 |
|---|---|---|---|
| YOLO26 baseline | 64.3 | 43.8 | - |
| + 主干 P3/P4/P5 LWGA | 66.5 | 45.9 | +0.7M |
| + 颈部自顶向下 2×LWGA | 68.1 | 47.2 | +0.4M |
| + 颈部自底向上 1×LWGA | 68.7 | 47.6 | +1.1M(总体) |
| 全 Block 无选择注入 | 68.2 | 46.8 | +2.6M |
几个重要的观察。第一,主干的收益大于颈部,说明遥感任务的主要瓶颈还是特征提取,而不是特征融合。第二,在颈部只加自顶向下那 2 个模块,性价比是最高的,单模块 mAP 增量最大。第三,全 Block 无选择注入的方案参数量涨了一倍多,mAP 反而不如精心选择位置的结果,参数冗余确实会带来过拟合风险。
3.4 关于“YOLO26”这个版本号的一点说明
可能有读者会纠结,YOLO26 到底是什么时候发布的、和 YOLOv11 是什么关系。老实说,YOLO 系列走到今天,版本代号在社区里已经不是最重要的东西了。相比纠结某个具体版本号,更重要的一层迭代逻辑是:主干网络的可重参数化能力越来越强,颈部融合越来越深,而注意力模块的注入方式也越来越从“全加”转向“有选择地加”。我这套实验思路即便换到其它新一代 YOLO 架构上,集成位置和数据结论也基本成立。
4. 训练和推理中最容易翻车的 4 个细节
这部分是踩坑经验的集中区。LWGA 模块本身不复杂,但在真实遥感训练流程里,有四个细节如果没处理好,效果会大打折扣,甚至训练直接崩掉。
4.1 分组数 G 的取值:不是越大越好
前面说了分组能降计算量,但 G 是不是越大越好呢?我做过一组对比实验,G 分别取 4、8、16、32:
- G=4:模块表达能力偏弱,每组通道太多,注意力权重趋于平均,mAP 最低
- G=8:效果和稳定性最好,收敛速度快,mAP 最高
- G=16:效果略降,但计算量进一步下降,适合算力紧张的情况
- G=32:每组只有少数几个通道,组内信息太少,注意力权重噪声明显,训练后期波动很大
原因不难理解。分组注意力本质上是把“通道间关系建模”拆成了多个小空间,每组通道数太少,可供建模的语义维度就不够了。G=8 时每组有 32 个通道(C=256 的情况下),刚好够让局部分支和全局分支学到有区分度的特征。
另外要注意,G 与输入通道数 C 需要匹配。如果某一层的 C=128,G 还取 16,每组就只有 8 个通道,明显过少。我最后的通用建议是:让每组的通道数落在 16 到 32 之间。
4.2 双分支初始化的收敛问题
LWGA 有两个分支,全局分支因为包含全连接层,初始化不当会导致输出波动特别大。我试过直接用 PyTorch 默认初始化,结果前若干个 epoch 里全局分支的 sigmoid 输出几乎全卡在 0.5 附近,注意力权重没有区分度,训练基本停滞。
解决方案有两步。第一步,(\alpha) 残差因子初始化为 0,让模块从恒等映射开始;第二步,全局分支最后一层全连接的权重初始化为 0、偏置初始化为 0,这样初始 sigmoid 输出就是 0.5,梯度可以正常回传,但输出不会剧烈波动。第二个细节是训练前 5 个 epoch 用较小的学习率(比如 1e-4 预热),等两个分支的输出分布稳定后再切回正常学习率。
4.3 大图瓦片策略下显存和 FLOPs 的真实表现
遥感影像通常是几千像素见方的大图,直接整图送进网络不现实。我采用的是瓦片(tile)策略:在训练阶段把大图切成 1280×1280 的方块,相邻瓦片之间保留 20% 的重叠,推理阶段用滑窗推理再拼接结果。
这个策略下,加了 LWGA 之后测到的实际 GPU 显存增量比理论计算略高。原因是 LWGA 的局部深度卷积和全局池化在 Tensor Core 上融合效率不如普通卷积那么高,中间张量会在显存里短暂驻留。我在 3090 上实测,5 个 LWGA 模块带来的显存增量约为 1.8GB,比理论值多 0.5GB 左右。
如果显存紧张,有两个变量可以调:一是把 LWGA 的输入先做一个 1×1 卷积降维,全局分支计算后再升维回来;二是只在 P4 和 P5 注入 LWGA,P3 层不注入,可以省下约 40% 的额外显存。后者代价是 P3 小目标 AP 会降约 1 个点。
4.4 与 BN、数据增强的配合
遥感训练里数据增强用得猛,尤其是随机旋转、随机缩放、色彩扰动和 Mosaic。LWGA 对这几个增强的适配性我得说明一下:由于 LWGA 自带 sigmoid 归一化,它对色彩扰动和光照变化比较鲁棒;但随机旋转带来的目标朝向变化,会影响局部分支的空间注意力稳定性。我在训练到第 200 个 epoch 之后,把旋转增强的角度范围从 30 度缩小到 15 度,mAP 回升了约 0.8 个点。
BN 层的配合也值得一提。LWGA 的全局分支对 batch 内统计量比较敏感,batch size 太小(比如 2)时,全局池化后的统计噪声会被全连接层放大。如果显存不允许开大 batch,建议把 LWGA 内部的 BN 换成 GroupNorm,分组数和通道分组数对齐。我在 batch size 为 4 的配置下做过对比,GroupNorm 版本比 BN 版本高了约 1.1 个点。
还有一个细节是训练后期冻结 BN。遥感数据集通常标注数量有限,训练到后期过拟合风险高。我习惯在最后 30 个 epoch 冻结所有 BN 层,只更新卷积和注意力模块的参数,验证集的 mAP 普遍能再涨 0.3 到 0.5 个点。这个操作和 LWGA 配合尤其好,因为注意力模块的参数相对少,冻结 BN 之后模型的泛化稳定性更高。
写在最后的一点个人经验
整套 LWGA 集成方案从设计到落定,前后花了大约三周。最大的体会倒不是注意力机制本身有多神奇,而是“轻量”两个字在遥感任务里确实有不可替代的价值。分辨率一上去,任何一点计算量的浪费都会被放大;反而是那些有明确分工、能精确定位到问题本身的结构设计,才能真正改善结果。
如果让我给刚接触这个方向的人一个建议:先别追求加多少模块,先看你的数据集里漏检最多的是哪一类目标,是纹理不清的小目标,还是语义模糊的大目标。前者优先注入主干浅层和中层的 LWGA,后者则重点放在主干深层和颈部融合层。确认瓶颈在哪里,再去动网络结构,永远比盲目堆模块有效。