
1. 任务拆解与方案选型冷水珊瑚检测到底难在哪Lophelia pertusa是冷水珊瑚里最典型的一种常常在几百米甚至上千米深的水下形成大面积的珊瑚礁是深海生态系统的关键栖息地。要监测它的分布和健康状况靠潜水员不现实主流做法是让ROV水下机器人带着摄像系统在固定航线上跑回传连续视频流再由专业人员一帧一帧地看。视频一多人的眼睛根本顶不住动辄几十个小时的录像看久了漏判率会明显上升而且不同人的判定标准也不一致。这时候把目标检测模型拉到流程里让它先做粗筛把疑似Lophelia的帧和位置标出来再由生态学专家复核整个监测效率就能提升一个量级。这次选的检测框架是YOLOX而不是YOLOv5或者更早的YOLOv3主要考虑到几点一是Lophelia属于纹理复杂、边缘不规则的半刚性目标不是像行人、车辆那样有清晰边界的刚性目标需要 anchor-free 的回归方式减少框的误导二是水下图像普遍存在对比度低、颜色偏移的问题模型需要更强的特征提取能力三是部署环境可能是甲板服务器也可能是ROV上的小型计算盒YOLOX 提供了从MobileNet到DarkNet53一系列可换的骨干网络能灵活调整精度和速度的平衡。后面我会把每个环节的选择理由和实际参数都展开说方便你直接参考这个流程去套自己的水下目标数据集。整个项目可以拆成四个核心模块数据工程、模型训练、评估迭代、部署推理。看起来是标准的目标检测流程但每个环节放到水下场景都有坑。数据工程不是光抽帧和打标签水下视频的帧间重复率高、光照波动大抽帧策略要专门设计。模型训练的显存和BatchSize、EMA衰减系数、SimOTA的候选框数量这些参数都不是照抄COCO配置就完事的要结合目标大小分布和类别不平衡去调。评估阶段也不能只看mAP漏检率对生态监测是硬指标。部署阶段更麻烦ROV的工控机算力有限TensorRT或OpenVINO的精度损失怎么控制都是实际问题。接下来我按这条主线逐个模块拆把能复现的配置、参数和踩坑记录都写出来。1.1 核心难点水下图像退化与目标形态建模Lophelia在ROV影像里通常呈现成片的白皙色或奶油色分枝状结构但这不是绝对的——墨蓝色水体把红色通道吃掉了珊瑚的色调会向灰绿偏移当ROV的补光灯角度变化时高光区域和阴影交替出现同一条珊瑚枝在相邻帧看起来像是两种东西。这就是水下检测和陆地检测最大的区别域偏移随时存在不能指望训练集和测试集是同一分布。形态上Lophelia的检测框也不像读车牌那样规整。它是一簇一簇的分枝框的边界怎么定本身就是个主观题。如果标注时不够谨慎会出现同一个珊瑚簇在相邻帧被标成不一样的框直接干扰模型的空间一致性。我的经验是标注规范一开始就要定死框尽量包含完整骨架主枝细小的末端分支如果超出画面边缘就不强行纳入宁可框略大一点不要在框的完整性上反复横跳。1.2 方案选型为什么YOLOX是平衡点YOLOX发布于2021年中放在今天已经不算新但在很多工业项目里依然是很好用的选择。它把anchor-based换成anchor-free减小了正负样本匹配的复杂性解耦头把分类和回归分开避免两个任务互相干扰。对Lophelia这种边缘不太规则的目标anchor-free的focal loss配合SimOTA匹配策略能把低质量预测过滤得比较干净。相比YOLOv5YOLOX的部署灵活度更高官方提供了Python、C、TensorRT、ONNX、OpenCV DNN等一堆导出路径。相比YOLOv8YOLOX在端侧推理的速度和内存占用上更可控这对ROV上不富裕的算力来说很关键。选型时我的判断标准很简单如果团队没有大量时间做Relabeling和调参选YOLOX的extra分支成熟稳定社区案例多坑基本上都能搜到。其实还可以提一嘴YOLOX-PAI或者Nanodet这个方向但考虑到底层代码可控性和资料密度项目最终锁定了YOLOX的官方仓库。后面所有训练和评估都跑在PyTorch框架下骨干网络用了DarkNet53输入分辨率取640。这个选择在后续实验里证明是合适的更大分辨率比如960能把小目标召回拉高3到4个百分点但训练时间几乎翻倍推理速度也掉得明显在ROV场景里不算划算。2. 数据工程抽帧、标注、增强每一步都在决定上限很多项目在模型结构上花大力气结果精度上不去回头查全是数据的问题。水下目标检测尤其如此因为图像质量本身差数据再不干净模型就学不到东西。这一节我把实际操作流程写细一点包括参数和选择逻辑可以直接照着做。2.1 ROV视频抽帧策略与质量筛选ROV视频一般是25fps或30fps的MP4流连续几分钟内画面几乎静止如果全部抽帧数据极度冗余不说还会让相邻帧之间在训练集和验证集之间泄漏指标虚高。更麻烦的是视频里经常有手控操作和悬停观察的片断画面模糊和剧烈抖动占比不小直接拿去训练就是噪声。我这边采用的方法是“先抽关键帧再人工质量筛选”两步走按固定间隔抽帧间隔设置为每2秒抽1帧也就是12.5fps或15fps对应约25到30帧中抽1帧。对抽出的图像计算Laplacian方差做模糊检测低于阈值直接淘汰。再把保留帧按时间顺序每N帧划分为一个迷你段每个段里随机挑1到2帧避免空间冗余。模糊检测的阈值要自己看一批数据调不固定。ROV如果开启了防抖云台阈值可以设高一点如果镜头是固定在车体上的抖动严重阈值就得放松。这个度没有标准答案我通常的做法是先输出100张模糊分值的直方图人工看一下临界区域长什么样再定。抽帧之后一定要做数据集洗重。把分辨率、采集地点、光照条件等属性记录下来训练时按地点分组做K折验证防止同一个视频的帧同时出现在训练和测试里。我一开始偷懒没做分组直接在全体帧里随机划分结果mAP显示到了0.87换成按视频分组重新划分后掉到0.76虽然不好看但真实。2.2 标注规范与工具选型标注工具我用的是LabelImg和X-AnyLabeling轮着来。前者轻量简单适合批量矩形框标注后者对半自动辅助有帮助但水下目标本身是稀疏纹理自动标注的初始框经常歪还是要手动调整。很多同学喜欢一上来用任意角度旋转框或者多边形实例分割的标注方式觉得更精确但要注意后处理复杂度会指数上升YOLOX的常规训练管线并不直接支持多边形需要再转mask或旋转框非常麻烦。所以第一版老老实实矩形框先把工程跑通拿到基准确认任务可行性再考虑是否上实例分割。标注规范是数据质量的第一道闸门。Lophelia的定义我在项目里按下述规则执行具备明显分枝结构、整体呈白色或灰白色的目标且大小占画面至少12x12像素才允许标注。分枝稀疏、形态不清晰的不标。被泥沙半掩埋、只有小部分露出的不标。多个珊瑚簇挨在一起但主体分枝可区分的分开标注否则合并为一个框。画面边缘被截断的主骨架框的边界截至图像边缘。定了规范后至少要两个人分头标同一批图算一下框的IoU一致性低于0.7就得重新对齐标准。这个步骤看着费时间实际能省后面大量返工。标注量上第一版只训练单类Lophelia一共标注了8600个目标框分布在5300张图上其中约3000张来自不同海区和不同光照条件。类别单一是刻意的先保证核心目标不做错再考虑把海蛇尾、海葵、垃圾类加进来做多类扩展。单类的另一个好处是能精确分析误检来源比如把岩石误检成珊瑚问题出在纹理相似还是光照一目了然。2.3 增强策略模拟水下物理环境而不是盲目堆料通用的随机翻转、随机裁剪、色彩抖动这些常规增强对水下任务远不够。问题在于模型需要学会忽略偏蓝偏绿的光照、阴影变化和漫射噪声泛红的珊瑚在不同光照下要能被同一个模型认出。我尝试把增强分成三组对比实验基础组、强色彩组、物理模拟组。基础组就是MosaicMixUpRandomHorizontalFlipRandomAffine这套YOLOX自带。强色彩组在基础组之上加了HSV空间的大范围抖动色调偏移幅度从±10度加大到±25度饱和度从±10%加到±30%。物理模拟组更进一步参考水下成像模型对图像做通道级衰减和散射模拟。简洁的做法是把RGB三通道各自乘以不同系数比如红色通道乘0.55绿色通道乘0.85蓝色通道乘0.95再叠加高斯噪声和随机局部模糊。这种方法模拟了不同水深条件下红光的衰减差。实验结论很有意思强色彩组对mAP的提升最明显约涨了2.8个百分点物理模拟组提升约1.5个百分点但是对模型在极端蓝绿图像上的鲁棒性帮助很大。基础组是底线不能省。Mosaic和MixUp对提升泛化能力的作用很关键尤其在目标尺度变化大、样本分布不均衡的数据集上Mosaic可以把不同深度的珊瑚丛拼在一张图里让模型更适应尺度和背景的多样性。还有一个细节是Copy-Paste增强。把标注出来的珊瑚目标Roi区域随机裁剪粘贴到不含目标的背景区域上同时做一点透视变形和色彩扰动。效果很好因为天然增加了目标的数量和分布多样性。但要注意如果背景区域真的没有别的生物粘贴时不要破坏真实标注的语义边界。3. 训练配置YOLOX机制与参数设定的底层逻辑这一节讲训练侧。YOLOX本身不是单纯拿来就训的几个关键机制和超参数直接影响效果尤其在水下数据集上很容易踩到调参的坑。3.1 从Anchor-based到Anchor-free为什么这反而稳了YOLOX的最大改动在于Decoder部分完全去掉了预设的anchor框。传统YOLO系列需要聚类出若干组anchor尺寸在特征图每个位置生成多组预设框再去和gt做匹配。问题是Lophelia的尺寸和长宽比跨度极大近景大珊瑚和远景小珊瑚在同一个batch里出现预设anchor无论如何都很难照顾周全——anchor数量多了计算量上去数量少了召回率会掉。Anchor-free的做法简化了这一点让每个空间位置直接预测目标中心的存在概率和到四条边的距离。两级特征图下采样倍数不同配合FPN不同level的检测头分别对应大目标和小目标天然适应了珊瑚的尺度分布。这个机制在实际数据上的好处非常直接小目标漏检的比例明显下降尤其是在远端影像里Lophelia可能只有20x30像素大小anchor-based模型需要刚好匹配到合适的尺度层而anchor-free更容易对上。不过anchor-free也有代价中心点附近的所有特征都会参与预测一个长条形的珊瑚簇中心区域占的面积不大如果中心点的定义不准确回归的loss就容易混乱。YOLOX为此引入了中心采样center sampling策略在SimOTA时会限制正样本候选落在gt框中心附近的一定区域避免远离中心的特征点参与回归这算是很实用的设计。3.2 SimOTA标签分配让每个目标找最合适的预测SimOTA是把“目标分配”当做一个最优传输问题来近似求解。流程大致是对每个gt框找出它周围所有候选预测点以及这些点的预测得分和代价。用topk策略选择cost最小的若干预测点作为正样本。cost由分类loss和回归loss共同组成动态平衡多任务。最后在全局范围内逐步调整每个gt的样本数称为dynamic k。这个机制在类别多、目标密集的数据集上表现好但水下珊瑚场景常常是“稀疏大目标”一张图就0到3个目标。SimOTA没太多候选点可以选反而容易出现某些gt周围没有合适的正样本导致该目标完全没参与训练表现为loss下降正常但recall特别低。我调试时发现把SimOTA的center_radius从默认的2.5缩小到1.5让候选采样范围更贴合小尺寸目标和稀疏分布recall有明显回升。配合上3.1提到的center sampling很多边缘目标也能被正确分配。另外这个参数不能调到过小否则真实框中心偏移大的样本就完全匹配不上了反而是反效果。3.3 训练超参的实测记录YOLOX仓库的default配置是COCO语义下的产物直接对它做迁移训练就意味着要改几个关键位置。我最终用的配置如下这是实际项目里跑通的一组参数参数名值调整思路输入尺寸640x640在召回和速度之间取平衡BatchSize16单卡V100上的上限可放宽到32但梯度不稳OptimizerSGDmomentum0.9收敛稳定比Adam在检测上表现好初始学习率0.01 / BatchSize x 0.001按线性缩放规则学习率调度cosine annealwarmup5 epochs前1/8周期先warmup防开局发散Epoch150个完整epoch深水数据噪声大收敛偏慢EMA开启decay0.9998让模型权重更平滑weight_decay5e-4防止骨干过拟合冻结骨干前5个epoch冻结保护预训练语义特征不被破坏mosaic_prob0.85后期逐步降为0.3避免真值错位其中最重要的经验是初期冻结骨干。骨干用的是ImageNet预训练的DarkNet53如果一开始就放开所有层水下图像的大面积色偏会把浅层特征冲击得很厉害网络会花很长时间去重新适应而前5个epoch冻结让检测头和neck先学会把小目标定位出来骨干权重不被破坏之后整体微调收敛速度和最终精度都能改善。ema_decay这一项也值得专门说一句。0.9998是偏慢的EMA在150epoch的情况下能跟到很后面精度比0.999略高一点但模型拉到推理阶段时ema权重的表现通常是更好的。训练日志里要同时记录raw model和EMA model两个mAP很多人只看其中一个后期踩坑。4. 训练实录与评估指标我能看到什么到了什么水平这节记录一次实际训练的过程和评估环节包括Loss曲线陷阱、mAP不够用的地方以及为什么需要建立一套自研的评估协议。4.1 Loss曲线的正确打开姿势训练到第20到30个epoch时loss曲线整体向下但会发现分类分支的loss下降明显快于回归分支而且有轻微的平台期。这是正常的因为Lophelia的类别单一分类任务简单框回归才是难的部分。如果回归loss不断震荡不要急着调学习率先看是不是SimOTA的候选样本分配在变化——比如有些目标在前50个epoch被分配给了低层特征图后50个epoch又换成了高层特征会导致回归目标不一致。另一个镜像问题是mAP在训练集上很高0.94但验证集上一直上不去整体在0.74附近徘徊。这种情况基本就是过拟合。我在40epoch左右尝试把mosaic_prob降到0.5mixup关闭并加大random_crop的幅度让模型从小数据集模式切换到大尺度模拟模式mAP回升到0.81缓解了过拟合。Loss曲线只作为过程监控工具不要试图单看某一项loss高低来评判模型好坏因为整个训练期间loss的绝对值一直被各种开关mosaic、MixUp和标签分配策略影响横向比较没有意义。关注相对变化才是对的。4.2 评估指标为什么mAP要看IoU0.3而不是0.5生态监测类项目对漏检率的要求更高——漏掉一丛珊瑚对资源评估和变化趋势监控的影响比把一个石头误判成珊瑚要大得多。mAP0.5的常规threshold对稀疏小目标可能太严格Lophelia的边界框不确定性较高哪怕标注者也会有30%的IoU差异所以依赖0.5的阈值会把大量“检测对了但框不够准”的结果判成假阴性。我在项目里建立了一个多层次评估协议第一层mAP0.3用于评估“中心找对了没有”当作目标存在的指示器。第二层mAP0.5用于评估“目标定位质量”作为常规精度参考。第三层F1曲线最佳点的precision和recall看实际部署时的平衡表现。第四层按目标尺寸分层统计小目标像素面积32x32、中目标32x32到96x96、大目标的recall防止“只看总量骗自己”。实测最好模型在上述协议下mAP0.3大概0.86mAP0.5大概0.78recall在小目标段为0.68大目标段为0.87。另一个关键指标是F1的阈值位置发现最佳F1在0.52左右这个值在部署时可以直接作为置信度阈值的前置设定。4.3 小目标和背景干扰是主要瓶颈所有误差分析做完漏检主要集中在小目标和背景底质高度相似的区域。海底的砂石、碎壳和珊瑚死骨骼在灰度纹理上跟活的Lophelia很像模型经常把小块的死珊瑚骨骼误判为活体这个问题的本质是训练数据里活体与死骨骼样本不平衡。处理思路包括引入负样本难例挖掘把验证集里被误判为目标的非目标图块抽样加入训练集并直接标注为背景。同时调整数据集的采样策略让每批batch里难负例占比保持在15%到20%。最终误检率下降了大概一半。5. 部署实践与常见问题排查从PyTorch到ROV工控机的旅程训练只是前半段水下项目真正麻烦的是把模型挪到现场环境里跑起来还要稳定运行。5.1 推理速度与精度的平衡选择ROV上能部署的算力通常是一块NVIDIA Xavier或者类似Jetson设备计算能力非常有限。直接跑PyTorch模型不现实需要先转成TensorRT或者ONNX。我的步骤是PyTorch权重转ONNX使用opset11输入固定尺寸640x640。ONNX转TensorRT用FP16遍历一层层检查精度损失。给模型输入加preprocess水下图像先做直方图均衡化再归一化到0~1实测能提升最终精度约1.2个mAP点代价是额外增加3ms耗时。推理用Engine对象反复调用不再走ONNX Runtime的接口减少调度开销。整个FP16转换后在Xavier上大约跑到50ms一帧约20FPS连续处理720P视频很吃力但能跑。如果再叠加ROV本身的姿态震动和光源变化抽帧处理控制在10FPS以下留余量比较稳妥。5.2 常见问题速查表现象可能原因排查方向训练loss持续下降但验证mAP不动过拟合关MixUp降低mosaic_prob加大random_crop小目标全漏检输入分辨率太低 / 小目标样本不够提升到768加入Copy-Paste增强检查SimOTA候选范围大量把石头误报成珊瑚难例样本不足难例挖掘添加背景负例部署精度比验证集低一大截预处理不一致 / 图像色偏差异统一mean/std和归一化顺序现场抽帧做在线校准检测框整体偏移标注规范不一致 / 中心采样偏移重新对齐标注框检查SimOTA center_radius深蓝图像检测变差训练集覆盖不足做水下物理模拟增强增加深水样本关机重启后Engine挂掉TensorRT序列化与版本不匹配重新生成engine避免跨设备序列化5.3 难例挖掘的具体实施方式难例挖掘是提升部署效果最具性价比的操作。具体做法是拿训练好的模型在验证视频里跑一遍推理把被误判为目标的高置信度负样本图块自动截取出来按置信度降序排列然后人工扫一遍确认这些确实都是背景或非目标再将其裁剪后放入训练数据标注为negative空标签并且给予它们约1.5倍的loss权重。这个过程迭代两到三轮误检率可以显著下降。这里有个很隐蔽的坑难例挖掘做多了模型会变得过度保守把真正的珊瑚也压制掉了。所以每做完一轮难例挖掘就要回归一遍验证集让mAP和recall都保持正向趋势再继续否则宁可停下来。6. 工程扩展方向从单类检测到长期生态监测项目到这一步已经能用YOLOX完成Lophelia的基础识别检测我从自身的体验来看整套流程成熟后还能往几个方向扩展。6.1 多类目标扩展与Joint Detection冷水珊瑚礁生态系统的监测往往不止关注Lophelia本身。海蛇尾、海葵、海绵、深海鱼类都是重要的指示物种。把这些类别添加到同一个模型里甚至可以用共享骨干的multi-head结构比单独为每个物种准备一套模型要节省大量资源。训练时要注意的是类别不均衡——Lophelia样本多海蛇尾样本少可以给少数类用重采样或focal gamma调整。6.2 从2D框到形态分割矩形框能告诉科学家“这里有Lophelia”但给不出生物量的有效估计。下一步很自然是把检测升级为实例分割比如用YOLO-Seg或者Mask R-CNN直接输出珊瑚簇的像素级轮廓。有了轮廓数据可以估算珊瑚覆盖面积、分支密度甚至分析生长速率。不过分割标注成本比检测高很多如果不是直接需要生物量数据检测框的输出就足够支撑大部分监测需求了。6.3 视频时序信息的利用ROV视频是时间连续的每一帧的检测结果天然形成了轨迹。利用这一点可以把单一帧的漏检通过前后帧的检测结果补回来——当前帧没检测到但前后各5帧都检测到了那这一帧大概率也有目标只是被模糊或遮挡干扰了。我采用简单的时间投票机制维护一个10帧的滑动窗口目标框在窗口中连续出现8次以上就认定这个目标存在并把位置做平滑外插。这套后处理能显著提升视频层面的召回率尤其面对ROV悬停和小幅晃动时的检测稳定性提升非常明显。6.4 当前局限与谨慎心态需要清醒认识到目前这套系统的输出更适合做“区域监测和变化趋势分析”而不是“绝对丰度评估”。光照条件和ROV离底高度对检测结果的影响仍然很大不同航次之间的数据可能会带来精度大幅波动。使用的时候要做好Mindset模型帮你高效筛选出疑似目标最后由生态学专家做最终判断这才是健康的使用方式。任何号称可以直接替代人工计数的系统在水下场景里目前还很不可靠。我自己在这个项目里学到的最大一条是数据的均匀性和标注一致性直接影响整个项目的天花板模型结构和调参只能在它的基础上做微调。与其花大量时间在刷网络上各种结构变更不如先花心思把采像方案定好让ROV上的补光灯和相机参数保持稳定这样后期的模型训练难度才会真正降下来。最后再分享一个小技巧训练前花一天时间对整个数据集做一个颜色统计直方图看看有没有异常的颜色偏移样本把它挑出来单独处理往往能给最终模型带来意想不到的稳定性提升。