YOLOv5道路数据集实战:从目录检查到训练避坑全指南
简介这份面向自动驾驶场景的YOLOV5格式目标检测数据集覆盖卡车、行人、交通信号灯、车辆等11个类别图片分辨率为512×512 RGB每张图像包含多个目标可服务于自动驾驶感知、密集目标检测、智能交通监控等模型的训练与验证。资源压缩包共2000个文件由1999个txt标签文件与1个Python可视化脚本组成压缩包约493MB数据按YOLOV5目录结构组织并划分训练集与验证集能够直接接入YOLOv5等主流训练流程无需额外预处理。已有173人学习下载。标签文件与图像一一对应边界框标注清晰完整附带的py脚本无需修改即可随机抽取一张图片绘制边界框并保存至当前目录帮助用户快速核对标注质量同时降低新手入门门槛适合目标检测方向的学生、科研人员与工程师作为基础数据集使用。1. 拿到就能跑的 YOLOv5 道路数据集11 类目标、两万张图先别急着训做目标检测的人都知道训练只是调参数据准备才真正磨人。这份以 YOLOv5 目录结构交付的自动驾驶道路信息检测数据集训练集 21031 张、验证集 5266 张统一 512x512 RGB压缩后约 558MB。11 个类别覆盖卡车、行人、交通信号灯、轿车等路况目标每张图含多个目标既适合自动驾驶环境感知训练也可以拿来研究密集目标检测与类别不均衡。数据来自 Roboflow 项目导出目录已按 images/train、labels/val 排好解压就能接进 train.py。适合刚跑通 YOLOv5 想拿现成数据练手的新手也适合需要道路场景做迁移学习的工程师以及研究小目标检测的研究者。开训前我建议先花二十分钟把数据整体摸一遍后面几章就是把这件事拆开做。2. 拉通目录与标注看懂 11 类标签的 txt 五列用 show.py 快速目检下载资源解压后第一件事不是急着找训练脚本而是确认这份数据的目录结构跟你想的是不是一回事。YOLOv5 的数据加载逻辑很简单遍历 images 下的图片然后去 labels 下找同名 txt。如果目录结构对不上后面所有训练配置都会在同一个地方反复报错。这类数据虽然标着“直接可用”但“可用”的前提是路径约定一致所以我一般会把一开始十分钟花在拆目录和读标签上。2.1 目录结构与命名规则images/train 与 labels/train 一一对应整个数据集的文件组织是经典的 YOLO 目录形态datasets/ ├── images/ │ ├── train/ │ │ ├── 1478020420705248954_jpg.rf.63GBA3Hkah9rjMaupqYz.jpg │ │ ├── 1478020424703748932_jpg.rf.235e35f42ac68ff7b6a4692136886a89.jpg │ │ └── ... │ └── val/ │ ├── 1478899785956270120_jpg.rf.5b7c9700edb9f9899ee55cc65d88518a.jpg │ └── ... └── labels/ ├── train/ │ ├── 1478020420705248954_jpg.rf.63GBA3Hkah9rjMaupqYz.txt │ └── ... └── val/ └── ...逻辑说明image 和 label 的文件名完全一致只有扩展名不同。train 目录下 21031 张 jpg 对应 21031 个 txtval 目录下 5266 张 jpg 对应 5266 个 txt这个对应关系是 YOLOv5 能正常训练的基础。文件名里的_jpg.rf.加一段哈希是 Roboflow 导出时留下的命名特征不是脏数据不影响训练但如果你自己写脚本按列表序号去匹配图片和标签就容易出问题。我一般建议按完整文件名做匹配不要用索引。验证一个数据集是否完整最直接的方法就是数两边文件数是否相等ls datasets/images/train/*.jpg | wc -l ls datasets/labels/train/*.txt | wc -l ls datasets/images/val/*.jpg | wc -l ls datasets/labels/val/*.txt | wc -l第一行命令统计训练集图片数第二行统计训练集标签数三四行对应验证集。两边数字一致是最低要求不一致说明有图片缺标签或者有标签缺图片这种数据集直接开训轻则白丢样本重则训练中断。2.2 十一个类别文本把分类名与 class_id 的顺序固化下来项目里附带 11 个类别 txt 文本文件每个文件写一个类别名这是整个数据集的“类别字典”。要提醒的是YOLO 格式中 class_id 与类别名的对应关系完全由顺序决定不靠文件名。Roboflow 导出的类别顺序通常不是按人眼习惯排的所以要把这份顺序固化下来之后写 data.yaml 时直接引用。我一般会写一个几行的脚本把类别文本文件读成列表import os class_files sorted(os.listdir(classes)) names [] for f in class_files: with open(os.path.join(classes, f), r, encodingutf-8) as fp: names.append(fp.read().strip()) print(类别总数:, len(names)) for idx, name in enumerate(names): print(idx, name)逻辑说明sorted(os.listdir(classes))按文件名排序如果类别文件本身带序号排序结果就和实际编号一致strip()去掉换行符和首尾空格保证 names 列表里是干净的类别名。参数上注意两点一是类别总数必须输出为 11少了说明有文件没读进来二是把打印出来的序号和名称核对一遍确认第一列整数与类别顺序对得上。到这一步你已经拿到了每个 class_id 对应的实际含义。后面训练时如果发现行人被识别成卡车、信号灯和交通标志混在一起大概率就是这步的对应关系没对齐而且这种错位在训练过程里不会有任何报错提示。2.3 show.py 可视化脚本随机取图、绘制边界框、保存结果项目里提供的 show.py定位就是“不改一行代码直接看标注效果”。把脚本放到数据集目录下直接运行python show.py脚本做的事可以归纳成三步从数据集中取一张图片解析同名 txt 里的每一行目标框用 OpenCV 把框和类别文本画回图上并保存到当前目录。运行成功后你会在当前目录看到一张绘制了若干矩形框的图片每个框对应一个目标。这个步骤能在训练前暴露标注和图像之间的直接问题比如框明显漂移、宽高比异常、框内目标根本不是对应类别等。因为是 512x512 的等比例绘制框的位置是否合理一眼就能判断多目标场景下也能直观看到密集程度。我会在解压后先跑一次 show.py再手动抽查 train 和 val 各二十张图这个动作成本不到三分钟但能立刻确认整个数据集的标注质量。可视化通过后再进入下一步的数据体检后面几章的内容才有一个可靠前提。3. 训练前数据体检检查类别分布、越界坐标与空标签避免带病进 train.py很多数据集看着目录整齐、文件名成对实际一跑训练就暴露问题有的标签是空的有的坐标越界有的类别分布极度不平衡。这些问题不会让训练直接崩溃但会让 mAP 上不去而且你很难判断是模型问题还是数据问题。所以开训前做一次数据体检成本很低收益却很直接。3.1 YOLO txt 五列格式class_id、中心点坐标与归一化宽高打开任意一个标签 txt会看到类似下面的内容5 0.492188 0.634766 0.267578 0.387695 2 0.718750 0.539062 0.139844 0.338867 0 0.125000 0.281250 0.080078 0.153320每一行代表一个目标共五个数字第一列是类别索引范围 0 到 10对应 11 个类别第二三列是目标框中心点的 x、y 坐标按图片宽高做了归一化第四五列是目标框的宽和高同样是归一化到 0 到 1 之间的数值。YOLO 选归一化坐标而不是绝对像素好处是图像 resize、缩放、padding 之后标注不需要跟着改这也是它被广泛用于目标检测工程的原因。对比 COCO 的 JSON 格式和 VOC 的 XML 格式差异很明显COCO 的 bbox 存的是左上角绝对像素坐标加宽高VOC 存的是四个角点绝对坐标而 YOLO 存的是相对比例。如果之前习惯用标注工具导出 COCO 或 VOC转成 YOLO 时要记住两个换算公式cx (xmin xmax) / (2 * image_width)w (xmax - xmin) / image_width。这份数据集的图片宽高都是 512转换时分母就用 512一旦用错尺寸所有框都会系统性偏移视觉检查时才能看出来。3.2 批量检查脚本越界框、空文件与字段数异常写一个简单的 Python 脚本跑一遍训练集标签目录把最常见的三类问题一次性扫出来import glob label_files glob.glob(datasets/labels/train/*.txt) empty_samples [] bad_samples [] for path in label_files: with open(path, r) as f: lines f.readlines() if not lines: empty_samples.append(path) continue for line in lines: parts line.strip().split() if len(parts) ! 5: bad_samples.append((path, fcolumns{len(parts)})) continue cls, cx, cy, w, h map(float, parts) if not (0 cx 1 and 0 cy 1 and 0 w 1 and 0 h 1): bad_samples.append((path, fout of range: {line.strip()})) print(空标签文件数:, len(empty_samples)) print(异常标签文件数:, len(bad_samples)) for p, msg in bad_samples[:20]: print(p, msg)逻辑说明脚本遍历训练集 labels 目录下的所有 txt第一层检查文件是否为空白第二层检查每行是否刚好是五个字段第三层检查归一化坐标是否落在合法区间内。越界判断用 0 到 1 闭区间cx、cy 大于 1 或小于 0说明归一化分母用错w、h 大于 1 更是明显异常。参数上注意map(float, parts)会直接转换字符串为浮点数如果某一行混入非数字字符会抛异常遇到这种情况建议单独打印该行内容多半是标注工具导出时混入了脏数据。这段脚本对 train 和 val 都要跑一遍。结果为空说明标签格式整体干净如果扫出成批越界优先怀疑是图像尺寸与归一化分母不一致而不是单张图片标注问题。3.3 类别分布与长尾情况看清各目标数量级再决定训练策略道路场景数据集天然存在类别不均衡轿车、卡车这类常见目标数量庞大摩托车、自行车、行人可能少一个量级。统计一下目标分布能让你对后续 mAP 的合理范围有心理预期。from collections import Counter counter Counter() for path in label_files: with open(path, r) as f: for line in f: counter[int(line.split()[0])] 1 print(总目标数:, sum(counter.values())) for cls_id in sorted(counter): print(cls_id, counter[cls_id])逻辑说明脚本读取训练集所有标签按每行第一列的类别 id 计数最后输出每个类别出现的总次数。参数上注意这里统计的是目标框数量不是图片数量一张图里可能有多个同类目标会重复计数。类别分布的价值在于判断长尾程度如果某个类别只有几百个框而其他类别有几万个那它的 AP 天然低于常见类别整体 mAP 被拉低不是模型能力问题而是数据分布决定的。看到这种结果时后续训练就应该考虑类别加权、过采样或单独评估该类别的检测效果而不是盲目增加 epoch。4. 从数据到模型写 data.yaml、跑 train.py在 512 分辨率下完成首轮训练数据体检通过后进入正式的 YOLOv5 训练流程。这一章把配置文件和训练命令的关键参数拆开讲清楚让你知道每个参数为什么这么设改什么会影响什么。4.1 编写 data.yaml路径、类别数与 names 顺序必须和标注完全对齐YOLOv5 的 train.py 通过--data参数接收一个数据配置文件内容如下train: /home/you/datasets/images/train val: /home/you/datasets/images/val nc: 11 names: 0: truck 1: pedestrian 2: traffic_light 3: car 4: bicycle 5: motorcycle 6: bus 7: traffic_sign 8: person 9: dog 10: other上面 names 里的具体名称是示意实际以你项目里 11 个类别文本文件为准。关键点是nc必须等于 names 列表长度而且 names 的下标顺序必须与标签文件里每一行的第一列数字严格对应。train 和 val 路径建议写绝对路径因为相对路径在换工作目录运行时容易解析错位训练报找不到图片时排查起来很浪费时间。另外注意 YAML 的缩进规则nc: 11和names:是同一层级names 下面每个类别前是两个空格加序号冒号后面必须有空格。这类语法错误不会在训练前暴露而是会在加载配置时报yaml.YAMLError或直接报 key 不存在属于低级的配置问题。4.2 训练命令的参数解析img 512、batch、epochs 与 workers以 ultralytics/yolov5 仓库为例训练命令这样写python train.py \ --data data/road.yaml \ --weights yolov5s.pt \ --img 512 \ --batch 32 \ --epochs 100 \ --workers 8 \ --project runs/train \ --name road_512参数说明--img 512是训练输入边长这份数据集的原始图就是 512x512不需要额外 resize输入尺寸和原始尺寸一致时信息损失最小。--batch 32在 8GB 显存搭配 512 输入的情况下勉强能跑如果显存是 6GB 就降到 16。--workers 8是数据加载线程数Linux 下设 8 或 16 都行Windows 下过高容易报Dataloader worker相关错误。--epochs 100对两万张图的训练集是合理的起步值配合 YOLOv5 默认的 Mosaic 增强和 AutoAnchor一般在 20 到 40 个 epoch 就能看到验证集 AP 明显上升。预训练权重首轮建议用yolov5s.pt训练速度快、显存占用小。如果追求更高精度等 s 版本跑通后再换yolov5m.pt或yolov5l.pt。对 512 分辨率加多目标场景s 模型已经能证明数据集的可用性没必要一上来就堆大模型训练时间翻倍但收益未必成比例。4.3 验证评估val.py 输出 mAP、Precision、Recall 与混淆矩阵训练完成后单独跑一次验证脚本看最终效果python val.py \ --data data/road.yaml \ --weights runs/train/road_512/weights/best.pt \ --img 512 \ --conf 0.001 \ --iou 0.65参数说明--conf 0.001是置信度阈值val.py 默认用很低的阈值以保证 PR 曲线覆盖完整面积上报 mAP 时不要人为调高这个值否则结果不具备可比性。--iou 0.65是 NMS 的 IoU 阈值YOLOv5 仓库默认值一般不用改。输出结果里mAP0.5是 IoU 阈值取 0.5 时的平均精度mAP0.5:0.95是 0.5 到 0.95 每间隔 0.05 取阈值后求平均后者对框的定位精度要求更严格。这份数据类别不均衡长尾类别的单类 AP 会比头部类别低很多建议把每类 AP 单独拉出来看而不是只盯一个均值。5. 避坑记录Roboflow 导出标签最容易翻车的四个坑用 Roboflow 导出的数据集我踩过不少坑这里总结四条高频问题每一条按现象、原因、解决三个维度写清楚你遇到类似情况时可以按图索骥。5.1 现象可视化时框画在目标旁边或整体偏移用 show.py 跑出来发现矩形框不在目标上有的偏左上有的偏右下整体呈系统性偏移。原因最常见的是图片与标签文件名匹配错误。比如自己写脚本时用列表索引去匹配而不是按文件名匹配导致标签和图片错位另一种可能是 Roboflow 导出时原图做了 resize 或自动旋转但标签没有同步更新。对这份数据来说图片是 512x512标签应该以 512 为归一化分母如果分母错用成 416 或 640框就会出现固定比例的偏移。解决先写脚本按完整文件名比对 images 与 labels 两边的集合把不匹配的文件挑出来删除或重命名。然后随机抽查若干张图确认框和目标的大致位置关系。如果所有框都统一偏移检查归一化分母是否等于图像实际宽高如果只有个别图偏移重点看那几张图的文件名是否有特殊字符或重复前缀。5.2 现象训练报错提示类别索引超出范围训练刚开始或中途控制台抛IndexError: index 10 is out of bounds for axis 0 with size 10这类错误或者 loss 直接变成 NaN。原因data.yaml 里nc和names的长度与标签中实际出现的最大 class_id 不一致。比如标签里某行第一列是 10但 names 只有 10 个元素索引范围是 0 到 9访问 index 10 就溢出。这类错误在读取标签时不报因为 YOLOv5 是在建立类别映射时才校验。解决写一个扫描脚本统计所有标签里出现的最大 class_idimport glob max_cls -1 for path in glob.glob(datasets/labels/*/*.txt): with open(path) as f: for line in f: cls int(line.split()[0]) if cls max_cls: max_cls cls print(最大 class_id:, max_cls, - nc , max_cls 1)逻辑说明遍历 train 和 val 全部标签记录第一列的最大值。YOLO 的 class_id 从 0 开始所以实际类别数是最大值加 1。把这个数字填进 yaml 的nc并保证 names 列表长度一致。这一步跑完后索引溢出问题基本绝迹。5.3 现象验证集 mAP 虚高但实际检测效果很差训练过程 loss 正常下降验证集 mAP 数值很好看但把模型拿去做实际推理时框的位置明显不准跟训练时的验证结果对不上。原因最常见的是数据集划分泄露。Roboflow 导出时如果原始项目里 train 和 val 存在同名或近似同名的图片模型相当于在“见过”的图上验证mAP 自然虚高。另一种可能是归一化坐标检查时越界框被 YOLOv5 自动裁剪裁剪后的框仍然有效但位置已经变了视觉上感觉不准。解决检查 train 和 val 两个目录下是否存在相同文件名最简单的办法是在两个目录间做一次文件名交集计算。同时用 show.py 随机抽验证集的图对比标签框和实际目标的位置确认 val 的标注质量。mAP 虚高的问题早发现早处理拖到模型部署阶段再发现返工成本很高。5.4 现象GPU 显存不足CUDA out of memory训练刚开始或跑到第一个 epoch 中途显存直接爆掉报CUDA out of memory。原因512x512 输入加上默认的 Mosaic 增强训练时实际显存占用会明显高于单张推理的峰值batch size 设成 32 在 8GB 显卡上属于临界状态如果同时跑着其他程序很容易爆显存。解决先把--batch降到 16显存占用几乎减半。如果还想用大的有效 batch可以借助 YOLOv5 的--nbs参数做梯度累积比如--batch 16 --nbs 64意思是每 64 张图累积一次梯度等价于用 64 的 batch 训练但显存占用保持在 16 的水平。另外关掉其他占显存的进程或者把--workers适当降低都能缓解显存压力。环境配置这类问题与其反复试参数不如先看一遍nvidia-smi确认显存实际占用情况。6. 进阶把图片与标签的全量比对写成一个习惯训练前先跑整理一个不依赖 YOLOv5 工程的小脚本用来快速检查数据集两边的文件是否完全对应。我后来把这个脚本和前面几章的坐标校验、空文件检查合并成一个dataset_check.py每次拿到新数据集都先跑一遍再决定要不要开训。6.1 图片与标签一一对应的硬校验import os data_root datasets for split in [train, val]: img_dir os.path.join(data_root, images, split) lab_dir os.path.join(data_root, labels, split) imgs {os.path.splitext(f)[0] for f in os.listdir(img_dir)} labs {os.path.splitext(f)[0] for f in os.listdir(lab_dir)} print(f[{split}] images: {len(imgs)}, labels: {len(labs)}) print(f 缺标签的图片: {len(imgs - labs)}) print(f 缺图片的标签: {len(labs - imgs)})逻辑说明用集合的差集运算同时查两个方向imgs - labs是哪些图没有对应标签labs - imgs是哪些标签没有对应图片。os.path.splitext(f)[0]去掉扩展名后比较主文件名正好兼容 Roboflow 导出的_jpg.rf.这类带哈希的命名。train 和 val 分开跑输出结果都为零才能进入下一步。我最早用这份数据训练时就是没做这个对称性检查结果跑到中途 dataloader 报文件缺失回去一看 labels 目录比 images 少了三百多个 txt等于那三百张图白放。从那以后我每次拿到新的数据集都会强制先跑一遍dataset_check.py把文件名对应、空标签、越界坐标一次性查完确认没问题才写 data.yaml。这套流程帮我规避掉了八成数据层面的坑也让后面调模型参数时能把精力集中在模型本身而不是反复怀疑数据有问题。希望这篇拆解能帮你在用这份道路检测数据集时少走几步弯路直接把手上的 YOLOv5 环境跑起来。本文还有配套的精品资源点击获取