ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

YOLO11-MAFPN:面向无人水面航行器的多尺度自适应目标检测方案

YOLO11-MAFPN:面向无人水面航行器的多尺度自适应目标检测方案

无人水面航行器(USV)的目标检测,跟常规的地面视觉任务完全不是一回事。去年我在岸边调试一条感知链路,最初用的就是YOLO11默认配置,后来沿着特征融合做了几处改动,才慢慢形成了YOLO11-MAFPN这套方案。回头写这篇帖子,是因为那段时间踩的坑挺典型,而且水面目标检测的资料确实分散,多数人照着通用检测的教程做,一上船就翻车。这篇文章不打算写成论文复现报告,而是记录我从问题定位、结构改动、训练细节到实船部署的完整过程,给做水面感知或者打算在USV上落地视觉算法的朋友一个能直接参考的路线图。

1. 水面目标为什么难检测:三个让人头疼的现实问题

很多人一听说无人水面航行器检测,第一反应是“不就是小目标检测吗”。这句话只对了一半。小目标确实是核心矛盾,但水面场景还有另外两个更隐蔽的问题:平台自身在晃,以及背景本身比目标更像目标。这三个问题叠加在一起,才导致通用目标检测模型在水上表现拉胯。

1.1 目标“小”不是唯一问题,运动本体也在“晃”

水面目标检测最直观的难点是目标尺度。一艘浮标在远端可能只有十几个像素,甚至比通用数据集里的一个头盔还小。但如果你以为放大输入分辨率就能解决,那大概率会被现实教育一次。USV本身是浮在水面上的,波浪一起,镜头就跟着上下颠簸,画面里每一帧都存在不同程度的运动模糊;船体转向时,目标在图像里的移动速度又很快,这种模糊不是高斯噪声那种均匀干扰,而是目标边缘被“拖”成一片,模型很难用常规的纹理特征去抓它。

我当时的做法是把帧间隔拆开看,发现相邻两帧之间同一目标的位移经常超过十个像素,这在陆基固定摄像头场景里很难见到。目标尺度还在快速跳变:前一秒一个浮标占满画面,下一秒船转了个角度,它在图像里就缩成一个小点。通用检测模型假设训练数据里的目标尺度分布相对稳定,到了水上这种假设直接失效。所以单纯加高分辨率、加注意力模块,不一定能解决根本问题,真正要紧的是让网络在不同尺度上都能持续稳定地感知目标。

1.2 背景比目标更像目标:波浪、眩光、水花都是干扰

水面的背景复杂度经常被低估。我最开始跑了一批从岸边拍的巡航视频,发现检测器频繁把波浪纹理识别成前景目标。逻辑上也说得通:浅层特征对高频纹理很敏感,波浪有规律的明暗条纹,在特征层面和某些船体边缘极其相似。到了逆光时段,水面强反光会把目标的边缘信息直接冲掉,整个画面变成高光区一片白,模型这时候基本靠猜。

水花也是一个重要干扰源。船体航行时激起的白色浪花,无论从颜色还是形状上都和部分航行器目标非常接近。我在统计误检时发现,浪花误检可以占到总误检数的三分之一以上。还有一个冷门问题:水雾和雨滴附着在镜头保护罩上,会形成固定位置的模糊斑点,这些斑点对空间注意力模块影响特别大——注意力给它们赋予了较高权重,但它们是纯噪声。水面场景对视觉感知模型来说就是一个“背景强特征重叠”的战场,背景不是低纹理区域,而是具备高频纹理、高亮度、非刚性形变的复杂环境。

1.3 FPN的“长脖子”弊端:深层语义与浅层细节不可兼得

回到YOLO11默认的特征金字塔结构。它的脖子部分采用自顶向下的路径融合,把深层语义信息逐步传递回浅层,同时把浅层细节补充进去。这个设计在通用目标上很成熟,但对水面小目标存在一个天然矛盾:浅层特征空间分辨率高、边缘细节丰富,但语义抽象程度不够;深层特征语义强,但小目标的轮廓细节基本上已经在下采样过程中丢得差不多了。

你可以把默认的FPN理解成一条很长的人工通道:浅层细节要绕路经过多次特征变换才能到达输出层,而每一次3×3卷积和上采样组合,本质上都是对信息的一次“过滤”。小目标本身的可用像素点就少,在这种长距离传递里很容易被当成噪声清洗掉。我当时画过特征热力图,发现单纯做随机初始化训练的模型,其浅层特征在浮标位置确实有响应,但响应强度跟旁边波浪区域的响应差不了多少。这才是MAFPN需要动手改的地方:与其让特征在长长的通路里“翻山越岭”,不如直接提供一条更短的路径,把细节信息在多个尺度上做双向补充。

2. 引入MAFPN:在YOLO11颈部做的三处关键结构改动

MAFPN全称按我的理解可以展开为Multi-scale Adaptive Feature Pyramid Network,翻译过来就是多尺度自适应特征金字塔网络。它并不是推翻FPN重新设计,而是在YOLO11原有基础上加了三个针对水面场景的改动:浅层细节补强旁路、轻量注意力模块、输出端尺度解耦。下面一个一个说清楚改了什么、为什么这么改、代价是什么。

2.1 给浅层增加一条“细节补强旁路”

第一个改动是给颈部加一条浅层旁路。具体实现上,取骨干网络输出的第二个阶段特征图,记为S2层,它的分辨率通常是输入图像的1/4或者1/8,小目标的轮廓信息主要集中在这里。我先用一组3×3卷积把S2特征图的通道数压缩到一个合适的中间维度,然后把它直接插入到后续每一级融合节点的输入里,跳过了中间几次高倍下采样带来的信息损失。

这个改动的本质是提供一条“短接线路”。原来一条浮标轮廓信息要从S2层一路反反复复变换才能到达输出层,现在它可以直接从旁路插到最接近检测头的位置,路径缩短,细节保留自然就好很多。这里有个工程上的取舍:S2层分辨率高,特征图尺寸大,如果把通道维度搞得太高,显存占用会迅速上升。所以旁路的通道数我控制在64到128之间,配合1×1卷积做特征压缩,确保整体计算量增加不超过原模型的5%。

这份改动后来在消融实验里成了收益最稳定的一项,后面我会单独讲数据。它的可贵之处在于不依赖复杂训练技巧,纯粹是信息流路径的优化。如果你只是在默认YOLO11上想先做一个低成本改动,这条旁路是最值得先试的。

2.2 轻量注意力模块:不是所有通道都值得被同等对待

第二个改动是加一个轻量注意力模块。水面场景里,不同颜色、不同材质的特征在不同光照下的重要性差异很大。比如晴天时颜色信息很可靠,逆光时颜色信息几乎失效;波浪区域的高频纹理有时候是噪声,有时候又恰好是目标边缘。如果不加选择地把所有通道都交给融合层去处理,卷积网络往往会平均用力,导致真正有辨识力的特征淹没在大片无效响应里。

我采用的是一个两步式注意力计算。第一步是通道注意力:对特征图做全局平均池化,把每个通道压缩成一个标量,再经过两层映射生成通道权重,让网络学会“关注哪些颜色和纹理”。第二步是空间注意力:在通道维度上做均值折叠,得到一个二维的空间权重图,相当于告诉网络“关注画面里的哪些位置”。两个权重图先逐元素相乘,再与原特征图相加,形成最终的加权特征。

这一步的设计原则是轻量。我试过把通道注意力和空间注意力做成复杂的前后串联结构,结果在逆光片段上出现了明显的训练震荡,收敛反而不如简单结构。所以最后保留的是并联相乘的形式,参数量增加控制在十分之一以内。从效果上看,这个模块主要提升了误检抑制能力:波浪区域的响应被压下去了,而真正浮标和船舶所在区域的响应被保留。也就是说,它不是帮你找到更多目标,而是帮你少把背景当目标。

2.3 输出端按尺度“分权”一样可以涨点

第三个改动放在检测头之前。原版YOLO11会把三个不同尺度的特征层分别送入三个检测分支,处理不同大小的目标。但在水面场景中,尺度跳变极其频繁,有些目标在两个尺度层之间都很“接近”,假如让网络死板地按尺度切分,容易出现小目标层不够细、大目标层不够大的尴尬。

MAFPN在这里加了一个尺度解耦模块。简单说,先把三个特征层分别做一次1×1卷积,生成各自的对齐表示,然后用一个softmax操作在通道维度上计算三层特征的融合权重,再让分类分支和回归分支各自使用一份经权重重组后的特征。这样网络可以在优化过程中自己决定:对某一个特定目标,我更信任哪个尺度层的特征。其实就是“分权”,把原来硬性分配的尺度归属变成了软性选择。

这个改动对远近距离交替出现的水面场景帮助明显。测试时有一段模拟视频里,同一个目标从远端靠近再驶远,尺度变化覆盖了三个特征层。默认结构一直在“切换分支”,而改动后的结构在切换过程中更加平滑,定位框的抖动明显变小。代价是训练前期的收敛速度稍慢,需要配合更长的warm-up阶段,这个问题在训练部分会提到。

3. 训练阶段的细节,比网络结构更影响精度

结构改完之后,如果你直接拿默认参数去训练,效果大概率会打折扣。我训练YOLO11-MAFPN的最大体会是:在USV这种场景下,训练策略对最终精度的影响不亚于结构本身。损失函数、数据增强、超参数乃至NMS参数,每一项都值得单独调一轮。

3.1 损失函数调整:接受正负样本极度不均的现实

水面图像里,目标区域占比非常小。我统计过一个典型批次,一幅1280×1280的图像中,全部标注框的面积加一起可能只占整幅图像的2%以下。也就是说,模型在训练中看到的大多数像素都属于背景。这时候如果沿用默认的分类损失,模型会被大量容易区分的背景样本带着走,很难关注到困难正样本。

我的解决方案是在最后两个阶段的分类损失里引入Focal Loss的思想,对易分类样本降低权重,让模型把注意力放在那些难分的目标上。回归损失部分保留CIoU的变体,同时在计算损失时加入一个按目标框面积调整的权重系数:面积越小的目标,其回归损失权重越高。这个处理直接针对水面小目标漏检问题,实测下来小目标类别的召回率提升最明显。

另外一个细节是标签平滑。水面场景的标注质量参差不齐——一个几十像素的浮标,不同标注员标出来的框可能相差两三个像素,这在高分辨率输入下会被放大。我在分类损失里加了很小的标签平滑系数,防止网络对标注噪声过拟合。需要注意的是,损失函数的改动不要和结构改动一起上。如果你同时改了注意力模块和损失函数,出了性能波动你就不知道是谁的问题。我的顺序是先把结构调稳定,再单独调损失,每一项改动都跑一轮完整训练验证。

3.2 用“合成+翻转+逆光模拟”把数据量翻一倍

水面数据集的公开资源远不如陆基视觉丰富,大多数团队都得靠自采。但自采数据有一个特点:往往集中在一段晴好天气里,目标类型和光照条件都很单调。这样的训练集学出来的模型,阴影、逆光、雨雾一折腾就废。

数据增强方面有几个值得注意的做法。水平翻转是我常用的,但垂直翻转坚决不用——水面和天空的方向关系一旦被破坏,网络会学到错误的空间语义。亮度扰动和对比度扰动是必须的,它能模拟从日出到正午再到傍晚的光照变化。更有效的还有逆光模拟:我在图像上生成一个非均匀的亮度掩膜,把画面局部提亮,同时叠加少量高斯噪声,让模型学习“即使看不清边缘,也能靠色差和上下文判断出目标位置”。

复制粘贴增强也是一个涨点利器。从同一批数据里裁出不同场景中的目标,贴到当前画面的背景区域,合称copy-paste。这个操作对小目标特别管用,因为它可以在不改变目标几何形状的情况下,人为增加目标数量。我在实践中发现,粘贴位置要避开已有目标的附近,否则两个目标重叠会造成混乱标签。马赛克增强也有用,但它会让小目标被裁切掉一半。如果你正在用小目标为主的数据集,马赛克增强不宜开得过大。

训练配置上,我最终采用的是图像输入1280×1280分辨率,300轮完整训练,前50轮用warm-up让注意力模块先稳定,之后学习率从1e-4开始余弦退火。如果显存不足,可以先按640分辨率训练前200轮,再把输入切到1280微调,精度差距通常可以缩得很小。

3.3 一个容易被忽略的超参:置信度阈值和NMS的联动

很多人在模型训练完之后,直接默认置信度阈值0.25,IOU阈值0.45,然后上船测试。水面场景这样搞会吃大亏。因为水面阴影和浪花在NMS之前会给出不少高置信度的假正样本,如果阈值设置不当,光调结构根本解决不了“纵轴误检密集”的问题。

我的经验是先调NMS的IOU阈值,再调置信度阈值,顺序不能反。水面目标尺寸小、间距近,默认的0.45在浮标密集区域容易把两个邻近目标合并成一个框。把IOU阈值降到0.35左右,可以避免过度合并,代价是可能出现少量重复框,这时候再把置信度阈值适当提高到0.5,既能压住浪花误检,又能保留较稳的召回。如果你更看重高召回,置信度阈值可以维持在0.3附近,但IOU阈值必须往下调。

这个“阈值联动”的综合调整通常能带来一到两个百分点的mAP50变化,而且完全不改网络结构。最隐蔽的问题是:很多人最后汇报精度时只提mAP,却不说明用的是哪套阈值。实测下来阈值不同,同一模型在整个测试集上的表现可以相差一个档次。所以任何对比实验,务必统一后处理参数,否则结论不可信。

4. 消融实验数据:看看到底哪些改动在起作用

结构改了、训练策略也调整之后,关键是搞清楚每一项改动到底贡献了多少。我搭建了一套比较完整的消融实验流程,每一步都在相同的数据集、相同的训练配置和相同的后处理参数下进行。这里给出我手头数据上的结果,先声明:这是我在自建水域数据集上的实测,换一套数据绝对值会有出入,但相对涨幅趋势大概率可以参考。

4.1 改动项整理和逐项收益

先把几个实验配置说清楚。基线模型是YOLO11n加默认特征金字塔结构,训练配置与MAFPN完整版完全一致,保证可比性。测试集包含晴好天、逆光、薄雾三类场景,目标类型主要是浮标、航道标识、小型船舶。评价指标使用mAP50、mAP50-95、模型参数量和单帧推理耗时。

结构变体mAP50mAP50-95参数量(相对基线)单帧推理耗时(相对基线)
基线YOLO11n0.8120.513100%100%
加入浅层旁路0.8310.523103%102%
加入注意力模块0.8430.531104%104%
加入尺度解耦0.8510.538105%106%
完整YOLO11-MAFPN0.8560.543107%108%

从表里看,浅层旁路带来的提升约1.9个点的mAP50,注意力模块进一步贡献了约1.2个点,尺度解耦大约贡献0.8个点。完整版相比基线提升了4.4个点的mAP50,参数量增加7%,单帧推理耗时增加不到10%。这个开销换来小目标召回率明显上升,在嵌入式设备上是可以接受的。

需要特别说明的是,mAP50-95的涨幅比mAP50温和,这是因为水面数据里大量小目标的定位精度本来就很难达到高IoU标准。如果你在论文或项目汇报里只放mAP50,可能会高估模型的实际定位能力。把两个指标放在一起看,才能客观判断结构改良的效果。

4.2 为什么“浅层旁路”收益最稳,其他模块有坑

在消融实验里,浅层旁路是每次跑都会带来稳定提升的改动。原因也很直白:它不是去“教会”网络什么,而是把本来就有用的信息用一条更短的路传递到了输出端。这属于架构层面的优化,不依赖于网络是否见多识广,也不依赖特定数据分布。无论晴好天还是逆光场景,这条旁路提供的轮廓细节都对最终检测有利。

注意力模块的收益相对温柔,但它有一个很典型的坑:不能重复堆叠太多。我在实验里试过在多个融合节点都加入双分支注意力结构,训练损失前期下降很快,中后期就开始震荡,最后收敛效果反而不如只在关键节点放置一次。我怀疑原因是重复堆叠注意力容易让特征图过度平滑,损失掉高频边缘信息,这在小目标检测里尤其致命。所以如果你也想加类似模块,牢记“轻量”两个字,加在关键路径上即可,别追求数量。

尺度解耦模块的坑则体现在训练收敛稳定性上。不加warm-up直接把学习率开到默认值,前30轮会出现剧烈的loss波动。原因大概是输出端的权重重组改变了分类和回归分支的梯度分布,网络的优化面发生了变化。我把warm-up阶段拉长到50轮之后,波动基本消退了。这个模块的加分幅度不算最大,但它与水面目标的尺度跳变契合度最高,当你想应对“远中近目标交替出现”的场景时,它的价值会凸显出来。

4.3 一个真实现象:mAP涨了,漏检却多了?

消融实验里有一个让我记忆很深的现象:某一版结构调整后,整体mAP50涨了,但我拿实际巡航视频验证时发现,远端极小浮标的漏检数反而增加了。原因是mAP计算时,所有尺寸目标一起算平均,如果中等目标和大目标的检测结果大幅改善,小目标的退步会被平均掩盖掉。如果你只盯总指标的涨跌,很容易得出“结构有效”的错误结论。

后来我强制要求自己按目标尺寸拆开统计。具体做法是参照通用目标检测的划分规则,依据标注框面积把所有样本分成小目标、中目标和大目标三组,每组单独算AP和漏检率。这一拆就暴露了问题:有的改动对中大型目标增益明显,对小目标几乎没有改善甚至略有损害。这也解释了为什么在实船场景里,模型明明在指标上更好看了,操作员却抱怨“远处的关键浮标开始丢了”。

所以我要特别建议:水面目标检测的评估报告,不要只写一个mAP。至少拆成AP-S、AP-M、AP-L三档,再统计一个“远端小目标漏检率”,也就是最小像素范围内的目标没有被召回的比例。你后续做的任何结构改动,都要用这些尺寸拆分数据来验收,而不是拿平均值自欺欺人。

5. 从岸上实验室到实船环境:部署与验证的碎碎念

模型在离线测试集上刷高分为“能检测”,真正上船稳定工作才是“好用”。从实验室到实船部署这段路,我遇到了不少只在推理环境里才会暴露的问题。模型转换、嵌入式资源限制、实船动态工况下的误检控制,每一项单独拎出来都够写一篇长文。这里挑几个最典型的展开。

5.1 转模型格式遇到的第一批坑:算子不被支持、精度波动

YOLO11-MAFPN在训练框架里跑通之后,第一件事是把它导出为标准推理格式。这个过程大部分人都会碰头:自定义注意力模块里的一些操作,在转换时不被标准算子集支持。我的做法是在导出前把注意力模块内部的计算重写,用最基础的多维矩阵乘法、加法、归一化操作进行等价替换。看起来是在“把简单问题复杂化”,实际上是为了避开那些冷门的融合算子,让部署环境能直接执行。

另一个坑是低精度推理。一般为了让嵌入式设备跑得更快,很多人会把模型转成FP16甚至更低精度的格式。水面反光场景和一般室内场景不太一样,高亮区域在低精度下会产生更大的数值波动。我在FP16推理时发现,个别逆光帧的检测框会出现跳变,同一个目标在相邻帧里一会儿被识别成船舶一会儿被识别成浮标。后来我保留FP32格式备份作为对照,一旦发现问题就来回比对,确认是精度问题还是模型本身的问题。

在嵌入式设备上,完整的YOLO11-MAFPN在桌面级GPU上跑很轻松,但挪到边缘设备后单帧推理时间接近120ms。这个速度对防碰撞类应用来说只能算勉强。如果要做实时避障,必须叠加脉冲式推理策略,也就是每隔几帧跑一次检测,中间帧用跟踪算法补位。结构改良带来的精度提升,在算力受限环境下会部分转化为帧率压力,这一步需要提前评估。

5.2 水面回波、雨滴、飞沫:误报过滤要在系统层面解决

模型上船之后,新问题层出不穷。镜头被浪花打湿后,画面上会出现固定位置的大块模糊,检测器会把水滴的圆弧边缘当成目标轮廓。岸边建筑的倒影在水面上轻微晃动,和真实船体在特征上非常相似。这些误报如果只靠模型结构去解决,会陷入无休止的路:压掉一种误报,保不准另一种误报又冒出来。

我最终的方案是把后处理从“一帧独立判断”改成“时间序列投票”。具体做法是维护一个滑动的五帧窗口,检测框在同一位置连续出现三帧以上才输出有效目标,单帧偶发的检测结果直接丢弃。这个机制对浪花误检和飞沫干扰效果很好,因为背景类的误检往往不稳定,而真实目标在连续帧间的位置变化是有规律可循的。

同时,置信度阈值不要固定死。水面环境照度变化极大,固定阈值在正午和傍晚表现完全不同。我写了一个简单的环境亮度估计逻辑:统计图像平均亮度,逆光时自动降一点置信度阈值,浪花大时自动升一点阈值。这个自适应规则总共不到几十行代码,但在实船长期运行中带来稳定性提升相当显著。

5.3 给也想试的朋友的建议:改动顺序比模块数量重要

如果你正准备在一个USV感知项目里尝试YOLO11-MAFPN或者类似思路,我的建议是先别急着把三处改动全堆上去。先保证你有一份干净、覆盖面广的水面数据集,这句话说了很多遍,但确实是决定成败的关键。用YOLO11默认结构先跑出一个基准结果,然后只加浅层旁路,看涨点是否稳定,接着再逐步加注意力模块和尺度解耦。每一步都要完整训练并做尺寸分组评估,才能真正知道你的场景吃哪一套。

结构改完之后,一定要做回归测试。拿那些原模型能稳定检出的目标,一段一段视频去对比新模型是否出现新增漏检。结构改良经常像跷跷板:小目标好了,大目标可能略受影响;近处好了,远漏检可能变多。没有回归测试的模型改动,就算整体均值涨了也不敢上船。

就我自己现在的使用习惯来看,MAFPN里三处改动中浅层旁路是真正的性价比之王,注意力是掉点最容易被高估的模块,尺度解耦则是对付尺度跳变的特殊武器。如果你时间有限、资源有限,浅层旁路加一套好的训练策略,很可能就已经解决了你水面数据上大半的漏检问题。结构之外的训练细节和部署后处理,反而会决定你这个模型在实船环境里能用多久、稳不稳。先拿到干净数据,把结构改动一项一项做扎实,再谈“创新”二字,这是我这次项目下来最深的体会。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进