ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

YOLOv8道路坑洞检测:小数据集训练与部署实战

YOLOv8道路坑洞检测:小数据集训练与部署实战 简介针对道路坑洞检测场景的YOLO系列目标检测数据集共1990张带标签图像面向计算机视觉开发者、智能交通与道路养护领域研究者可直接用于模型训练与验证。压缩包内包含2000个文件其中txt标签580个、xml标签1420个分别对应YOLO格式与VOC格式并附带data.yaml配置文件及划分好的训练集、验证集适配yolov5、yolov8、yolov7、yolov10、yolo11等主流框架免去自行标注和格式转换的繁琐步骤。资源包大小166.52MB结构清晰标签与图像按对应关系组织便于批量读取与调试。目前已有148人学习下载。对于缺少坑洞样本的算法落地项目这份数据能显著降低数据采集与标注成本帮助快速验证模型性能推动道路巡检自动化。1. 从一张 1990 张的坑洼图像集说起路面坑洞检测是道路养护里最典型的小目标、高变体视觉任务。坑洼没有固定轮廓光线、水渍、裂缝遮挡都让边界变得模糊而巡检车和手持设备拍到的画面又常常伴随运动模糊和曝光不均。一个只带 1990 张图像和标签的压缩包听起来规模不大但用在 YOLO 系列模型上恰好处于“从零训练不现实、直接微调又偏小”的中间地带。搞懂这个数据集的结构、标签格式和训练策略比再攒三万张图更实际。这套东西能解决什么一是让 YOLOv5/v8 快速在道路场景上收敛出可用的检测器二是给“小数据 强增强 预训练微调”这条管线一个完整的落地样板。适合谁做智慧养护、巡检算法验证的工程师以及刚把 YOLO 跑通、需要真实数据来调参的入门者。下面直接按“数据解剖 → 训练前处理 → 参数与排错 → 部署验证”的顺序拆开讲。2. 解压后先别急着训练搞清数据集目录和标签的真实格式解压 ZIP 后第一件事不是打开图片看坑洼长什么样而是用tree或find命令把整个目录结构打出来。很多道路检测数据集的压缩包会把图片和标注分两个文件夹存放但 YOLO 训练器默认要求图片和同名 txt 标签放在同一个目录镜像下。如果你不先确认这一点后面写data.yaml时路径全是错的。2.1 用一条命令快速摸清压缩包的真实结构unzip 道路坑洞检测数据集-1990张图像带标签-坑洼.zip -d pothole_data cd pothole_data find . -maxdepth 3 -type f | sed s#[^/]*$## | sort | uniq -c这段命令把压缩包解压到pothole_data然后按目录层级统计文件数。sed部分只保留路径前缀uniq -c就能看出哪一层放的是图片、哪一层放的是标签。常见布局有两种images/与labels/平级或者所有文件混在一起。如果是后者你需要先做一次拆分否则 YOLO 的train.txt和val.txt会把 txt 标注也当成图片路径。2.2 标签内容决定了你要不要写转换脚本打开任意一个标注文件用cat或者head看一眼内容。YOLO 格式的标签每一行是“class x_center y_center width height”数值已归一化到 0~1。如果看到的是多边形坐标、或者像 KITTI 那样的“类别 截断 遮挡 角度 bbox 尺寸”格式就必须先做格式转换。head -3 labels/000001.txt # 输出示例 # 0 0.5234 0.6211 0.1832 0.2417这里0代表类别索引后面四个数分别是 bbox 中心 x、中心 y、宽、高。如果只有一类坑洼类别索引就是 0。如果数据集把坑洼、裂缝、修补块都标了就要看类别名映射文件。我一般会把classes.txt或obj.names打开和标签索引对一遍防止出现“索引 1 在训练集表示裂缝、在验证集却表示坑洼”的错位。2.3 图片分辨率和标注质量的快速体检1990 张图看着不多但分辨率差异可能很大。无人机拍的俯视图和行车记录仪拍的近景图目标尺度完全不同。写个小脚本统计一下宽高分布python3 - EOF import os from PIL import Image imgs os.listdir(images) ws, hs [], [] for f in imgs[:200]: w, h Image.open(os.path.join(images, f)).size ws.append(w); hs.append(h) print(avg:, sum(ws)//len(ws), sum(hs)//len(hs)) print(min:, min(ws), min(hs), max:, max(ws), max(hs)) EOF这一步能直接决定训练时要不要开rect模式以及锚框初始化需不需要重算。分辨率差异大的数据集如果强行imgsz640拉平小目标的细节会丢得很厉害。3. 训练前必须做的三步数据集重组织、YOLO 配置和增强策略数据本身没问题不等于能直接开训。YOLO 的训练器对数据集路径结构有固定预期你在 Kaggle 或 Gitee 上拿到的压缩包往往不满足这个预期重组织就是第一个绕不开的步骤。3.1 把图片和标签改成 YOLO 标准布局常见做法是在项目根目录下重新建一套文件夹结构mkdir -p pothole_yolo/images/{train,val} mkdir -p pothole_yolo/labels/{train,val} cp pothole_data/images/*.jpg pothole_yolo/images/train/ cp pothole_data/labels/*.txt pothole_yolo/labels/train/ # 按 9:1 或 8:2 分出验证集 python3 - EOF import random, os, shutil files os.listdir(pothole_yolo/images/train) random.seed(42) random.shuffle(files) val files[:int(len(files)*0.2)] for f in val: shutil.move(fpothole_yolo/images/train/{f}, fpothole_yolo/images/val/{f}) shutil.move(fpothole_yolo/labels/train/{f[:-4]}.txt, fpothole_yolo/labels/val/{f[:-4]}.txt) EOF注意验证集划分必须图片和标签同步移动否则训练时Dataset会报“label 缺失”或“image 缺失”。如果原始标签文件和图片不是同名这份代码会漏掉建议先用diff检查两边文件名集合是否一致。3.2 data.yaml 里最容易写错的三个字段path: pothole_yolo train: images/train val: images/val nc: 1 names: [pothole]第一处path要填相对于你执行训练命令位置的路径不是绝对路径。第二处nc必须和标签里出现的最大索引 1 相等如果标签里出现过索引 5nc至少是 6写 1 会在 loss 计算时直接崩掉。第三处是names列表的长度要和nc一致名字本身随便起但顺序必须和标签索引对应。3.3 增强参数小数据集的命脉1990 张图上直接训 YOLOv8不增强的话大概率过拟合。合理配置增强参数是这步的核心参数推荐值说明hsv_h0.015色调偏移不宜大道路颜色变化有限hsv_s0.5饱和度增强可以缓解阴天和强光差异fliplr0.5水平翻转对坑洼有效但不能开flipudmosaic1.0默认开启但小数据集建议降到 0.8mixup0.2对坑洼这种纹理型目标效果不稳定谨慎开启degrees5巡检车拍摄有轻微旋转5 度就够注意翻转策略坑洼在路面上的位置没有方向性水平翻转安全垂直翻转会让“天空”出现在路面区域破坏场景语义训出来的模型在真实道路上会误检路牌。4. 用 YOLOv8 跑通训练命令、损失曲线判读和三个高频报错这个数据集叫“yolo 算法道路坑洞检测”说明就是为 YOLO 系列准备的用 YOLOv8 实测最稳。yolo命令行工具已经足够完成从训练到导出的全部流程不需要写额外的 Python 脚本。4.1 最小训练命令和显存预算yolo train datapothole.yaml modelyolov8s.pt epochs100 imgsz640 batch16 patience10 projectruns/pothole nameexp1modelyolov8s.pt是关键的迁移学习设定它会自动下载 COCO 预训练权重。batch16在 640 分辨率下约需 12 GB 显存如果你只有 8 GB 卡改成batch8或imgsz512。patience10是早停轮数数据集小的时候 loss 容易震荡早停阈值可以放宽到 15。训练启动后注意看首屏输出的类别数和标签数。YOLO 会在数据集扫描阶段就计算每个类别的实例数量如果发现某个类别只有几十个标注框后续 mAP 大概率被这个类拉低。这时可以考虑把该类别从训练中剔除或者用复制粘贴增强去补。4.2 训练中怎么判断模型有没有在学别只看box_loss绝对值要看下降趋势。正常情况是前 20 轮 loss 快速下降然后进入平台期。如果box_loss在 50 轮后反复波动不下降说明学习率偏高需要调低lr0到 0.001 或改用cos_lrTrue做余弦退火。另一个可靠信号是验证集上的mAP50和mAP50-95的差值。坑洼检测场景里mAP50达到 0.7 以上但mAP50-95只有 0.3 多说明框的大致位置对了但 IoU 精度不够问题出在回归分支可以增大iou阈值或检查标注框边缘是否贴得过紧。4.3 三个实际训练中最常见的报错第一个是AssertionError: train: Label class 1 missing from training。这个报错说明标签里有的类别没有出现在训练集划分中而验证集里有。解决方法是把类别少的样本用脚本抽出来人为分配到训练集或者在data.yaml里缩减类别数。第二个是CUDA out of memory。除了调小batch更推荐开启fraction0.7让 PyTorch 只使用 70% 显存避免和数据加载器的缓存冲突。第三个是No labels found in image folder。这往往是标签文件扩展名不是.txt或者标签和图片文件名有隐藏空格。用ls -la看看文件列表再用file命令确认标注文件的真实格式。5. 训练完别急着部署用混淆矩阵和剪枝手段榨干小数据集的剩余价值1990 张图训出来的模型直接上生产环境大概率会在陌生路面上翻车。最后一章不聊理论聊点实际能落地的增强手段。5.1 用混淆矩阵找系统性误检训练结束后yolo val会生成confusion_matrix.png。重点看“background”那一列。如果很多检测框落在背景类上说明模型把路面裂缝、积水阴影当成了坑洼。这时候不是加数据而是检查标注框是不是把裂缝也框进去了。道路场景里坑洼和裂缝常伴生标注员的画框习惯会直接影响模型的决策边界。5.2 用剪枝把模型压到能上嵌入式设备yolov8s的参数量大约 11M跑在 Jetson 或 RK3588 上还算宽裕但如果要部署到更低功耗的设备可以用torch.prune做通道剪枝import torch from ultralytics import YOLO model YOLO(runs/pothole/exp1/weights/best.pt) for module in model.model.modules(): if hasattr(module, conv) and hasattr(module.conv, weight): torch.prune.ln_structured(module.conv, nameweight, amount0.2, dim0) torch.save(model.ckpt, pothole_pruned.pt)剪枝后必须重新训练几个 epoch否则精度会掉到不可接受。5.3 把模型导出为 ONNX 并检查推理输出最后一步是导出验证目的是确认整个链路从训练的模型格式到实际部署格式之间没有信息丢失yolo export modelruns/pothole/exp1/weights/best.pt formatonnx opset12 halfTrue导出成功后用onnxruntime或onnx2trt推理一张验证集图片检查输出的坐标是否落在合理范围内。如果输出的置信度普遍低于 0.1大概率是halfTrue在导出时精度损失过大改成halfFalse重试。这一步做完这套数据集才算真正从 zip 变成了可用的道路巡检检测能力。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进