恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
YOLOv8水上目标检测实战:从数据集构建到边缘部署
首页
资讯中心
/
YOLOv8水上目标检测实战:从数据集构建到边缘部署
YOLOv8水上目标检测实战:从数据集构建到边缘部署
发布时间:2026/8/27 5:23:53
简介目标检测是计算机视觉领域的核心任务之一其本质是通过深度学习模型在图像中定位并识别出感兴趣的目标。在实际工程中模型选型、数据质量与部署方式共同决定系统的最终效果尤其面对港口、航道、锚地等复杂水域场景时环境多变、目标尺度差异大、小目标密集等特点对检测精度和实时性提出了更高要求。多模型并联方案虽然直观但显存占用高、推理耗时成倍增加且维护成本大难以满足边缘设备部署需求。采用单模型多类别检测策略可大幅简化系统架构降低资源消耗。文章从数据集的构建、标注规范的制定、训练超参数的调优到TensorRT加速与Jetson平台部署系统梳理了基于YOLOv8实现船只、行人、海上标志物三类目标检测的完整流程为水上安全监控相关项目的落地提供了可复用的工程参考。 先交代一下背景我做水上安全监控项目时面对的现场是港口岸线、近岸航道和锚地需要在一路视频流里同时盯住三类目标——过往船只、甲板或码头上的行人、以及浮标灯标这类海上标志物。最早我们跑的是三个独立模型并联后来实在受不了显存和维护成本最终换成了YOLOv8单模型三分类方案训练收敛后产出了一套可直接使用的训练权重配套的原始数据集大约在1万张的量级。这篇就来完整复盘这套方案数据集怎么攒、标注怎么定、训练参数怎么调、模型为什么选YOLOv8而不是别的以及最后是怎么把权重部署到边缘设备上的。如果你也在做类似的水上目标检测项目这篇应该能帮你少走不少弯路。1. 海上安全场景的三类目标为什么值得合并成一个模型1.1 从三模型并联到单模型统一的现实收益先说最开始踩的坑。客户给的需求是帮我同时检测到船、人、浮筒我们当时图省事直接把以前做过的船只检测模型、行人检测模型再临时加一个标志物检测模型三个一起跑。软件上串起来倒是快但一上真机就暴露了问题三路推理同时跑GPU显存直接吃紧单帧处理时间也成倍增加。更要命的是三个模型各自输出一套检测框不同模型的置信度标准不一致融合逻辑稍有不慎就产生重复报警或者漏报。换成单个YOLOv8模型之后一次前向推理同时输出三个类别的检测框单帧推理时间降到了原来的三分之一左右显存占用也明显下降。维护上更是省心——以前更新一个类别要重新训练对应的模型还要处理版本对齐现在只需要维护一套权重、一个配置文件。对边缘部署来说单模型方案几乎是必须的。后面要在Jetson这类嵌入式设备上跑多模型并联在算力和内存上都很难撑住单模型则是完全可行的。这个决策回头看是在项目初期就应该确定的而不是等到部署阶段才被迫重构。1.2 任务定义船只、行人、海上标志物的检测边界合并成一个模型不代表把所有水面上能看到的东西都塞进去。理清检测边界特别重要否则标注和训练都会失控。我在项目里对这3个类别做了明确的定义船只boat货船、渔船、快艇、帆船、工程船等各类水上航行或停泊的载具。锚泊状态的船也算只要它是一个完整的水面载具。行人person甲板上的人、码头岸线上的人、以及落水人员。落水者露在水面上的身体部分很小属于典型小目标但必须归入这一类因为安全监控里落水检出比什么都重要。海上标志物maritime_marker浮标、灯标、灯塔、立标、警示浮筒等一切助航标志。这一类别公开数据集里几乎没有是标注量的大头也最容易被漏掉。边界情况我在标注规范里特别注明了几类水面漂浮的木板、集装箱残骸等无动力漂浮物不标岸边固定的建筑物不标海鸟不标。最初版本里我把海鸥也标了进去结果训练完模型对海鸥的响应特别强反而干扰了行人检测后来直接放弃这一类别模型精度明显回升。这个教训让我养成了习惯——新增类别之前先问自己这个类别对业务目标有帮助吗如果没有就不要让它挤占模型的表达空间。2. 1万数据集的产出过程不是简单凑数而是按需配比2.1 数据来源公开数据、自采图像与合成样本的比例网上有很多人问数据集在哪里下载对水上场景来说公开数据远没有想象中那么丰富。我的1万张图片大致是这样的结构公开数据约3000张自采和合作方提供约5500张合成渲染约1500张合计约1万张有效图片对应检测框总量超过2万。公开数据主要来自三个渠道SeaShips数据集船舶检测为主包含了货船、渔船、集装箱船等常见船型适合做船只类底料、Singapore Maritime Dataset新加坡海事数据集包含港口、航道、船舶等多种场景、以及COCO数据集里筛选出来的船和行人子集。要注意的是公开数据集虽然质量高但场景偏向特定水域和国内港口环境存在差异直接全量灌进去效果并不好。我是按场景相似度筛了一遍只保留了和实际项目环境相近的部分。自采数据是主力。我们通过无人机在港口周边飞了几轮加上岸基摄像头的录像抽帧以及合作方提供的船载视频凑出了五千多张真实场景图片。这里最大的好处是贴合实际视角无人机俯瞰视角和监控摄像头的高位平视视角各有覆盖两种视角下的目标尺度分布差异很大对模型泛化能力的提升非常关键。合成数据主要解决海上标志物样本不足的问题。浮标、灯标这类目标在不同水域的外形差异很大真实场景里又不可能快速大量采集。我试着用UE引擎渲染了一批海洋场景在场景里放置了不同颜色、不同形状的浮标模型再通过域随机化调整光照、天气、海面纹理。合成图虽然和真实图有差距但用来补足类别多样性和视角多样性非常有效——不过注意合成数据占比不宜超过20%否则模型的真实场景表现会变差。2.2 数据清洗决定模型上限的隐形步骤很多初学者拿到图片就急着标注这是个大坑。数据清洗决定的是模型的上限标注和训练只是逼近这个上限。这一万多张原始图里真正能用的其实不到一万。清洗我分了三步。第一步去模糊。监控视频抽帧经常抽到运动模糊严重的帧船在高速航行时尤其明显。这类图片人眼勉强能认出来但标注出来的框位置本身就不准模型学到的特征自然也不干净。我按拉普拉斯方差做了自动筛除低于阈值的直接淘汰再人工过一遍剩余可疑图片。第二步去重复。视频抽帧会产生大量相邻重复帧同一艘船在连续十几帧里几乎是一样的。如果全部保留模型会对这个特定目标过拟合影响泛化能力。我是用感知哈希算法对图片做相似度计算相似度超过一定阈值的只保留一帧。这一步处理完有效样本量直接少了五分之一。第三步去语义偏差。这一点最容易被忽略。公开数据集里的行人很多是城市街道场景的行人衣着、姿态、拍摄视角和甲板上的工作人员差异很大。从COCO里筛出来的行人子集如果直接用反而会在海上场景里引入不少误检。我最后只保留了那些和场景环境港口、码头、船舷相关的行人样本。2.3 标注规范的实操细节遮挡、小目标与类别边界的处理数据集有了标注规范决定模型能学到什么。这里分享几个在我们项目里实际落地过的规则。关于遮挡目标被遮挡面积小于完整面积的50%时照常标注完整目标框遮挡超过50%但目标主体可辨认时标注可见部分遮挡超过80%则不标注。为什么要这么定因为完全遮挡的目标和不存在没有区别标进去只会制造噪声。但部分遮挡的目标比如船舷后面探出半个身子的人恰恰是实际监控中常见的情况如果完全不标模型就学不会目标被挡住但确实存在这类样本。关于小目标在640×640输入下边界框短边小于8像素的目标不标注。这个标准是经过实验验证的——更小的目标即使在训练时勉强参与计算学习到的特征也非常有限对最终模型没有正向帮助。但要注意并不是所有小目标都不标落水人员这类安全攸关目标即使只有十几像素也要标注。所以阈值是一个参考关键还是看业务意义。关于类别边界我前面提到的船只和海上标志物容易混淆的问题在标注规范里必须要写清楚。以实物定义为准船是载具浮标是助航设施两者即使从远处看形状接近也要按实际功能归类。这个规则看起来简单但多个标注员同时作业时如果没有明文规定很快就会出现同一目标在不同图里标成不同类别的情况。标注工具我推荐X-AnyLabeling它支持加载YOLOv8模型作为预标注模型人工先标注一部分然后用模型辅助预标注人工只负责修正。1万张图如果纯人工标注三个标注员大概要三周加上模型辅助后压缩到了一周半。如果你用的是LabelImg效率会低不少但流程上是一样的。补一句标注完成之后一定要做一次二次复核我一般按10%的比例随机抽检要求类别准确率不低于98%框的IoU与真实目标不小于0.8。3. YOLOv8选型评估为何它是这个任务的最优解3.1 从YOLOv5到YOLOv8真正改变检测体验的几点YOLOv5用了很久从跑通第一个Demo到后来做小项目很多代码基础都是在v5上搭的。但这次做海上目标检测我切换到YOLOv8之后发现几个关键变化恰好都命中了我这个场景的痛点。第一个是C2f结构替代C3。YOLOv8的Backbone采用了C2f模块通过split和concat的组合让梯度流动更丰富特征重用的能力更强。这个改动带来的直观效果是在相同参数量下模型对船舶这种外形差异极大的类别货船和小渔船差别比猫和狗还大的表征能力更好。第二个是Anchor-Free。YOLOv5是Anchor-Based训练前要对数据集做K-Means聚类找合适的anchor尺寸。海上目标尺度变化极其剧烈从几像素的远距离浮标到铺满整个画面的近景货轮固定anchor很容易照顾了远处忘了近处。YOLOv8直接回归目标中心点和宽高不需要预设anchor省掉了聚类这一步对小目标和超大目标的适应性也更好。第三个是Decoupled Head。分类分支和回归分支分开每个分支各自处理自己的任务。之前用YOLOv5的时候有的目标分类对了但定位框偏得离谱或者框的位置很好但类别置信度低这就是耦合头里两个任务互相干扰的表现。YOLOv8的解耦头把这两个任务分开优化显著改善了定位和分类的协调性。3.2 COCO预训练权重的作用与迁移策略训练YOLOv8预训练权重几乎是必需品。COCO权重在千万级图片上预训练过模型已经学会了通用特征的提取——边缘、纹理、形状、颜色组合。这些通用特征对任何视觉任务都有价值我们无非是在它的基础上做一次领域适配。但要注意COCO预训练模型里person这个类别有大量的先验知识boat类别也有但海上标志物完全不在COCO类别清单里。这意味着模型需要学习一个全新的类别概念。我实测了不同模型尺寸从COCO预训练权重出发迁移的效果输入分辨率640验证集2000张。数据大致如下模型参数量mAP50mAP50-95推理耗时(1660Ti)YOLOv8n3.2M0.8120.482约2.1msYOLOv8s11.2M0.8610.541约3.2msYOLOv8m25.9M0.8830.578约5.6msYOLOv8l43.7M0.8920.593约9.8ms最终交付选择了YOLOv8s。原因很简单m模型以上精度的提升幅度已经很小但推理耗时几乎翻倍。对实时监控场景来说更快的推理意味着可以在相同算力下跑更多的路数。当然如果你只做离线分析追求极致精度选m或l也是合理的。4. 训练细节全记录配置、超参与损失曲线判读4.1 环境配置与数据集组织训练环境用的是Ubuntu 20.04Python 3.9PyTorch 2.0CUDA 11.8ultralytics 8.x。显卡是GTX 1660Ti6GB显存。这块卡在YOLOv8的讨论里很常见性能中规中矩但对s模型来说完全够用。数据集的目录结构就是YOLO的标准组织方式dataset/ ├── data.yaml ├── train/ │ ├── images/ │ │ ├── img_0001.jpg │ │ └── ... │ └── labels/ │ ├── img_0001.txt │ └── ... └── val/ ├── images/ └── labels/每个txt标注文件的格式是class_id x_center y_center width height坐标都是相对于图片宽高的归一化值。data.yaml内容如下path: /path/to/dataset train: train/images val: val/images nc: 3 names: 0: boat 1: person 2: maritime_marker训练集和验证集按8:2划分划分时确保同一场景的视频帧不会同时出现在两个集合里否则会造成严重的数据泄漏——验证集里的画面和训练集太像指标虚高换到真实场景就露馅。训练命令很简单yolo detect train \ datadata.yaml \ modelyolov8s.pt \ epochs300 \ imgsz640 \ batch16 \ patience50 \ optimizerAdamW \ lr00.001 \ device04.2 超参数选择在1660Ti上如何取舍超参数这里有几个实际取舍值得展开说一下。输入分辨率imgsz我选了640。这是YOLOv8的默认值也是速度和精度比较均衡的点。更大的分辨率比如960会明显提升小目标检测能力但对显存的要求也更高而且训练时间几乎翻倍。这个在后面精度瓶颈与优化一节会再细说。Batch size6GB显存下YOLOv8s用batch16刚好能跑如果再开Mosaic增强时峰值会接近极限。如果换m模型batch必须降到8以下。我在项目里采用了一个比较实用的办法训练前期用batch16到了最后20个epoch如果显存紧张就减半。其实ultralytics里也可以开启梯度累积等效扩大batch。学习率官方默认lr00.01但我实际用0.001。原因是迁移学习场景下较大学习率容易破坏COCO预训练权重里已经学好的底层特征尤其是我们还有maritime_marker这种新类别前期学习率太大会导致训练震荡。从0.001起步配合Warmup训练过程平滑很多。Mosaic增强YOLOv8默认在训练前10个epoch之后才启用Mosaic但最后一个epoch会自动关闭。如果需要手动控制可以在训练配置里调整。Mosaic对丰富上下文非常有效四张图拼在一起模型必须学会在不同背景下识别目标。但对小目标来说Mosaic会让目标在拼接后的图中更小反而不利。所以最后10个epoch关闭Mosaic、回归真实分布是提高收敛精度的关键技巧。4.3 训练过程中的损失曲线与评估指标训练到第50个epoch左右各项指标就已经接近最终水平的一半了。这里分享一个判断训练是否正常的经验正常情况下train/box_loss、train/cls_loss、train/dfl_loss三条曲线应该平滑下降val/box_loss等对应验证曲线应该是同步下降或小幅波动。如果训练损失还在降但验证损失已经开始反弹那就是过拟合说明模型开始背训练集了。配合patience50的早停机制验证指标连续50轮不提升就自动停止。最终模型在验证集上的指标是mAP500.861、mAP50-950.541。这个水平在海上目标检测里算是中上。分解到每个类别看船只类因为样本量大、外形特征丰富AP最高海上标志物居中行人最低主要原因就是行人目标在监控视角下普遍偏小落水者更是只有几十个像素严重拉低了整体指标。还有一个经常被忽略的细节训练完一定要看confusion_matrix.png它会直观展示哪些类别的目标被错误分到了哪个类别。我看了这张图才发现boat和maritime_marker之间存在明显混淆——远处的小船和小浮标在外观上确实太像了。这个信息帮助我在后续迭代中做了针对性补充。5. 精度瓶颈与针对性优化手段5.1 小目标行人漏检分辨率与切片推理行人AP最低根子在于目标太小。在岸基监控常见的画面里一条200米外的船上人的身高可能只有二三十像素。YOLOv8在640输入下对这样的小目标确实很吃力。有两个优化方向训练侧和推理侧。训练侧最直接的方法是提升输入分辨率。我把部分训练图片的分辨率从640提升到960模型学到的特征粒度更细小目标召回率明显上升。但代价是显存占用和训练时间同步上升建议只在模型收敛后使用较小学习率微调最后N个epoch也就是先低分辨率粗训练再高分辨率精调。推理侧则推荐切片辅助推理。思路是把大图先切成若干有重叠的小块每个小块独立过模型最后合并所有检测结果再统一做NMS。对于4K监控画面切成640大小的切片后小目标在切片里相当于放大了好几倍检测效果提升显著。我实测这一招把小目标召回率从0.61提升到了0.79代价是推理时间涨了大约三倍。所以它更适合对实时性要求不高的场景或者至少不能对所有视频流无脑开。5.2 海浪反光、逆光与雨雾天气的鲁棒性提升海上场景和城市道路的最大区别在于环境极端多变。正午的强反光会让船体表面过曝傍晚逆光时人和船的轮廓几乎融入背景雨雾天气更是让能见度骤降。这类样本如果不在训练集里模型在真实部署时会明显掉点。我的做法是在数据层面加了几类离线增强让模型提前见过这些坏天气——HSV颜色空间扰动模拟不同光照加入运动模糊模拟镜头抖动或船体震动用图像叠加噪点和雾化效果模拟雨雾。所有这些增强的强度都控制在人眼还能认出目标的范围内过度增强会让模型学到错误的纹理关联。有一点要特别注意增强是在线还是离线。ultralytics默认的在线增强在训练时自动完成但像模拟雨雾这种比较重的增强建议做离线版本单独生成一批增强图混入训练集而不是在每次epoch随机变化。因为离线增强可以人工检查效果避免增强过度导致标注语义失真。5.3 类别混淆问题的数据侧修正刚才说了boat和maritime_marker的混淆问题。这个不能只靠模型调参解决根子在数据分布。我做了两件事。第一补充远距离小目标的样本。很多混淆发生在目标距离很远、轮廓模糊的情况下但正常标注里这种样本很少——因为标注员自己也认不准。我强制要求标注员对远距离目标做更保守处理能明确判断类别的才标判断不了的宁可放弃也不允许瞎标一个类别。因为错误标注对模型的伤害远大于漏标注。第二在训练时对容易混淆的类别适当加权。ultralytics支持在损失函数中按类别设定权重但更简洁的方式是直接调整数据集里各类别的样本比例。我补充了一批浮标和船同时出现在画面中的样本让模型有机会学习两者的上下文差异——比如近岸布设的浮标往往排列成线位置固定而船在移动还可以利用船舶的尾迹等特征进行判别。6. 从权重到实际部署推理加速与嵌入式落地6.1 导出ONNX与TensorRT加速训练出来的best.pt是PyTorch格式不能在嵌入式设备上直接高效运行。需要先导出为中间格式再在目标平台上进行加速部署。导出ONNX的命令很直接yolo export modelbest.pt formatonnx opset12导出的ONNX可以在任何支持ONNX Runtime的环境里跑但速度和TensorRT比还有差距。如果想追求极致性能需要进一步导出TensorRT engineyolo export modelbest.pt formatengine device0 halfTrueTensorRT的FP16推理在NVIDIA Jetson系列上效果非常明显。实测精度损失在0.5%到1%之间但推理速度几乎翻倍。如果对精度特别敏感可以用INT8量化精度损失约2%到3%速度还能再上台阶。但INT8需要准备校准集校准集的代表性直接影响量化精度我建议用1000张左右覆盖不同光照条件的数据。还要注意一个坑导出engine时如果指定了固定输入尺寸后面推理也必须用相同尺寸。最好在导出前就确定部署时的实际输入规格不要训练用640、导出用640、部署代码里又resize成608这样会有隐患。6.2 嵌入式平台部署要点在Jetson Orin Nano上FP16的engine跑640×640输入单帧推理大概28毫秒约35FPS已经满足实时监控的需求。如果平台更弱比如Jetson Nano 4GB帧率会掉到十六七帧需要缩小输入尺寸或者降低检测置信度阈值来换取速度。嵌入式部署有几个隐藏瓶颈光看模型推理时间是不够的。首先是图像解码4K视频流的H.264解码本身就消耗不少CPU推荐用硬解码器Jetson的NVDEC而不是OpenCV的软解码否则CPU会成为瓶颈。其次是预处理与后处理归一化、letterbox、坐标映射这些操作如果在CPU上串行执行耗时可能比模型推理还长建议把这些操作也放到GPU上或者用TensorRT的预处理插件合并到engine里。最后提一下内存。Jetson系列共享内存模型推理用的显存和图像解码用的内存是同一块物理内存。同时跑多路视频流时内存分配要提前规划好不然很容易出现OOM。我的经验是先用jetson_clocks打开高性能模式再实测不同路数下的内存余量留出30%的缓冲。7. 复盘与经验这套权重适合什么场景不适合什么场景7.1 实测表现与边界条件训练完成这套权重之后我在多种条件下做了打点测试把真实表现和适用边界基本摸清楚了。适配良好的场景白天和黄昏时段的港口监控、近岸航道、锚地无人机在100到300米高度对近岸水域的巡检船载摄像头对前方海面的目标识别。这些场景下模型输出稳定虚警率可以控制在可接受范围。表现受限的场景夜间完全无光环境基本失效因为模型依赖可见光特征除非配合红外或补光极端雨雾天气下检测框会漂移卫星或极高空视角的俯瞰图中目标尺寸过小模型也难以输出可靠结果。这里有个很重要的认知模型权重本身不解决数据没覆盖到的问题。数据集决定了模型能力的上限权重只是逼近了这个上限。用户如果用这套权重去跑一个和训练数据分布差异很大的场景效果不好不应该奇怪。7.2 后续优化方向这个项目做完之后还有几个可以继续投入的方向列出来给需要的朋友参考。第一海上标志物类别其实可以细分。当前所有标志物作为一个类训练相对稳定但对业务来说航标和警示浮筒的语义差别较大。如果数据量足够建议拆成浮标类、灯标类、警示牌类这样下游业务可以做更有针对性的联动。第二引入时序信息。单帧检测始终存在偶发误检通过ByteTrack或StrongSORT做目标跟踪利用目标的运动轨迹做一致性过滤能显著降低虚警率。静止的浮标不会突然跳变位置移动的船也不会在相邻帧间瞬移这个逻辑对海上场景特别有效。第三半监督学习扩充数据。海上数据采集成本高标注成本更高。可以考虑用当前模型在大量无标注视频上跑一遍生成伪标签再通过置信度阈值筛选高质量伪标签加入训练集迭代式提升模型精度。这个方案我已经在另一个项目里验证过是个性价比极高的思路。最后提醒一下训练完一定要保留完整的训练配置和数据集版本信息包括data.yaml、超参数、预处理代码、关键脚本。我见过太多人训练完只留了一个best.pt过了两三个月想复现结果忘了当时用的增强参数只能从头摸索。版本管理这些看不见的细节往往才是项目后续可维护性的真正保障。本文还有配套的精品资源点击获取