
简介这份资源面向从事道路巡检、智能交通与计算机视觉方向的研究者及工程人员提供一套按YOLOV5目录规范整理好的日本马路路面缺陷检测数据集可直接投入目标检测模型训练省去格式转换与标注清洗环节。包内共2000个文件以1999个txt标注文件与1个Python可视化脚本为主压缩包约753.56MBtxt文件承载图像对应的边界框与类别信息py脚本用于快速核验标注效果。数据涵盖纵向裂纹、横向裂纹、坑洞、不规则裂缝等7类路面缺陷图像为600×600的RGB图片并已划分训练集7757张与验证集1955张各自配套等量标签文件另附类别文本说明。随机传入一张图片即可绘制并保存边界框脚本无需修改即可运行便于直观检查标注质量。目前已有327人学习适合需要快速验证检测算法或搭建路面病害识别流程的读者。1. 日本马路路面缺陷检测数据集7 类标注到底能训出什么模型如果你手头只有一份标注数据却要判断它值不值得投入标注清洗、格式转换和训练调参的时间那这份日本马路路面缺陷检测数据集YOLOV5 目录格式7 类别就是典型的“先看分布再动手”的样本。它解决的不是“有没有数据”的问题而是“路面缺陷这种长尾、小目标、强光照变化的场景用 YOLOV5 目录格式能不能直接跑通训练并落地到巡检”。适合两类人一类是想用 YOLOV5 训练自己的数据集、但还没搞清目录结构和标签规范的算法新手另一类是做道路巡检、无人小车或边缘设备部署需要先验证数据质量再决定要不要上树莓派或 RK3568 的工程人员。这份数据的关键不在“日本”两个字而在于 7 类缺陷的标注粒度是否统一、YOLOV5 目录格式是否开箱即用、以及类别不平衡会不会让模型在稀有类上直接摆烂。2. YOLOV5 目录格式拆解从 images/labels 到 data.yaml 的最小闭环2.1 目录结构不是随便摆的错一层就白训YOLOV5 对目录的容忍度很低常见做法是严格按下面的层级组织。很多人把图片和标签混在一个文件夹里训练脚本不会报错但会静默跳过所有标签最后 mAP 掉到 0 还找不到原因。# 标准 YOLOV5 数据集目录结构 dataset/ ├── images/ │ ├── train/ # 训练集图片jpg/png 均可 │ │ ├── road_001.jpg │ │ └── road_002.jpg │ └── val/ # 验证集图片 │ ├── road_101.jpg │ └── road_102.jpg ├── labels/ │ ├── train/ # 训练集标签与图片同名.txt 格式 │ │ ├── road_001.txt │ │ └── road_002.txt │ └── val/ │ ├── road_101.txt │ └── road_102.txt └── data.yaml # 数据集描述文件逻辑说明images 和 labels 必须同级train/val 子目录名必须一致。YOLOV5 在训练时通过替换路径中的/images/为/labels/来查找标签所以图片和标签的文件名不含扩展名必须严格一一对应。参数上图片可以是 jpg、png、bmp但标签必须是.txt且每行格式为class_id x_center y_center width height全部归一化到 0~1。2.2 data.yaml 里三个字段写错训练直接跑偏data.yaml 是 YOLOV5 训练入口7 类缺陷的映射关系全在这里。常见错误是nc写成 8 或者names顺序和标注时的 class_id 对不上导致模型把裂缝学成坑槽。# data.yaml 示例对应 7 类路面缺陷 path: ./dataset # 数据集根目录 train: images/train # 训练集相对路径 val: images/val # 验证集相对路径 nc: 7 # 类别数必须和 names 长度一致 names: 0: longitudinal_crack # 纵向裂缝 1: transverse_crack # 横向裂缝 2: alligator_crack # 龟裂 3: pothole # 坑槽 4: rutting # 车辙 5: raveling # 剥落 6: patch # 修补逻辑说明path可以用绝对路径但迁移到服务器时容易失效建议用相对路径并在训练命令里cd到项目根目录。nc和names的索引必须从 0 开始连续不能跳号。如果标注时用了 1~7 作为 class_id这里必须改成 0~6否则训练时会出现索引越界或类别错位。2.3 标签格式转换从 VOC/COCO 到 YOLO 的四个边界坑如果原始标注是 XML 或 JSON需要转成 YOLO 格式。转换脚本本身不复杂但边界条件处理不好会引入脏标签。import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, img_w, img_h, class_map): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_map: continue # 跳过未定义类别避免索引错乱 cls_id class_map[cls_name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 边界裁剪防止标注框超出图像范围 xmin max(0, min(xmin, img_w)) xmax max(0, min(xmax, img_w)) ymin max(0, min(ymin, img_h)) ymax max(0, min(ymax, img_h)) if xmax xmin or ymax ymin: continue # 跳过无效框 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) return lines逻辑说明class_map是类别名到 0~6 的映射字典必须和 data.yaml 的 names 顺序一致。边界裁剪解决的是标注框超出图像边缘的问题不裁剪会导致归一化坐标大于 1YOLOV5 虽然能读但会引入噪声。xmax xmin的判断过滤掉零面积框这种框在训练时会产生无效梯度。参数上坐标保留 6 位小数足够YOLOV5 内部会再做一次归一化。3. 7 类路面缺陷的分布检查与训练集划分策略3.1 先统计再划分别让稀有类在验证集里消失拿到数据后第一件事不是直接训练而是统计每类样本数和标注框数量。7 类缺陷里龟裂和坑槽通常样本少纵向裂缝和横向裂缝样本多直接随机划分会导致验证集里稀有类只有个位数甚至为零。import os from collections import Counter def count_instances(label_dir): counter Counter() for txt_file in os.listdir(label_dir): if not txt_file.endswith(.txt): continue with open(os.path.join(label_dir, txt_file)) as f: for line in f: cls_id int(line.strip().split()[0]) counter[cls_id] 1 return counter # 分别统计 train 和 val train_counter count_instances(dataset/labels/train) val_counter count_instances(dataset/labels/val) print(训练集类别分布:, dict(sorted(train_counter.items()))) print(验证集类别分布:, dict(sorted(val_counter.items())))逻辑说明统计的是标注框数量而不是图片数量因为一张图可能包含多个缺陷。如果某类在验证集中少于 10 个实例mAP 波动会非常大建议改用分层抽样或手动调整划分。参数上cls_id直接取每行第一个整数不需要解析坐标。3.2 分层抽样让每个类别在验证集里都有足够样本常见做法是按类别分组后按比例抽取保证验证集里每类至少占 10%~20%。如果数据量小可以适当提高验证集比例到 30%但训练集不能低于 70%。import random from collections import defaultdict def stratified_split(label_dir, val_ratio0.2): # 按类别收集图片名 cls_to_files defaultdict(list) for txt_file in os.listdir(label_dir): if not txt_file.endswith(.txt): continue with open(os.path.join(label_dir, txt_file)) as f: classes set(int(line.split()[0]) for line in f if line.strip()) for c in classes: cls_to_files[c].append(txt_file.replace(.txt, .jpg)) val_files set() for c, files in cls_to_files.items(): random.shuffle(files) n_val max(1, int(len(files) * val_ratio)) val_files.update(files[:n_val]) return val_files逻辑说明一张图可能属于多个类别所以用 set 去重。n_val至少为 1防止稀有类在验证集中完全缺失。参数上val_ratio根据数据量调整数据量小于 1000 张时建议 0.25~0.3。3.3 类别不平衡的三种处理方式别只会过采样路面缺陷数据天然不平衡龟裂和坑槽可能只占 5%。常见做法有三种过采样稀有类、在 loss 里加类别权重、或者用 focal loss。YOLOV5 默认用 BCEWithLogitsLoss可以通过修改hyp.yaml里的cls_pw参数给正样本加权。# hyp.yaml 中与类别不平衡相关的参数 cls_pw: 1.0 # 类别正样本权重稀有类可调到 2.0~3.0 obj_pw: 1.0 # 目标置信度正样本权重 fl_gamma: 0.0 # focal loss 的 gamma设为 1.5~2.0 可缓解不平衡逻辑说明cls_pw直接乘在分类 loss 上调大后模型更关注稀有类但过大会导致误检增加。fl_gamma大于 0 时启用 focal loss对易分类样本降权。参数上建议先跑 baseline看混淆矩阵再决定调哪个不要一上来就改一堆。4. 用 YOLOV5 训练路面缺陷模型的参数与显存调优4.1 从预训练权重起步别从零训YOLOV5 在 COCO 上预训练的权重对边缘、纹理特征已经有很好的提取能力路面缺陷检测属于纹理类任务迁移效果通常比从零训好很多。常见做法是下载yolov5s.pt或yolov5m.pt根据显存选模型大小。# 训练命令示例单卡 8G 显存 python train.py \ --data dataset/data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch-size 16 \ --epochs 100 \ --device 0 \ --workers 4 \ --project runs/train \ --name road_defect逻辑说明--img 640是输入分辨率路面缺陷目标通常不大640 够用显存紧张可降到 512。--batch-size 16在 8G 显存下跑 yolov5s 比较稳yolov5m 建议降到 8。--workers是数据加载线程数Windows 下建议设为 0 或 2Linux 下可以设 4~8。--device 0指定第一块 GPUCPU 训练用--device cpu但速度会慢很多。4.2 学习率和 warmup前 3 个 epoch 决定模型会不会崩YOLOV5 默认用 SGD学习率lr00.01warmup 3 个 epoch。如果数据量小或者类别不平衡严重lr0可以降到 0.001~0.005warmup 加到 5。# hyp.yaml 中学习率相关参数 lr0: 0.01 # 初始学习率 lrf: 0.01 # 最终学习率 lr0 * lrf momentum: 0.937 # SGD 动量 weight_decay: 0.0005 warmup_epochs: 3.0 warmup_momentum: 0.8 warmup_bias_lr: 0.1逻辑说明lrf控制余弦退火的终点太小会导致后期学习停滞太大则 loss 震荡。warmup_epochs让学习率从低到高爬升避免初期梯度爆炸。参数上如果训练 loss 在前几个 epoch 就变成 nan优先检查学习率是否过大或标签是否有非法值。4.3 显存不够时的四个降级手段8G 显存跑 640 分辨率、batch 16 通常够用但如果报 CUDA out of memory按下面顺序降级先降 batch-size 到 8再降 img 到 512然后换 yolov5n最后开梯度累积。# 梯度累积batch-size 8累积 2 次等效 batch 16 python train.py \ --data dataset/data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch-size 8 \ --accumulate 2 \ --epochs 100逻辑说明--accumulate让梯度在多个小 batch 上累加后再更新等效增大 batch 但不增加显存。参数上累积次数不要超过 4否则训练速度下降明显。如果开了 AMP自动混合精度还爆显存检查是否有其他进程占用 GPU。5. 训练过程排查loss 不降、mAP 为 0、验证集翻车的血泪经验5.1 现象训练 loss 正常下降但验证集 mAP 始终为 0原因标签路径不对YOLOV5 静默跳过所有标签模型只学背景。解决检查labels/train和labels/val下是否有.txt文件文件名是否和图片一一对应data.yaml里的train和val路径是否指向包含 images 的目录。5.2 现象训练几个 epoch 后 loss 变成 nan原因标签坐标超出 0~1 范围或者学习率过大。解决用脚本扫描所有标签找出坐标大于 1 或小于 0 的行重新裁剪把lr0降到 0.001warmup_epochs加到 5。5.3 现象验证集 mAP 波动极大时高时低原因验证集样本太少或者类别分布和训练集差异大。解决用分层抽样重新划分保证每类在验证集至少 10 个实例如果数据量确实小改用交叉验证或增大验证集比例。5.4 现象模型在坑槽和龟裂上几乎检不出原因这两类样本少且和背景对比度低。解决在hyp.yaml里把cls_pw调到 2.0fl_gamma设为 1.5同时对稀有类做离线增强比如随机裁剪、亮度扰动增加样本多样性。5.5 现象训练时 GPU 利用率低速度慢原因数据加载是瓶颈--workers设得太小或者图片分辨率太大。解决Linux 下把--workers调到 8确认磁盘 IO 不是瓶颈如果图片是 4K 分辨率先离线缩放到 640 再训练不要依赖训练时 resize。6. 从训练到部署用 ONNX 导出和 RK3568 量化验证模型是否真的能用训练完拿到best.pt只是第一步路面巡检场景通常要部署到边缘设备比如树莓派 4B/5 或者 RK3568。导出 ONNX 再量化是常见路径但量化后的精度损失需要验证。# 导出 ONNXopset 12 兼容性较好 python export.py \ --weights runs/train/road_defect/weights/best.pt \ --include onnx \ --img 640 \ --batch 1 \ --opset 12逻辑说明--batch 1导出静态 batch适合边缘设备。--opset 12对 RKNN 工具链兼容性较好。导出后用onnxruntime跑一张测试图对比 PyTorch 和 ONNX 的输出差异如果 mAP 掉超过 2 个点检查是否有不支持的操作被替换。import onnxruntime as ort import numpy as np # 验证 ONNX 输出是否正常 sess ort.InferenceSession(best.onnx) input_name sess.get_inputs()[0].name # 构造一个 1x3x640x640 的随机输入 dummy np.random.randn(1, 3, 640, 640).astype(np.float32) outputs sess.run(None, {input_name: dummy}) print(输出形状:, [o.shape for o in outputs])逻辑说明ONNX 输出通常是[1, 25200, 12]其中 12 4 个坐标 1 个置信度 7 个类别概率。如果输出形状不对检查导出时的--img和--batch是否和推理时一致。参数上RK3568 量化建议用 INT8但需要校准集校准集从验证集里抽 100~200 张覆盖所有 7 类。量化后在验证集上重新跑一遍 mAP如果掉点超过 5 个优先检查校准集是否覆盖了稀有类。我一般会保留一份 FP16 的 ONNX 作为兜底INT8 只在算力实在不够时用。这套流程走下来从数据检查到边缘部署大概需要两三天但能避免训完发现模型根本跑不动的尴尬。希望帮到你。本文还有配套的精品资源点击获取