简介:这份面向自动驾驶场景的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 个 txt,val 目录下 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", encoding="utf-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, f"columns={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, f"out 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 仓库默认值,一般不用改。输出结果里mAP@0.5是 IoU 阈值取 0.5 时的平均精度,mAP@0.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_id:
import 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 环境跑起来。
本文还有配套的精品资源,点击获取