做海洋安防相关的深度学习数据集和做普通的目标检测数据集体验完全不一样。海面空旷、光线刺眼、浪花反光真正要找的目标往往只是几十像素大小的小点。我最近整理完一套规模为10625张的无人机海上搜救数据集覆盖海上搜救人员识别、违规游泳识别、无人艇自主导航、海洋安全监控及水上救援预警等场景统一转成了深度学习常用的YOLO格式用来训练检测模型和搭建预警链路。这篇文章就把这套数据从标注、清洗、增强到训练、评估、部署的全过程捋一遍也把我在实际项目中踩过的坑连带着排查思路一起写出来。1. 先把场景拆明白同一套数据为什么服务三件事聊数据之前必须把任务拆清楚否则类别定义和标注规范会很快乱成一个球。标题里出现的几个场景看起来各说各话拆开看其实是三大类任务对应三套不同的产品功能。1.1 海上搜救人员识别不等于“检测到人”那么简单搜救场景中落水人员在画面里出现的方式非常多样可能只有一个头露出水面可能是一截手臂在挥动可能是一个橙红色的救生衣也可能是一整个身体呈大字型漂在海面上。普通的人体检测模型尤其是以城市街道为训练背景出来的模型很难接得住这些姿态。无人机高空视角下人变成俯拍的人字形低空侧视角下人可能只有半个肩膀在水面晃动。所以我在设计类别时把“人”这个孤立的标签拆成了几个可用形态完整人体用person表示仅露出头部的用head表示穿救生衣的目标单独作为lifejacket还有救生圈ring_buoy。这样虽然会出现同一目标被多个框同时框中的情况但实际救援调度时输出“发现一个穿救生衣的落水者”和输出一个笼统的person决策价值完全不同。海上搜救人员识别的本质不是让人工去看报警截图而是让系统直接给出“目标是什么状态、可能需要什么救援资源”的可执行信息。还要提醒一点有些项目会把person直接塞进很多类导致模型在远距离小目标上既学头部又学全身最后两类都学不好。我的做法是给head和person划定明确的标注规则如果目标外接框高度小于目标整体长度的1/3就只标head如果身体可见超过一半就标person。这个规则要写进标注文档里让每个标注员执行同一条标准。1.2 违规游泳识别靠“区域加行为”而不是单靠检测违规游泳识别在游泳池场景和海洋场景完全不是一个难度。岸边监控拍摄的是海岸线、水库或者码头水域系统要回答的问题不是“画面里有没有人”而是“有没有人进入了禁泳水域”。单纯依赖目标检测结果很容易出错。比如有人站在沙滩边、有人在岸边栈道上他们也是person但系统不应该报警。我比较推荐的工程做法是先用YOLO检测出水面区域的人员目标再在逻辑层做一道区域规则过滤。把禁泳区预先画成多边形矢量然后取检测目标中心点坐标判断中心点是否落入禁泳区并且还要判断该点是否在水线以下。两个条件同时成立才触发“违规游泳”预警。这个检测加规则的双层架构比让模型直接学习“游泳”这个概念要稳定得多因为游泳本身是一个时序动作单帧图像很难看出“正在游泳”和“正在漂浮”的区别。在数据整理时我把swimmer单独设为一个类别与person_full区分开。场景里常常出现游泳圈、浮球、泡沫板这类目标它们和人体极度相似不单独标注的话模型会把漂浮物当成人员误报率居高不下。我会明确标注凡是人体在水中且与水接触面积超过躯干一半的目标标记为swimmer如果只是上半身在岸上标记为person。这个细节看似微小但直接决定了违规游泳识别功能能否上线。1.3 无人艇自主导航检测要求从“有没有人”变成“障碍物在哪”无人艇在海上自主导航时避障算法需要的是场景中所有障碍物的位置、尺寸、类别归属。与救援识别不同导航任务中的目标类别更杂。航道上的客船、渔船、摩托艇、皮划艇、浮标、礁石、桥墩、漂流物全都可能成为阻碍路径的威胁。无人艇自主导航数据集目的是让模型学会“凡是会上障碍的都给我框出来”。我给的类别体系是九类head、person_full、lifejacket、ring_buoy、swimmer、boat、jetski、buoy、floating_debris。其中前几类服务于救援和违规游泳后几类服务于自主导航避障。一次标注多份复用。无人艇做避障时只需要从完整的推理结果中过滤掉人员相关类把boat和floating_debris等交给路径规划模块。反过来救援场景则忽略船艇类目标只看人员类目标。这样设计的好处是整套系统只需要维护一个检测模型而不是每个功能训练一个模型。1.4 海洋安全监控与救援预警数据只是触发器预警链路才是结果海洋安全监控及水上救援预警是一个端到端的系统视觉检测只是最前面的传感器数据触发器。在实际项目里检测框要往上送到业务平台至少要携带目标类别、置信度、归一化坐标、相机编号或无人机编号、GPS位姿信息以及时间戳。我常说一句话如果AI只输出一个坐标那它只是模型如果AI能输出一个可定位、可追溯的事件那它才是一个报警系统。这套10625张的数据集虽然只覆盖视觉识别这一层但从训练阶段我就保持了“目标必须能换算到GPS”的约束否则后端的救援物资投放、驱离广播、警示灯联动都会因为坐标断链而落空。2. YOLO格式的组织细节别在txt文件里翻车深度学习训练中YOLO格式是最常见的检测标注格式之一代码生态也成熟但这不代表它不会出问题。10625张图对应的标注文件有上万个任何一个小错误都会被模型放大。2.1 YOLO标注格式的参数含义YOLO格式的核心特征是每张图对应一个同名txt文件每一行代表一个目标类别ID、归一化中心点横坐标x_center、归一化中心点纵坐标y_center、归一化宽度width、归一化高度height。所有坐标值都除以图像宽高范围在0到1之间。这个格式最大的坑是类别ID错位。比如我一开始把lifejacket排在第3位后来调整类别顺序变成第4位结果直接用了旧脚本重新导出训练集和验证集的txt对应关系不一致模型训练出来之后识别结果整体错乱。排查了很久才发现是一个类别映射表的版本没同步。解决办法其实很简单整个项目只保留一份categories.txt作为唯一真源所有标注生成、数据拆分、可视化检查工具都从这份文件读取禁止任何人手改ID。查看标注时推荐用可视化工具把框画回原图上而不是用文本阅读器看数字。一张图里有多个目标时txt文件里是一堆小数肉眼根本看不出框是不是贴着目标边缘。我踩过一次之后给团队定下规矩任何标注文件更新后必须随机抽取10%的样本渲染成可视化图片标注框颜色按类别分配人眼扫一遍没有大问题才能进入训练环节。2.2 10625张图如何按来源管理10625张图并不算大所以每一张都要有效。我在整理时按拍摄平台做了划分无人机俯拍约4600张来自不同飞行高度和不同角度岸基固定摄像头约3400张主要服务于违规游泳识别无人艇第一视角约2600张贴近水面目标尺度和运动模糊都很极端最外补充了25张合成渲染图专门覆盖前三种来源都缺失的极端姿态。无人机的图像从30米到150米高度都有俯角从20度到90度这样模型在巡逻高度变化时不会突然失效。岸基图像里的游泳者普遍很小一个1080P画面中可能只有20乘30像素这给我后续训练带来很大压力但恰好是违规游泳场景中最真实的形态。无人艇视角则完全不同目标出现在画面两侧时形变很大浪花还会间歇遮挡船体这部分数据如果太少无人艇避障模型会明显偏科。按来源划分还有一个重要好处验证集和测试集可以做到场景级分层抽样而不是简单按图像随机切分。同一段无人机视频里相邻帧背景高度相似如果训练集和验证集中出现同一段视频的连续帧模型会在验证集上表现虚高部署到新环境立刻露馅。2.3 训练集、验证集、测试集的正确分割我把10625张图按照视频片段先分组同段视频的帧全部归入同一个片段然后以片段为单位进行分割。训练集约160个片段验证集约20个片段测试集约20个片段。这样能保证同源视频不会同时出现在训练和验证中评估结果更贴近真实部署。如果项目里全部是单张离散图片没有视频分组那就按照拍摄地点和时间段分段不要直接随机分配。测试集应当包含一些模型完全没见过的水域环境和天气状态否则无法检验泛化能力。3. 数据清洗、增强与标注质量把控很多人的第一个动作是直接训练我现在的第一个动作永远是清洗。数据里的脏标签、漏标、错位对检测模型的影响远超多数人的直觉。3.1 清洗标准要严到有点苛刻我对这10625张图的清洗动作包括分辨率低于640的图直接淘汰水面过曝到镜面反光完全吞没目标的图会保留一批但标注时格外小心画面严重模糊、镜头进水、目标肉眼看不清的图直接删除。还有一类图是摄像头带严重偏色这类图我会单独抽出来放到验证集中用来测试模型在异常画质下是否还能工作。另外要对标注框的几何一致性做脚本检查。同一个目标在相邻几帧中框尺寸突然跳变超过50%或者目标中心点像蛇形抖动基本可以判定该段标注不稳定。我写了一个简单的质检脚本统计每个类别标注框的长宽比有没有异常。比如person通常高大于宽如果出现大量横躺的person框多半是标注符方向错了或者类别映射混乱需要回去修数据。3.2 海上场景的数据增强别用公共场所那套做目标检测训练增强是不可少的但海上场景有很强先验海平面是一条明显水平线地平线的姿态不能乱旋转。用随机旋转90度或180度会生成大量海平面倾斜的负样本模型很容易学到错误的世界结构。我带位选用的增强策略是水平翻转因为海面和海岸线在左右方向天然对称小角度旋转控制在正负10度以内随机亮度、对比度和HSV抖动用来模拟太阳高度角变化高斯模糊和亮度衰减叠加模拟海雾低能见度Mosaic和MixUp主要用来提升小目标的识别能力。我在YOLO的训练配置里还关闭了极端平移和90度旋转避免船体形变被错误建模。说起来简单但很多人直接用默认配置结果训练出来的模型在真实海面上一遇到水平线起伏就疯狂误报。3.3 小目标漏检的针对性处理海面救援识别最难的就是小目标。一个离岸300米的游泳者在1080P岸基图中只有20乘30像素连人脸都算不上。直接拿640分辨率训练这类目标几乎学不到有效特征。我的做法有三个。第一训练输入尺寸提升到1280而不是默认的640对小目标召回有明显增益第二在数据增强里加入局部裁剪放大把图像中疑似小目标的区域切出来单独训练第三推理阶段用“切图推理”的思路把高清大图切成多个有重叠的切片分别检测再把检测框映射回原图坐标最后做NMS合并。这样部署端虽然增加了计算量但对于远距离落水人员识别召回率提升非常实在。我在项目实测中远端目标的召回率从0.62提到了0.79靠的就是这三点。4. 训练、评估与部署的实测记录数据准备妥当之后训练参数、评估策略、部署优化同样决定系统能不能用。我把自己跑过的完整流程和参数决策过程写在这里直接抄作业也可以。4.1 训练配置与模型选择机器是两张24GB显存的独立显卡实际训练时并没有全部吃满。我对比过YOLOv8n和YOLOv8m两个规模最终选用YOLOv8m原因很直接它在精度和推理速度之间的平衡点更适合边缘部署nano版本的小目标漏检率我接受不了x版本在边缘算力盒子上又跑不出实时性。data.yaml里的关键配置是imgsz: 1280epochs: 200batch: 16lr0: 0.005hsv_h: 0.015hsv_s: 0.6hsv_v: 0.4scale: 0.3fliplr: 0.5mosaic: 0.8mixup: 0.1patience: 30前20个epoch的损失下降非常快之后主要靠小目标类别的召回率一点一点爬升。最终测试集mAP0.5约0.87mAP0.5:0.95约0.51。需要强调这个数值和COCO数据集的指标不可直接对比因为海上场景中正样本很少、背景占比极大检测框一旦命中IoU往往很高mAP会虚高。真正要盯的是重点目标的回忆率而不是一个全类别平均分。4.2 类别不平衡处理九类数据天然不均衡。boat和floating_debris的样本量很大而swimmer和head这类关键小类非常少。如果不干预模型会倾向于学成船类检测器人员类完全被压掉。我采用的方案是训练时重采样每个epoch按类别频率抽取子集保证小类的样本量不低于大类的三分之一。落到具体动作上就是对小众类的训练图片做了不同程度的上采样让swimmer类图像每轮循环被多次看到。这种做法也会增加过拟合风险因此配合了较大的数据增强参数。简单来说就是让少数类在模型眼中不再“稀有”。4.3 无人机和无人艇部署端的实际表现把模型部署到无人机自带的嵌入式算力盒子上我用高效边缘推理框架转成FP16精度单帧耗时大约18毫秒能支撑30帧视频流的实时处理。这个速度在悬停巡检时没问题但无人机在快速巡航时云台震动和镜头对焦变化会造成大量运动模糊纯单帧检测会出现同一目标跳帧漏检。我的做法是在后端加了一小段目标跟踪逻辑同一目标连续两帧出现在相邻位置才将其标记为有效目标。这个方法牺牲掉一点点实时响应但报警误报率肉眼可见下降。无人艇端的部署还要多考虑时间戳对齐检测框必须和姿态传感器、全球导航设备的时间戳对齐才能计算出目标相对船体的真实方位否则避障算法拿到的是一组滞后数毫秒的坐标航行安全性大打折扣。这个细节很多团队容易忽略。5. 你一定会遇到的问题排查与避坑实录任何数据集项目训练阶段跑通只是开始真正花时间的是在部署现场处理五花八门的误报和漏报。5.1 海鸥和白色泡沫被当成落水者我第一次把模型拿到新拍摄海域测试时发现海面上的海鸥、白色的浮沫、甚至背光浪花的亮区都被模型检成了person。原因很清楚训练集里的背景样本不够丰富模型并没有真正学到人的结构特征只是学到了“海面上一个浅色小目标”这种肤浅关联。解决这类问题最有效的手段是硬负样本挖掘。把模型在无人员视频上的所有误报结果收集起来把所有包含误报目标的图像整理成负样本单独放到训练集中并标注为ignore区域或者干脆作为无目标图片送入训练。跑两轮之后海鸥和浪花的误报率下降了一大截。这个步骤麻烦但必须要做属于做一个海上检测项目绕不过去的功课。5.2 低角度阳光造成的框抖动太阳高度角很低时海面会形成一层拉得很长的金色光路检测框在光路上反复横跳。这类问题靠训练模型很难根治因为训练数据里即便包含了逆光场景模型还是会受到巨大亮度梯度的干扰。我在后处理阶段把NMS阈值从0.45提到0.55同时对同类目标相距过近的框做了基于距离的合并重叠阈值的灵敏度调高了一些最终让同一个游泳者不再被框成三四个叠在一起的检测框。此外我还单独把早晨和傍晚时段的数据分出来做了一个评估集专门监控模型在低照度环境下的表现。这个评估集不会进入训练只当作上线前的一个验收开关。5.3 漏标比错标更致命多人协作标注时最容易发生漏标。比如画面里四条船只标注了三艘模型天然会把那条漏掉的船当成背景直接抑制召回率。这种情况在图像目标检测中造成的破坏力比误标更大而且隐藏很深靠训练指标很难察觉。我的对策是两级审核制。第一级是模型辅助预标注先让一个弱一点的模型跑完所有图片自动生成候选框人工再在候选框基础上补漏和修正。这个方案层级优点很多标注员不用从零画框工作量和遗漏率都大幅下降。第二级是人工二次抽检把已完成的标注图像随机抽10%叠加可视化后由另一名成员独立检查。两轮下来漏标率从肉眼可见的级别降到很难再影响训练。5.4 换一个水域模型性能突然下降模型在A海域表现正常部署到B海域港口后误报率立刻升高。这通常不是模型参数出了问题而是新场景里存在训练数据里没见过的视觉元素比如另一种颜色和形状的浮筒、外形完全不同的桥墩、特殊涂装的工程船。泳装颜色在不同海滩也差异很大。解决这个问题的标准姿势是给每个新场景准备一定量的快速微调样本。不需要很多一次新接入带上几百张新场景图片做迁移学习通常能让模型在半天内适应新环境的视觉分布。不要指望一个固定训练集能包打天下海洋环境的视觉差异远远大于城市街道。6. 后续可以继续扩展的方向这套10625张的数据集虽然已经覆盖了搜救识别、违规游泳和无人艇导航三类核心功能但后续要真正变成一个完整的海洋安全监控系统还有几个方向可以做深。第一是热红外和可见光的数据融合。海上救援很多发生在夜间或低能见度天气普通的可见光模型基本失效而红外图像对温度敏感人体在海面上会有较高的温差响应。把双光谱数据一起标注训练多模态检测模型会让整套救援系统全年全天候可用。第二是行为识别。目前模型只能回答“有一个人在水里”但救生系统还希望知道这个人是在正常游泳还是已经失去自主运动能力。这需要引入时序模型把连续若干帧的检测结果串联起来分析划水频率和位移轨迹。第三是事件预警告警链路。检测框输出之后要通过推算映射到GPS坐标并自动触发附近的救援资源调度以及喊话驱离设备。这些应用层工作依赖的底层数据仍然离不开标注质量过硬、场景覆盖全面的原始数据集。我个人在实际整理这批数据的体会是10625张这样一个规模放在数据集领域并不算大真正让它有价值的是场景覆盖逻辑、类别定义规范和防泄漏的数据分割。只要这三件事做扎实哪怕只有几千张图也能稳稳支撑起海上搜救、违规游泳识别、无人艇自主导航以及救援预警的完整落地。最后再给一个非常土但极其有效的建议训练开始前随机抽100张图像把YOLO标注框可视化之后一张一张看。不要相信任何txt文件里的数字肉眼看到的框才是最诚实的质检报告。这个小动作能帮你躲过至少一半的训练翻车。
阅读完成 · 觉得有帮助?