YOLOv5车辆检测实战:car_dataset数据集清洗训练调参与推理
2026/9/10 14:15:18 网站建设 项目流程

简介:面向目标检测开发者与学习者的车辆检测数据集,涵盖白天、夜间及俯视场景的车辆图片,适用于YOLOv5、YOLOv3、SSD等主流目标检测模型的训练与评估,能有效支撑自动驾驶、智慧交通等场景的算法验证。压缩包共7210个文件,其中包含2403张jpg原图、2404个txt标签和2403个xml标签;txt采用YOLO格式,xml采用VOC格式,两种标注文件与图片一一对应,可直接用于不同训练框架,无需额外转换脚本,资源包整体约803.77MB。已有1817人学习/下载,所有数据统一标注为car单类别,标注内容清晰一致,既可用于从零训练车辆检测器,也可以在预训练模型基础上进行微调,适配不同算力设备与项目周期。对于缺少自采数据或需要多场景验证的目标检测项目,这份数据集能显著降低数据准备与清洗成本,帮助开发者把精力集中在模型结构与参数调优上,提升车辆检测系统的迭代效率。

1. 拿到 car_dataset 压缩包之后,先别急着解压开训

做车辆检测的工程里,car_dataset这种名字的数据包几乎每个算法工程师都收过。它一般是别人整理好的 YOLO 格式(或 VOC 格式)图片包,压缩成一个.rar,又因为分卷或重复整理被标注成-1。你要面对的核心问题不是“能不能用 YOLOv5 跑车辆检测”,而是“这份数据我敢不敢直接喂给模型”。

大多数在网上下载、或被直接转交的车辆数据集,第一关根本卡在格式上——标注是不是归一化的中心点坐标?类别编号和你的业务能不能对齐?图片数量和标签数量差了一大截?这些问题不解决,后面训练曲线再漂亮,放到自己的摄像头场景里照样误检漏检。本文就顺着“数据整理 → 配置训练 → 调参收敛 → 推理验证”这条线,讲清楚 YOLOv5 车辆检测从数据集落地到模型能用的常见做法,并给足可以照着敲的命令和参数说明。

2. 先把 car_dataset 拆开,验证图片与标注是否完整

2.1 解压并检查目录结构

不管压缩包是从哪里拿到的,第一件事是把它放到一个纯英文路径下解压。YOLOv5 的训练逻辑会用到os.path.join拼路径,中文目录在部分 Windows 环境下会触发编码错误,这个在社区里每天都有新人踩。Linux 下直接解压:

unrar x car_dataset-1.rar

如果没有unrar,CentOS 系用yum install unrar,Ubuntu/Debian 系用apt install unrar,macOS 用brew install unrar。解压之后先看目录长成什么样,常见的组织方式是:

car_dataset-1/ ├── images/ │ ├── train/ │ │ ├── 00001.jpg │ │ ├── 00002.jpg │ └── val/ ├── labels/ │ ├── train/ │ │ ├── 00001.txt │ │ └── 00002.txt │ └── val/

如果是这种结构,就说明数据整理者已经按 YOLOv5 的约定分好了训练集和验证集。但很多时候你拿到的是草稿版:所有图片在同一个文件夹、所有.txt也在同一个文件夹,甚至没有固定的val集。碰到这种情况,先不急着写脚本移动文件,先确认标注文件是 YOLO 格式还是 VOC 的 XML 格式。

YOLO 格式的.txt每行对应一个目标,每行 5 列:class x_center y_center width height,坐标全部相对图片宽高做了归一化,取值范围在 0 到 1 之间。VOC 格式则是 XML 文件,记录的是绝对像素坐标。这篇讲 YOLOv5,所以按 YOLO 格式来处理。

2.2 用脚本计算图片数量、标签数量与类别分布

解压出来先别急着配环境,写一个一次性统计脚本,把数据的家底摸清楚。labels/train里有多少个.txtimages/train里有多少张.jpg/.png,两者数量差多少,这是第一个关键指标。差值越大,说明越多的标注被漏掉或转存失败。

import os from collections import defaultdict img_dir = 'car_dataset-1/images/train' label_dir = 'car_dataset-1/labels/train' imgs = {os.path.splitext(f)[0] for f in os.listdir(img_dir)} labels = {os.path.splitext(f)[0] for f in os.listdir(label_dir)} print('images:', len(imgs)) print('labels:', len(labels)) print('missing:', len(imgs - labels)) cls_count = defaultdict(int) total_boxes = 0 for f in os.listdir(label_dir): if not f.endswith('.txt'): continue with open(os.path.join(label_dir, f), 'r') as fin: for line in fin: parts = line.strip().split() if len(parts) == 5: cls_count[int(parts[0])] += 1 total_boxes += 1 print('total boxes:', total_boxes) for cls in sorted(cls_count.keys()): print('class', cls, ':', cls_count[cls])

这段脚本做了三件事:统计imageslabels文件名集合的差集、统计每类目标的框数量、统计总框数。逻辑上先用set求差,找到有图无标注和标注无图的文件;再逐行读标注文件,parts[0]是类别编号,parts[1:]是坐标。如果缺标注的图片超过总图片数的 1% 到 3%,我一般会直接把这些图片从训练集里移除,而不是去补标。原因是后续 YOLOv5 在Dataset里会对每个 label 做缓存检测,缺标注的图片在训练中报错很难排查,得不偿失。

2.3 检查坐标越界和空标注问题

常年制作用的车辆标注文件里,最隐蔽的坑是坐标越界。比如目标刚好出现在图片边缘,标注软件输出的是0.997 0.501 0.012 0.34,看起来在[0,1]区间内,但标注框的左上角计算出来是负数。YOLOv5 在utils/datasets.py里会对坐标做截断,但截断逻辑在训练早期会带来一定程度的标注扰动。

更常见的问题是:有的.txt文件是空的,表示这张图没有目标。YOLOv5 默认会把这些图当作背景样本,但车辆检测场景里背景图占比太高,会让模型偏向输出低置信度。我一般会把空标注文件也统计出来,记录数量占比。整体原则是:背景图不超过 20%,超过的话就把部分纯背景图拿掉,不让模型在收敛阶段把重心放在抑制误检上。

另外,val目录往往比train更乱。很多下载来的数据集压根没有划分验证集,需要自己做。用train_test_split或者简单的随机抽样划分,建议按 0.9/0.1 的比例拆,车辆检测这种较大的数据集不需要留 20% 做验证。代码上直接用shutil.move配合random.sample就可以完成。

import random from pathlib import Path import shutil src_img = Path('car_dataset-1/all_images') src_label = Path('car_dataset-1/all_labels') val_img = Path('car_dataset-1/images/val') val_label = Path('car_dataset-1/labels/val') names = [p.stem for p in src_img.glob('*.jpg')] val_names = set(random.sample(names, int(len(names) * 0.1))) for name in names: if name in val_names: shutil.move(str(src_img / f'{name}.jpg'), str(val_img / f'{name}.jpg')) shutil.move(str(src_label / f'{name}.txt'), str(val_label / f'{name}.txt'))

做法上优先保证同名的图片和标注文件一起移动,避免出现验证集里面只有图片没有标注。另外选在移动之后打印一次val_imgval_label的文件数量做复核。

3. 配置 YOLOv5 环境与 car.yaml 数据文件

3.1 环境安装的常见做法

YOLOv5 对 Python 版本要求不算苛刻,Python 3.8 到 3.11 都能跑,但 PyTorch 版本要和 CUDA 匹配好。最省事的方式是先建一个独立的 conda 环境,再装依赖,不要把全局环境弄乱。

conda create -n yolov5 python=3.9 -y conda activate yolov5 cd yolov5 pip install -r requirements.txt

requirements.txt里涉及的核心依赖有torchtorchvisionopencv-pythonnumpymatplotlibpyyamltqdm。装完之后用一段几行代码的脚本验证 CUDA 是否真的可用:

import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))

torch.cuda.is_available()返回True不代表训练一定没问题,还要看 PyTorch 对应的 CUDA 版本和你机器的显卡驱动是否兼容。如果这里返回False,大概率是装了 CPU 版本的 PyTorch,需要去 PyTorch 官网按照 CUDA 版本重新安装。车辆检测训练动辄一两个小时起步,CPU 训练不是不能跑,而是迭代一次的速度会让你怀疑服务器是不是死机了。

3.2 写 car.yaml,注意类别号对齐

YOLOv5 的数据配置是 YAML 格式,核心就三件事:path指到数据集根目录、trainval指向子目录、ncnames列出类别数量与名称。对车辆检测来说,names列表的下标顺序必须和标注文件里class列的数字严格对应。

path: ./datasets/car_dataset-1 train: images/train val: images/val nc: 1 names: 0: car

写这个文件有两个容易出错的地方。第一,trainval的路径不是从磁盘根目录开始,而是相对于path字段。写成./datasets/car_dataset-1/images/train这种绝对路径只有在所有机器上目录都一致时才不会出问题,换到别的机器就要改,所以 YOLOv5 作者也是推荐用上面的相对写法。第二,nc的取值必须和实际标注里的类别数量一致。如果标注文件里出现过class 1,但这里nc写成 1,训练时会把所有类别为 1 的框当成越界类别忽略掉,训练日志里 Loss 看起来正常,但验证集 mAP 会极低。

3.3 手动验证 YAML 配置是否生效

配置好之后,可以用 YOLOv5 自带的train.py先做一个极短的 smoke test,而不是直接进入正式训练。一个 1 个 epoch 的测试不会消耗太多时间,但能快速暴露数据路径、标注格式和类别映射的问题。

python train.py --data car.yaml --weights yolov5s.pt --epochs 1 --batch-size 4 --img 640

如果数据路径写错,这里会直接报AssertionError: train: No labels in ...或者FileNotFoundError。如果数据没问题,日志会打印出每张图片里标注框的数量、坐标范围等统计信息。这一步通过之后,再进入正式的参数调整。注意--weights yolov5s.pt会去下载预训练权重,网络不通的情况下需要手动准备好权重文件放到仓库根目录。训练车辆检测时我一般很少用yolov5x或者yolov5l直接开训,先用s做通途验证,确认数据没毛病再换成大模型,能省不少时间。

4. 训练超参数设置与收敛判断

4.1 训练命令和常用参数的取舍

数据确认无误后,进入正式训练。车辆检测场景下,yolov5syolov5m是性价比最高的两个起点,yolov5l适合对精度有硬性要求、且不介意推理帧率的场景。训练时最常用的命令:

python train.py \ --data car.yaml \ --weights yolov5s.pt \ --img 640 \ --batch-size 16 \ --epochs 100 \ --patience 20 \ --workers 8 \ --cache ram

参数说明:--img 640是输入图片的短边尺寸,YOLOv5 会按长宽比缩放后补边。车辆检测里目标大小跨度很大,路口的车可能占满整张图,也可能在高空监控里只有几十个像素,640是个稳妥起步值。如果目标是密集小车流,可以考虑--img 1280,但显存占用会成倍增长。--batch-size按显存调整,16 是 24G 显存训练yolov5s的安全值,8G 显存就降到 8 或 4。--patience 20表示 20 个 epoch 内验证集 mAP 没有提升就提前终止。--cache ram把图片加载进内存,省去每轮 epoch 重复读取磁盘的 IO 开销,前提是内存足够容纳整个数据集。

还有两个容易被忽略但影响很大的参数:--multi-scale--hyp--multi-scale会让图片尺寸在 0.5 到 1.5 倍之间随机缩放,车辆目标在真实场景里透视差异明显,开启后泛化通常会改善,但训练时间变长约 10% 到 20%。--hyp指向一个超参数文件,YOLOv5 默认使用data/hyps/hyp.scratch-low.yaml,如果想改学习率、数据增强强度,可以复制一份改参数,然后用--hyp指定。

超参数文件里影响比较大的三个参数是lr0(初始学习率)、mosaic(马赛克增强概率)和fliplr(水平翻转概率)。lr0默认 0.01,如果训练时 Loss 在一开始就剧烈震荡,降到 0.005 试试。车辆检测对水平翻转不敏感,车辆左右对称,fliplr保持默认 0.5 没问题。mosaic默认 1.0,也就是百分百使用马赛克增强,在最后 10 个 epoch 会自动关闭,这是 YOLOv5 内置的调度逻辑。

4.2 观察训练日志和 results.png 判断是否需要停

训练过程中,每完成一个 epoch 会打印一行关键指标,核心要看PRmAP@0.5mAP@0.5:0.95四个值。车辆检测任务里,工程上最关心的是mAP@0.5,因为部署时默认置信度阈值基于PR曲线来定。

训练结束或提前终止后,产出在runs/train/exp目录下。打开results.png,里面有十几张小图,重点看两件事。第一件是val/box_losstrain/box_loss的曲线是否同步下降,验证集 box loss 如果在某个 epoch 后反而持续上升,说明开始过拟合了,即使mAP还在缓慢波动,也应该停止训练。第二件是mAP_0.5曲线的爬升速度,如果到第 60 个 epoch 还在明显上涨,就把--epochs加大到 150 或者 200。

验证集指标非常依赖标注质量。如果 mAP@0.5 卡在 0.6 上不去,先别急着换大模型,回到labels目录随机抽几张图,把标注框画出来看有没有错标和漏标。这一步可以用 YOLOv5 的utils/plots.py辅助,也可以用一个简单脚本读取 YOLO 格式坐标后用 OpenCV 画框。标注里常见的错误是车顶视角被标了一半范围,或者两个并排车辆被标成一个框,这会让box_loss始终下不去。

4.3 显存不足和 nan 的排查思路

训练车辆检测数据集的batch-size调的太激进,最容易撞上CUDA out of memory。解决方案不是立刻降batch-size,是先用--cache ram降低数据读取的内存压力,再把--workers降下来,最后才降batch-sizeworkers设置太高时,多个 DataLoader 子进程会各自复制一部分内存,表现为显存没满但总内存爆掉,报错信息看起来像DefaultCPUAllocator: can't allocate memory

nan的出现则更复杂。常见原因包括:标注文件里出现0 0 0 0之类的全零坐标,YOLOv5 计算box的 IoU 时除数为零;或者图片本身损坏,用 OpenCV 读取时返回None,导致输入的张量含缺失值。排查时先写个简单循环逐张读取图片检查是否可解码,再检查标注文件的坐标是否有全零行。还有一种情况是学习率过大导致梯度爆炸,那种情况产物里不止有nan,通常还会伴随 Loss 突然飙到几十万再变成nan,把--hyp里的lr0降到 0.001 到 0.002 基本能解决。

5. 推理阶段处理重叠框和输出车辆位置的技巧

训练完成后,detect.py是跑在测试集上的常用入口。车辆检测的推理结果里,一个典型问题是同一辆车被输出多个重叠框,尤其是镜头里出现车的侧面、并且车身与其他车紧挨着的时候。detect.py有一个重要的--agnostic-nms参数,它控制 NMS 是否在类别之间互相抑制。车辆检测数据集中往往只有car一类,这个参数开不开影响不大;但如果标注里同时有carbustruck,同一个空间位置不可能同时存在两类车,这时--agnostic-nms会强行在类别之间做抑制,输出的框数量会明显减少,画面也干净得多。

另一个实用技巧是直接改输出逻辑,把检测到的车辆位置写进 SQLite 或 CSV,方便下游做数量统计。平时做车辆检测项目时,我经常会写一个很小的推理脚本来接detect.py的输出:

import torch import cv2 model = torch.hub.load('ultralytics/yolov5', 'custom', path='runs/train/exp/weights/best.pt', force_reload=True) model.conf = 0.35 model.iou = 0.45 model.agnostic = True img = cv2.imread('demo.jpg') results = model(img) df = results.pandas().xyxy[0] for _, row in df.iterrows(): print(row['xmin'], row['ymin'], row['xmax'], row['ymax'], row['confidence'])

代码里的model.confmodel.iou是推理阶段最值得调的两个数字。conf是置信度阈值,摄像头里车流密集、有遮挡时,把conf从 0.25 抬高到 0.35 到 0.45 会在漏检和误检之间做出一个偏保守的取舍。在品牌车型接近、颜色相近的停车场场景里,低置信度框往往是误检的重灾区,抬高阈值比调模型有效得多。iou是 NMS 的 IoU 阈值,设得越低,重叠框被抑制得越狠。

results.pandas().xyxy[0]的作用是把检测结果转成 Pandas DataFrame,每一行是xminyminxmaxymaxconfidence,坐标是原始图片的像素坐标,可以直接用于画框或写入业务系统的计数逻辑。使用该脚本时注意torch.hub.load联网下载模型会受网络环境影响,路径替换成本地仓库后,推理基线性能会更稳定,不需要在每次启动时都进行一次检查。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询