news 2026/10/13 20:20:56

水下目标检测比赛实战指南:从数据清洗到模型部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
水下目标检测比赛实战指南:从数据清洗到模型部署

水下检测的比赛,我前前后后参加过几次,从第一次连榜单前二十都摸不着,到后来能稳定把名次刷进第一梯队,中间踩过的坑比想象中多得多。很多人一看“水下目标检测”这六个字,觉得不就是把YOLO换到水下数据集上跑一遍吗?真上手之后发现完全不是这么回事。这篇文章就把我最近一次参赛的全过程拆开讲一讲:数据怎么处理、模型怎么调、训练怎么稳、上线怎么快,以及那些比赛成绩单上不会写、但实际操作中极其关键的细节。

这篇内容适合两类人看。一类是准备参加水下目标检测相关比赛的同学,另一类是做工业水下巡检、水下机器人视觉方案的工程师,本质上大家面对的问题是同一个:图像质量差、目标尺寸小、标注噪声大、检测实时性要求高,把这些点一个个啃下来,成绩自然就上去了。

1. 赛题和数据:水下图像和普通图像到底差在哪

拿到赛题后我做的第一件事不是急着写代码,而是把训练集从头到尾翻了一遍。按时间排序、按类别排序、按清晰度排序、按颜色分布排序,翻完三遍之后,我对“水下图像”这四个字的理解彻底变了。

水下图像和常规自然图像最大的区别,不是简单“加了点蓝色调”,而是一个由物理过程主导的成像退化问题。水体对光有强烈的吸收作用,红光在很浅的深度就衰减得差不多了,剩下的主要是蓝绿光,所以水下图像普遍偏蓝偏绿,色彩信息严重缺失。同时水中悬浮的颗粒、浮游生物会造成光的散射,图像呈现一层雾霾感,对比度极低。再加上拍摄设备运动、水流扰动,图像往往带有运动模糊和轻微失焦。

这就带来几个非常具体的后果。第一,标注的质量参差不齐。很多目标在肉眼里都已经模糊成一团色块,标注者只能凭轮廓和经验去标,导致标注框边缘不齐、位置偏移、甚至漏标。第二,类别间的外观差异被削弱。海胆和石头在水下图像里长得非常像,颜色纹理都被水体抹平了,单纯靠RGB颜色特征很难区分。第三,小目标占比极高。水下生物往往距离相机较远,或者藏在缝隙里,大量目标在图像中只占几十个像素,用普通检测器根本抓不住。

我在赛前给自己定了三条数据层面的原则:先看数据再定方案,不迷信任何预训练权重,所有实验的基线必须能复现。

1.1 我如何处理训练集里的脏数据和噪声标注

水下数据集的“脏”是常态,关键是怎么在保持样本量的前提下把噪声的影响压到最低。

先做了一遍人工抽样检查。从每个类别里随机抽了几百张图,逐个看标注框有没有明显错位、有没有把一个目标拆成两个框、有没有大目标被截断成两部分。这一步很费时间,但值得做。查下来发现最大的问题不是漏标,而是“标过头”——因为图像模糊,标注者经常会把一坨珊瑚礁、一条鱼尾巴、甚至水里的一团气泡给框进去,这些噪声框混进训练集后,模型学到的是错误的边缘响应,推理时很容易把气泡、阴影误判为目标。

处理方式不是直接删样本,而是对训练集做了加权过滤。我写了一个简单的规则:计算每个标注框的置信度评分,结合图片清晰度、标注框与真实目标的交并比估算值,把明显低质量的样本从训练集主体中剔除,单独放在一个“难例低质集合”里。主训练集保持干净,低质集合用来做难例挖掘和二次微调。这样做的好处是既保留了数据量,又避免噪声直接冲击模型主干。

增强策略上,我没有用太多花哨的方法。水下图像的增强核心就两条:模拟退化、模拟色变。常规翻转旋转之外,我加了随机高斯模糊、随机亮度对比度扰动、随机色偏偏移,用来模拟不同深度、不同水质条件下的成像差异。有一点特别注意:不要用太强的饱和度增强,因为水下图像本来颜色就弱,强行提饱和会让模型误以为颜色是重要特征,反而拉低了在真实海底环境下的泛化能力。

另一个容易被忽略的点是图像尺寸。水下赛题的目标普遍偏小,很多人直接用640×640输入,结果小目标漏检严重。我在实验后把训练输入改成了832分辨率,推理时再配合多尺度滑窗,小目标的召回率提升非常明显。代价是训练显存占用变大,后面我会讲怎么用梯度累积和混合精度把训练成本压回来。

1.2 类别不均衡:不是所有类别都配拥有同样的待遇

水下比赛的类别分布通常很不均衡,有些常见物种占了训练集的一半以上,稀有物种可能只有几百个实例。如果不做处理,模型会对高频类过拟合,对低频类几乎失去检测能力。

我统计了一下训练集各实例数量后,做了三件事。第一,对高频类别做欠采样,比如把某常见类别的采样概率降低,避免它反复出现在每个batch里。第二,对低频类别做重复过采样,确保每一个稀有实例每个epoch至少能见几次。第三,按类别调整损失权重,低频类的loss权重拉高,让模型在优化时更倾向于学习这些类别的特征。

这里有个实操经验供参考:欠采样不要降得太过分,否则高频类会和低频类互相干扰,边界框回归反而变乱。我在调到高频类采样概率为原来的0.7、低频类补充采样到原样本量2倍左右的时候,各类别AP的均衡性最好。

2. 模型选型思路:为什么我最后没有盲目堆大模型

水下目标检测的模型选型,很多人一上来就追着大模型跑,觉得参数量越大、FLOPs越高,效果就一定越好。这次比赛我用了几组对照实验,结果让我把之前“大力出奇迹”的想法彻底改了。

模型的最终效果是数据集、算力、训练策略三者匹配的结果。水下数据集普遍不大,一个几千万参数的大模型在这种数据规模下非常容易过拟合,尤其是当训练集本身标注噪声很大的时候,大模型会更快地“记住”噪声而不是学习到鲁棒特征。更大的问题在于推理速度,水下机器人的实际应用场景对帧率有硬性要求,你总不能为了检测精度把机器人的巡航速度降到龟速。

我选型的思路是:以YOLO系列检测器作为基线,对比了不同规模配置。具体来说,我尝试了轻量级配置、中等规模配置、以及加重版配置三档。实验下来最意外的是:中等规模配置在验证集上的mAP明显高于加重版配置,而推理速度是后者的近两倍。主要原因在于数据量撑不起大模型的容量,大模型在训练后期开始震荡,验证集mAP不升反降。

于是我把实验重心放在了中等配置这个基线上,后续所有优化都围绕它展开。

2.1 训练时冻结主干:一个被低估的稳定策略

有一个在比赛里帮了我大忙的trick,说出来很简单:训练初期冻结主干层。具体做法是在前20到30个epoch里,把骨干网络前面的若干层参数固定住,只训练检测头和新加的部分层,等检测头基本收敛之后再解冻主干联合微调。

这个策略对两种场景特别有效。一是数据集和预训练域差异大的时候,比如我用的是自然图像预训练权重,直接全量微调可能导致主干的低级特征在早期被大量破坏,反而丢失了原有权重的通用表征能力。二是标注噪声大的时候,冻结主干可以让模型先稳定地拟合清晰目标,再慢慢适应噪声样本,避免了训练早期的剧烈震荡。

实测下来,冻结主干训练出来的模型,在验证集上比全量微调的模型mAP更高,而且训练过程平顺得多,batch loss曲线几乎看不到明显的尖峰。解冻后的最终收敛也更快,因为检测头已经处在正确的参数区间附近了。

2.2 检测头替换:从固定尺度到自适应多尺度预测

水下目标尺度差异极大,同一张图里可能同时有占满半个画面的近景鱼群和只有几十像素的远处目标。默认的检测头对不同尺度目标的适应性有限,尤其是极小目标,很多时候直接就被下采样过程给“抹平”了。

我在中等配置基础上做的一个关键改造,是把检测头换成支持多尺度自适应预测的结构。具体来说,在特征金字塔部分增加了针对小目标的额外预测层,也就是把骨干网络中更浅、分辨率更高的特征图接入检测头,专门负责小目标检测。同时给这个额外预测层配置了独立的下采样倍数和锚框尺度。

这个改动的效果非常直观。没改之前,小目标类别的AP低得可怜;改完之后,小目标的召回率大幅提升,整体mAP也跟着上了一个台阶。代价是计算量略有增加,但对比赛来说完全值得。

3. 训练策略:把每一轮epoch的收益拉满

模型结构定下来之后,训练策略就成了决定成绩上限的关键。这个环节我试过的东西非常多,真正留下来并且效果稳定的主要就那么几条,下面按重要性从高到低讲。

3.1 优化器、学习率和调度方式的具体配置

我使用的优化器配置如下:初始学习率0.01,使用余弦退火调度,带动量的SGD优化器。这个组合在水下数据场景下比AdamW更稳定。很多人误以为Adam系列一定是最好用的,但在检测任务里,带动量的SGD在长时间训练下往往能逼近更好的极小值,而且对学习率的敏感性相对低一些。

学习率我建议不要贪快。我见过有人把初始学习率设到0.1甚至更高,想让模型快速收敛,结果loss直接炸掉。水下数据集小,学习率太大必然震荡。我用0.01起步,配合余弦退火逐步降低,到训练末期学习率降到了初始值的约5%,模型基本收敛稳定。

batch size的选择上,由于显存有限,我的实际限制在中等规模。这个量级配SGD完全够用,关键是梯度保持稳定。如果显存不够又不想降batch size,可以开梯度累积,等效扩大batch size,训练曲线会更平滑。

3.2 混合精度训练:省显存还有意外收益

训练时我全程开了混合精度。这个操作最直接的好处是显存占用直接下降,原本放不下的更大batch size变得可行了,训练速度也快了很多。但让我没想到的是,混合精度训练出来的模型在验证集上的精度居然还略有提升。

原因大概是梯度噪声的引入起到了一定的正则化作用。混合精度下的低精度计算会带来微小的数值扰动,相当于给模型加了一层隐式的抗过拟合保护。再加上训练速度变快,同样的时间可以跑更多epoch,整体收益是正向的。

有一个小坑要提醒:如果模型里用了自定义的动态尺度操作,在低精度计算时可能出现数值溢出,表现为loss突然变成nan。碰到这种情况,检查一下相关操作是否被强制放到了float32计算,一般就能解决。

3.3 EMA模型权重滑动平均:你值得拥有

权重滑动平均EMA是这个比赛里我不敢想象没有它的工具。原理很好理解:维护一份模型参数的“影子版本”,每次更新完参数后,把影子参数往当前参数方向缓慢滑动一点,最终使用影子参数做推理。因为影子参数是历史众多参数的加权平均,它比单一时间点的参数更平滑、更不容易陷入尖锐的极小值,泛化能力通常更好。

实践下来,用EMA权重做推理,验证集mAP比用实时权重能高出约2个百分点左右。这是一个纯白捡的收益,代价只是多一点显存和维护代码。比赛框架里一般都有现成实现,勾选开启即可。

3.4 数据增强策略选择心得

我最终采用的增强组合是:马赛克增强、混合增强、随机仿射变换、随机色调扰动、模糊模拟。这套组合针对水下场景做了两处专门设计:一是模糊模拟要和真实水下图像的模糊程度相匹配,太强会把目标真的糊没了,太弱则起不到退化模拟的作用;二是混合增强的比例控制,混合增强用太多了会让模型依赖背景完成识别,反而牺牲了真实场景下的泛化能力。

增强有个隐藏风险是叠加过度。如果同时开马赛克、混合、多种随机扰动,训练图像会被改得面目全非,模型的训练loss虽然好看,但验证集上表现很差。我找了一个平衡点:每个batch里约一半样本保持相对轻增强,另一半用强增强,这样模型既能学到鲁棒特征,也不会和原始分布脱节。

4. 一次完整的踩坑排查:训练loss正常但验证mAP上不去

比赛过程中最折磨人的一个阶段是:训练loss一路下降、很平滑,但验证集上的mAP就是不涨,甚至偶尔往下掉。那段时间我反复调参都没有起色,后来通过一套系统性的排查,发现是三个问题叠加造成的。

4.1 第一个坑:验证集本身有错

我首先怀疑模型,于是把验证集拿出来重新做了一轮可视化。把预测结果画在图上、把标注框也画在图上,一帧一帧人工看。结果发现不少图像里存在标注错位的情况——有些目标的标注框比目标本身大了一圈,有些把背景区域框进去但漏了真正的目标。这类噪声标注在训练集里影响的是学习,在验证集里影响的是评分,两者同时被污染的时候,训练loss再低,验证指标也体现不出来。

处理方式是把明显错误的验证样本筛掉,重新清洗出一个干净的验证集。这一步做完之后,无论如何训练水平没有变,验证mAP立刻回升了几个点。这件事给我的教训是:任何比赛开始前都要先花时间把验证集清洗干净,否则后面所有实验结论都建立在流沙之上。

4.2 第二个坑:默认NMS参数和水下小目标不匹配

模型改完之后又引入了一个新问题:检测结果里同一目标被多个框重复框住,或者高置信度的框被低置信度的框干扰导致被抑制掉。排查到后面,定位到是NMS(非极大值抑制)参数的问题。

默认设置对常规目标适用,但水下小目标密集排列,有些目标之间的交并比本来就高,默认阈值会把相邻的多个真实目标误判成一个,导致小目标大量漏检。我调整了NMS的阈值参数,提高了相邻重叠框的容忍度,同时针对小目标增加了置信度修正逻辑——小目标的预测置信度普遍偏低,如果不做修正,NMS阶段很容易把这些真实目标当成噪声框杀掉。

4.3 第三个坑:验证阶段没有做多尺度推理

前两个问题解决之后,mAP又有一次小幅提升,但仍然没有达到预期。最后查出来是验证/推理阶段的问题。我训练时用的是高分辨率输入,但验证时图省事直接用了默认分辨率,小目标在低分辨率下本身就丢了大量细节,检测结果自然差。

改成验证阶段做多尺度推理之后,mAP来了最后一波明显上涨。所谓多尺度推理,就是同一张图在几个不同分辨率下分别推理,再把结果合并,小目标在大分辨率下更容易被召回,大目标在小分辨率下定位更稳,合在一起取长补短。代价是推理时间翻了几倍,但作为验证阶段提交答案,完全值得。

5. 比赛之外的事情:推理加速与真实场景落地

比赛成绩不是终点,我参赛的另一个动力是把方案搬到真实的水下机器人平台上跑。这就要解决推理速度问题,和精度问题同等重要。

5.1 模型剪枝与量化:体积变小,速度变快

我的做法是先用结构化剪枝把冗余通道剪掉,然后做INT8量化。剪枝的原则是只剪那些对最终输出贡献低的通道,量化的关键是用验证集做校准,找到一个合理的量化范围,避免数值分布被压缩在一个很小的区间里导致精度崩掉。

做完这两步,模型体积缩小到原来的四分之一左右,推理速度提升显著,精度损失控制在极小的范围内。对于一台算力和存储都有限的水下机器人来说,这一步很关键。剪枝和量化之后最好再用训练集做几轮短微调恢复精度,效果会更稳。

5.2 从PyTorch到C++部署:让模型真正上船

比赛阶段用PyTorch训练很方便,但真正上船部署的时候,还是得转成C++环境下的推理引擎。这个过程中最需要注意的坑是算子的兼容性。不是所有PyTorch算子都能被推理引擎高效支持,有些复杂的自注意力模块在转换时会退化为低效实现,甚至编译失败。

我的建议是:从模型设计阶段就要考虑部署友好性。能用标准卷积实现的功能,就不要为了花哨引入复杂的自定义算子。比赛里拿分虽然可以“怎么花怎么来”,但如果目标是落地,模型的工程约束必须前置到设计阶段。

转换时我走的是先转ONNX再转推理引擎的路线,注意固定推理分辨率,并关闭训练时用到但推理时不需要的模块(比如EMA权重和增强)。导出前先用真实样张做一次逐层对比,确认输出一致后再上平台,避免转换后模型静默出错。

6. 线上环境与真实水下场景的差距:开集问题和模型退化

最后想聊一个比较少被提但实际很致命的问题:模型在比赛验证集上成绩不错,一到真实水域就开始乱报,这就是典型的水下目标的开集识别问题。

比赛的数据集通常来自有限的几个拍摄点、固定的几种水温和水质环境。模型在训练集里见过的“水下世界”只是很小的一小片,到了真实环境,遇到没见过的鱼种类、没见过的水下植被、没见过的岩石纹理,模型不会说自己不会,它会强行给出一个高置信度的预测,把各种非目标误判成目标。

我这次比赛后做了一次模拟实验:把一批与训练集完全不同的水下视频喂给模型,结果一堆假阳性框,置信度还不低。这个问题的本质是模型没有学会“拒绝”,它的训练目标只有对已知类别的判别能力,没有对未知类别的拒识能力。

要解决这个问题,有几个方向可以尝试。一是引入背景负样本,专门从各种水下环境里采集包含大量“非目标”图像,让模型学会把这些区域判别为背景。二是对模型的预测置信度做一个分布校准——真实目标输出的置信度通常集中在一个区间,假阳性往往呈另一类分布,利用这一点可以在后处理阶段加一道过滤。三是做温度标定,把模型的概率输出重新校正一下,让它对自己的不确定更有感知。

当然,这些问题在比赛评分里不会直接体现,但如果你的目标是让方案真正投入使用,这些才是比刷AP更重要的细节。我在实际测试中发现,经过负样本增强和置信度过滤之后,假阳性率下降了一半以上,而且模型在已知目标上的召回率几乎没有损失,说明这个方向还有很大的优化空间。后续我计划沿着这个思路继续做下去,把拒识能力整合到最终的部署方案里。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 20:20:51

图神经网络入门:从消息传递到GCN实战

前几天有位朋友问我一个问题,我觉得很适合作为这篇入门文章的开场。他说:"我已经会了卷积神经网络,但是现在手里的数据不是图片,是一张社交关系网——每个用户是一个点,用户和用户之间有关注和转发的连边。我该怎…

作者头像 李华
网站建设 2026/10/13 20:20:46

Source Insight 4.0 高效配置指南:编码、缩进与代码格式化

1. 为什么这些"小设置"值得单独写一篇Source Insight 4.0 这个工具,做嵌入式、驱动、大型 C/C 项目的人基本都绕不开。它的代码跳转、符号索引、关系窗口确实好用,但真正每天高频使用的,反而是那几个看起来不起眼的设置&#xff1a…

作者头像 李华
网站建设 2026/10/13 20:20:34

STM32F103C8T6移植uC/OS-II指南:裁剪配置与任务切换避坑

简介:实时操作系统(RTOS)是嵌入式开发中常见的资源管理方案,而任务切换的可靠性依赖内核的底层机制。在Cortex-M3内核上,uC/OS-II通过SysTick提供系统心跳,借助PendSV完成上下文切换,从而保证高…

作者头像 李华
网站建设 2026/10/13 20:19:45

从“会说话”到“会干活”:智能体技能库设计与落地实践

这些年做大模型应用相关的开发,我发现在智能体落地的路上,最常卡人的不是模型本身,而是“模型明明会说话,却不会干活”。项目标题里这个agent-skills,说白了就是把“会说话”变成“会干活”的那层关键能力库——它是一…

作者头像 李华
网站建设 2026/10/13 20:19:33

C语言联合与枚举:内存复用与类型约束的实战解析

1. 从结构体说起:为什么还需要联合和枚举我在实际项目里最常见的类型定义,其实还是结构体,它解决了“把不同类型的数据打包成一个整体”的问题。但写多了之后你会发现,光有结构体还不够,有两类需求它搞不定&#xff1a…

作者头像 李华
网站建设 2026/10/13 20:19:30

Django结合TensorFlow的股票预测系统设计与实现

1. 项目整体设计与架构拆解毕业设计做股票预测系统,是我见过最多人选择的方向之一。每年都有大量计算机相关专业的学生把“基于深度学习的股票走势预测”作为课题,但绝大多数人卡在同一个地方:模型训出来了,却不知道怎么变成一个能…

作者头像 李华