
简介面向自动驾驶场景的道路异常检测数据集包含8000张真实道路图片覆盖轻型机动车汽车、摩托车等、重型机动车公交车、卡车、拖拉机等、道路损坏坑洼、裂缝、凸起、井盖、未铺面道路、行人、减速带六大类场景丰富且贴近实际路况适合自动驾驶道路检测项目使用也可作为通用道路检测数据的补充。资源包共1个文件为PDF格式大小5.08MBPDF内附数据集详细介绍及百度网盘获取方式数据采用LabelImg标注提供VOC、COCO、YOLO三种格式标签可直接投入YOLO等目标检测模型训练省去数据格式转换的麻烦。同时附赠YOLO11一键训练脚本和博主训练结果日志帮助快速启动实验并参考训练效果。目前已有203人学习适合从事目标检测、自动驾驶感知方向的开发者与研究者下载使用。1. 道路异常检测自动驾驶数据集的最后一块拼图自动驾驶感知系统里行人、车辆、交通标志这类常规目标早已被研究得很透彻真正让模型在量产路上翻车的往往是路面上的坑洼、裂缝、未铺面道路、减速带这些不起眼的异常。通用目标检测数据集COCO、VOC里几乎没有这类标注导致模型在结构化道路上表现尚可一进入城乡结合部或者施工路段漏检率立刻飙升。这个8000张图的自动驾驶道路异常检测数据集恰好补上了这块拼图它把道路场景划分为六个维度覆盖机动车、道路损坏、未铺面道路、行人、减速带并提供VOC/COCO/YOLO三种格式标注和YOLO11一键训练脚本让做目标检测落地的工程师省掉从数据清洗到格式适配的大半工作量。这篇文章从类别设计、标注格式转换到训练调优完整拆解这套数据集的使用路径。2. 六分类体系拆解从类别定义看真实道路场景的数据分布2.1 类别设计逻辑为什么把机动车拆成LMVs和HMVs这个数据集最值得琢磨的不是有没有行人、有没有车而是它对车辆类别的划分方式。类别体系里车辆被拆成了LMVs轻型机动车和HMVs重型机动车两个大类而不是像COCO那样用统一的cartruck标签。LMVs 轻型机动车汽车、摩托车、小型卡车、小型货车HMVs 重型机动车公交车、卡车、拖拉机、JCB挖掘机、厢式货车Road Damages 道路损坏坑洼、裂缝、凸起、井盖Unsurfaced Roads 未铺面道路未铺设的泥土路、碎石路Pedestrians 行人路边行人或过马路的行人Speed Bumps 减速带减速带和减速坎这种拆分是有实际工程考量的。自动驾驶决策模块对车型的响应策略完全不同跟在一辆小型货车后面和跟在一辆JCB挖掘机后面可通行空间和刹车距离的预估模型不一样同样一个凸起目标在轿车底盘和卡车底盘下的通过策略也不同。如果数据集里全部打成vehicle模型学到的特征就是带轮子的东西决策模块拿不到粒度更细的信息。所以这个拆类方式本质上是为下游规划和控制模块服务的而不只是给检测模型刷mAP。2.1.1 类别混淆风险与标注边界拆得细的代价是类别间容易混淆。小型货车和厢式货车在侧视角下非常接近摩托车在远距离下只有几十个像素JCB挖掘机和卡车在部分角度下轮廓相似。数据集用labelimg人工标注但标注边界是否清晰直接决定模型收敛后的上限。实操中建议先做一次标注分布统计确认每个类别的bbox数量和尺寸分布再看是否有类别需要合并或补充样本。2.2 道路损坏与未铺面道路最难标注的目标类型道路损坏类和未铺面道路类是这个数据集的差异化价值所在。坑洼、裂缝、凸起、井盖这类目标有几个特性形状极不规则、长宽比差异大、容易被阴影和积水干扰、很多目标在图像里只占几百个像素。裂缝可能是细长的斜线井盖是规则的圆形凸起是低对比度的曲面——这些目标用通用的矩形框框住目标的标注方式本身就存在信息损失同一个坑洼不同标注员的框选范围可能差出百分之三十的面积。未铺面道路则更特殊它往往是一个大面积的区域型目标但在目标检测框架里被当成离散目标来框。这种情况下标注框的边界实际上是道路延伸到哪儿的主观判断不同图片的标注标准可能不一致。用这个数据集训练时我建议把Unsurfaced Roads和Road Damages当作一个整体来评估——如果模型把未铺面道路上的裂缝框成了Road Damages而不是Unsurfaced Roads这在工程上是否可以接受取决于你的下游任务。2.3 行人、减速带与稀疏类别的样本平衡数据集共有8000张图六个类别理论上每张图都包含多种目标。但实际分布里行人和减速带这类目标的数量一定远少于机动车。我在处理这类不平衡数据时的经验是先看各类别的实例数不能只看图片数。假设一张图里有10辆车和1个行人模型对行人的训练样本量其实只有车辆的十分之一。YOLO训练时这个数据集提供的默认脚本里一般会配置类别权重或者通过mosaic数据增强来缓解不平衡但如果你发现某个类别的recall明显偏低优先去检查这个类别的实例数量。下面这段脚本可以直接用来统计数据集的类别分布和bbox尺寸分布我在拿到任何目标检测数据集时都会先跑一遍import os from collections import Counter import cv2 label_dir labels/train image_dir images/train class_names [LMVs, HMVs, Road Damages, Unsurfaced Roads, Pedestrians, Speed Bumps] cls_counter Counter() box_sizes {name: [] for name in class_names} for label_file in os.listdir(label_dir): if not label_file.endswith(.txt): continue image_file os.path.join(image_dir, label_file.replace(.txt, .jpg)) h, w cv2.imread(image_file).shape[:2] with open(os.path.join(label_dir, label_file)) as f: for line in f: cls_id, cx, cy, bw, bh map(float, line.split()) cls_counter[class_names[int(cls_id)]] 1 box_sizes[class_names[int(cls_id)]].append((bw * w) * (bh * h)) for cls in class_names: sizes box_sizes[cls] print(f{cls}: 实例数{cls_counter[cls]}, bbox像素面积中位数{sorted(sizes)[len(sizes)//2]:.0f})这段脚本的逻辑遍历YOLO格式的label文件读取每一行的类别ID和归一化的中心点坐标、宽高乘以图片实际宽高得到像素级面积。跑完以后重点关注两件事一是实例数最少的类别是否低于总数5%如果是训练时要给这类样本更高的loss权重或做类别增强二是bbox像素面积中位数——如果某个类别的中位面积特别小比如低于5000像素说明模型需要更高的输入分辨率或者更强的特征融合结构才能学好。2.4 按场景切分数据集时的注意事项8000张图如果要自己重新划分train/val/test注意这个数据集的采集来源是真实道路场景可能存在同一路段连续帧的相似图片。如果随机划分训练集和验证集里可能出现高度重复的背景导致验证分数虚高。常见做法是按采集时间或者路段编号划分而不是按图片文件名随机分。如果资源包里没有提供现成的划分文件可以用文件名中的序列号做分桶切分保证同一视频片段只出现在一个集合里。3. VOC/COCO/YOLO三格式转换从labelimg标注到训练体系的必经之路3.1 三种格式的核心差异与坐标系数据集的原始标注用labelimg完成然后导出成VOCxml、COCOjson、YOLOtxt三种格式。这三种格式的差异本质上是坐标系表达和数据结构组织的差异。VOC格式把每个目标的类别和bbox存放在xml文件里坐标是绝对值即左上角x、左上角y、右下角x、右下角y单位是像素。COCO格式把数据集中所有图片的标注汇总到一个json文件里bbox坐标用的是左上角x、左上角y、宽度w、高度h同样是像素绝对值但需要维护categories、images、annotations三个数组的ID对应关系。YOLO格式每张图对应一个txt文件每行是一个目标内容是类别ID cx cy bw bhcx、cy是bbox中心点的归一化坐标bw、bh是归一化宽高取值范围都在0到1之间。选型建议如果训YOLO系列直接用YOLO格式最省事如果要做迁移学习或者模型对比实验COCO格式更适合因为ultralytics的yolo格式也支持直接读取COCO如果要在labelimg里复查标注VOC格式读取最直观。3.2 格式互转的完整脚本实际项目中拿到数据集第一件事往往不是直接训练而是确认标注格式是否和你的训练框架匹配。这份数据集虽然给了三种格式但训练前最好自己过一遍转换逻辑避免某个文件导出不完整。下面是我常用的VOC转YOLO脚本核心逻辑也可以反过来从YOLO转成VOC或COCO。import os import xml.etree.ElementTree as ET from glob import glob classes [LMVs, HMVs, Road Damages, Unsurfaced Roads, Pedestrians, Speed Bumps] def voc_to_yolo(xml_file, out_dir): tree ET.parse(xml_file) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) base os.path.splitext(os.path.basename(xml_file))[0] with open(os.path.join(out_dir, base .txt), w) as out_f: for obj in root.iter(object): cls obj.find(name).text if cls not in classes: continue cls_id classes.index(cls) xmlbox obj.find(bndbox) xmin float(xmlbox.find(xmin).text) ymin float(xmlbox.find(ymin).text) xmax float(xmlbox.find(xmax).text) ymax float(xmlbox.find(ymax).text) 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 out_f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n) os.makedirs(labels_train, exist_okTrue) for xml_file in glob(VOC2007/Annotations/*.xml): voc_to_yolo(xml_file, labels_train)逻辑说明遍历xml里的每个object节点取出类别名和bndbox子节点里xmin、ymin、xmax、ymax四个绝对坐标然后统一换算成归一化的中心坐标和宽高。这里最容易被忽略的是归一化时除以的是图片的实际宽高不是默认的640或416。如果图片里有EXIF旋转信息导致宽高和实际显示不一致需要在转换前用PIL先矫正一下否则YOLO训练时会出现标注错位。COCO格式转换类似但需要额外维护图片ID和类别ID的全局映射我一般直接用ultralytics的yolo2coco脚本或者用pycocotools自带的工具类手工写容易在ID连续性上出bug而且COCO json格式要求所有annotations的id不能重复很多转换脚本在这里踩坑。3.3 转换后的标注校验技巧格式转换最怕的不是代码逻辑错而是边界情况漏处理空标注文件、超出图片边界的bbox、类别ID越界。健壮的做法是转换完以后做一遍自动校验核心查三件事。第一每个txt文件是否都有对应的图片文件反向也查一遍防止训练时报FileNotFoundError。第二所有坐标是否在[0,1]区间内YOLO训练时如果出现大于1的归一化坐标ultralytics不一定会报错但loss会异常高而且不收敛。第三每行是否有且只有5个数值多了少了都是label文件损坏。我在转换完以后习惯跑一个快速校验脚本统计异常label的数量如果超过5条直接定位到对应文件重新标注。校验逻辑很简单读入每行检查浮点数个数检查坐标范围检查类别ID是否小于类别总数。这个小步骤能在训练前拦截掉大部分loss不降的数据问题。4. YOLO11一键训练脚本落地从数据组织到mAP稳涨4.1 数据集目录结构与data.yaml配置YOLO11的训练框架ultralytics对数据集的目录结构有约定。拿到这份资源后先把图片和label按下面的结构组织好dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml注意images和labels这两个目录必须在同一个父目录层级下训练时框架通过data.yaml里的path找到父目录然后自动匹配images/train和labels/train。如果图片和标签目录名字对不上或者train/val划分不一致训练会直接跳过匹配不到的图片但不会报错很多人训练完才发现训练样本数不对。data.yaml文件的内容要注意几个字段path: /path/to/dataset train: images/train val: images/val nc: 6 names: 0: LMVs 1: HMVs 2: Road Damages 3: Unsurfaced Roads 4: Pedestrians 5: Speed Bumpspath字段建议写绝对路径。写相对路径时如果训练脚本所处的当前目录和dataset不在同一目录层级会报图片路径找不到。train和val的值是相对path的路径不能写成/images/train这种带盘符或根路径的形式。类别顺序必须和label txt文件里的类别ID一一对应这个数据集如果已经按上述六个类别排序生成label就不用动。4.2 训练脚本的关键参数解读资源包里附赠的一键训练脚本本质上是封装了ultralytics YOLO训练接口的Python脚本核心就几十行。重点不是跑通它而是理解里面每个参数在这个数据集上的效果。下面按重要性解释。python train.py \ --data data.yaml \ --model yolov11s.pt \ --epochs 200 \ --batch 16 \ --imgsz 640 \ --device 0 \ --workers 8 \ --cache ram \ --patience 30参数说明model选用yolov11s.pt作为预训练权重。如果机器显存够大12GB以上可以换yolov11m.pt在道路小目标上的精度通常更高但训练时间约增加一倍。选s还是m的核心依据是bppbbox像素面积中位数如果第2章统计的bpp中位数小于5000像素建议直接上m。imgsz默认640但这个数据集的坑洼、井盖、裂缝目标多为中小目标。如果显存允许把imgsz提到800或960小目标的mAP会有显著提升代价是训练时间按平方增长。我一般先在640上跑通流程再单独做一次960的验证实验。cache ram表示把图像预加载到内存里。8000张图大概占10到15GB内存如果机器内存紧张改成cache disk或去掉会慢一些但稳定性更好。patience设30采用的是早停策略和DataSet的best.pt判断逻辑一致连续30个epoch验证集mAP没提升就停止省时间。4.2.1 一键脚本隐藏的锚框调参坑ultralytics YOLO11的anchor是自适应学习的理论上不需要手动设置但实际训练时如果数据集的bbox长宽比分布和COCO预训练权重差异过大比如这个数据集里的裂缝类长宽比可能达到1:10前几十个epoch的loss会比较高。脚本如果带了auto_anchor相关配置建议保持开启。如果不小心关掉了自动锚框且训练日志里的cls_loss降不下去优先检查这件事。4.3 针对道路异常检测的小目标优化这个数据集和通用目标检测数据集的另一个差异是大量目标在图像中的占比非常小。远距离的行人可能只有30×60像素井盖在俯视角下可能只有40×40像素。类似的目标检测比赛经验表明YOLO11在小目标上的表现受两个因素影响最大输入分辨率和数据增强方式。YOLO11默认开启mosaic增强把四张图拼接成一张训练对小目标效果较好。但要注意如果训练集里宽高比差异极大的图比如4K横图和竖屏图混在一起mosaic生成的拼接图可能导致小目标被裁掉一半边框严重截断反而干扰学习。我一般会把mosaic关闭的概率从默认的0调高到0.3即30%的epoch不做mosaic保留原始尺度分布。另外ultralytics训练脚本里还有一个close_mosaic参数默认等于epochs表示最后10轮关闭mosaic。这是为了消融拼接图的噪声让模型在最后阶段见到干净的原始图片。如果你发现验证集的mAP波动很剧烈上下超过3个点可以把close_mosaic调大让模型多适应几轮原始分布。4.4 训练过程监控的几个信号训练跑起来以后不用等到结束才判断好坏。前20个epoch重点看box_loss和cls_loss是否单调下降如果box_loss在5个epoch内没有下降趋势大概率是学习率设定问题YOLO11默认lr为0.01batch16时可以适当降为0.005。如果cls_loss在下降但box_loss波动大去看label是否有坐标越界。如果验证集的mAP50-95停滞在某个值长期不变先排除是不是某几个类别的样本量太少导致类别权重失衡。5. 训练结果日志解读与实测调优技巧5.1 日志里的关键指标怎么读博主提供的训练结果日志核心就是ultralytics在训练结束后输出的那串指标。我拿到日志先看四个数mAP50、mAP50-95、precision、recall。mAP50达到0.9以上说明整体目标能被检测到mAP50-95在0.6以上说明box定位精度不错。如果mAP50高但mAP50-95明显低差值超过0.3说明检测框位置不稳定目标虽然被找到了但框的边界抖动大这种情况通常是bbox回归权重不足优先把box_loss的权重从默认的7.5调高到10。日志里还有每个类别的AP值这部分往往比总mAP更有价值。我处理类似数据集时大概率会看到Speed Bumps和Unsurfaced Roads的AP明显低于LMVs。这两类一个问题在于样本量不足另一个在于面积分布跨度大。针对这种情况调整思路不是盲目加数据而是考虑是否将Speed Bumps和Road Damages中形状接近的子类比如减速坎和凸起做label smooth处理降低类别间的互斥性。5.2 结果可视化验证不要只看指标训练结束后用训练好的权重对验证集做一次推断把预测结果可视化人工看200张图的预测效果。重点看三类错误第一类远距离小目标漏检典型表现是图片里有很小的行人或井盖模型没框出来。这类错误在指标上体现为recall偏低。优化方式是提高输入分辨率或增加小目标检测头。第二类减速带和路面阴影误检典型表现是把深色路面阴影框成了Road Damages。这类错误在指标上体现为precision偏低。优化方式是在数据增强时增加亮度扰动和对比度扰动让模型学会忽略纯色区域。第三类HMVs里的小型货车和LMVs里的厢式货车互相混淆典型表现是同一辆车在两帧图片里被分到不同类别。这类错误需要检查离线标注的质量必要时合并类别重训。5.3 增量训练与模型部署的几个落地建议如果8000张图训练完某个实际路段场景下依然漏检率高最常见的方法是收集该场景的图像用已有模型做伪标注人工修正后增量训练。增量训练时把epochs降到50到80把预训练权重换成已训练好的best.pt而不是COCO权重学习率调低到原来的十分之一避免灾难性遗忘。部署方面YOLO11的模型导出为ONNX或TensorRT格式用yolo export modelbest.pt formatonnx opset12即可完成。自动驾驶场景的检测模型推理链路里建议在模型输出后加一个目标尺寸过滤逻辑根据摄像头安装角度和俯仰角过滤掉实际道路范围之外的目标框减少误检输入给决策模块。最后补充一个实操经验训练时在data.yaml里为验证集选一批和训练集场景差异最大的图比如雨天、夜间、强逆光图片单独建一个test-hard目录作为暴力测试集。这比单纯看mAP更接近真实道路异常检测的部署环境——模型在明亮柏油路上的表现和它在湿滑坑洼路面上的表现往往是两回事。本文还有配套的精品资源点击获取