多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

YOLOv8水下管道检测实战:数据集处理、模型训练与避坑指南

YOLOv8水下管道检测实战:数据集处理、模型训练与避坑指南 简介这份面向水下管道巡检的检测识别资源包基于Ultralytics YOLOv8框架服务于海洋工程与基础设施维护场景帮助工程人员快速识别和定位水下管道。压缩包共2000个文件以1985个VOC格式xml标签文件为主同时包含数据配置yaml、说明文档md及清单txt整体约878MB。数据集部分包含7971张标注好的图像类别为underwater-pipe水下管道已按train/val/test划分完成并附有data.yaml可直接用于YOLOv5、v8、v9、v10、v11、v12等主流版本训练。资源内还提供训练好的模型与使用教程md文档详细说明了从数据加载、模型调用到推理输出的完整流程便于学习者将模型迁移至真实巡检影像中。目前已有118人学习下载适合从事水下探测、海洋设施巡检及计算机视觉检测的开发者参考使用。1. 水下管道检测YOLOv8到底解决了什么没解决什么水下管道的检测识别和路面目标检测完全是两码事。路面上的车、人、标识牌有大量公开数据集和预训练权重拿过来微调一下就能用水下管道没有这个条件——水体吸收红光后画面整体偏蓝绿泥沙、气泡和悬浮物制造大量视觉噪声管道经常和背景融为一体线状结构又让标注和检测都更麻烦。Ultralytics YOLOv8之所以在这个领域流行是因为它的训练和推理链路足够成熟数据格式简单ultralytics-yolov8-pred-underwater-pipes这类带着数据集和训练好的模型的压缩包正好命中了一线工程师最缺的两种资源标注好的水下场景数据和可以直接跑的权重。这篇文章会把数据集处理、训练参数、预测推理和踩坑路径完整过一遍让你拿到这类压缩包后能直接复现而不是把时间浪费在试错上。2. 数据集到手先别急着训练标注格式、类别分布与划分策略2.1 从压缩包到YOLO格式确认数据集到底长什么样一个带数据集和训练好的模型的压缩包解压后东西其实不多但很多人一拿到就急着跑训练命令结果不是路径不对就是标签格式不对。先花两分钟把目录结构列出来这一步能避免后面很多困惑。我一般会先跑find命令看看整个目录树。find . -maxdepth 3 -type d | sort正常的水下管道数据集解压后至少会有这几样东西按train和val分好的images目录、对应的labels目录、一个data.yaml或data.yml配置文件以及weights目录下放着训练好的best.pt。train里面是训练图片val里面是验证图片labels里是每张图片对应的YOLO格式标注txt文件。这个时候打开data.yaml看几行确认类别数和类别名是否符合预期。水下管道检测通常只有一个类别pipe如果有多个类别比如pipe和flange就要先确认自己需要检测的范围是不是和数据集标的范围一致。有些人拿到多类别的数据集不管三七二十一直接训练结果预测出来的类别有七八种下游逻辑根本用不过来。# data.yaml 典型内容 # 注意路径用相对路径还是绝对路径取决于训练时的工作目录 train: ./dataset/images/train val: ./dataset/images/val nc: 1 names: 0: pipe这里nc为1意味着模型只需要把管道从背景里分出来。相比多类别的场景单类别的训练难度低不少但要警惕另一种风险数据集里除了管道还有电缆、绳索、鱼网这些长条状物体模型很可能会把它们当成管道一起检出来。这个问题的处置放到第5章讲。2.2 标注质量检查脚本统计类别、目标大小和坏标注拿到数据集后别急着训练先跑一段标注统计脚本能省不少返工时间。YOLO格式的标签txt每一行五个数值类别id、归一化中心x、归一化中心y、归一化宽、归一化高。我见过不少数据集打包时标注文件里的类别id写错或者有坐标为负数的坏行这类问题在训练时不会直接报错但会让模型学到大面积错误。# check_labels.py from collections import Counter import os label_dir dataset/labels/train cls_counter Counter() bad_lines [] box_count 0 wh_list [] for fname in sorted(os.listdir(label_dir)): if not fname.endswith(.txt): continue path os.path.join(label_dir, fname) with open(path, r) as f: for line in f: parts line.split() if len(parts) ! 5: bad_lines.append((fname, line.strip())) continue try: cls_id int(parts[0]) cx, cy, w, h map(float, parts[1:5]) except ValueError: bad_lines.append((fname, line.strip())) continue if not (0 cx 1 and 0 cy 1 and 0 w 1 and 0 h 1): bad_lines.append((fname, line.strip())) continue cls_counter[cls_id] 1 box_count 1 wh_list.append((w, h)) print(类别分布:, dict(cls_counter)) print(标注框总数:, box_count) print(异常行数:, len(bad_lines)) for fname, content in bad_lines[:10]: print(f {fname}: {content}) if wh_list: avg_w sum(box[0] for box in wh_list) / len(wh_list) avg_h sum(box[1] for box in wh_list) / len(wh_list) print(f平均框宽: {avg_w:.4f}, 平均框高: {avg_h:.4f}) else: print(没有有效标注框检查数据集)这段脚本的输出几个关键量类别分布提示你每个类别有多少个目标如果某个类别的框数比另一个少一个数量级就需要考虑数据增强或采样策略异常行数直接告诉你标注文件里有多少行格式错误这类标注不清理训练时模型会把错误当真理学进去平均框宽高比则决定imgsz选择如果平均目标宽度不足0.1那在640分辨率下目标只有64像素宽属于小目标范畴建议训练时imgsz至少给到640以上。2.3 解决train/val划分泄漏按视频编号划分而不是随机打乱水下管道数据绝大部分来自巡检视频的连续截图这带来一个很隐蔽的问题直接按帧随机划分训练集和验证集会导致时间上相邻的帧在两个集合里同时出现。模型在训练时看过这一段管道的画面验证时又拿相邻几帧来打分mAP数字虚高得厉害等部署到真正没见过的新视频上效果会掉一个档次。这是水下管道检测里最典型的黑匣子现象。可以先用脚本检查train和val目录下的文件名看是否带视频编号或时间戳。比如文件名是video01_00123.jpg这种前面的video01就是视频编号后面四位是帧号。ls dataset/images/train | sed s/_[0-9]*\.jpg$// | sort -u train_vids.txt ls dataset/images/val | sed s/_[0-9]*\.jpg$// | sort -u val_vids.txt comm -12 train_vids.txt val_vids.txt如果comm输出有内容就说明同一个视频的帧同时进了训练集和验证集。解决方式是重新按视频编号划分把属于同一视频编号的所有帧全部归入同一个集合。有的数据集在打包时已经做了按场景划分但花两分钟检查一遍毕竟有备无患。重新划分后你会发现验证集mAP比之前低一些这恰恰说明之前的数字有水不用慌。3. Ultralytics YOLOv8训练链路环境配置、命令与核心参数3.1 环境搭建ultralytics安装的版本兼容与GPU验证训练的第一步是把Ultralytics库装好用对。YOLOv8的官方实现都统一在ultralytics这个包下pip安装即可但实际安装中经常遇到报错Could not find a version that satisfies the requirement ultralytics。看到这个报错先别急着换pip源多数情况是Python版本太低或者pip源同步滞后。我的环境习惯是Python 3.9到3.11之间用一个独立的虚拟环境来装这样不会干扰其他项目。python -m venv yolo_env source yolo_env/bin/activate pip install --upgrade pip pip install ultralytics装完先验证一下库能不能正常导入顺便确认有没有把CUDA对应的PyTorch装上。如果这里出问题训练时会一直在CPU上跑速度慢到你怀疑人生。python -c import torch; print(CUDA available:, torch.cuda.is_available())如果CUDA不可用大概率是PyTorch版本和本机CUDA驱动不匹配。建议用PyTorch官网给出的命令重新安装对应的版本而不是强制装最新版。GTX 1660 Ti之类的6GB显存卡跑yolov8n和yolov8m都没有问题只是batch要大一些的话会卡显存。3.2 训练命令拆解模型选择、imgsz、batch与epochs数据集路径确认没问题之后先用最小的yolov8n模型把整个训练流程跑通再换大模型追求精度。这个顺序很重要小模型训练快、显存占用低50个epoch几分钟到十几分钟就能跑完如果数据或标注有问题这个时候暴露出来成本最低。yolo detect train \ modelyolov8n.pt \ datadata.yaml \ imgsz640 \ epochs50 \ batch8 \ patience10 \ projectunderwater_pipe \ nameexp_n # 确认无误后换 yolov8m 提升精度 yolo detect train \ modelyolov8m.pt \ datadata.yaml \ imgsz640 \ epochs100 \ batch8 \ patience15 \ projectunderwater_pipe \ nameexp_m这里几个核心参数需要说明。imgsz是训练时的输入尺寸YOLOv8会在训练时按这个尺寸缩放图片。水下管道往往不是占满整幅画面的目标640是常用起点如果管道很细很小可以试试1280但显存占用会明显上涨。batch是一次喂给网络的图像数量6GB显存跑yolov8m建议8及以下跑yolov8n可以给到16。patience是早停参数连续多少个epoch验证指标不提升就停止设10到15比较合理。还有一个容易被忽略但很实用的参数是mosaic。Ultralytics默认在训练前10个epoch开启mosaic数据增强把4张图拼接成一张对小目标检测提升明显。但水下管道是线状物体拼图可能把一条完整的管道切断反而让模型学到不完整的形状特征所以如果发现训练曲线波动大可以在训练后半段用close_mosaic参数提前关掉它。yolo detect train \ modelyolov8m.pt \ datadata.yaml \ imgsz640 \ epochs100 \ mosaic0.5 \ close_mosaic10mosaic0.5表示mosaic增强的概率是0.5close_mosaic10表示训练最后10个epoch强制关闭mosaic。这两个参数是水下线状目标训练时比较值得调的比默认设置更容易让模型稳定收敛。3.3 训练日志与损失曲线的读法不要只关心mAP训练过程中终端会输出每一轮的box_loss、cls_loss、dfl_loss以及precision、recall、mAP50、mAP50-95。很多人只看mAP50觉得到了0.9就万事大吉但其实mAP50-95对定位精度更敏感因为它在多个IoU阈值下做平均。水下管道是线状物体如果框的位置偏移了半个身位mAP50仍然可能很高但mAP50-95会暴露问题。如果发现mAP50和mAP50-95差距过大说明模型虽然能看见管道但位置不够准。这时候首先考虑的是标注质量回到第2章的统计脚本看看是否有大量框的宽高比极端异常。其次可以增加训练epochs或调低学习率。最后还有一种可能验证集划分出了问题把第2.3节的检查再做一遍。训练结束后project/name目录下会有best.pt和last.pt分别是最优权重和最后一轮权重。预测时加载best.pt这也是这个压缩包里训练好的模型部分的来源。加载方式很简单但有个细节值得提醒如果你后续要换图像分辨率做推理最好在训练时就用接近的分辨率否则模型从640分辨率迁移到1280分辨率上速度和精度都会不稳定。注意有些老教程会把YOLOv8权重说成是yolov8.pt一类的文件名但实际上Ultralytics官方把不同尺寸的模型分成yolov8n.pt、yolov8s.pt、yolov8m.pt、yolov8l.pt、yolov8x.pt几档n最轻量x精度最高但速度最慢。水下管道这种单类别任务里yolov8s到yolov8m是性价比最高的区间。4. 用训练好的模型做预测从单张图片到批量视频的完整流程4.1 单张图片与批量预测predict的输入输出细节预测是pred这个标题关键词对应的核心动作。用Ultralytics库跑预测入口统一是model.predict输入既可以是单张图片路径也可以是文件夹路径、视频文件路径甚至numpy数组。日常巡检中最常见的是对一个文件夹下的多张图片批量预测。from ultralytics import YOLO model YOLO(underwater_pipe/exp_m/weights/best.pt) results model.predict( sourceunderwater_test_images/, conf0.25, iou0.5, imgsz640, saveTrue, save_txtTrue, save_confTrue, projectpred_output, nametest_run )saveTrue会生成可视化图单张图有检测框、类别名和置信度用来看效果很直观。save_txtTrue会把检测结果写成txt文件每行对应一个检测框类别id、归一化框坐标、置信度。save_confTrue是在txt里追加一列置信度。工程上对接下游系统时save_txt输出的东西往往比可视化图更重要因为你后续要做的是把框坐标传给控制程序或生成报告。predict里还有一个容易被忽略的参数是max_det默认300。水下管道场景中一帧画面里通常不会有那么多目标但如果画面里噪声太多模型可能把碎片也当成候选框max_det设小一点可以降低后处理内存占用比如设成20。另外classes参数可以在推理时过滤类别如果你训练的是多类别模型但下游只关心管道这一类推理时指定classes[0]就能把其他类别的输出全部屏蔽掉。4.2 视频推理与连续帧稳定性抽帧预测更实用水下巡检数据很大比例是视频。视频推理可以按帧直接跑也可以先抽帧再跑这两种方式各有适用场景。如果要求在线实时检测就按帧跑但要看GPU算力够不够如果只是离线分析巡检录像抽帧是更务实的选择。# 直接按帧跑视频 yolo detect predict \ modelunderwater_pipe/exp_m/weights/best.pt \ sourceunderwater_video/segment_01.mp4 \ conf0.25 \ saveTrue # 抽帧之后批量预测 ffmpeg -i underwater_video/segment_01.mp4 -vf fps2 frame_%04d.jpg yolo detect predict \ modelunderwater_pipe/exp_m/weights/best.pt \ sourceframe_dir/ \ conf0.25 \ saveTrue抽帧预测有一个额外的好处便于排查。如果哪个时间点检测异常可以按帧号直接回溯到对应时刻逐帧核对原始画面。fps2表示每秒钟抽2帧水下管道的运动速度通常不会太快2帧每秒已经足够捕捉到管道位置变化。如果管道被水流带着摆动的幅度很大可以提高到fps5但要注意这会让标注和排查的工作量成倍增加。4.3 结果结构化输出把检测框坐标喂给下游预测完成不是终点。在水下管道巡检系统里检测结果通常要接入下游处理比如计算管道中心线偏移、统计疑似破损区域的帧区间、生成巡检报告。这一环节需要从results里直接读取结构化数据而不是解析可视化图片。from ultralytics import YOLO model YOLO(underwater_pipe/exp_m/weights/best.pt) results model.predict(underwater_test_images/, verboseFalse) for i, r in enumerate(results): if len(r.boxes) 0: continue for j, box in enumerate(r.boxes): cls_id int(box.cls[0]) conf float(box.conf[0]) x1, y1, x2, y2 box.xyxy[0].tolist() print(f帧 {i}, 目标 {j}: cls{cls_id}, conf{conf:.3f}, fbox({x1:.1f}, {y1:.1f}, {x2:.1f}, {y2:.1f}))这里box.xyxy返回的是像素坐标比起解析save_txt里归一化坐标再乘图像尺寸省了一步换算。对于一些带旋转角度的管道检测需求YOLOv8默认的检测头只能输出水平矩形框如果需要旋转框就只能转向mmrotate库的方案这一点提前想清楚能避免后面返工。注意如果后续要计算管道在图像中的角度、宽度等几何指标水平矩形框是不够用的建议在项目立项阶段就确认清楚检测输出的维度。如果只需要判断有没有管道和大致位置YOLOv8的水平框完全够用。5. 水下管道检测常见问题排查五个实操避坑记录5.1 图像整体偏蓝绿色模型识别效果差现象训练时验证集mAP不错一到真实水下视频上漏检率飙升。原因水下图像颜色分布和普通图像差异极大。大部分预训练权重是在ImageNet或COCO这种陆地场景上训练的模型对纹理和颜色的先验都偏向普通场景。如果训练集和验证集都来自同一批水下视频颜色风格一致模型学到的可能是蓝绿色背景下的管道而没泛化到不同水质下的管道。解决采集数据时尽量覆盖不同水质的视频混入一些颜色偏暗、有泥沙的环境。如果样本无法扩增可以在训练时打开增强对色调、饱和度、亮度做随机扰动让模型不容易聚焦在颜色上。具体做法是在训练命令中调整hsv_h、hsv_s、hsv_v参数yolo detect train \ modelyolov8m.pt \ datadata.yaml \ imgsz640 \ epochs100 \ hsv_h0.02 \ hsv_s0.8 \ hsv_v0.4hsv_h0.02表示色相在正负2%范围内随机扰动hsv_s0.8是饱和度扰动幅度hsv_v0.4是明度扰动幅度。水下图像三个通道的分布很特殊适当增大hsv_s能让模型在训练时看到更多样的颜色组合降低对蓝绿色背景的依赖。5.2 训练不收敛loss在几十个epoch后仍然波动现象训练日志里box_loss、cls_loss曲线震荡mAP始终在0.3以下。原因最常见的是学习率设置不当或者batch太小导致梯度不稳定。水下数据集往往样本量不大几百张图时batch从8改到4会让梯度噪声变大模型难以收敛。解决先确认batch是不是太小6GB显存跑yolov8m时batch至少要有4再小就换yolov8n如果batch没问题把初始学习率从默认的0.01降到0.001并保留前几个epoch的warmup。Ultralytics默认带warmup_epochs3前面会把学习率从很小逐渐升到设定值。我习惯用以下命令组合排查yolo detect train \ modelyolov8n.pt \ datadata.yaml \ imgsz640 \ epochs50 \ batch8 \ lr00.001 \ warmup_epochs5 \ patience10如果换了小模型、降了学习率仍然不收敛问题大概率出在标注上回到第2章的脚本检查标注文件看有没有坐标大于1的异常值或类别id超出范围的情况。5.3 训练好的模型在图片上出现大量误检框现象在非管道区域也画了框且置信度不低。原因如果水下图像里有一些和管道纹理接近的物体比如电缆、鱼网、水草排列模型会把这些目标当成管道。另外如果训练集里管道样本太少模型会倾向把所有细长物体都判为管道。解决先看误检框集中在哪类场景把这类场景的负样本没有管道的图片加入训练集。YOLO支持训练时识别负样本——只要该图片没有标注文件模型就会学习到这些区域没有目标。还有一种做法是提高conf阈值但这是治标不治本只对后处理有效模型本身的特征没变。如果负样本难收集重点关注5.1的数据增强方案让模型学到更细的纹理特征而不是形状特征。5.4 验证集指标高但实际场景效果差现象mAP50有0.9以上到真实项目现场跑视频检出率明显下降。原因九成是数据划分泄漏也就是第2.3节说到的按帧随机划分导致训练集和验证集有重叠。另外一成是验证集选取过于接近训练集分布比如全部来自同一段视频。解决回到第2.3节检查视频编号是否在train和val中交叉必须保证同一个视频的帧全部在同一个集合里。划分完之后再看验证集里的图像多样性——如果验证集只有一段视频里的帧指标就没有参考价值。重新划分后mAP指标下降是正常的不用慌那才是模型真实水平的分数。5.5 批量预测视频时显存溢出现象预测到一半报CUDA out of memory进程退出。原因视频推理时ultralytics会把整帧送入GPU如果视频分辨率是4Kimgsz设置又很大显存就会被撑满。尤其部署到6GB显存的卡上画面一复杂就崩。解决先降低imgsz比如从640降到480对视频推理来说分辨率影响通常可以接受。还有一个实用的技巧是给视频做抽帧预测而不是逐帧预测管道运动速度一般不快每秒抽2帧检测一次既能覆盖巡检需求又不会让显存吃紧。# 抽帧预测思路先用ffmpeg抽帧 ffmpeg -i underwater_video/segment_01.mp4 -vf fps2 frame_%04d.jpg # 再对抽出的帧批量预测 yolo detect predict \ modelunderwater_pipe/exp_m/weights/best.pt \ sourceframe_dir/ \ conf0.25 \ saveTrue抽帧这个做法在工程里还有一个好处如果某个时间段检测结果异常你可以直接定位到具体的帧号排查效率比逐帧回放高得多。6. 进阶水下管道模型上线前的验证与导出技巧模型训练完、预测也跑通了接下来要做的事情是在下结论之前验证模型是否真的可靠。第一个技巧是拿训练好的模型去跑一段训练集里没有出现过的独立视频对比模型输出的连续帧看管道在画面里的框是否连贯。如果某几帧框突然消失又出现不要急着怪模型先看是不是该帧画面出现大面积气泡或悬浮物遮挡这是水下场景的正常噪声可以在后处理中把连续丢失低于3帧的间隙用插值补上。第二个技巧是关注mAP50-95而不是mAP50。水下管道检测识别很多时候不只是找到管道还要给下游提供管道位置坐标。mAP50允许框的位置有一定偏差但坐标偏差在实际工程里会传导到后续测量和机械定位。我习惯在验证集上额外跑一次不同conf阈值下的precision-recall曲线选择一个让precision和recall都比较平衡的阈值而不直接用默认的0.25。第三个技巧是对比不同尺寸模型的推理耗时。常见做法是先在本地用yolov8m跑通全流程确认精度达标后再评估轻量部署的可能。把模型导出为ONNX或TensorRT格式用yolo export一条命令就能完成在部署到rk3588这类边缘设备时几乎是必经之路。导出命令如下yolo export modelunderwater_pipe/exp_m/weights/best.pt formatonnx imgsz640导出前在验证集上确定好最终使用的imgsz一旦导出后续推理的输入分辨率就要和导出时保持一致不然精度会受影响。我自己做项目时的一个重要习惯是把训练好的模型、数据划分脚本、评估结果和最终参数清单一起归档。因为这类项目往往要跨几个月迭代今天用的参数三个月后如果不记录重新调时要花不少时间还原。有一次我在一个老项目上就因为忘了记录数据增强参数回头复现时发现结果怎么都对不上翻遍邮件才找到当初调整的hsv参数从那以后参数清单就成了固定动作。希望帮到你。本文还有配套的精品资源点击获取
返回列表