简介这套数据集面向自动驾驶感知、目标检测方向的开发者和研究者包含8000张源自真实道路场景的高质量图像涉及城市道路、公路及非铺装路面等多种环境覆盖轻型机动车、公交车/卡车/拖拉机等商用车、道路损坏、未铺面道路、行人、减速带六类典型目标适用于道路异常检测项目也可作为自动驾驶通用道路检测数据的有效补充。考虑到原始图片体积较大资源以PDF形式交付压缩包内仅含1个PDF文件大小约5.08MB文档中说明了数据集基本情况、类别分布及百度网盘获取方式读者可据此先判断是否满足项目需求。已有203人学习下载。标注采用labelimg完成质量较高同时提供VOC、COCO、YOLO三种主流格式可直接接入算法训练流程并附赠YOLO11一键训练脚本和博主训练结果日志便于快速复现训练效果、对照调整参数。1. 自动驾驶场景道路异常检测这套 8000 张图数据集到底能解决什么问题目标检测在自动驾驶场景里最容易被忽视的往往是那些根本不在常规检测清单上的东西——路面裂缝、坑洼、凸起、未铺装的土路、突然出现的减速带。绝大多数公开数据集都集中在车辆、行人和交通标志上把路面本身当成背景直接忽略。这套道路异常检测数据集恰好补这个缺口8000 张真实场景道路图片六个类别覆盖轻型机动车、重型机动车、道路损坏、未铺面道路、行人、减速带每张图都带 VOC(xml)、COCO(json)、YOLO(txt) 三种格式标签另附一份 YOLO11 一键训练脚本和训练日志。对做自动驾驶感知、路面巡检、车路协同相关项目的工程师来说这套数据能直接当基础训练的底料也能拿来补充通用道路检测场景的缺失类别。学生党做毕设、竞赛想快速上手 YOLO 训练流程同样可以拿它走通一条完整的检测流水线。下面我把数据集结构、格式转换、训练参数和踩坑记录逐层拆开尽量让拿到手的朋友少走弯路。2. 六个类别与标签结构先把数据集的“边界条件”摸清楚2.1 类别划分背后的标注逻辑这套数据集的分类体系不是随意拍的它基本覆盖了自动驾驶场景中路面和交通参与者的绝大多数异常与常规目标。六类分别是类别名全称包含对象LMVs轻型机动车汽车、摩托车、小型卡车、小型货车HMVs重型机动车公交车、卡车、拖拉机、JCB 挖掘机、厢式货车Road Damages道路损坏坑洼、裂缝、凸起、井盖Unsurfaced Roads未铺面道路未铺设的土路、碎石路Pedestrians行人路边行人、过马路行人Speed Bumps减速带减速带、减速坎这个分类逻辑有两个值得注意的点。第一LMVs 和 HMVs 是按“尺寸和使用场景”切分的而不是按严格的车种划分这样做的好处是检测头不需要在同类物体上做过于精细的区分——摩托车和小型货车在视觉特征上差异很大但它们在自动驾驶决策中的语义角色接近合并成一个类别能有效降低类间混淆。第二Road Damages 这个类别把坑洼、裂缝、凸起、井盖放在一起意味着训练出来的模型只需要回答“这里路面异常”不需要判断具体是哪一种异常。在真实自动驾驶场景里决策系统更关心“有没有异常”而不是“异常叫什么名字”这种粗粒度标注反而让模型泛化能力更强。实际使用中如果你需要细分可以在这套数据集基础上做二次标注把 Road Damages 拆成四类。但建议第一次训练时不要拆先跑出基线结果后面再按需细化。2.2 labelimg 标注的坑与质量判断数据集说明里提到用的是 labelimg 标注软件这很符合数据集标注的常规做法。labelimg 标注出来的 VOC 格式 xml 文件结构长这样annotation folderJPEGImages/folder filenameimg_0001.jpg/filename size width1920/width height1080/height depth3/depth /size object namespeed_bumps/name bndbox xmin812/xmin ymin654/ymin xmax1024/xmax ymax732/ymax /bndbox /object /annotation注意几个判断标注质量的关键点。看filename是否与图片实际文件名严格一致很多数据集训练时报 “No labels found” 或者图片和标签对不上根因就是文件名不匹配。再看bndbox的坐标值是否超出图片边界labelimg 手动标注时偶尔会画出边框外需要用脚本清洗。最后看一眼是否所有图片都有对应标注文件如果 8000 张图有几百张没标注训练时 YOLO 会跳过这些图导致实际训练样本数低于预期。我自己拿到数据集会先跑一段校验脚本把所有 xml 文件扫描一遍统计每个类别的框数量分布。从数据集介绍看Pedestrians 和 Speed Bumps 这两类的样本量大概率偏少因为路面上行人和减速带的出现频次本身就低于车辆。后面第三章讲格式转换时再说怎么处理类别不平衡。3. 从 VOC 到 COCO 再到 YOLO三种格式的转换脚本与坐标换算3.1 三种格式的核心差异这套数据集同时给 VOC、COCO、YOLO 三种格式但大多数人实际训练时只会用到其中一种。三种格式的核心差异在两点标注信息的组织方式和坐标系的定义方式。VOC 格式是单张图片对应一个 xml 文件框的坐标是绝对的像素坐标左上角(xmin, ymin)和右下角(xmax, ymax)。COCO 格式是每张图片作为一个 entry 放在一个大 json 数组里多了一个segmentation多边形字段框坐标同样用绝对像素值但表示方式是(x, y, width, height)x 和 y 是框左上角顶点。YOLO 格式每张图片对应一个 txt 文件每行一个目标格式是class_id x_center y_center width height关键区别是这四个值全部归一化到 0~1 之间除以图片宽高。归一化坐标的好处是与图片分辨率解耦模型训练时不管输入尺寸是 640 还是 960标注都不需要重新计算。但坏处是——如果原始图片分辨率不统一归一化后的坐标精度在低分辨率图上会损失。这套数据集是真实场景图片分辨率可能有差异转换时要留意。3.2 写一个可靠的 VOC 转 YOLO 脚本网络上流传的格式转换脚本很多但大多没有处理边界异常。我一般会写得更保守一些转换前检查坐标合法性、类别映射正确性import xml.etree.ElementTree as ET import os # 类别映射表顺序必须与后续训练的 data.yaml 完全一致 class_mapping { lmvs: 0, hmvs: 1, road_damages: 2, unsurfaced_roads: 3, pedestrians: 4, speed_bumps: 5 } def voc_to_yolo(xml_path, out_dir): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) # 图片文件名用于生成对应的 txt 文件名 filename root.find(filename).text base_name os.path.splitext(filename)[0] yolo_lines [] for obj in root.findall(object): cls_name obj.find(name).text.lower() if cls_name not in class_mapping: print(f未知类别 {cls_name} 出现在 {xml_path}) continue cls_id class_mapping[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, xmin) ymin max(0, ymin) xmax min(img_w, xmax) ymax min(img_h, ymax) # 过滤掉异常框宽或高为 0 的框没有训练意义 if xmax xmin or ymax ymin: print(f异常框被过滤: {xml_path}) continue # 绝对坐标转 YOLO 归一化坐标 x_center ((xmin xmax) / 2) / img_w y_center ((ymin ymax) / 2) / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h yolo_lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) if yolo_lines: with open(os.path.join(out_dir, base_name .txt), w) as f: f.write(\n.join(yolo_lines)) # 批量处理 voc_dir path/to/VOC/Annotations yolo_dir path/to/YOLO/labels os.makedirs(yolo_dir, exist_okTrue) for xml_file in os.listdir(voc_dir): if xml_file.endswith(.xml): voc_to_yolo(os.path.join(voc_dir, xml_file), yolo_dir)这段脚本的核心逻辑有三处。第一是类别映射表必须保证和训练时data.yaml里的 class 列表顺序完全一致否则模型学到的类别语义就串了。第二是边界清洗真实数据集里标注框超出图片边界是常态不在转换时处理训练时 loss 会异常波动。第三是异常框过滤宽或高为 0 的框通常是误标注直接丢弃比强行保留更稳妥。COCO 转 YOLO 的套路类似只不过解析对象从 xml 换成了 json坐标换算逻辑多一步——把 COCO 的(x, y, w, h)先转回(xmin, ymin, xmax, ymax)再做同样的归一化。如果你手里的训练框架只支持一种格式建议以 YOLO 格式为基准因为它存储简单、读取快Ultralytics YOLO11 默认就是这种格式。3.3 训练集与验证集划分的隐藏陷阱格式转换完成后还要做数据集划分。这里有个常见的翻车点直接随机打乱全部图片分 train/val结果同一场景的连续帧被分到了两边验证指标虚高。自动驾驶场景的图片往往来自视频抽帧相邻帧高度相似模型在验证集上的表现会明显好于真实路测。稳妥的做法是按场景分组划分比如先检查文件名是否有场景前缀。如果原始文件名是无序的纯数字无法区分场景退而求其次的做法是按时间戳或者拍摄批次分组。数据集说明里没写图片之间的场景关联关系我一般建议先看一下文件名的命名规律再决定划分策略。实在分不清场景至少保证 train:val 9:1 以上减少验证集混入相似帧的概率。4. YOLO11 一键训练脚本实战参数配置与训练流程4.1 从数据集到 YOLO11 训练配置YOLO11 是当前 YOLO 系列的最新版本延续了 Ultralytics 框架的 API 风格。拿这套数据集训练第一步是把数据集的目录结构整理成 YOLO 标准布局dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamldata.yaml 是训练入口的关键文件内容如下# 数据集根目录配置推荐写绝对路径避免相对路径解析问题 path: /home/user/dataset train: images/train val: images/val # 类别名称与编号顺序必须与标签文件中的 class_id 一一对应 nc: 6 names: 0: lmvs 1: hmvs 2: road_damages 3: unsurfaced_roads 4: pedestrians 5: speed_bumps这里的nc: 6对应数据集六大类names列表的索引顺序与第三章转换脚本里的class_mapping必须完全一致。很多人训练半天发现 loss 收敛但检测结果全乱大概率就是类别顺序在两个文件里对应不上。4.2 训练脚本与关键参数解读YOLO11 的一键训练脚本核心就几十行但参数选对了训练效率差很多。下面是针对这套 8000 张自动驾驶场景数据集调过一轮的脚本from ultralytics import YOLO # 加载 YOLO11 预训练权重可选 yolo11n.pt / yolo11s.pt / yolo11m.pt model YOLO(yolo11s.pt) # 训练参数按自动驾驶场景做了针对性调整 results model.train( datadata.yaml, epochs100, imgsz640, batch16, workers8, device0, # 优化器与学习率 optimizerSGD, lr00.01, lrf0.001, momentum0.937, weight_decay0.0005, # 数据增强参数 hsv_h0.015, hsv_s0.7, hsv_v0.4, degrees10.0, translate0.1, scale0.5, fliplr0.5, mosaic1.0, # 训练策略 warmup_epochs3.0, cos_lrTrue, patience20, # 输出与验证 projectruns/detect, nameroad_abnormal, exist_okTrue, valTrue, plotsTrue )几个关键参数选择的理由说一下。optimizer选了 SGD 而不是 Adam。很多新手习惯性用 Adam但在目标检测中SGD 配合合适的 momentum 和 cos 学习率衰减在验证集上的泛化能力通常更好。Adam 收敛快但容易停留在尖锐极小值对路面这种细粒度异常目标并不友好。mosaic1.0是 YOLO 系列最核心的数据增强手段把四张图拼成一张训练能显著提升小目标的检测能力。对 Road Damages 这类经常只占几十个像素的目标来说属于必选项。degrees10.0只给 10 度的旋转增强。自动驾驶场景的地平线基本是水平的旋转太多反而会引入不符合真实的样本分布。bilinear插值或者默认的填充方式对验证结果影响不明显不需要特意去改。4.3 训练日志与结果输出训练完成后在runs/detect/road_abnormal目录下会生成一批关键文件文件内容关注点weights/best.pt验证集表现最优的权重最终部署用这个weights/last.pt最后一个 epoch 的权重断点续训与继续调优用results.csv每个 epoch 的 loss 与指标曲线看是否过拟合或欠拟合confusion_matrix.png混淆矩阵可视化看哪些类别互相混淆val_batch*.jpg验证集预测结果直观判断检测质量博主提供的训练日志可以作为参考基线。结合我的经验这套六分类数据集在 100 个 epoch 内mAP0.5 大概率落在 0.75~0.85 区间具体取决于类别不平衡程度。如果 Road Damages 和 Speed Bumps 这类小目标的标注框普遍偏小mAP0.5:0.95 会明显低于 mAP0.5这是正常现象不代表模型坏了。判断训练是否正常按三个维度检查train loss 是否单调下降后在某个区间震荡val loss 是否与 train loss 同步走势metrics/mAP50(B)是否在 epoch 30~60 之间出现明显爬升混淆矩阵对角线是否显著高于非对角线。三条都满足就说明训练流程本身没有大问题。5. 避坑8000 张图训练路上的常见问题与排查记录5.1 现象训练前几步 loss 直接冲到 NaN训练启动后 loss 在前 10 个 batch 内变成 NaN训练进程直接崩溃。比较常见的原因有两个一个是学习率设置过高一个是标签文件里有脏数据。我排查时会先看 loss 变成 NaN 之前的最后一个正常值。如果 loss 在前几个 step 就从几万跳到 NaN优先怀疑学习率。把lr0从 0.01 降到 0.001 再试90% 的情况能解决。如果 loss 本身数值正常在某个 batch 突然 NaN那基本就是标签问题——某个 txt 里出现了大于 1 的归一化坐标或者 class_id 超出了nc范围。检查脚本很直接# 检查 YOLO 格式标签文件的合法性 import os label_dir dataset/labels/train max_cls 5 # 类别编号最大为 5 for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue with open(os.path.join(label_dir, fname)) as f: for line in f: parts line.strip().split() cls_id int(parts[0]) coords [float(x) for x in parts[1:]] if cls_id max_cls: print(f类别越界: {fname} - {cls_id}) if any(c 0 or c 1 for c in coords): print(f坐标越界: {fname} - {line.strip()})解决问题后再重新训练。注意模型加载的预训练权重不会因为一次 NaN 就损坏重新启动训练不需要重新下载权重文件。5.2 现象mAP 在 60 个 epoch 后停滞验证集指标不再变化训练到后期 mAP 曲线变成一条水平线不再上升。很多时候不是模型容量不够而是类别不平衡在作祟。8000 张图里车辆类别的数量远多于道路损坏和行人模型把大部分容量都花在了拟合大类上小类别学不到位。解决办法可以加cls损失权重让模型更关注样本少的类别model.train( datadata.yaml, epochs150, # 通过损失权重调节类别不平衡默认都是 1.0 cls0.5, # 类别损失权重适当调大 box7.5, # 边框损失权重 dfl1.5, # 分布损失权重 ... )如果调损失权重没用更直接的办法是对样本少的类别做过采样——复制 Pedestrians、Speed Bumps 和 Unsurfaced Roads 这三类的图片到训练集中使每个类别的框数量大致在一个数量级。我做过对比实验这个数据集上过采样比调 loss 权重的收益更明显。5.3 现象验证集 mAP 很高但实拍视频里大量漏检小目标训练指标挺漂亮一放到真实行车记录仪视频里坑洼、井盖、减速带基本漏检。这个问题的根源是尺度不匹配。YOLO11 默认的imgsz640在真实路面上一个小坑洼可能只有 20×20 像素缩放到 640 分辨率后几乎消失。两个解决方向。一是提高输入分辨率imgsz960或imgsz1280但显存不够就得减小 batch。二是在数据增强里加大scale的随机范围让模型在训练中适应更多尺度的目标。5.4 现象所有类别被预测成同一个类训练完测试发现所有检测框都被归为 lmvs 或者 road_damages其他类别完全没有输出。这是典型的类别映射错位——标签文件里 class_id 的含义与names列表的顺序不一致。举个具体场景假设转换脚本里class_mapping把lmvs设为 0但data.yaml里names: 0: road_damages那么模型学到的 0 号类别实际是 lmvs推理时却按 road_damages 去解析概率分布。检查办法是拿一张验证集图片把模型预测结果的类别名称和标签文件里的类别编号逐一对比。这个坑极其隐蔽查过一次之后我每次训练前都会写段自动校验脚本比对标签首行 class_id 与 names 顺序。5.5 现象训练时显存溢出 OOM40GB 显存也报 OOM多半是 batch 和 imgsz 的组合超出显存容量。YOLO11 在训练时还会为 Mosaic 增强预留额外显存所以同一套参数下训练比推理多占一倍左右的显存。解决优先级从低到高先降 batch 到 8 或 4再考虑降imgsz到 544 或 480最后才考虑换轻量模型yolo11n.pt。不推荐直接关闭 Mosaic——它对小目标检测太重要了。如果显存确实紧张也可以把cacheTrue改成cacheFalse让图片按 batch 实时读取而不是全部缓存进内存省内存和显存换一点磁盘 IO。6. 推理验证与进阶用混淆矩阵和实测视频把模型“校准”到能用前面的训练完成后拿到了best.pt但一个权重文件离“能上路”还差一步——验证。我一般会做三层验证每一层都可能暴露不同的问题。第一层是标准验证集的指标曲线看 mAP0.5 和 mAP0.5:0.95。第二层是看混淆矩阵这个数据集上特别关注 Road Damages 是否被误判为 Speed Bumps因为坑洼和减速带的视觉特征有点接近都是路面上突然出现的结构变化。第三层是真实场景测试找一段行车记录仪视频用下面的推理脚本跑一遍from ultralytics import YOLO # 加载训练好的权重 model YOLO(runs/detect/road_abnormal/weights/best.pt) # 对图片目录批量推理 results model.predict( sourcetest_videos/record_01.mp4, conf0.25, # 置信度阈值调低可减少漏检但增加误检 iou0.45, # NMS 的 IoU 阈值 imgsz640, saveTrue, save_txtTrue, # 同时保存检测结果到 txt classes[2, 3, 5] # 只看道路损坏、未铺面道路、减速带 )这几行脚本里conf和iou是两个最值得调的参数。自动驾驶场景对漏检的容忍度极低我会把conf从默认的 0.25 降低到 0.15让模型把一些把握不大的路面异常也报出来宁可误检后期过滤不能漏检直接撞过去。classes参数可以只过滤出 Road Damages、Unsurfaced Roads、Speed Bumps 三类做专项检查观察模型在小目标上的表现。验证过程中如果发现某一类检测框大量重叠同一个坑洼被重复框出说明 NMS 阈值设得偏高把iou从 0.45 降到 0.3 试试。反过来如果同一个目标只保留了一个框但位置明显偏移说明两个框被 NMS 误合并了这时要把阈值调回到 0.5。进阶技巧方面这套数据集还有一个适合做增量训练的玩法。先把训练好的模型部署到车载设备或者边缘盒子——比如 rk3588 这类平台——用少量真实路采图片在best.pt基础上微调 20~30 个 epoch学习率降到lr00.001。这么做的好处是模型在保留原始数据集学习成果的同时能快速吸收当前部署环境的场景光照、摄像头角度、路面材质等域差异实测比从头训练收敛快得多最终 mAP 也能再高几个点。一个更细节的验收习惯我会把模型跑完的新场景视频抽几十帧出来人工数一遍 Ground Truth 框数量与模型预测框数量的比值。比值低于 0.8 说明漏检偏多优先降 conf比值高于 1.2 说明误检偏多优先调 NMS。这套指标比只看 mAP 直观得多尤其是面对 Road Damages 这种小目标密集出现的情况——mAP 计算会惩罚每个错检但如果一个坑洼被框成三个小框mAP 很高而实际体验很差。从那以后我每次拿到新的检测数据集都会强制自己走一遍同样的流程先校验标签合法性再检查类别映射一致性接着划分场景隔离的验证集最后训练完用实拍视频做一次人工抽样比对。这套习惯帮我避掉了不少看起来莫名其妙、实际上都是标注和配置小问题的坑。希望这份拆解能给你省下一些排查时间让 8000 张图真正发挥出它该有的价值。本文还有配套的精品资源点击获取