尧图精选

YOLO车辆检测实战:2129张图像数据集训练与调优指南

🕒 发布时间:2026/10/1 18:24:31 📁 来源:尧图网络
简介这是一份面向目标检测学习与工程实践的YOLO系列车辆数据集覆盖卡车、小型车、摩托车、公交车四类常见道路目标适合正在做车辆检测项目、课程设计或算法验证的开发者与研究者使用。数据集已按训练与验证需求划分完毕并附带data.yaml配置文件可直接接入yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等主流版本开展训练与测试。压缩包共约2000个文件整体62.4MB其中1589个xml文件对应VOC格式标注411个txt文件对应YOLO格式标注两种标签分别存放便于按框架灵活选用YOLO标签采用类别索引与归一化中心点、宽高坐标符合标准解析规范。目前已有111人学习下载。读者可借此省去数据采集与标注成本快速搭建车辆检测基线对比不同YOLO版本的训练效果并借助现成标签完成模型评估与调参验证。1. 从 2129 张带标签图像说起这套车辆数据集到底能跑出什么手头拿到一个叫yolo算法-车辆数据集-2129张图像带标签--卡车-小型车-摩托车-公交车.zip的压缩包第一反应往往不是兴奋而是犯嘀咕2129 张够不够训一个能用的车辆检测模型四类目标卡车、小型车、摩托车、公交车里公交车和卡车在视觉上高度相似会不会互相打架标签到底是 YOLO 的 txt 格式还是 VOC 的 xml这些问题不搞清楚直接开训就是浪费显卡。这篇笔记就围绕这个数据集展开把「拿到一份中小规模车辆数据集之后怎么从零跑通 YOLO 训练、怎么判断它值不值得投入、哪些参数必须调、哪些坑一定会踩」讲透。适合两类人一类是刚接触 YOLO 目标检测、想找一个真实场景数据集练手的新手另一类是做交通监控、卡口识别、自动驾驶感知预研需要快速验证一个车辆检测 baseline 的工程师。2129 张不算大但四类车辆的标注如果质量过关足够训出一个 mAP50 在 0.85 以上的可用模型前提是你别在数据格式和类别平衡上翻车。2. 先搞清楚数据集结构2129 张图像带标签到底长什么样2.1 解压后先做三件事目录清点、格式判定、类别统计拿到压缩包别急着写训练脚本先解压看结构。常见的车辆数据集有两种组织方式一种是images/和labels/平行目录对应 YOLO 格式另一种是JPEGImages/Annotations/ImageSets/对应 VOC 格式。判定方法很简单看标签文件后缀——.txt是 YOLO.xml是 VOC。# 解压并查看顶层结构 unzip yolo算法-车辆数据集-2129张图像带标签--卡车-小型车-摩托车-公交车.zip -d vehicle_dataset cd vehicle_dataset find . -maxdepth 2 -type d | head -20 # 统计图像数量和标签数量 find . -name *.jpg -o -name *.png | wc -l find . -name *.txt | wc -l find . -name *.xml | wc -l这段命令的逻辑是先解压到独立目录避免污染当前路径然后用find逐层查看目录结构最后分别统计图像、txt 标签、xml 标签的数量。参数说明-maxdepth 2限制递归深度避免在大数据集上输出爆炸-o是 find 的或条件注意-name *.jpg -o -name *.png要加括号才严谨这里简化写法在多数 shell 下也能跑。如果 txt 数量和图像数量对不上说明有图像漏标这是第一个要记录的质量问题。2.2 用脚本统计四类目标的分布别让类别不平衡埋雷卡车、小型车、摩托车、公交车这四类在真实道路场景里的出现频率天然不均。小型车可能占 70%公交车可能只占 5%。如果直接开训模型会对小样本类别欠拟合。所以第二步必须做类别分布统计。import os from collections import Counter # YOLO 格式每行 class_id x_center y_center width height label_dir vehicle_dataset/labels class_names [truck, car, motorcycle, bus] # 按 data.yaml 里的顺序 counter Counter() for txt_file in os.listdir(label_dir): if not txt_file.endswith(.txt): continue with open(os.path.join(label_dir, txt_file), r) as f: for line in f: parts line.strip().split() if len(parts) 5: counter[int(parts[0])] 1 total sum(counter.values()) for cid, name in enumerate(class_names): cnt counter.get(cid, 0) print(f{name}: {cnt} 个标注框, 占比 {cnt/total*100:.1f}%)逻辑说明遍历 labels 目录下所有 txt每行第一个字段是类别 id累加计数。参数说明class_names的顺序必须和训练时data.yaml里的names完全一致否则统计结果会张冠李戴。跑完如果发现某一类占比低于 5%就要考虑用数据增强mosaic、mixup或者类别权重来补偿。这一步不做后面训练出来的模型在公交车上大概率是瞎的。2.3 可视化抽查随机抽 20 张图把框画出来统计是数字可视化才是真相。抽 20 张图把标注框画上去重点看三件事框有没有偏移、有没有漏标、公交车和卡车有没有标混。import cv2 import random import os img_dir vehicle_dataset/images label_dir vehicle_dataset/labels class_names [truck, car, motorcycle, bus] colors [(255,0,0), (0,255,0), (0,0,255), (255,255,0)] samples random.sample(os.listdir(img_dir), 20) for img_name in samples: img cv2.imread(os.path.join(img_dir, img_name)) h, w img.shape[:2] txt_path os.path.join(label_dir, img_name.rsplit(.,1)[0] .txt) if not os.path.exists(txt_path): print(f漏标: {img_name}) continue with open(txt_path) as f: for line in f: cid, xc, yc, bw, bh map(float, line.split()) x1 int((xc - bw/2) * w); y1 int((yc - bh/2) * h) x2 int((xc bw/2) * w); y2 int((yc bh/2) * h) cv2.rectangle(img, (x1,y1), (x2,y2), colors[int(cid)], 2) cv2.putText(img, class_names[int(cid)], (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, colors[int(cid)], 2) cv2.imwrite(fvis_{img_name}, img)逻辑说明YOLO 格式的坐标是归一化的中心点加宽高需要乘以图像宽高还原成像素坐标再画框。参数说明colors按类别给不同颜色方便肉眼区分random.sample保证每次抽的图不一样。重点检查公交车和卡车——这两类在侧面视角下轮廓接近如果标注员偷懒很容易标错。发现超过 5% 的错标建议先清洗再训否则模型学到的就是错的。3. 从零跑通 YOLO 训练环境、配置、启动一条龙3.1 环境搭建CUDA、PyTorch、Ultralytics 的版本对齐YOLO 训练翻车一半以上是环境问题。常见做法是用 conda 建独立环境先装 PyTorch 再装 ultralytics。版本对齐的原则是PyTorch 的 CUDA 版本要和你显卡驱动支持的 CUDA 版本匹配ultralytics 用 pip 装最新稳定版即可。conda create -n yolo_vehicle python3.10 -y conda activate yolo_vehicle # 根据你的 CUDA 版本选择这里以 CUDA 11.8 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python # 验证 python -c import torch; print(torch.cuda.is_available(), torch.__version__)逻辑说明先建环境隔离依赖再装带 CUDA 支持的 PyTorch最后装 ultralytics。参数说明--index-url指定 PyTorch 官方 wheel 源避免装到 CPU 版本torch.cuda.is_available()返回 True 才算成功。如果返回 False先查显卡驱动版本再查 CUDA 版本是否匹配别急着怀疑代码。3.2 写 data.yaml四个类别名和路径一个都不能错YOLO 训练靠data.yaml找数据、认类别。这个文件写错训练直接报错或者类别全乱。# vehicle_data.yaml path: /absolute/path/to/vehicle_dataset train: images/train val: images/val test: images/test nc: 4 names: 0: truck 1: car 2: motorcycle 3: bus逻辑说明path是数据集根目录train/val/test是相对路径。参数说明nc是类别数必须和 names 长度一致names 的顺序必须和标签里的 class_id 对应顺序错了模型会把卡车认成公交车。如果数据集没有预先划分 train/val需要自己按 8:1:1 切分切分脚本要保证图像和标签同步移动。3.3 启动训练命令行参数怎么设才不浪费显卡环境好了、yaml 写好了就可以启动训练。以 YOLOv8 为例一条命令搞定但参数要按数据集规模调。yolo detect train \ datavehicle_data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/vehicle \ nameexp1逻辑说明modelyolov8s.pt表示用预训练权重做迁移学习小数据集必须用预训练否则收敛慢且效果差。参数说明epochs100对 2129 张图够用配合patience20早停防止过拟合imgsz640是标准输入尺寸显存不够就降到 416batch16按显存调8G 显存用 8 或 16lr00.01是初始学习率小数据集可以降到 0.005 更稳。启动后盯着 loss 曲线如果 cls_loss 不降多半是标签格式或类别名有问题。3.4 训练过程监控看什么指标、什么时候该停训练不是启动了就完事要盯几个关键指标。YOLO 会在 runs 目录下生成 results.csv 和可视化曲线。指标正常表现异常信号处理box_loss持续下降后趋稳震荡不降降学习率或查标签cls_loss持续下降突然飙升查类别是否标错mAP50逐步上升卡在低位查数据量或增强mAP50-95缓慢上升远低于 mAP50正常定位精度难逻辑说明box_loss 管定位cls_loss 管分类mAP 是综合指标。参数说明mAP50 是 IoU 阈值 0.5 下的平均精度对车辆检测来说 0.85 以上算可用mAP50-95 更严格通常比 mAP50 低 0.1 到 0.2。如果训练到 50 轮 mAP50 还在 0.5 以下别硬撑停下来查数据。4. 避坑指南车辆数据集训练最容易翻车的五个地方4.1 现象公交车被识别成卡车置信度还不低原因公交车和卡车在侧面视角下都是长条形如果标注时边界框画得松两类特征高度重叠。加上公交车样本少模型倾向于把它归到样本多的卡车类。解决先统计两类样本量如果公交车少于 200 个框用 mosaic 增强时对公交车图像提高采样权重或者在损失函数里给公交车类加 class_weight。更直接的办法是清洗标注把公交车和卡车的边界框画紧突出公交车的大面积车窗特征。4.2 现象训练 loss 正常下降但验证集 mAP 一直上不去原因训练集和验证集分布不一致。常见于随机切分时某些场景比如夜间、雨天的图全被分到训练集验证集里没有。解决切分时按场景分层抽样保证每个场景在 train/val 里都有。如果数据集本身场景单一那就别指望验证集 mAP 能反映真实泛化能力得另找外部测试集。4.3 现象训练到一半 CUDA out of memory原因batch 设太大或者 imgsz 设太高。2129 张图用 yolov8s 在 8G 显存上batch16 imgsz640 是临界值。解决先把 batch 降到 8如果还爆就降 imgsz 到 416。另一个隐藏原因是 dataloader 的 workers 设太多导致内存泄漏把 workers 从 8 降到 4 试试。4.4 现象标签文件里有空行或坐标超出 0-1 范围原因标注工具导出时产生脏数据或者人工修改时手误。解决训练前跑一个校验脚本检查每行是否有 5 个字段、坐标是否在 0 到 1 之间、class_id 是否在 0 到 3 之间。发现异常行直接剔除或修正别让脏数据进训练。import os bad [] for txt in os.listdir(vehicle_dataset/labels): with open(os.path.join(vehicle_dataset/labels, txt)) as f: for i, line in enumerate(f): parts line.strip().split() if len(parts) ! 5: bad.append((txt, i, 字段数不对)); continue cid int(parts[0]) coords list(map(float, parts[1:])) if cid not in range(4) or any(c 0 or c 1 for c in coords): bad.append((txt, i, 类别或坐标越界)) print(f发现 {len(bad)} 处异常) for b in bad[:10]: print(b)逻辑说明逐行校验字段数、类别 id、坐标范围。参数说明range(4)对应四类坐标必须在 0 到 1 之间。这个脚本跑一遍能拦掉大部分低级错误。4.5 现象推理时小目标摩托车漏检严重原因摩托车在图像里占像素少YOLO 下采样后特征丢失。2129 张图里如果摩托车样本本身少问题更突出。解决训练时开启close_mosaic10让最后 10 轮关闭 mosaic 增强专注小目标或者把 imgsz 提到 800 再训一轮。推理时把 conf 阈值从 0.25 降到 0.15能召回更多摩托车但误检会增加需要权衡。5. 进阶技巧用这套数据集把模型推到可用线以上5.1 迁移学习 冻结训练小数据集的正确打开方式2129 张图不算多从头训必然过拟合。正确做法是分两阶段先冻结 backbone 训 head再解冻全量微调。# 第一阶段冻结 backbone只训检测头 yolo detect train datavehicle_data.yaml modelyolov8s.pt epochs30 freeze10 lr00.01 # 第二阶段解冻全量微调降低学习率 yolo detect train datavehicle_data.yaml modelruns/vehicle/exp1/weights/best.pt epochs70 lr00.001逻辑说明freeze10冻结前 10 层backbone 主体只更新检测头让模型先适应车辆数据的类别分布。参数说明第一阶段学习率可以高一点第二阶段必须降否则会破坏已学到的特征。两阶段加起来 100 轮比一次性训 100 轮效果更稳。5.2 用混淆矩阵定位类别混淆针对性补数据训练完看混淆矩阵能直接看出哪两类在互相误判。如果公交车和卡车混淆严重就针对性地补这两类的难例样本。from ultralytics import YOLO model YOLO(runs/vehicle/exp2/weights/best.pt) metrics model.val(datavehicle_data.yaml) print(metrics.confusion_matrix)逻辑说明model.val会在验证集上跑一遍输出混淆矩阵。参数说明矩阵对角线是正确分类非对角线是误判。重点看公交车行和卡车列的交叉值如果数值大说明这两类需要更多区分性样本。5.3 导出 ONNX 做部署前的最后验证训练完的 pt 模型要部署通常先导出 ONNX。导出后必须做一次推理对齐确认精度没掉。yolo export modelruns/vehicle/exp2/weights/best.pt formatonnx imgsz640逻辑说明导出 ONNX 后用 onnxruntime 跑一张测试图和 pt 模型的输出对比。参数说明imgsz640必须和训练时一致否则输入尺寸不匹配会导致精度下降。如果 ONNX 推理结果和 pt 差异超过 1%检查是否有算子不支持或动态轴设置问题。这套流程走下来2129 张图的车辆数据集能训出一个在四类目标上 mAP50 达到 0.85 以上的模型公交车和卡车的混淆能压到可接受范围。我自己踩过的最大坑是没做类别统计就开训结果公交车几乎全漏回头补数据浪费了两天。所以拿到数据集先统计、再可视化、最后才训练这个顺序别省。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →