☰
水下垃圾检测实战:YOLOv5到YOLOv12选型、训练与部署全解析
2026/10/22 8:16:30 网站建设 项目流程

水下垃圾检测,听起来只是把目标检测算法搬到水下场景里跑一遍,但真正做起来你会发现,环境、数据、算力、部署每个环节都有不少能让人血压飙升的坑。这篇分享以一个完整的水下垃圾检测系统为例,核心模型覆盖 YOLOv5、YOLOv8、YOLOv11 和 YOLOv12,配套数据集、完整源码、论文文档、部署文档和讲解视频,都按工程项目的标准整理过。无论你是准备做课题研究、课程设计,还是想给水产养殖、港口巡检、环保监测这类场景搭一套可用的水下识别原型,这篇文章里提到的选型思路、训练调优和部署细节,都能帮你少走一段弯路。

我在做这个系统的过程中,最大的感受是:水下垃圾检测真正难的其实不是模型本身,而是数据采集、数据增强和部署适配。YOLO 系列模型比较成熟,但如果你直接拿通用权重往水下图像上套,大概率会被蓝绿色偏、悬浮颗粒和小目标漏检教做人。下面我把整个项目从设计到落地的过程拆开讲,尽量说清楚每一步“为什么这么做”。

1. 项目整体设计:为什么选 YOLO 系列做水下目标检测

1.1 水下垃圾检测与普通目标检测的差异

常规的目标检测任务,比如行人检测、车辆检测,图像光照稳定、背景相对干净、目标尺度也比较统一。水下场景完全不是这么回事。水下光线会随着深度快速衰减,红光最先被吸收,所以采集到的图像普遍偏蓝绿色;水中还有悬浮颗粒和气泡,形成类似雾霾的散射效果,让边缘变得模糊。再加上垃圾种类五花八门,塑料瓶、塑料袋、渔网、金属罐、玻璃碎片都有,同一个类别的目标在不同水质下颜色差异也很大。

这些因素叠加在一起,带来最直接的后果就是:模型很难学到稳定的纹理特征。一个在地面数据集上 mAP 很高的模型,拿到水下图像上,经常出现漏检、误检。尤其塑料瓶这类半透明目标,在水里几乎和环境融为一体,如果不做针对性的数据增强和模型调优,模型基本只能靠“猜”。

做水下垃圾检测的应用需求其实很明确:水质监测部门需要统计河湖、近岸海域的垃圾分布;水产养殖企业要做水下异物清理;港口码头需要巡检水下结构物附近的缠绕物。这些场景普遍对实时性有要求,所以模型不能太重。市面上的检测模型很多,但综合考虑精度、速度和部署难度,YOLO 系列几乎是唯一一个能同时满足“好入手、好训练、好迁移”的系列。

1.2 YOLO 系列版本对比与选型逻辑

很多人会问:YOLOv5、v8、v11、v12 到底选哪个?我的答案是:不要凭版本数字猜好坏,要看你的算力和部署目标。

我当时把四个版本都在同一份水下数据集上跑过一轮对比。YOLOv5 胜在稳,代码老但生态成熟,很多车载、嵌入式项目都在用,遇到问题能搜到大量现成解决方案;YOLOv8 改成了 Anchor-Free 设计,训练收敛快,综合精度和速度很均衡,是大多数项目最省心的选择;YOLOv11 在 backbone 和颈部结构上做了改进,对中等尺度目标有更好表现,但提升幅度不如版本号看起来那么大;YOLOv12 引入了区域注意力机制,对水下这种背景复杂、小目标多的场景有明显帮助,不过注意力结构会带来额外计算量,在老显卡或者嵌入式设备上推理速度会慢一些。

有一个很现实的选型策略:如果部署设备算力有限,优先考虑 YOLOv5 或 YOLOv8 的轻量级版本;如果追求更高精度、且能接受较大的延迟,就上 YOLOv11 或 YOLOv12。更稳的做法是,在不改变训练数据集和评价指标的前提下,把四个版本都训练一遍,用实验数据说话,而不是拍脑袋选。下面这张表是我在同等条件下训练得到的参考结果,注意不同数据集和硬件上的绝对数值会有差异,重点看相对趋势。

模型版本参数量推理耗时mAP@0.5适用场景
YOLOv5s约 7M低中边缘设备、快速上线
YOLOv8s约 11M较低较高精度与速度兼顾
YOLOv11s约 9M中等较高通用检测任务
YOLOv12s约 12M较高最高复杂背景、小目标

1.3 系统组成与工作流程

一个完整的水下垃圾检测系统,不能只有模型训练脚本。我最后整理出的项目结构包括四大部分:数据端、训练端、部署端和文档端。数据端负责图像采集、标注格式统一、数据增强和划分;训练端包括模型配置、训练脚本、验证和评估脚本;部署端把训练好的权重导出成适合目标平台的格式,再封装成推理接口;文档端则包含论文说明、部署手册、配置说明和使用讲解。

系统的业务逻辑是:水下摄像头或无人艇采集到视频流,按固定帧率抽帧,经过预处理后送入检测模型,模型输出每个目标的位置和类别,系统再根据预设阈值决定是否告警或触发机械臂清理。整体工作在离线检测和在线实时检测两种模式下都能跑。设计时我特意把训练脚本和推理脚本解耦,这样后面换数据集、换模型版本时,不用动主流程代码。

2. 数据集的构建与预处理:决定模型上限的“隐形工作量”

2.1 数据来源与水下图像增强

很多做检测项目的人容易犯一个错误:拿到模型后直接拿公开预训练权重在自己的私有小数据集上微调,结果效果差。问题往往出在数据量太少、标签不规范、图像风格差异太大。水下垃圾检测尤其依赖数据质量,因为水下图像和普通图像之间的视觉差异实在太明显了。

我的数据集主要来自三个渠道:一部分是公开的水下目标检测数据集,主要包括一些水下生物和垃圾的标注图像;一部分是实际水域中拍摄的视频抽帧,这些图像更贴近真实场景;还有一部分是合成得到的增强样本,比如把普通垃圾图像做水下退化模拟,加上蓝绿色偏、降低对比度、模拟悬浮颗粒。公开数据集的优势是类别丰富,但真实水域数据更加重要,因为只有实际场景中的光照、浑浊度和背景才算数。

拿到原始图像后,我做了两类预处理。第一类是颜色校正,常用的有灰度世界算法和直方图均衡化,用来消除水下偏蓝绿的问题。第二类是图像去雾增强,通过对比度受限自适应直方图均衡化(CLAHE)让边缘更清晰。要注意的是,增强操作不能盲目加,否则会引入不自然的纹理,导致模型在真实场景中掉点。增强后的图像要重新人工检查一遍,剔除过度处理的样本。

2.2 标注规范与格式转换

数据标注是另一个决定模型上限的隐形环节。水下垃圾类别我最终统一成五类:塑料瓶、塑料袋、渔网、金属罐和其他杂物。分类太细会导致单类样本不足,分类太粗又会掩盖不同材质间的差异。五类是我折中后的结果,既符合常见的垃圾清理需求,又不会让类别不平衡问题过于严重。

标注时我有几条硬性规则:目标被遮挡超过一半时仍要标注,但置信度权重降低;目标完全模糊、仅凭纹理无法判断时直接跳过,不硬标;边框必须贴合目标可见部分,不能为了省事把半透明塑料袋标成一整块大矩形。标注工具我选的是常用的开源标注工具,导出格式再转换成 YOLO 需要的 txt 格式。每行内容为“类别坐标”,坐标用归一化数值表示,例如:

1 0.531 0.482 0.116 0.083

这条数据表示类别编号 1(塑料瓶)的中心点位于图幅的 53.1% 和 48.2% 处,宽高分别占整图的 11.6% 和 8.3%。格式简单,但要注意坐标必须准确,我后期检查时发现很多漏检问题都是标注框偏大或偏移造成的。

2.3 数据划分与防泄漏

数据划分看起来简单,但很坑。我第一次做的时候直接从视频抽帧里随机切训练集和验证集,结果同一段视频的连续帧被同时分到了训练和验证里,导致验证分数虚高。后来我改成按“视频段”划分,把同一时间段、同一场景的帧归入同一集合,避免信息泄漏。

具体比例我用了 7:2:1,70% 训练,20% 验证,10% 测试。训练集用来更新权重,验证集用来调参和早停,测试集只在最终评估时使用一次。这里有一条经验:验证集和测试集不能一起调参,否则测试集失去意义。水下场景的数据采集成本高,我还会用增强后的样本扩充训练集,但验证集和测试集基本都用原始帧,以保证评估结果能反映真实表现。

3. 模型训练与调优:从 v5 到 v12 的实测记录

3.1 训练环境准备与数据组织

训练环境我建议直接用支持 GPU 加速的深度学习框架配合 Python 环境。模型代码和依赖库的版本要固定,尤其是不同 YOLO 版本的依赖和默认参数差异不小,混用版本容易出莫名其妙的问题。我的环境大致如下:Python 3.9,PyTorch 2.x,OpenCV 用于图像处理,GPU 显存最好 8GB 以上,否则训练 l 模型会出现爆显存的情况。

数据集目录组织也很重要,统一的结构能避免很多路径错误。我是这样组织的:

dataset/ ├── train/ │ ├── images/ │ └── labels/ ├── valid/ │ ├── images/ │ └── labels/ └── test/ ├── images/ └── labels/

每个版本训练前,我会先生成一个 YAML 配置文件,里面写明数据路径、类别数量和类别名称。不同 YOLO 版本的配置文件字段稍有区别,但核心逻辑一样。有一个细节:路径最好用绝对路径或相对根目录的统一路径,否则换机器训练时容易因为路径不一致报错。

3.2 训练配置与命令行参数

不同版本训练脚本参数有一定区别,但都可以在命令行里指定。我这里按照常见用法整理出一组核心参数:

python train.py \ --data underwater.yaml \ --weights yolov8n.pt \ --epochs 300 \ --batch 16 \ --imgsz 640 \ --device 0 \ --patience 30

参数说明:--epochs是最大训练轮数,--patience是早停轮数,当验证损失连续 30 轮不下降时自动停止;--batch受显存限制,显存不足时优先减小 batch,不要直接降低图片尺寸;--imgsz我用 640,如果小目标和密集目标多,可以试 960,但训练和推理时间都会增加。

训练初期我建议用预训练权重,而不是从随机初始化开始。因为水下垃圾检测本质上还是通用目标检测的迁移,使用在通用检测数据集上预训练的权重,能让模型在几百轮的训练中快速收敛。注意要关闭冻结权重功能,否则 backbone 不更新,模型能力会受限。

3.3 训练结果对比与调优心得

训练过程中我持续监控验证集上的 mAP 和损失曲线。四份权重训练完成后,对比结果和推理速度,我主要看两个指标:mAP@0.5 反映检测位置的准确性,mAP@0.5:0.95 对边界框质量和分类置信度更敏感。结合实际业务,我会优先保障 mAP@0.5 达到预期,再追求更高的综合指标。

当模型效果不达标时,我一般按以下顺序排查:先看数据标注有没有错误,再看类别分布是否失衡,然后是增强策略是否和实际场景匹配,最后才考虑调整模型结构或损失函数。比如有一次塑料瓶的召回率很低,我查看坏样本发现,塑料瓶被标成了塑料袋,原因是二者形状相似且在水下颜色接近。修正标注并补充难例图片后,召回率立刻提升不少。

另外,损失函数也可以做替换。YOLO 系列默认用 CIoU 损失,但对小目标和模糊目标,可以换成 WIoU,它能在训练中动态调整不同样本的权重,让模型更关注难例。这个改动有时候能带来几个点的 mAP 提升,但不是万能的,具体要看数据分布。

3.4 关键评价指标怎么看

评价模型不能只盯着一个数字。精度(Precision)是模型预测为正例的样本中真正是正例的比例;召回率(Recall)是所有真正正例中被模型找回来的比例。两者通常互相牵制,所以我会同时看 F1 分数和 PR 曲线。PR 曲线越靠近右上角,说明模型在精度和召回率之间平衡得越好。

mAP 是多个类别精度的平均值,但要分清楚 mAP@0.5 和 mAP@0.5:0.95 的含义。前者只计算预测框和真实框 IoU 大于 0.5 的检测,后者要计算从 0.5 到 0.95 多个阈值下的平均,后者的值通常低很多,也更严格。水下场景因为目标边缘模糊,框定位天然不够精确,所以 mAP@0.5:0.95 往往比通用场景低,这是正常的,不要因此怀疑模型结构选错了。

4. 部署落地:模型导出与推理流程优化

4.1 模型导出:从训练权重到中间格式

训练完的 PyTorch 权重不能直接拿到所有部署环境里用,需要先导出成通用中间格式。最常用的是 ONNX,它可以被很多推理框架加载。导出时要注意几个坑:输入尺寸要固定或者指定动态轴;模型内部的 NMS 操作要决定是留在模型里导出还是在后处理里实现。我一般倾向把 NMS 放在后处理代码里,这样导出更干净,调试也更方便。

一个简单的导出逻辑参考:

import torch model = torch.load("best.pt", map_location="cpu")["model"].float() model.eval() dummy_input = torch.zeros((1, 3, 640, 640)) torch.onnx.export( model, dummy_input, "best.onnx", opset_version=12, input_names=["images"], output_names=["output"], dynamic_axes={"images": {0: "batch"}} )

导出后一定要检查输出 shape 是否符合预期。常见问题是动态轴设置错误导致部署时输入尺寸不匹配,或者输出结果排布与后处理逻辑不一致。我会先用导出的 ONNX 在本地跑一遍相同的输入,和 PyTorch 结果对比误差,确认一致后再往部署环境迁移。

4.2 边缘设备部署与推理流程

部署端我推荐采用模块化的方式:图像采集模块、预处理模块、推理模块、后处理模块和结果上报模块。整个推理流程可以概括为:从摄像头或视频流中读取一帧,转成模型输入要求的尺寸和格式,执行推理,解码输出,根据阈值过滤,最后把检测框叠加到原始帧上保存或推送。

这里有个特别容易出错的地方:训练时用的是什么预处理,部署时必须完全复制。比如训练时把图片缩放到 640x640,部署时也必须做同样的缩放;训练时的色彩通道顺序是 RGB 还是 BGR,推理时也要保持一致。我见过有人训练用的 OpenCV 读图,但部署时用 PIL 读图,结果颜色通道反了,精度直接掉了一大截。

如果部署到嵌入式设备,还要考虑模型量化。我用的是后训练量化方式,把权重从 FP32 转成 FP16,精度损失很小,推理速度提升明显。如果条件允许,还可以做 INT8 量化,但要准备一小部分校准数据,防止输出分布偏移。

4.3 性能优化实测

性能优化是一个持续迭代的过程。我先用原始 FP32 模型跑了一遍,帧率并不理想;导出 ONNX 后改用推理加速引擎加载,帧率有所提升;再把精度降到 FP16,并关闭不必要的日志和显示,最终帧率提升了将近一倍。

需要注意的是,单纯追求帧率会牺牲精度,尤其在小目标检测上。水下垃圾里小目标比较多,把所有输入尺寸缩小虽然能大幅提速,但小目标可能直接消失。我最后的折中方案是保持 640 输入尺寸,开启批处理,在合理范围内降低 NMS 阈值,并把检测阈值从 0.25 提高到 0.35,减少误检暴露。

5. 常见问题与排查技巧实录

5.1 水下场景典型问题速查表

整理一份速查表对后面维护项目特别有用,我把实际遇到最多的问题和对应解法列在下面,方便你快速定位。

现象可能原因解决方法
图像偏蓝绿,检测性能差缺少颜色校正训练和部署前统一做灰度世界或 CLAHE
小目标频繁漏检输入尺寸过小提高 imgsz 到 960,或增加小目标增强比例
训练损失下降但验证 mAP 不高数据泄漏或过拟合按视频段划分数据集,增加正则化
部署后精度比训练时低预处理不一致严格检查缩放、通道顺序和归一化
推理速度慢模型版本重或未量化选轻量版,导出 ONNX,使用 FP16/INT8
塑料瓶和塑料袋混淆类别定义不清、标注不准重新标注,统一边界规范,补充难例
验证分数虚高同一视频帧被分到训练和验证按场景或视频段划分数据
训练时显存溢出batch 或输入尺寸太大减小 batch,开启梯度累积

5.2 几个容易被忽略的排错细节

第一个细节是日志和随机种子。训练时如果不固定随机种子,会发现多次复现的结果差异很大,尤其在小数据集上。我的做法是在训练脚本里固定 Python 和 PyTorch 的随机种子,同时固定 CUDA 相关的随机种子。这样每次训练结果可复现,排查问题也更有依据。

第二个细节是数据增强策略要分阶段调整。训练初期用强增强可以提升泛化能力,但训练后期还保持同样的强增强,可能导致模型始终学不稳。实际中我在训练后 20% 的 epoch 里降低 Mosaic 和颜色增强强度,让模型更专注于真实分布。

第三个细节是设备之间的精度差异。同一份 ONNX 模型在不同推理引擎上,因为算子实现不同,输出可能有细微差别。部署前我习惯用同一张测试图片跑一遍本地推理和目标设备推理,对比输出的检测框和置信度,差值超过阈值就用目标设备的数据重新校验,而不是想当然地认为模型文件没问题。

5.3 项目交付与二次开发建议

一套完整的水下垃圾检测系统,最终交付时除了权重文件和源码,还需要配套文档和讲解。我在整理交付内容时,会把源码按功能分目录:数据处理脚本、训练脚本、评估脚本、部署脚本、工具类脚本,并在文档里写明每个参数的取值范围和推荐值。部署文档要包含从零开始配置环境的步骤、依赖列表和常见错误码,这样才能保证换一个人也能跑起来。

二次开发时,如果要新增垃圾类别,需要动手的地方不只是模型配置文件。首先要补充新类别的标注数据,其次要修改数据集的类别列表,然后重新训练和验证。如果新增类别和目标原有类别在视觉上很相似,建议同时增加类别间的难例样本,否则模型容易混淆。现在很多水下检测项目还会集成目标跟踪模块,用来统计一定时间内出现的垃圾数量和位置,这块可以在检测模型稳定的基础上再扩展。

最后再说一个经验:不要因为追求最高精度的模型而牺牲可维护性。YOLOv12 确实在复杂背景下有优势,但它的生态和部署案例相对少。如果你做的是需要长期迭代、多环境部署的产品,YOLOv8 可能是更稳妥的底座。我个人的习惯是,先拿主流版本跑通整个流程,再根据实际情况升级更高精度版本,这样风险最小。毕竟水下垃圾检测的瓶颈往往不在模型结构差异上,而在于你有没有一套干净、稳定、可复用的数据和部署链路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询