简介面向YOLO系列算法的车辆检测数据集专注于公交车、卡车、摩托车、行人、自行车、小型车等常见交通目标可服务于自动驾驶感知、智慧交通监控、车流量统计等场景中的模型训练与算法验证特别适合初、中级目标检测开发者使用。该压缩包共包含2000个文件核心文件类型为xml标注文件压缩后整体大小约205.35MB。数据集已完成训练集与验证集划分同时提供YOLO格式txt和VOC格式xml两套标签并配有data.yaml配置文件能够直接适配YOLOv5、YOLOv7、YOLOv8、YOLOv9、YOLOv10、YOLO11等多个主流算法版本免去手动格式转换的麻烦。标签字段含义清晰yolo格式记录类别索引与归一化的目标框中心点、宽高xml格式则适合在VOC流程或自定义数据管线中灵活使用。整体目录结构规整可直接用于目标检测入门练习也可支撑车辆检测类项目快速原型验证。目前已有98人学习浏览感兴趣的开发者可以下载体验。1. 9767张车辆检测图为什么值得你从零复现一遍数据管线拿到这份YOLO算法-车辆检测数据集大多数人第一时间想的是解压、训练、看mAP但我在两个项目里用它踩出来的结论是真正决定项目成败的不是模型选型而是你花在标签校验和数据划分上的那几小时。标题里这9767张图像、六类目标——公交车、卡车、摩托车、行人、自行车、小型车——覆盖了城市道路和高速场景的绝大部分常见目标适合做智慧交通、辅助驾驶的检测基线。新手可以直接拿它练手跑通YOLO全流程熟手则能把它当作评估自己模型鲁棒性的「复测集」。本文按我的实际复现路径展开从标签格式讲到训练参数再到按类验收全程不假设你有任何额外数据集照着操作就能把训练跑起来。2. 先读懂这份数据集的内部构成六类分布与YOLO标签格式2.1 六类目标的真实分布为什么行人总是最难的那一档在跑训练之前我最先做的事是把每个类别的标签数量统计出来。标题只告诉你「9767张图像带标签」不会告诉你六类样本是否存在严重不平衡而这直接决定最后mAP的可信度。常见的做法是把标签文件读进脚本按类别ID计数再配合条形图观察分布。真实场景里卡车和小型车通常占大头摩托车和自行车偏少行人则经常出现「样本少且多为远处小目标」的双重问题。如果你发现某类只有几百个框另一类有两万个框后续的增强策略和类别权重都要调整而不是拿着默认参数直接开跑。统计脚本很简单把每张图的txt标签读一遍累加每个类别出现的次数顺带把空标签文件筛出来from pathlib import Path import collections labels_dir Path(labels) empty_files [] per_class collections.Counter() for txt in sorted(labels_dir.glob(*.txt)): with open(txt, r, encodingutf-8) as f: lines [line.strip() for line in f if line.strip()] if not lines: empty_files.append(txt.name) continue for line in lines: cls_id int(line.split()[0]) per_class[cls_id] 1 print(每个类别的目标数量) for cls_id in sorted(per_class): print(fclass {cls_id}: {per_class[cls_id]}) print(空标签文件数量, len(empty_files))这段代码的逻辑labels目录下每个txt文件对应一张图每个非空行是一个目标第一列是类别ID。统计出来的数字如果和标题里的六类能对上说明标签结构基本健康如果类别ID超过5说明标签里有越界类别号这种文件训练时要么被忽略要么直接报错。int()强转在遇到非数字字符时会抛异常这也是一个快速筛错手段。唯一值得改的参数是labels_dir的路径如果你的标签放在别的目录下改这一行即可。2.2 YOLO坐标系的换算逻辑从像素框到归一化txtYOLO系列统一采用「类别ID 归一化中心点 归一化宽高」的txt格式每一行代表一个目标第一列类别ID从0开始第二三列是目标框中心点的x和y坐标相对图像宽高的比值第四五列是宽和高同样是比值。举例来说一张1920×1080图像里一辆小型车的像素框左上角是(240,300)、右下角是(960,900)那么中心点x就是((240960)/2)/19200.3125中心点y就是((300900)/2)/10800.5556宽高分别是(960-240)/19200.375和(900-300)/10800.5556最终写成一行为5 0.3125 0.5556 0.3750 0.5556。很多标注软件导出的标签是VOC或COCO的像素坐标转成YOLO时就需要这一套换算。我一般会写一个从归一化回到像素的校验脚本把框画回原图确认没有坐标越界也确认框和肉眼看的位置基本一致import cv2 def yolo_to_pixel(line, img_w, img_h): cls_id, xc, yc, w, h map(float, line.split()) x1 int((xc - w / 2) * img_w) y1 int((yc - h / 2) * img_h) x2 int((xc w / 2) * img_w) y2 int((yc h / 2) * img_h) return int(cls_id), (x1, y1, x2, y2) img cv2.imread(images/000001.jpg) h, w img.shape[:2] with open(labels/000001.txt, r) as f: for line in f: if not line.strip(): continue cls_id, box yolo_to_pixel(line, w, h) x1, y1, x2, y2 box if x1 0 or y1 0 or x2 w or y2 h: print(f越界: {line.strip()}) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(check.jpg, img)yolo_to_pixel的输入是归一化浮点值和图像宽高返回像素坐标系下左上角和右下角。脚本的关键参数是img_w和img_h从cv2.shape取的是(height, width)顺序不要写反否则框会整体错位。如果发现大量目标框集中在图像边缘或者明显没包住车体大概率是标签导出时坐标被错误处理例如没有除以宽高就写进了txt。这种错误在训练时不会报错但会让模型学到一个偏移的分布后面所有指标都不可信。2.3 标签与图像的文件名对齐一张图对应一个标签训练前还要确认images和labels下的文件名一一对应。YOLO的默认约定是同一张图的标签文件与图像文件同名仅扩展名不同比如images/000001.jpg对应labels/000001.txt。如果解压后的命名规则不是这样训练时要么缺正样本要么数据加载阶段直接报错。检查方式用两行set运算from pathlib import Path img_names {p.stem for p in Path(images).glob(*.jpg)} lbl_names {p.stem for p in Path(labels).glob(*.txt)} print(缺标签的图像, sorted(img_names - lbl_names)[:10]) print(缺图像的标签, sorted(lbl_names - img_names)[:10]) print(f图像 {len(img_names)} 张标签 {len(lbl_names)} 个)缺标签说明这张图没有监督信号会被YOLO静默跳过缺图像说明标签是孤立文件基本可以删除。常见原因是某次批量导出时部分图损坏或者标注平台只导出了部分图片。我的习惯是把这个检查脚本放在数据集根目录每次拿到新数据集先跑一遍几秒钟就能把名字不配对的文件全部找出来省得训练跑到一半才发现某个类别的样本数少得离奇。3. 把9767张图拆成训练集、验证集和测试集划分方案与校验脚本3.1 随机划分还是目录划分先看数据的组织方式拿到9767张图别急着全量训练先把训练、验证、测试三份划分出来。常见比例是7:2:1或8:1.5:0.5我默认用8:1.5:0.5因为验证集只需要足够稳定地评估模型不需要太多。如果解压后自带train/val目录直接写配置就行如果所有图像混在同一个images目录就要自己写随机划分。需要注意的是道路视频抽帧而来的数据集常有相邻帧连续出现的情况如果它们被分到了train和val两侧验证指标会虚高。标题没有提供序列信息所以常见做法还是先按文件随机划分再用重复检测脚本检查有没有高相似图像串集。3.2 按固定随机种子划分的Python脚本我习惯用路径列表的方式做划分不复制图像而是生成三个txt文件每个文件一行图像路径。这样磁盘占用最小换数据集也只要改路径。import random from pathlib import Path image_dir Path(images) all_images sorted(image_dir.glob(*.jpg)) print(图像总数, len(all_images)) random.seed(42) random.shuffle(all_images) train_ratio, val_ratio 0.8, 0.15 n len(all_images) n_train int(n * train_ratio) n_val int(n * val_ratio) train_set all_images[:n_train] val_set all_images[n_train:n_train n_val] test_set all_images[n_train n_val:] def write_list(path, imgs): with open(path, w, encodingutf-8) as f: for img in imgs: f.write(str(img) \n) write_list(train.txt, train_set) write_list(val.txt, val_set) write_list(test.txt, test_set) print(ftrain{len(train_set)}, val{len(val_set)}, test{len(test_set)})这段脚本的关键参数是随机种子seed我固定为42保证每次划分结果一致便于复现。如果你的环境里shuffle行为跨Python版本不同可以先用sorted()固定列表顺序再shuffle正是上面代码的做法。txt里写的是相对路径images/000001.jpg这样数据集整个挪到别的机器也不用改配置。如果你改成绝对路径则每次移动目录后都要重新生成txt。3.3 划分后的三项校验类别比例、重复帧、空标签划分完成以后别直接开训练先检查train和val里每个类别的目标数量占比。如果训练集里公交车占0.5%验证集里公交车占5%这个划分就是失败的模型会被验证集的分布带偏。检查方式是把2.1节的统计脚本分别跑在train和val的标签目录上输出比例差异差异超过一倍就需要重新划分。第二项是重复帧检测视频抽帧数据集里常见。肉眼很难发现两张图是不是同一场景用MD5可以快速找出完全相同的副本感知哈希能找近似重复但计算量较大先用MD5过滤掉最严重的泄漏import hashlib from pathlib import Path def md5(path): return hashlib.md5(path.read_bytes()).hexdigest() groups {} for img in all_images: groups.setdefault(md5(img), []).append(img) dups {k: v for k, v in groups.items() if len(v) 1} print(重复图像组数, len(dups)) for k, v in list(dups.items())[:5]: print(重复组, [p.name for p in v])MD5完全一致说明是同一张图的不同副本如果分布在train和val里验证集评估会被灌水。第三项是空标签划分前的统计结果里如果空标签文件超过总数的3%就要回到源数据确认是否应该过滤。这种背景图可以让模型学到「没有目标时不要乱输出」但如果比例太高验证集会因为大量空图拉低调用的均值mAP的表现也会失真。4. 用YOLOv8跑通车辆检测数据yaml配置、训练命令与收敛判断4.1 yaml的五个字段类别顺序决定预测结果的正确性YOLOv8的数据配置是一个yaml文件里面写path、train、val、nc和names五个字段。最容易翻车的是names的顺序它必须和标签文件里的类别ID一一对应。这份数据集的类别顺序从标题看是公交车、卡车、摩托车、行人、自行车、小型车那names就要写成[bus, truck, motorcycle, pedestrian, bicycle, car]ID 0对应busID 5对应car。如果写反训练时模型loss能正常下降但预测出来的类别全是错的这种「静默错误」最浪费时间。path: /home/user/datasets/vehicle train: train.txt val: val.txt test: test.txt nc: 6 names: 0: bus 1: truck 2: motorcycle 3: pedestrian 4: bicycle 5: car一个验证yaml对不对的土办法把val临时指向train.txt启动一次只跑一个epoch的验证看一眼输出里的类别名字是否和标签ID对应。注意path字段建议写绝对路径避免相对路径与txt里的相对路径拼接后出现两级目录错位。如果你从事过多个数据集混用的项目一定遇到过path写错报错No labels found的情况先检查这里。4.2 训练命令与batch、epochs、imgsz参数的实际含义写好yaml后一条命令即可启动训练yolo detect train datavehicle.yaml modelyolov8s.pt epochs100 batch16 imgsz640 device0 workers8参数的选择逻辑yolov8s是速度和精度折中的选择显存不够就换yolov8n要求精度就换yolov8m或yolov8l。batch16在8GB显存下比较稳如果报CUDA out of memory降到8或者把imgsz降到512。epochs100对一万张以下的数据集够用但也别只看数字要结合loss曲线判断有没有收敛。device0指定GPUworkers8是加载图像的进程数Windows下workers别超过4否则容易引发缓冲区的卡死问题。训练时终端输出的box_loss、cls_loss、dfl_loss三列前几十个epoch是快速下降期后几十个是平台期。如果loss从epoch 10开始反复震荡不降先看是整体震荡还是单列震荡。整体震荡常见原因是学习率太高单列如cls_loss震荡则可能是类别分布异常。每轮结束还会打印验证集mAP50和mAP50-95这两个才是真正要盯的指标。mAP50是IoU取0.5时的平均精度mAP50-95是在0.5到0.95区间内多个IoU阈值下的均值后者更严格也更反映框的定位质量。对这份数据我训练的100轮结果里mAP50在0.85以上mAP50-95在0.6到0.7之间达不到就往第5章的坑里找原因。4.3 加载预训练权重还是从零训练两种起点的差异modelyolov8s.pt表示用COCO预训练权重做迁移学习这是推荐做法。车辆检测的六类里卡车、摩托车、行人、自行车在COCO里都有对应或近似的类预训练模型已经学到了通用特征收敛速度和最终精度都比从零训练好。如果尝试modelyolov8s.yaml从零训练同样的epoch数下mAP50一般会低5到10个百分点而且训练前期loss下降非常慢。我见过有人为了「避免COCO偏见」故意从零训练结果小目标检测反而更差因为数据量不足以让backbone学到足够鲁棒的中层特征。4.4 断点恢复与产物文件best.pt、last.pt怎么用训练中断是常态尤其是多人共用GPU时。YOLOv8支持断点恢复用resumeTrue加模型权重路径yolo detect train datavehicle.yaml modelruns/detect/train/weights/last.pt resumeTrue训练结束后runs/detect/train/weights/下会有两个文件best.pt是验证集指标最好的权重last.pt是最后一轮权重。推理和验收入直接用best.pt因为我发现车辆检测场景里最后几轮往往出现过拟合征兆last.pt的泛化能力通常不如best.pt。如果磁盘空间紧张last.pt可以在确认best.pt可用后删掉省几百MB很划算。5. 车辆检测数据集落地避坑标签偏移、类间混淆、小目标漏检与类别不平衡5.1 标签框偏移导致loss降不下去现象训练到第50轮左右box_loss卡在0.06上下不再下降val的mAP50反复横跳怎么看都不像收敛。原因标签框和真实目标之间存在系统性偏移常见于标注工具导出时坐标没对齐或者图像resize后标签没有跟着变换。统计上看一部分框偏左上一部分偏右下模型学到的框中心分布是散乱的。解决用2.2节的还原脚本随机抽查50张图把标签框画出来与原图叠放。如果偏移有固定方向比如所有框都偏右上10像素那是导出代码里坐标加减反了修正后重新导出如果是零散偏移就回到原始标注平台或工具链重新导出一次标签。不要指望模型自己修正偏移它学到的就是「带偏移的分布」推理时照样错。这个坑最隐蔽的地方在于loss能降指标也不算太难看但框的位置始终不贴合车体边缘。5.2 摩托车和自行车互相误检现象验证集里摩托车的precision很高但recall很低混淆矩阵里摩托车那一行有很大一部分被预测成了自行车。原因这类数据集的常见标注定义问题。摩托车和自行车在较远距离时外形相似标注员如果没有统一「看发动机/排气管」的判定口径很容易标混。另一个原因是图像里骑手的姿态相似模型提取到的区分特征不够。解决先统计两者标签数量如果数量悬殊考虑对少数类做过采样。更直接的做法是把两个类别的标签抽样打印出来逐张人工复核手动修正明显标错的框。我处理过一份类似数据集人工复核了300张图发现近10%的标签归类错误修正后摩托车的AP从0.52涨到0.71。如果业务上实在不要求区分两者也可以把两个类别ID合并成「两轮车」类再重新评估这种取舍在交通流量统计场景里经常出现。5.3 远处小目标车辆漏检现象整体mAP50-95偏低但把测试图拆开看近处卡车能被检出远处摩托车和行人几乎全漏。原因训练时imgsz640原图1920×1080被缩放到640宽后一个原本只有20×20像素的小目标被压成7×7像素特征彻底模糊。这是车辆检测里最常见的「小目标黑匣子」——总指标不告诉你它丢了多少小目标。解决第一个选项是提高训练分辨率比如imgsz1280但这会加大显存占用迭代变慢第二个选项是训练时做随机裁剪让模型多看到局部放大后的目标第三个选项是推理阶段用SAHI这类切片辅助推理把大图切成带重叠的patch分别检测再合并结果。对比下来切片对mAP50-95的提升最明显但推理时间也成倍增加适合离线分析场景。我在一次路侧项目里把imgsz从640提到1280行人的召回率从0.3提到0.52代价是单卡训练时间从6小时变成11小时值不值取决于你的业务实时性要求。5.4 类别不平衡让mAP虚高的陷阱现象某次训练mAP50到了0.9但把测试集按六个类别分别算AP后发现小型车AP是0.97行人只有0.3验证集平均指标被多数类拉高了。原因数据集里小型车和卡车的框占绝大多数模型把所有类别学成了「多数类优先」少数类几乎不出现在正样本里。9767张图整体量级不小但六类目标的框数量差距可能达到几十倍。解决三个办法。第一是给损失函数加类别权重YOLOv8没有直接的类别权重参数但可以用实例过采样在dataloader里按类别欠采样或过采样第二是数据增强时针对少数类做copy-paste把行人或摩托车的框随机粘贴到道路上这是我在之前一个模拟项目里用过最见效的方法行人的AP从0.3涨到0.55第三是调整置信度阈值用更低的conf过滤recall增加但precision可能下降需要业务上能接受误检。最终我一般以按类别算出的AP列表为准而不是单看一个mAP50数字。5.5 图像尺寸混合导致batch内目标scale跳跃现象loss曲线正常下降但val的mAP50-95一直低于预期抽查bad case发现模型对中距离目标特别好对特写大目标反而漏检。原因数据集里可能混着1920×1080的大图和800×600的小图YOLO训练时统一resize到640×640。大图里一辆接近满屏的卡车会被等比缩小小图里同样一辆卡车却占据不同比例。目标是同一个语义尺度分布却非常宽模型学起来就分裂。解决先统计所有图像的宽高和宽高比如果比例集中在1.7到1.9之间说明是统一视频尺寸抽帧没问题如果从4:3到16:9都有建议按宽高比分组训练或者把四周做填充而不是直接拉伸。直接拉伸会让物体变形标签框与物体外形失配这是很多人没注意到的隐性错误。my做法是统一用letterbox填充到训练尺寸YOLOv8默认就是这么处理的所以如果你为了省事用cv2.resize直拉图片再喂自定义管线才会踩进这个坑。6. 用混淆矩阵和按类AP完成模型验收到底能不能上线的量化标准训练完best.pt官方val命令会给你一堆指标但我会额外做两件事。第一件是跑一遍验证集生成混淆矩阵和PR曲线第二件是按类别单独统计AP因为总体mAP会掩盖少数类问题。yolo detect val datavehicle.yaml modelruns/detect/train/weights/best.pt conf0.25验证结果会出现在runs/detect/val下其中confusion_matrix.png横轴是预测类别纵轴是真实类别对角线越高越好。具体技巧是看非对角线上的热点如果摩托车和自行车之间有明显高亮块说明类间混淆仍然严重如果background列很高说明误检较多需要提高conf阈值。单独看一张混淆矩阵图还不够还要对数值敏感一点矩阵右下角的数值是「无目标被正确拒绝」的比例这个数字太低说明模型在空路上乱框项目上线的拦路虎往往在这里。按类AP的统计我一般用脚本直接读取验证结果from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) metrics model.val(datavehicle.yaml, conf0.25, iou0.5) names [bus, truck, motorcycle, pedestrian, bicycle, car] for i, name in enumerate(names): result metrics.box.class_result(i) print(f{name}: mAP50{result[0]:.3f} mAP50-95{result[3]:.3f})这里class_result返回的列表第一列是mAP50第四列是mAP50-95我更看重后者因为它同时惩罚框的定位误差。如果某一类的AP比多数类低了0.3以上基本可以判定类别不平衡问题没解决需要回到第5章的过采样或者copy-paste方案而不是加训练轮数。验收的时候还有一个习惯把bad case图导出按类别分目录保存下次训练前先看这些图确认是标注错还是模型错避免盲目调参。这个习惯是某次mAP 0.9上线后被用户反馈「老是漏摩托车」换来的血泪经验——如果你手头这个模型也是准备拿去跑夜间巡航或批量分析请务必按类别逐项验收别只看总平均。希望帮到你。本文还有配套的精品资源点击获取