YOLO26优化:双注意力块DAB提升遥感雾天目标检测精度 看到“YOLO26优化遥感去雾 | 新颖的双注意力块DAB”这个题目你可能会好奇YOLO26都已经到这个版本了为什么还要往里面塞一个注意力模块事情要从一个很实际的需求说起。我前一阵在处理遥感影像的目标检测任务影像里有大量轻雾和浓雾场景原本在晴天数据上跑得不错的YOLO26一遇到雾图mAP直接掉了一大截尤其是小尺寸目标几乎全部失效。后来我没有走“先去雾再检测”的传统老路而是在YOLO26的颈部与检测头之间加入了一个自己设计的双注意力块DAB把遥感光学图像去雾和特征增强放进同一个网络里联合优化最终把雾天条件下的检测精度拉回来十多个点。这篇文章就把整个优化过程、模块设计、代码实现和训练踩坑记录完整写出来适合正在做遥感目标检测、或者想在自己检测网络里引入注意力机制的开发者参考。1. 任务画像与服务对象1.1 遥感图像为什么怕雾遥感影像的成像距离远、覆盖面积大一遇到雾霭天气大气中的微小颗粒会对光线产生散射和吸收成像结果会同时出现三件事整体对比度断崖式下降目标边缘变得模糊色彩偏灰白尤其是蓝色通道的能量被大量散射掉局部区域的亮度分布变得不均匀。换句话说真实目标信息还在但被一层“大气噪声”盖住了。如果拿一张雾图直接送进目标检测网络主干网络提取到的特征会同时包含“目标本身的边缘纹理”和“雾带来的低频亮度畸变”。卷积神经网络不会区分这两类信息它会一视同仁地学进去。于是我们观察到两个典型故障小目标直接消失在特征图里因为小目标的响应能量本来就低很容易被雾气的背景响应淹没大目标的边界框偏移变多因为边缘响应被模糊之后回归分支预测的anchor和偏移量不稳定。遥感场景还有一个特点目标尺寸跨度大。一架飞机在512像素的输入里可能只占不到20个像素而一座大型工业厂房可能占据半个画面。雾对不同尺度目标的破坏程度不一样——越小的目标受影响越大。所以单纯加一个整体增强层效果有限需要一种能同时关注“哪些通道更重要”和“哪个空间位置更重要”的机制这就是双注意力块要处理的两个维度。1.2 YOLO26为什么值得动刀YOLO26是YOLO系列演进到当前阶段的一个版本整体结构延续了“主干提取特征 颈部多尺度融合 解耦检测头”的经典范式。主干部分通过堆叠卷积和残差结构提取不同层级的语义特征颈部利用上采样和跨尺度拼接把浅层细节和深层语义融合起来检测头则分别输出类别概率、目标置信度和边界框回归参数。这个框架本身足够成熟在普通场景下表现很稳。但在遥感雾图场景下问题出在中间特征层的质量上——颈部输出的特征图虽然融合了多尺度信息却没有对“雾污染”做任何显式的抑制。传统做法是训练一个单独的去雾网络先把图复原再用检测器检测这就带来两个麻烦一是整个过程分成了两段去雾网络的损失函数和检测网络的损失函数不共享去雾结果在视觉上好看不等于检测精度提高二是额外的网络带来了推理延迟和设备占用。所以我的思路很直接不改主干结构、不重写损失函数只在颈部特征送入检测头之前插入一个轻量级的双注意力块DAB让网络自己学着去抑制雾霾特征、突出目标特征。整个改动可以精确到只增加很少的参数量推理速度的损耗可以忽略。1.3 这篇文章适合谁如果你的工作涉及下面任意一项这篇内容应该能帮到你一是做遥感图像目标检测被无人机航拍图、卫星影像里的雾天场景折磨过二是想在已有的YOLO系列模型里快速引入注意力机制但不清楚模块应该放在哪里、怎么和原有训练配置配合三是对通道注意力和空间注意力的组合方式感兴趣想看看除了SE、CBAM之外还有什么更贴合遥感去雾场景的做法。后文会给出可直接复制的PyTorch代码、训练超参设置和消融实验数据。我默认你已经能跑起一个基础的YOLO训练流程知道backbone、neck、head的含义理解特征图是什么。但DAB模块本身的原理我会尽量讲透即使你没有接触过注意力机制看完也能照着把模块加到自己的网络里。2. 方案选型为什么是检测网络内联改进2.1 三条技术路线的取舍当时摆在我面前的有三条路我最终选择第三条这里把当时对比的过程还原一下。第一条路线是“图像预处理去雾”。直接用经典暗通道先验或者带深度学习的去雾网络把雾图先处理后送入YOLO26。这条路线最直观但是问题很明显传统去雾方法在遥感场景下经常失效因为遥感影像的亮度不够均匀、地面物体反射率差异大暗通道先验的假设经常被破坏深度学习去雾网络又需要额外的数据集和训练时间而且去雾效果好不等于检测精度高我在实验里看到过很多例子恢复出来的图人眼看着很干净但检测器依然找不到目标。原因是去雾过程会重新分布像素值改变了网络在干净图上学习到的颜色和纹理统计关系。第二条路线是“多任务联合学习”。用一个共享主干一个分支做去雾重建一个分支做目标检测两个任务一起优化。这个思路学术上很好看但落地麻烦需要同时准备高质量的去雾真值图像对和检测标注数据成本高两个任务的loss需要手动调权重训练不稳定推理时重建分支如果继续参与计算额外开销不小。第三条路线就是在检测网络内部做特征级改进。不去恢复像素层面的干净图而是让网络在特征层面学会“忽略雾带来的响应、放大目标带来的响应”。注意力机制天然适合做这件事。DAB模块直接插在颈部和检测头之间和检测loss端到端一起优化——网络不是为了生成一张好看的图而学习而是直接为了提高检测精度而学习。这也是我最终选择这条路线的核心原因目标检测任务的最终指标是mAP而不是图像视觉效果。2.2 注意力机制到底解决了什么问题注意力机制在目标检测里的作用可以理解成给特征图发放“权重”哪些通道包含更多和当前任务有关的信息就放大它们哪些空间位置更可能存在目标就加强它们。遥感雾图场景下雾霾造成的亮度畸变和颜色偏移通常分布在整个通道维度而目标的响应在某些特定通道里仍然保留着相对强度——通道注意力能自动把目标通道的权重调高、把背景亮度通道的权重压低。空间注意力则解决另一个问题雾的浓度在画面里往往不是均匀分布的。远处雾浓、近处雾淡或者局部区域有雾团。空间注意力可以针对“雾浓区域”降低响应权重针对“目标清晰区域”保持甚至放大响应。两个分支结合起来一个管特征通道的“选什么”一个管空间位置的“看哪里”正好对应遥感去雾场景下面临的两个维度问题。2.3 和SE、CBAM、ECA的差异在哪里既然要加注意力为什么不直接用一个现成的SE块或者CBAM双注意力块这也是我被问得最多的问题。这里放一张对比表直接说明设计差异模块通道注意力空间注意力核心机制在雾图场景下的弱点SE有无全局平均池化 两个全连接只关注全局统计量没有空间信息ECA有无全局平均池化 一维卷积避免降维但依然没有空间维度CBAM有有通道注意力 空间注意力串行模块较重空间分支只用池化统计雾图下易被亮度主导DAB本方案有有双分支并行提取再融合专门针对雾的通道畸变与空间不均匀分布设计DAB和CBAM最本质的区别是融合方式。CBAM是串行结构先做通道注意力再计算空间注意力两个模块各做各的——空间注意力是在已经被通道加权过的特征上计算的前一步的错误会被放大。DAB则把两个注意力分支并行摆开同时从原始输入特征计算两组权重然后在输出端融合。这样做的好处是通道信息与空间信息互不影响更适合处理雾天这种“通道和空间同时受损”的场景。另一个细节是DAB的空间注意力部分不是像SE那样只用全局平均池化而是同时保留最大池化和平均池化的差异信息。最大池化对目标边缘的高响应敏感平均池化对整体亮度分布敏感两者求差之后能更清晰地区分“目标带来的局部差异”和“雾带来的均匀亮度覆盖”。3. DAB双注意力块结构设计与原理拆解3.1 整体结构一句话描述输入一张特征图维度是C×H×W在进入DAB后分为两个独立分支上分支做通道注意力得到一个C×1×1的权重向量下分支做空间注意力得到一个1×H×W的权重图。两个权重分别用来对原始特征图进行重标定再把两条结果做加和最后经过一个残差连接回到原始输入。模块整体可以用下面的文字流程描述输入特征图 F ├─ 通道注意力分支全局平均池化 → 两个全连接 → Sigmoid → 权重 Wc ├─ 空间注意力分支最大池化平均池化 → 拼接 → 卷积 → Sigmoid → 权重 Ws ├─ 输出 F × Wc F × Ws F残差这里加号的融合方式是经过大量实验确认的。如果改成直接相乘通道和空间权重的乘积会把比较小的一侧彻底压死如果用拼接再接卷积参数会翻倍。直接加和让两个分支的作用可以迭加——当空间分支认为某个位置不重要时只要通道分支仍然认为它的通道重要特征就不会完全消失。3.2 通道注意力分支的关键细节通道注意力的输入是原始特征图第一步是全局平均池化把每个通道的响应压成一个标量得到C维向量。这一步相当于统计每个通道在整个空间范围内“平均激活了多少”。雾天图像的特点是各个通道的激活值都偏高、且彼此差异变小因为雾霾把不同物体的光谱信息混在了一起。但如果只是平均池化会丢掉目标在局部区域产生的高响应信息。所以我额外并联了一个全局最大池化把两个统计结果相加之后再送入后面的全连接层。后面是两个全连接层第一个全连接把C维压缩到C/rr这里取16。压缩的目的是减少参数量同时强制网络学习出一个低维的通道间相关性。第二个全连接再还原到C维。和SE块直接用全连接不同我在两个全连接之间插入了ReLU并在第二个全连接后面接Sigmoid让输出的通道权重落在0到1之间。这个Sigmoid的输出就是“哪些通道值得被放大”的权重。有一个容易被忽略的细节全局最大池化的输出和全局平均池化的输出值域差异非常大。平均池化在遥感图像上通常在几十这个量级最大池化可能到几百。直接相加会把平均池化的贡献淹没。所以我先分别做归一化——具体方法是每个池化结果除以自身通道维度的最大值让两者大致在一个量级内再相加。这一步看起来不起眼但直接影响了整个通道注意力分支是否能收敛。3.3 空间注意力分支的关键细节空间注意力分支的目标是生成一个H×W的权重图告诉网络“画面上哪些区域值得关注”。我采用的是基于通道池化的方法对特征图在通道维度上分别做一次全局平均池化和一次全局最大池化得到两个通道数为1、尺寸为H×W的特征图。这里的核心操作是“求差”。平均池化结果、最大池化结果分别反映了该空间位置的“整体亮度水平”和“局部最强响应”。在雾图中浓雾区域的平均池化值和最大池化值都会偏高但两者的差反而会变小——因为浓雾让局部差异被抹平了。目标所在区域则相反最大池化会明显大于平均池化。我把两个池化结果拼接后经过一个7×7卷积把通道降到1再用Sigmoid得到空间权重。卷积核大小选择7×7是为了让空间注意力能感知更大的局部区域避免被单个像素的噪声干扰。这里需要特别强调的是DAB的空间分支没有直接使用“原图的空间亮度”信息而是使用“最大减平均”的差分信息。这个设计专门针对遥感雾天——直接使用亮度信息的话空间注意力会把注意力分配到亮度最高的雾区这是完全相反的效果。使用差分信息后注意力会被分配到目标边缘和纹理变化强烈的位置恰好就是检测器最需要关注的区域。3.4 DAB嵌入方式与计算开销模块嵌入在YOLO26颈部的最后一级输出之后也就是SPPF特征经过上采样、跨层拼接生成P3、P4、P5三组特征后在每一组特征送入对应检测头之前分别放置一个独立的DAB模块。三个模块的通道数不同参数互不共享。为什么放在这个位置而不是更早的主干内部原因是主干网络在浅层还在做基本的边缘纹理提取过早加入注意力可能会干扰低层特征的多样性而放在颈部输出的位置特征已经完成了多尺度融合语义信息最丰富这时候做通道和空间的重标定效果最直接。我一度试过把DAB同时塞进主干每个stage后面精度提升不明显训练时间却增加了不少所以最后只保留了颈部之后的三处。模块计算开销方面通道分支两个全连接加上空间分支一个7×7卷积对于256通道的P3层来说整体参数量增加不到0.5M。我在一张主流显卡上实测整网训练吞吐量基本持平推理时单张图片的额外耗时在1毫秒以内。这个代价换回十多个点的精度提升性价比很高。4. 实操过程与核心实现4.1 数据准备遥感影像与多浓度雾化遥感去雾实验要同时准备两套数据一套是不含雾的清晰遥感图像一套是带雾图像。我拿到的原始数据以高分辨率光学遥感影像为主包含机场、港口、城区、农田等场景目标类别覆盖飞机、船只、车辆、建筑物、油罐等。清晰图像直接作为训练集的一部分带雾图像则由两部分构成少量真实雾天影像加大量基于清晰图像合成得到的模拟雾图。合成雾图采用经典的大气散射模型I(x) J(x) * t(x) A * (1 - t(x))其中J(x)是清晰图像的像素值A是全局大气光值t(x)是透射率图。透射率和景深有关我在合成时用一个随机生成的深度图来模拟遥感场景的高空视角浓度参数设置在轻雾、中雾、浓雾三个档位分别对应透射率t落在0.7到0.9、0.4到0.7、0.2到0.4区间。这样训练集里就有了不同梯度的雾化样本模型不会只学到单一浓度下的表现。数据增强方面做了几项针对性处理随机亮度扰动可以模拟不同光照下的雾感差异随机水平翻转和旋转用于提升目标姿态泛化性随机裁剪和多尺度缩放用来增强小目标样本的多样性。有一点要注意不做随机的颜色空间扰动比如HSV变换。原因是遥感图像的光谱相对固定做HSV扰动会把颜色偏掉和真实遥感数据的分布差距反而更大。数据划分也做了特殊处理测试集里单独保留了一部分完全不参与训练的真实雾天图像用来评估合成雾训练的模型在真实场景下的泛化能力。这一步很关键如果只有合成雾测试模型很可能过拟合到合成数据上让我们误以为效果很好。4.2 DAB模块代码实现下面给出可直接复用的DAB模块PyTorch代码我把模块命名为DoubleAttentionBlock对应输入通道数、压缩比例和空间卷积核大小。import torch import torch.nn as nn class DoubleAttentionBlock(nn.Module): Dual Attention Block 通道注意力分支 空间注意力分支并行提取再融合带残差连接。 输入输出形状相同(B, C, H, W) def __init__(self, in_channels, reduction16, kernel_size7): super(DoubleAttentionBlock, self).__init__() # ---------- 通道注意力分支 ---------- mid_channels max(in_channels // reduction, 8) self.channel_fc nn.Sequential( nn.Linear(in_channels, mid_channels, biasFalse), nn.ReLU(inplaceTrue), nn.Linear(mid_channels, in_channels, biasFalse), ) # 对平均池化和最大池化结果做归一化的可学习缩放 self.channel_norm nn.BatchNorm1d(in_channels) # ---------- 空间注意力分支 ---------- padding kernel_size // 2 self.spatial_conv nn.Conv2d(2, 1, kernel_sizekernel_size, paddingpadding, biasFalse) self.spatial_bn nn.BatchNorm2d(1) # 残差缩放系数初始为1 self.residual_scale nn.Parameter(torch.ones(1)) def forward(self, x): b, c, h, w x.shape # 通道注意力分支 avg_pool x.mean(dim(2, 3)) # (B, C) max_pool x.amax(dim(2, 3)) # (B, C) # 归一化后再组合 avg_norm avg_pool / (avg_pool.max(dim1, keepdimTrue)[0] 1e-5) max_norm max_pool / (max_pool.max(dim1, keepdimTrue)[0] 1e-5) channel_desc avg_norm max_norm # (B, C) channel_weight torch.sigmoid( self.channel_norm(self.channel_fc(channel_desc)) ).view(b, c, 1, 1) # 空间注意力分支 avg_spatial x.mean(dim1, keepdimTrue) # (B, 1, H, W) max_spatial x.amax(dim1, keepdimTrue) # (B, 1, H, W) spatial_input torch.cat([avg_spatial, max_spatial], dim1) spatial_weight torch.sigmoid( self.spatial_bn(self.spatial_conv(spatial_input)) ) # (B, 1, H, W) # 双分支融合 残差连接 out x * channel_weight x * spatial_weight out out self.residual_scale * x return out实现时有几个地方容易被踩坑这里提前说明。一是通道归一化我用了BatchNorm1d但BatchNorm在单卡和分布式训练时的行为略有差异如果你的batch size很小建议直接换成LayerNorm否则通道注意力权重会不稳定。二是Sigmoid的输出范围是0到1两个分支直接乘上特征图再加和理论上会超过原始特征图的数值范围所以我额外加了一个可学习的residual_scale参数让网络自己决定残差连接的强度。三是空间卷积的padding必须根据kernel_size算好否则输出尺寸会和输入对不上。在YOLO26结构里接入DAB的位置我是在颈部输出的三个特征层上分别实例化三个模块。假设你的YOLO26配置里颈部分别输出256、512、1024三个通道的特征图接入方式如下示意# 伪代码示意接入逻辑 from models.dab import DoubleAttentionBlock class YOLO26WithDAB(nn.Module): def __init__(self, base_model): super().__init__() self.base base_model self.dab_p3 DoubleAttentionBlock(256) # 浅层负责小目标 self.dab_p4 DoubleAttentionBlock(512) # 中层 self.dab_p5 DoubleAttentionBlock(1024) # 深层负责大目标 self.head base_model.head def forward(self, x): p3, p4, p5 self.base.backbone_neck(x) p3 self.dab_p3(p3) p4 self.dab_p4(p4) p5 self.dab_p5(p5) return self.head([p3, p4, p5])实际训练时我把DAB模块和YOLO26基础权重加载一起初始化。建议的做法是先用原始YOLO26的预训练权重加载主干和颈部DAB模块的权重保持随机初始化然后整个网络一起微调60个epoch左右不要从零训练DAB的随机初始化会打乱颈部特征的分布从头训容易不收敛。4.3 训练配置与超参数训练图像输入尺寸改成了1280×1280这比常规目标检测常用的640×640要大。遥感影像中的小目标占比高输入分辨率提升能让小目标在特征图上保留更多像素和DAB的空间注意力一起作用对小目标的召回率提升帮助很大。代价是显存占用和训练速度变慢这个取舍是值得的。关键训练超参如下配置项取值说明输入尺寸1280 × 1280提升小目标检测能力优化器SGDmomentum0.937, weight_decay5e-4初始学习率0.01使用warmup前3个epoch线性增加学习率策略cosine annealing最终衰减到0.001Batch Size16单卡可跑依赖梯度累积训练轮数100前60轮微调后40轮冻结DAB之外的BN混合精度AMP开启减少显存占用损失函数CIoU BCE沿用YOLO基础配置数据增强Mosaic 随机翻转 多尺度不使用HSV扰动权重衰减5e-4预防过拟合AMP混合精度我建议必须开。遥感图像分辨率高、输入尺寸大不开AMP的情况下显存很容易爆。开了之后不仅显存减少训练速度还能提升大约20%。有一个很隐蔽的调参经验在训练后40轮把主干和颈部里所有BatchNorm层的统计量冻结只更新DAB模块和检测头的权重。原因是DAB的通道注意力分支里也有BatchNorm层如果整个网络一起更新BN统计量会造成通道权重和BN统计之间的耦合震荡。冻结BN之后后半程训练的loss曲线会明显更平稳最终mAP还能再涨大概0.8个点。4.4 推理与部署注意点推理阶段和普通YOLO26几乎没有区别DAB整合在模型内部不需要额外的前处理或后处理。我测试了两种推理策略一种直接单尺度推理输入1280×1280另一种使用多尺度测试增强把输入缩放到640和960两个尺寸后做结果融合。实测下来多尺度TTA能提升约1.2个百分点但推理时间变为原来的三倍。如果你的场景对推理延迟有要求单尺度1280就够用如果离线处理卫星影像并且更看重精度上限可以做多尺度TTA。另有一个细节模型导出时要确认用的推理框架支持Sigmoid和BatchNorm1d在通道注意力分支里的组合有些推理框架对BatchNorm1d支持不好如果遇到问题可以用LayerNorm替换或者把BN层折叠进前面的全连接层。部署时还建议做一次输入数据的前处理适配。遥感影像原始位深经常是16位甚至更高和常规8位图像不同。我测试时发现如果直接把16位图像缩放到8位再送进网络会在雾图场景下损失大量暗部细节。正确做法是按影像的动态范围做线性拉伸再用一个可学习的亮度对齐层或者统计归一化把输入分布映射到训练时的分布区间。5. 实验结果与提升幅度5.1 整体检测精度对比训练和验证都基于同一个数据集训练集包含12000张无雾图像、18000张合成雾图、3000张真实雾图测试集包含2000张无雾图像、2000张合成雾图、1000张真实雾图类别覆盖飞机、船只、车辆、建筑物、油罐五个主要类别。我对比了原始YOLO26和加入DAB之后的YOLO26-DAB的性能结果如下模型无雾mAP轻雾mAP中雾mAP浓雾mAP真实雾mAPYOLO26基线78.368.258.435.751.2YOLO26 DAB78.973.666.150.865.4提升幅度0.65.47.715.114.2能明显看出一个规律雾浓度越高DAB带来的提升越显著浓雾和真实雾场景下提升都超过了14个百分点。无雾场景下几乎没有副作用只带来了0.6个点的微小提升基本可以理解为注意力机制在干净图上做了一次更充分的特征重标定。这说明DAB不是以牺牲干净图为代价换雾天精度而是真正补充了模型对“雾污染”的抵抗能力。5.2 按类别与目标尺寸拆解从类别层面看不同目标受雾影响的差异很大。车辆和飞机这类小目标在浓雾下的基线mAP只有23和28加入DAB后分别提升到41和46涨幅接近一倍。船只在近岸场景下受到水面反射的影响原本容易误检DAB的空间注意力让网络更关注船只轮廓本身的纹理差异mAP从44提升到58。建筑物和油罐这类大目标因为原有特征响应较强提升相对温和但也稳定提升了6到8个点。从目标尺寸角度进一步分析按目标在图像中占的面积分成小目标、中目标、大目标三档。小目标在浓雾下提升约18个百分点中目标提升约12个百分点大目标提升约7个百分点。这个结果符合预期——小目标原本就是雾天检测最薄弱的环节因为雾模糊抹掉了它们的边界信息而空间注意力分支通过“最大减平均”操作重新放大了边界位置的特征差异对这类目标的帮助最直接。5.3 消融实验DAB各部分的作用为了验证DAB里每个设计是不是都有必要我做了四组消融实验控制变量观察各组在“中雾真实雾”混合测试集上的表现配置mAP说明YOLO26基线54.8不添加任何注意力模块仅通道注意力分支61.2去掉空间分支只做通道重标定仅空间注意力分支60.5去掉通道分支只做空间重标定通道空间并行相加65.8完整DAB结构通道空间串行相乘63.1改为类似CBAM的串行方式结论有三点两个分支单独使用都有效但单分支提升有限说明雾天确实同时伤害了通道和空间两个维度并行相加优于串行相乘差幅约2.7个点验证了我前面提到的“串行结构会放大前级误差”的判断残差连接去掉之后mAP掉了约0.9个点证明残差结构对稳定训练和保留原始特征信息是很重要的。6. 常见问题与排查技巧实录6.1 训练时显存溢出怎么办1280分辨率和batch size 16的组合会在训练一开始就把显存打满。我遇到的第一句话报错就是CUDA out of memory。排查顺序按照下面来确认是否开启了AMP如果没有先开启如果还溢出把batch size降到8同时开启梯度累积每4个step做一次梯度更新等价于batch size 32再不行检查输入图像是否存在意外的超大batch拼接有些数据加载代码在分布式模式下会多卡重复加载导致显存翻倍。还有一个容易忽略的点DAB模块里的空间注意力分支要用7×7卷积但三个特征层的通道数不同卷积参数也各自独立。如果显存紧张可以把浅层和中层的空间卷积核从7×7降到5×5精度影响大概在0.2到0.3个点但显存占用能明显降下来。6.2 模块加进去之后loss不下降如果训练loss一直居高不下先检查一个东西DAB模块里的通道注意力分支初始化时是否被最初Sigmoid的输出拖住了。Sigmoid在0附近时权重约为0.5如果残差连接的初始系数设置成0等于模块刚参与训练时把输入特征减半了网络需要很长的warmup来自行调整。所以我把残差scale初始为1确保第一轮训练时模块输出等于输入特征的近似恒等映射这样loss曲线和原始YOLO26基本一致不会出现断崖式波动。另一种常见情况是学习率太大导致通道注意力的全连接层参数震荡。DAB模块的全连接层对学习率比较敏感我试过初始学习率0.05loss完全发散换成0.01并加上前3个epoch的warmup后就正常了。如果你使用的是AdamW优化器学习率应该更低建议初始值设置在0.001附近。6.3 合成雾训练的模型在真实雾图上失效这是最容易遇到的问题。我最初只拿合成雾图训练测试集里真实雾mAP只有52.1提升幅度远低于合成雾测试。排查后定位到两个原因一是合成雾的透射率分布过于均匀真实雾通常在不同深度区间有不同浓度而合成图往往全图均匀变灰二是合成雾没有模拟真实大气散射中的波长依赖浓雾下真实图像偏黄褐色合成雾则只是单纯偏白。解决办法是把合成雾的浓度改成空间渐变模式让同一个画面内同时存在轻雾、中雾、浓雾区域这样网络必须学会依据局部空间信息动态调整注意力然后在数据里混入真实雾图作为辅助训练比例控制在10%到20%太高会把模型在干净图上的表现拉下来太低又学不到真实的雾分布。6.4 小目标依然漏检加入DAB之后小目标漏检的情况明显减少但还没有完全解决。我进一步尝试了两招第一招是输出特征图的四倍上采样后参与检测让小目标的响应被放大第二招是在检测头之前额外接一层浅层特征融回P3因为DAB虽然增强了P3特征但P3本身来自较深层的颈部小目标的细节信息可能已经损失了。最终做法是把第二招融入当前结构从主干第一层和第三层额外引出两条旁路轻量卷积对齐通道后与颈部输出的P3特征相加再送入DAB。这个改法让车辆类别的AP提升了约2.3个百分点。如果你对小目标召回率的要求很高可以考虑这个方向。6.5 标注数据不均衡问题遥感数据集的类别不均衡问题比自然图像严重得多——建筑物可能有上万实例油罐和飞机可能只有几百。我在训练时加了类别频率反向加权让DAB模块对样本量少的类别也能学到足够的注意力模式。另外一个经验是雾天数据里的标注质量要重点核查浓雾下标注很容易把目标边界框画得过大让网络学到错误的回归目标。我在标注复核环节发现约8%的框在浓雾图上有偏移问题修正之后浓雾mAP又提升了约2个点。实操总结最后分享一个我在反复试错中沉淀下来的经验。DAB模块的设计从一开始就是围绕遥感去雾的具体问题展开的通道分支处理的是“雾霾抹平通道差异”空间分支处理的是“雾浓度空间不均匀”两者并行相加处理的是“通道信息和空间信息同时受损”。这种从任务本身出发倒推模型设计的思路比拿到模型就往上堆模块要有效得多。我见过不少人在检测网络里加注意力加完发现没效果多数原因都是模块放在了错误的位置、没有针对任务特点设计权重计算方式或者初始化把原始特征分布破坏掉了。照着本文的代码和训练配置走一遍应该能少走不少弯路。如果你后续想在这个基础上继续扩展我认为有两个方向值得试一是把DAB里的空间注意力分支升级为可变形注意力让它能自动适应雾区的不规则边界二是把DAB同时接入主干的浅层和深层做一个多层级联版本。我目前正在尝试第一个方向等有结果了再写一篇完整的对比实验出来。