ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

交通车辆目标检测数据集:YOLO训练全流程与避坑指南

交通车辆目标检测数据集:YOLO训练全流程与避坑指南 简介这份交通车辆目标检测数据集面向自动驾驶感知、智能交通管理与计算机视觉算法研究者聚焦真实道路场景下的多类车辆识别问题。数据采集自实际交通环境覆盖多种光照条件与车辆姿态包含Bicycle、Bus、Car、Motorcycle、Truck五类道路主要参与者标注采用原生YOLO格式提供标准化边界框坐标与类别索引可直接用于YOLOv5/v7/v8等主流框架训练。压缩包共2000个文件以1251个txt标注文件、747张jpg真实场景图片为主另含1个yaml数据配置与1份docx说明文档整体约68.65MB目录结构清晰便于按类别检索。数据中保留车辆遮挡、多尺度目标等实际挑战有助于提升模型泛化能力除基础检测外还可扩展车辆计数与轨迹预测等任务。目前已有255人学习下载适合需要快速验证算法或构建交通感知原型的开发者参考使用。1. 交通车辆目标检测数据集从标注格式到 YOLO 训练落地的第一手拆解城市路口卡口、高速匝道、园区出入口这些场景里跑的目标检测模型十有八九绕不开「车」这个类别。但真正动手做过的人都知道公开的 COCO、VOC 里车辆样本又杂又散类别定义和实际业务对不上直接拿来训一个交通车辆检测器mAP 看着还行一上真实视频流就翻车。这份「交通车辆目标检测数据集.zip」解决的就是这个断层——它把交通场景下的车辆目标单独抽出来做成一份可以直接喂给 YOLO 系列yolov8、yolov11、yolov12 乃至社区里讨论的 yolov26 目标检测方向训练的数据包。适合谁做自动驾驶感知预研的、做智慧交通卡口算法的、带学生做目标检测课程设计的以及想拿一份干净车辆数据练手 YOLO 微调流程的从业者。它不是一个玩具样本集而是一份能让你把「数据准备 → 格式转换 → 训练 → 验证」整条链路走通的实战素材。2. 数据集结构与标注格式先搞清楚你拿到的是什么在动手写任何训练脚本之前我习惯先把压缩包解开用文件树和统计脚本把数据摸一遍。这一步偷懒后面格式转换和类别映射一定会出问题。交通车辆数据集这类资源常见的组织方式有两种一种是已经切分好 train/val/test 的目录结构另一种是原始图片加一份总的标注文件。你得先确认自己拿到的是哪种再决定后续怎么处理。2.1 目录结构与文件组织解压后典型的结构大致是这样不同来源会有差异但核心元素跑不出这几样# 解压后先看整体结构别急着写代码 unzip 交通车辆目标检测数据集.zip -d traffic_vehicle_dataset cd traffic_vehicle_dataset find . -maxdepth 2 -type d | sort # 常见输出 # ./images # ./images/train # ./images/val # ./labels # ./labels/train # ./labels/val # ./data.yaml如果看到的是images和labels平行、下面再分train/val那基本可以确定是 YOLO 格式的现成结构省事很多。如果只有一堆.jpg加一个.xml文件夹那就是 VOC 格式需要自己转。还有一种情况是图片全在一个目录、标注是一个大的.json或.txt这种多见于从标注平台直接导出的原始包处理成本最高。先跑一个统计脚本把图片数量、标注数量、类别分布摸清楚import os from collections import Counter img_dir images/train lbl_dir labels/train img_files [f for f in os.listdir(img_dir) if f.endswith((.jpg, .png, .jpeg))] lbl_files [f for f in os.listdir(lbl_dir) if f.endswith(.txt)] print(f图片数: {len(img_files)}) print(f标注文件数: {len(lbl_files)}) # 统计类别分布YOLO 格式每行第一个数字是类别 id class_counter Counter() for lbl in lbl_files: with open(os.path.join(lbl_dir, lbl)) as f: for line in f: if line.strip(): class_counter[int(line.split()[0])] 1 print(类别分布:, dict(class_counter))这段脚本干三件事确认图片和标注是否一一对应、统计总样本量、看类别是否严重不均衡。交通车辆数据集如果只标了 car 一类那class_counter应该只有一个 key如果分了 car、bus、truck、motorcycle那就要留意小类别样本量后面训练时可能要调损失权重。2.2 YOLO 标注格式的字段含义YOLO 的标注是每张图对应一个同名.txt每行代表一个目标格式是class_id x_center y_center width height后四个值都是归一化到 0~1 的相对坐标不是像素值。这一点是新手最容易搞错的地方——拿像素坐标直接写进去训练时框会全部跑到图像外面loss 一开始就炸。我一般会写个校验脚本检查所有坐标是否落在 [0,1] 区间def validate_yolo_labels(lbl_dir): bad_files [] for lbl in os.listdir(lbl_dir): if not lbl.endswith(.txt): continue with open(os.path.join(lbl_dir, lbl)) as f: for i, line in enumerate(f): parts line.strip().split() if len(parts) ! 5: bad_files.append((lbl, i, 字段数不对)) continue coords list(map(float, parts[1:])) if any(c 0 or c 1 for c in coords): bad_files.append((lbl, i, 坐标越界)) if coords[2] 0 or coords[3] 0: bad_files.append((lbl, i, 宽高非正)) return bad_files problems validate_yolo_labels(labels/train) print(f发现 {len(problems)} 处问题) for p in problems[:10]: print(p)参数说明coords[2]和coords[3]分别是归一化宽高正常必须大于 0如果出现 0 或负数说明标注时框画反了或者导出有 bug。这类脏数据不清理训练到中期会出现 loss 突然飙高的玄学现象很多人以为是学习率问题其实是标注在作祟。2.3 data.yaml 的配置要点YOLO 训练靠data.yaml告诉框架去哪找数据、有几个类别。一份合格的配置长这样path: ./traffic_vehicle_dataset train: images/train val: images/val nc: 1 names: 0: vehiclenc是类别数names是 id 到类名的映射顺序必须和标注文件里的class_id严格对应。如果数据集里 car 是 0、bus 是 1你这里写成 0: bus训练不会报错但推理出来的类别全是错的。我见过有人训完模型发现「所有车都被识别成公交车」查了半天是 names 顺序写反了。改完记得重新生成一遍缓存YOLO 会把标签缓存成.cache文件不删的话改了 yaml 也不生效。3. 从原始标注到 YOLO 训练格式转换脚本与参数设置拿到手的交通车辆数据集未必是现成的 YOLO 格式。VOC 的 XML、LabelMe 的 JSON、甚至 COCO 的 json都可能遇到。这一章把最常见的两种转换路径写清楚脚本可以直接抄。3.1 VOC XML 转 YOLO txtVOC 格式每张图一个 XML里面记录了图片尺寸和每个框的像素坐标xmin/ymin/xmax/ymax。转 YOLO 的核心就是把像素坐标归一化import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, img_w, img_h, class_map): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_map: continue cls_id class_map[cls_name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 转成中心点 宽高的归一化值 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) return lines class_map {car: 0, bus: 1, truck: 2} # img_w, img_h 需要从图片读取或用 PIL 获取逻辑说明class_map是你自己定义的类别映射必须和data.yaml里的names一致。归一化时除以的是图片真实宽高不是 XML 里写的size字段——有些标注工具导出的 size 和实际图片对不上以 PIL 读出来的为准更稳。坐标保留 6 位小数足够YOLO 内部会再处理。参数上有个细节如果xmax或ymax超出了图片边界标注时手抖画出去了归一化后会大于 1训练时会被裁掉或者报错。稳妥做法是加一句 clampx_center min(max(x_center, 0), 1) y_center min(max(y_center, 0), 1) w min(max(w, 0), 1) h min(max(h, 0), 1)3.2 COCO json 转 YOLOCOCO 格式的交通车辆数据集也不少见尤其是从大平台导出的。它的结构是images、annotations、categories三个数组转换时要先建立 image_id 到文件名的映射import json def coco_to_yolo(json_path, out_dir, class_map): with open(json_path) as f: data json.load(f) img_info {img[id]: img for img in data[images]} # 按 image_id 聚合标注 from collections import defaultdict ann_by_img defaultdict(list) for ann in data[annotations]: ann_by_img[ann[image_id]].append(ann) for img_id, anns in ann_by_img.items(): info img_info[img_id] w, h info[width], info[height] lines [] for ann in anns: cls_id class_map[ann[category_id]] x, y, bw, bh ann[bbox] # COCO 是左上角 宽高 x_center (x bw / 2) / w y_center (y bh / 2) / h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {bw/w:.6f} {bh/h:.6f}) # 写出同名 txt name os.path.splitext(info[file_name])[0] with open(os.path.join(out_dir, name .txt), w) as f: f.write(\n.join(lines))关键差异COCO 的bbox是[x, y, width, height]左上角坐标加宽高不是 xmin/ymin/xmax/ymax。这个坑我踩过直接套 VOC 的公式转出来框会整体偏移半个身位。另外 COCO 的category_id往往不是从 0 连续开始的比如从 1 开始必须用class_map重新映射不能直接拿来当 YOLO 的 class_id。3.3 划分训练集与验证集如果数据集没有预先切分得自己按比例分。交通车辆场景下我一般按 8:2 分 train/val且要保证两个集合里类别分布接近import random import shutil all_imgs [f for f in os.listdir(images/all) if f.endswith(.jpg)] random.seed(42) random.shuffle(all_imgs) split int(len(all_imgs) * 0.8) train_imgs all_imgs[:split] val_imgs all_imgs[split:] for phase, files in [(train, train_imgs), (val, val_imgs)]: for f in files: shutil.copy(fimages/all/{f}, fimages/{phase}/{f}) lbl os.path.splitext(f)[0] .txt shutil.copy(flabels/all/{lbl}, flabels/{phase}/{lbl})random.seed(42)是为了让划分可复现团队协作时大家拿到同一份切分结果。如果数据集里某些类别样本特别少比如 truck 只有几十个纯随机划分可能导致 val 里一个 truck 都没有验证指标失真。这种情况建议按类别分层抽样或者干脆对小类别做过采样。4. 用 YOLO 训练交通车辆检测模型配置、命令与显存调优数据准备好了接下来是训练。这一章以 YOLOv8 为主线yolov11、yolov12 的接口基本兼容把命令行参数、显存控制、训练监控讲透。社区里讨论的 yolov26 目标检测目前更多是方向性内容实际落地还是以稳定版本为主。4.1 训练命令与关键参数一条典型的训练命令yolo detect train \ datatraffic_vehicle_dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ device0 \ projectruns/traffic \ nameexp1逐个说参数modelyolov8n.pt是从预训练权重起步交通车辆这种单类别或少数类别任务用 nano 或 small 版本就够上 large 容易过拟合且推理慢。imgsz640是输入分辨率卡口场景车牌级目标多的话可以提到 1280但显存翻倍。batch16要看显卡8G 显存跑 640 分辨率大概能到 1612G 能到 32。lr00.01是初始学习率微调预训练模型时这个值合适从零训可以降到 0.001。patience20是早停耐心值20 轮验证指标不涨就停省时间。如果显存不够报 OOM优先降 batch其次降 imgsz最后才考虑换更小的模型。有个技巧是用batch-1让 YOLO 自动探测最大可用 batch但自动探测有时偏保守我一般手动试。4.2 训练过程监控与指标解读训练启动后控制台会打印每轮的 box_loss、cls_loss、mAP50、mAP50-95。交通车辆检测重点看两个mAP50反映框得准不准mAP50-95反映高 IoU 阈值下的精度。如果 mAP50 涨到 0.9 但 mAP50-95 卡在 0.5说明框的位置还不够精细可能是标注框本身偏大或偏小。# 训练结束后用验证集单独跑一次评估 yolo detect val \ modelruns/traffic/exp1/weights/best.pt \ datatraffic_vehicle_dataset/data.yaml \ imgsz640验证输出里有个per-class表格如果只有一类看 overall 就行。混淆矩阵在runs/traffic/exp1/目录下能直观看到漏检和误检。交通车辆场景常见的误检是把远处的小车识别成背景或者把货车和客车混淆——后者说明类别定义本身有歧义需要在标注规范上统一。4.3 推理与部署前的验证训完模型别急着上线先用几张真实场景图跑推理肉眼看看效果from ultralytics import YOLO model YOLO(runs/traffic/exp1/weights/best.pt) results model.predict( sourcetest_images/, conf0.25, iou0.45, saveTrue, projectruns/predict, nametraffic_test )conf0.25是置信度阈值低于这个值的框不输出iou0.45是 NMS 的 IoU 阈值控制重叠框的合并。交通场景车流密集时iou调太低会把相邻车辆合并成一个框调太高又会保留重复框0.45 是个常用起点。saveTrue会把画了框的图存下来方便快速检查。提示推理时如果发现大量漏检先别怀疑模型回头看看验证集里同类场景的标注是否完整。漏标比模型能力不足更常见。5. 避坑与排查交通车辆数据集训练中最容易翻车的五件事这一章是我自己踩过的坑也是带人做项目时被问得最多的。每条按「现象 → 原因 → 解决」写照着排查能省不少时间。5.1 训练 loss 从第一轮就是 nan现象启动训练后 box_loss 直接显示 nan几轮后进程退出。原因标注文件里有坐标越界或宽高为 0 的脏数据归一化后出现非法值反向传播时梯度爆炸。解决跑一遍 2.2 节的校验脚本把所有坐标越界和宽高非正的标注行删掉或修正。如果脏数据量大直接过滤掉对应图片。5.2 验证集 mAP 很高但实际推理全是漏检现象val 的 mAP50 有 0.95拿真实视频跑却几乎检不出车。原因训练集和验证集来自同一批数据分布太接近模型过拟合了或者验证集图片和训练集有重复。解决检查 train 和 val 是否有同名图片用 md5 去重另外找一批完全没参与训练的实拍图做测试别只看 val 指标。5.3 改了 data.yaml 的类别名但训练结果没变现象把names从vehicle改成car重新训练后推理输出的还是旧类别。原因YOLO 会缓存标签到.cache文件yaml 改了但缓存没失效。解决删掉labels/目录下所有.cache文件或者加cacheFalse参数禁用缓存。这个坑很隐蔽因为训练不报错只是结果不对。5.4 显存够但训练速度异常慢现象显卡是 3090batch 只设了 8但每轮要跑十几分钟。原因数据加载成了瓶颈可能是图片分辨率过大比如 4K 原图没缩放或者磁盘 IO 慢。解决训练前把图片统一缩放到接近imgsz的尺寸减少解码开销用 SSD 存数据加workers8提高数据加载并行度。5.5 小目标车辆检测效果差现象近处车辆检得很好远处几十像素的小车几乎全漏。原因下采样过程中小目标特征丢失640 分辨率下远处车可能只有十几个像素。解决提高imgsz到 1280或者在数据增强里加mosaic和scale让模型多见小目标标注时确保远处车辆也框到位别因为「看不清」就漏标。6. 进阶技巧用切片推理和类别平衡把交通车辆检测再提一档基础流程跑通后想再往上提精度有两个方向值得试。第一个是切片推理SAHI专门对付高分辨率交通监控图里的小目标。原理是把大图切成带重叠的小块分别推理后再把框拼回去这样远处小车在切片里就变成了「大目标」。用法上SAHI 可以和 YOLO 直接配合from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction detection_model AutoDetectionModel.from_pretrained( model_typeyolov8, model_pathruns/traffic/exp1/weights/best.pt, confidence_threshold0.25, devicecuda:0 ) result get_sliced_prediction( test_images/highway.jpg, detection_model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2 )slice_height/width是切片尺寸overlap是切片之间的重叠比例0.2 意味着相邻切片有 20% 重叠避免目标正好被切在边界上导致漏检。代价是推理时间成倍增加实时性要求高的场景要权衡。第二个方向是类别平衡。如果数据集里 car 占 90%、truck 只占 5%模型会偏向 car。除了在损失里加权更直接的办法是对小类别做数据增强——把 truck 样本复制多份配合不同的亮度、对比度、翻转让每个 epoch 里各类别出现次数接近。我一般会写个简单的过采样脚本把样本数少于最大类别 30% 的类别随机复制到 30% 的水平。还有个容易被忽略的点验证集要能反映真实场景的类别比例。如果真实卡口里 truck 占 20%但验证集里只有 2%那 mAP 再高也不代表实际可用。划分数据时按真实分布来指标才有参考意义。从那以后我每次拿到一份新的目标检测数据集都强制先跑一遍标注校验和类别分布统计再动手写训练脚本。这个习惯帮我省下了至少三次「训到一半发现数据有问题」的返工。希望帮到你。本文还有配套的精品资源点击获取
返回列表