
简介本资源为面向YOLOv5目标检测学习者的车辆检测数据集类别聚焦单一car适用于交通监控、自动驾驶感知、安全驾驶辅助等场景的模型训练与实验验证适合具备一定深度学习基础、希望快速搭建车辆检测流程的开发者与研究者。压缩包共约2000个文件以1285个txt标签、1284个jpg图像和1284个xml标注为主txt提供边界框坐标xml记录类别、坐标与面积等细节整体约147.64MB采用PASCAL VOC格式便于直接接入YOLOv5训练管线。目前已有4474人学习下载热度较高。读者可据此完成图像缩放、归一化与标签格式转换结合随机翻转、裁剪、旋转等数据增强提升泛化能力并通过调整学习率、批次大小与训练轮数观察mAP变化同时针对光照变化、遮挡与视角差异等难点进行专项优化也可迁移至其他检测任务。1. 拆开这个 car 车辆检测数据集为什么 2008 到 2011 的 txt 标注值得单独拎出来练手如果你手头正好有一批交通卡口、行车记录仪或者园区监控的图片想训一个只认“car”的检测器第一道坎往往不是模型结构而是标注。这份car车辆检测数据集.rar里躺着的就是一批已经标好的 PASCAL VOC 风格标注文件文件名像2008_005139.txt、2009_004630.txt、2011_001110.txt这样年份前缀直接暴露了它的来源——VOC2012 那套经典图像的标注子集只不过这里被筛成了单一类别 car。对做 yolov5 车辆检测数据集的人来说这种“单类、干净、格式统一”的包反而比动辄几十 G 的多类大集更好上手你不用先花两天写脚本清洗类别不平衡也不用担心 20 个类里有一半你根本不关心。它适合三类人刚学 YOLOv5 想跑通全流程的新手、需要快速验证某个 backbone 或超参改动的熟手、以及拿它当预训练冷启动再迁移到自己业务数据上的工程师。下面我按“先看清格式、再转成 YOLO、然后训练、最后避坑”的顺序把这份包从头到尾拆一遍。2. 从 VOC txt 到 YOLO txt标注格式差异与转换脚本2.1 先搞清楚这份包里的 txt 到底存了什么很多人一看到.txt就默认是 YOLO 格式这是第一个翻车点。这份数据集里的2008_005139.txt这类文件走的是 PASCAL VOC 的标注体系通常和同名.xml配对存在。VOC 的 xml 里一个目标长这样bndbox下面挂着xmin、ymin、xmax、ymax坐标是绝对像素值原点在左上角类别名写在name里这里是car。而 YOLOv5 要的 label 是每行class_id cx cy w h五个值全部归一化到 0~1cx cy是框中心点相对整图宽高的比例w h是框宽高相对整图宽高的比例。两者差了两层一层是绝对坐标转相对坐标一层是左上右下转中心宽高。如果你直接把 VOC 的 txt 丢进 YOLOv5 的labels目录训练不会报错但 loss 会一直不降mAP 趴在 0 附近——因为模型看到的是一堆越界的坐标。所以第一步永远是确认你手里 txt 的内容。用一条命令抽样看前几行# 随机抽一个标注文件看内容判断是 VOC 还是 YOLO 格式 head -n 5 2008_005139.txt # 如果是 VOC你会看到类似 # car 112 96 340 280 类别 四个绝对坐标顺序可能是 xmin ymin xmax ymax # 如果是 YOLO你会看到类似 # 0 0.4523 0.3810 0.2210 0.1980逻辑说明head -n 5只取前五行避免大文件刷屏。判断依据是——出现类别字符串car且数值大于 1 的基本是 VOC 绝对坐标只有 0/1 这种小数的是 YOLO 归一化坐标。参数上如果你的 txt 第一列是类别名而不是数字转换时还要建一个car - 0的映射表因为 YOLOv5 只认整数 class_id。2.2 写一个能复用的 VOC 转 YOLO 脚本假设你的包解压后是images/放图、annotations/放 xml或 txt我一般会写一个脚本一次性把 xml 转成 YOLO 需要的 txt并顺手生成train.txt/val.txt两个索引文件。下面这段是我常用的版本处理单类 car 足够多类也能直接扩展import os import glob import random import xml.etree.ElementTree as ET # 类别映射这份数据集只有 car 一类所以 car 固定映射到 0 CLASS_MAP {car: 0} IMG_DIR images XML_DIR annotations OUT_LABEL_DIR labels VAL_RATIO 0.2 # 验证集比例2000 张左右的话留 20% 够评估了 os.makedirs(OUT_LABEL_DIR, exist_okTrue) def convert_one(xml_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in CLASS_MAP: continue # 只保留 car其他类别直接跳过 cls_id CLASS_MAP[name] bnd obj.find(bndbox) xmin float(bnd.find(xmin).text) ymin float(bnd.find(ymin).text) xmax float(bnd.find(xmax).text) ymax float(bnd.find(ymax).text) # 绝对坐标转归一化的中心点 宽高 cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 裁剪到 0~1防止个别标注越界导致训练异常 cx, cy min(max(cx, 0), 1), min(max(cy, 0), 1) w, h min(max(w, 0), 1), min(max(h, 0), 1) lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) # 写同名 txt 到 labels 目录 out_name os.path.splitext(os.path.basename(xml_path))[0] .txt with open(os.path.join(OUT_LABEL_DIR, out_name), w) as f: f.write(\n.join(lines)) xml_files glob.glob(os.path.join(XML_DIR, *.xml)) for x in xml_files: convert_one(x) # 生成 train/val 索引图片路径按实际后缀调整 imgs glob.glob(os.path.join(IMG_DIR, *.jpg)) random.shuffle(imgs) n_val int(len(imgs) * VAL_RATIO) with open(val.txt, w) as f: f.write(\n.join(imgs[:n_val])) with open(train.txt, w) as f: f.write(\n.join(imgs[n_val:])) print(fdone: {len(imgs)} images, {n_val} for val)逻辑说明脚本先读 xml 的size拿到原图宽高这是归一化的分母绝对不能写死成 640因为 VOC 图像尺寸不统一。然后遍历每个object用CLASS_MAP过滤只留 car。坐标转换那四行是核心cx用(xminxmax)/2再除以宽w用xmax-xmin除以宽。最后加了一步裁剪到 0~1这是血泪经验——VOC 里偶尔有标注框超出图像边界的脏数据不裁的话 YOLOv5 训练时会出现 NaN loss。参数上VAL_RATIO按你的数据量调几百张就留 0.1几千张留 0.2 比较稳。2.3 转换后必须做的两项校验转完不要急着开训先跑两个校验。第一检查有没有图片没有对应 label或者 label 是空文件# 找出没有对应 label 的图片空标注会导致该图被当负样本 for img in images/*.jpg; do base$(basename $img .jpg) if [ ! -s labels/$base.txt ]; then echo missing or empty: $base fi done第二用 YOLOv5 自带的可视化脚本把几个 label 画回图上肉眼确认框没跑偏# 假设已 clone yolov5 仓库用它的工具画框检查 python yolov5/utils/plots.py --labels labels --images images --save-dir check_vis逻辑说明第一条命令用-s判断文件是否存在且非空空 label 文件意味着这张图被当成“没有目标”的负样本如果它其实有车就会教坏模型。第二条把归一化坐标反算回像素画框是转换正确性的最后一道保险。参数上--save-dir指定输出目录跑完去翻几张图重点看边缘处的车有没有被截断的框。3. 用这份数据集跑通 YOLOv5 训练配置、超参与启动命令3.1 目录结构与 data.yaml 的正确写法YOLOv5 对目录结构有约定我一般整理成这样和官方推荐保持一致省得改代码car_dataset/ ├── images/ │ ├── train/ # 训练图片 │ └── val/ # 验证图片 ├── labels/ │ ├── train/ # 对应 YOLO txt │ └── val/ └── data.yamldata.yaml是训练入口写错路径是最常见的“找不到图片”报错来源# data.yaml path: /abs/path/to/car_dataset # 强烈建议写绝对路径 train: images/train val: images/val nc: 1 # 类别数这份数据集只有 car names: [car] # 类别名顺序必须和 class_id 对应逻辑说明path是根目录train和val是相对path的子路径YOLOv5 会把它们拼起来找图。nc必须等于names的长度这里都是 1。参数上如果你偷懒写了相对路径训练脚本的工作目录一变就会报No images found所以我一律写绝对路径。另外names的顺序就是 class_id 的顺序car是 0转换脚本里映射成 0 才对得上。3.2 选模型规格与关键超参怎么定YOLOv5 有 n/s/m/l/x 五个规格参数量和精度递增。这份数据集是单类、场景相对固定我一般从yolov5s起步它 7M 左右的参数量单卡 8G 显存就能跑收敛快适合先验证数据管线通不通。等管线没问题、mAP 到瓶颈了再换yolov5m或yolov5l提精度。启动训练的命令# 从官方预训练权重冷启动单类检测迁移效果通常比从头训好 python train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data car_dataset/data.yaml \ --weights yolov5s.pt \ --cfg models/yolov5s.yaml \ --hyp data/hyps/hyp.scratch-low.yaml \ --name car_exp1 \ --cache逻辑说明--img 640是输入分辨率VOC 图像普遍在 500 左右缩到 640 是常见做法显存吃紧就降到 512。--batch 16是批次大小8G 显存跑 yolov5s640 大概能到 16爆显存就减半。--epochs 100对单类几千张图通常够看mAP0.5曲线平了就早停。--weights yolov5s.pt用 COCO 预训练权重做迁移这是提升小数据集效果最省事的一招。--hyp指定超参文件新手先用hyp.scratch-low.yaml它学习率偏保守不容易训崩。--cache把图片缓存到内存加速读取数据量大到内存放不下时去掉。3.3 训练过程中该盯哪几个指标启动后终端会刷一堆列别只看 loss。重点盯三个box_loss、obj_loss、mAP0.5。box_loss是边界框回归损失正常应该稳步下降obj_loss是目标置信度损失如果它不降反升多半是 label 有问题或者学习率太大。mAP0.5是验证集上的平均精度单类 car 的话这个值到 0.7 以上算可用0.85 以上算不错。训练完在runs/train/car_exp1/下有results.csv和results.png直接看曲线比盯终端直观。如果mAP在 20 个 epoch 后还贴着 0回去查第 2 章的转换校验八成是坐标没归一化或者类别 id 对不上。4. 车辆检测专属的避坑与排查清单4.1 现象训练 loss 正常下降但 mAP 一直是 0原因最常见的是验证集路径写错YOLOv5 在验证阶段找不到图或者找到了图但 label 目录结构不匹配导致验证时全是空标注。另一种可能是data.yaml里names写成了[Car]而 label 里 class_id 是 0虽然 id 对得上但如果你中途改过映射表就会错位。解决先确认val路径下的图片数量和labels/val下的 txt 数量一致再抽一张验证图用第 2.3 节的可视化脚本画框确认框位置正确。如果都对检查data.yaml的nc是不是写成了大于 1 的数。4.2 现象训练到一半 loss 突然变 NaN原因VOC 原始标注里存在越界框或宽高为 0 的退化框归一化后w或h为 0计算 IoU 时除零。也可能是学习率设太大梯度爆炸。解决回到转换脚本确认裁剪到 0~1 那步没被注释掉再检查有没有w或h小于 1e-6 的框有就丢弃该目标。学习率方面把--hyp换成hyp.scratch-low.yaml或者手动把lr0从 0.01 降到 0.001。4.3 现象模型把路牌、广告牌里的车也框出来误检高原因这份数据集来自 VOC场景以自然街景为主但你的测试场景如果是卡口特写域差异会导致模型对“车”的纹理过拟合到某些背景。另外单类训练缺少负样本约束模型容易把相似矩形物体当车。解决往训练集里掺入一批纯背景图没有车的图label 留空让模型学会“没有车”的样本。YOLOv5 支持空 label 文件作为负样本比例控制在 5%~10%。同时开数据增强--hyp里的mosaic、mixup默认开着能提升泛化。4.4 现象小目标车辆漏检严重原因VOC 图像里远处的车可能只有十几个像素缩到 640 后更小YOLOv5 的 P3 特征图 stride 是 8对小于 8 像素的目标基本无能为力。解决把--img提到 1280或者用yolov5m/l这种更大感受野的模型。另一个办法是切片推理把大图切成小块分别检测再合并代价是速度下降。如果业务允许优先提分辨率。4.5 现象换了批新数据mAP 掉得厉害原因新数据的光照、视角、分辨率分布和 VOC 差异大模型没见过的域直接崩。这不是模型问题是数据分布问题。解决别一上来就全量重训。先用新数据的一小部分做微调--weights指向你上一版训好的best.pt学习率调小到 0.001训 20~30 个 epoch 看效果。如果还不行再考虑把新旧数据混在一起重训。5. 从能跑到好用验证指标解读与迁移到自有数据的技巧训练跑通只是及格线真正决定这份数据集值不值得留在你工作流里的是它能不能当一块合格的“跳板”。我一般会做两件事先把验证指标读透再用它做迁移学习的起点。先说指标。YOLOv5 验证完会输出一张confusion_matrix.png单类 car 的话就是 2x2 矩阵横轴预测、纵轴真实。重点看右下角background那一列——如果真实是 car 但被预测成 background 的数量很大说明漏检多回去查小目标和遮挡如果 background 被预测成 car 的多说明误检多按 4.3 加负样本。另一个是PR_curve.png曲线下的面积就是 AP单类就是 mAP。曲线在中低召回区就掉下去的说明模型对困难样本没信心可以适当调低推理时的--conf-thres默认 0.25车辆检测场景我常降到 0.15 换召回代价是误检略升看业务更怕漏还是更怕错。再说迁移。这份数据集最大的价值不是让你训一个只能认 VOC 街景车的模型而是给你一个已经学会“车”这个概念的权重。当你手头有园区卡口、高速抓拍、停车场俯视这些自有数据时正确姿势是先用这份数据集训出一个best.pt再拿它当--weights去微调你的数据。微调时把--epochs降到 30~50--hyp换成hyp.finetune.yaml学习率更小--img设成和你业务图一致的分辨率。这样比直接用 COCO 预训练权重收敛快得多因为 COCO 里车只是 80 类之一特征被稀释过而这份数据集是纯 car特征更聚焦。有个细节值得单独提这份数据集的标注年份跨 2008 到 2011图像风格偏老色彩和噪点和现在的监控画面有差距。如果你直接拿它训完就上现代卡口可能会发现对夜间和低照度场景泛化差。我的习惯是微调时往自有数据里掺 10%~20% 这份数据集的图让模型同时见到新旧两种分布相当于一个轻量的域适应。实测这样比纯用自有数据训mAP 能稳 2~3 个点尤其是遮挡和远景场景。最后说一个验证技巧别只看 mAP 一个数。把验证集按目标框面积分成 small/medium/large 三档分别看 AP。YOLOv5 验证脚本默认不输出分档但你可以用val.py加--save-json导出预测结果再用 pycocotools 按面积算。如果 small 档 AP 明显低说明你的业务里小目标多要么提分辨率要么换更大模型别在超参上瞎调浪费时间。从那以后我每次拿到一个新数据集都强制先跑一遍格式校验和可视化再开训——这个习惯帮我省下的返工时间比任何调参技巧都值。希望这份拆解能帮你把这份 car 数据集用起来而不是让它躺在硬盘里吃灰。本文还有配套的精品资源点击获取