ARTICLE DETAIL

资讯详情

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

BDD100K人车识别数据集:YOLOv8训练与VOC标签转换实战

BDD100K人车识别数据集:YOLOv8训练与VOC标签转换实战 简介这份资源是面向目标检测方向的BDD100K人车识别数据集适合深度学习入门与进阶开发者、算法工程师及学生用于YOLO系列、Faster R-CNN、SSD等模型的训练与验证。数据集共15807张图片涵盖pedestrian、car、bus、rider、motorcycle、truck、bicycle七类目标同时提供YOLO与VOC两种标注格式并附有指定类别信息的yaml配置文件图片与txt标签已按训练集、验证集、测试集划分完毕可直接投入YOLOv5至YOLOv10等算法使用。资源包共2000个文件以1999个txt标签文件和1个yaml配置文件为主压缩包大小约917.9MB因体积超过1G已上传至百度网盘分享链接永久有效。目前已有417人学习下载适合需要快速获取标准化人车识别数据、开展模型对比实验或课程项目的读者省去自行标注与格式转换的时间成本。1. 拿到 BDD100K 人车识别数据集15807 张图、7 类目标为什么我第一件事是查标签格式上周帮一个做智慧交通检测的朋友排查训练不收敛的问题翻完他的数据目录我就明白了——他把一份 VOC 格式的标注直接喂给了 YOLOv8labels/里全是 XML模型当然学不到东西。这类翻车在目标检测项目里太常见了而 BDD100K 人车识别数据集恰好是那种「格式给得很全、但你得先搞清楚用哪套」的资源。这份数据集包含 15807 张图片覆盖 pedestrian、car、bus、rider、motorcycle、truck、bicycle 七类道路目标同时提供了 YOLO 格式的 txt 标签、VOC 格式的 xml 标签、指定类别信息的 yaml 文件并且已经按训练集、验证集、测试集切分好。它解决的核心问题不是「有没有数据」而是「拿到就能直接开训不用自己写转换脚本」。适合谁做车辆行人检测的算法工程师、跑 YOLO 系列课程设计的学生、需要快速验证检测模型 baseline 的从业者。如果你正在找一份开箱即用的人车识别数据集这份东西的完成度比我见过的大多数「整理版」要高一个档次。2. 拆开目录看门道txt、xml、yaml 三套标注怎么配合2.1 三种标注格式各自的职责很多人拿到数据集第一反应是「文件好多」其实这份资源的目录逻辑很清晰三套标注各司其职。YOLO 格式的 txt 标签是给 YOLO 系列v5 到 v10直接训练用的每行是class_id x_center y_center width height坐标全部归一化到 0~1。VOC 格式的 xml 标签是给 Faster R-CNN、SSD 这类框架用的里面存的是绝对像素坐标的xmin/ymin/xmax/ymax。yaml 文件则是 YOLO 训练时的数据配置入口告诉训练脚本图片在哪、类别名是什么、类别数是多少。这三套东西不是冗余而是覆盖了主流检测框架的两种标注范式。你不需要同时用三套选一套跟你训练框架匹配的就行。我一般会先确认训练框架吃哪种格式再决定保留哪套标签另一套留着做交叉验证或者格式转换的对照。2.2 目录结构与文件对应关系一份典型的切分后目录大概长这样我按常见组织方式还原一下bdd100k_person_car/ ├── images/ │ ├── train/ # 训练集图片 │ ├── val/ # 验证集图片 │ └── test/ # 测试集图片 ├── labels/ │ ├── train/ # YOLO 格式 txt与 images/train 一一对应 │ ├── val/ │ └── test/ ├── annotations/ # VOC 格式 xml可选保留 │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml # YOLO 训练配置关键点是images/train/xxx.jpg必须和labels/train/xxx.txt同名同数量YOLO 训练时是按文件名去配对标签的少一个或者名字对不上那张图就会被当成无标签背景图处理直接影响召回。我见过有人解压后图片在train/images/、标签在train/labels/路径层级不一致训练脚本找不到标签loss 一直降不下去。2.3 data.yaml 里到底写了什么yaml 文件是 YOLO 训练的入口配置内容结构一般是这样# data.yaml path: ./bdd100k_person_car # 数据集根目录 train: images/train # 训练集图片相对路径 val: images/val # 验证集图片相对路径 test: images/test # 测试集图片相对路径 nc: 7 # 类别数 names: # 类别名顺序必须和 txt 里的 class_id 对应 0: pedestrian 1: car 2: bus 3: rider 4: motorcycle 5: truck 6: bicycle这里最容易出问题的是names的顺序。txt 标签里的class_id是数字模型训练时靠 yaml 里的names把数字映射回类别名。如果 yaml 里0写的是car但 txt 里0实际标注的是pedestrian训练不会报错但推理出来的框全是错的类别。这种错误隐蔽性极强我建议拿到数据集后先抽 5 张图可视化验证一遍再开训。提示path字段在 YOLOv8 里支持相对路径和绝对路径但相对路径是相对于你执行训练的当前工作目录不是相对于 yaml 文件位置。跑训练前先pwd确认一下或者直接写绝对路径省心。3. 从零跑通 YOLOv8 训练环境、命令与参数怎么设3.1 环境准备与依赖安装这份数据集官方说明支持 YOLOv5 到 YOLOv10我以目前用得最多的 Ultralytics YOLOv8 为例走一遍完整流程。环境用 conda 隔离避免和系统里的其他包打架# 创建独立环境python 版本建议 3.9~3.11 conda create -n bdd_yolo python3.10 -y conda activate bdd_yolo # 安装 ultralytics会自动带上 torch 等依赖 pip install ultralytics # 验证安装能打印版本号就说明环境通了 yolo version如果你有 GPU装完 torch 后确认一下 CUDA 是否可用import torch print(torch.cuda.is_available()) # True 表示 GPU 可用 print(torch.cuda.get_device_name(0))torch.cuda.is_available()返回False是最常见的环境坑通常是 torch 版本和 CUDA 驱动不匹配。这种情况要么重装对应 CUDA 版本的 torch要么先用 CPU 跑一个小 epoch 验证数据管线通不通别一上来就怀疑数据集有问题。3.2 启动训练一条命令背后的参数含义环境通了之后训练命令本身很简单yolo detect train \ data./bdd100k_person_car/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ device0 \ workers4 \ projectruns/bdd \ nameexp1逐个说参数。data指向你的 yaml 配置文件路径写错会直接报Dataset not found。model是预训练权重yolov8n.pt是最小的 nano 版本适合先跑通流程确认没问题再换yolov8s.pt或yolov8m.pt提精度。epochs100是训练轮数15807 张图的数据量100 轮在单卡 3090 上大概几个小时。imgsz640是输入分辨率YOLO 系列默认 640如果你的目标偏小比如远处行人可以提到 1280但显存占用会翻倍。batch16根据显存调8G 显存跑 640 分辨率大概能到 16爆显存就往下调。device0指定第一块 GPUCPU 训练写devicecpu。workers4是数据加载线程数设太高在 Windows 上容易出问题Linux 下可以到 8。训练启动后你会看到每个 epoch 的输出重点关注三个指标box_loss、cls_loss、mAP50。box_loss降不下去说明框回归有问题cls_loss降不下去说明分类有困难mAP50是验证集上的主指标正常情况应该稳步上升。3.3 训练完怎么验证和推理训练结束后权重存在runs/bdd/exp1/weights/best.pt用验证集跑一遍评估yolo detect val \ modelruns/bdd/exp1/weights/best.pt \ data./bdd100k_person_car/data.yaml \ splitval \ imgsz640splitval指定用验证集也可以换成test看测试集表现。输出里会给出每一类的 precision、recall、mAP50、mAP50-95。人车识别这种场景car和pedestrian的 mAP 通常最高rider和motorcycle因为样本相对少、目标形态多变指标会低一些这是正常的不用一看到某类指标低就以为数据坏了。推理单张图片或者整个文件夹# 单张图片 yolo detect predict \ modelruns/bdd/exp1/weights/best.pt \ sourcetest.jpg \ conf0.25 \ saveTrue # 整个测试集文件夹 yolo detect predict \ modelruns/bdd/exp1/weights/best.pt \ source./bdd100k_person_car/images/test \ conf0.25 \ saveTrueconf0.25是置信度阈值低于这个值的框会被过滤掉。人车检测场景如果漏检严重就调低到 0.1误检太多就调到 0.4 以上。结果默认存在runs/detect/predict/下。4. 换框架不换数据VOC 标签喂给 Faster R-CNN 的改法4.1 为什么有人非要用 xml 标签YOLO 系列虽然火但不少团队的生产管线还是 Faster R-CNN 或者 SSD尤其是需要两阶段检测精度、或者已有基于 Detectron2、MMDetection 的代码库时。这份数据集提供了 xml 标签就是为了让这批人不用自己从 txt 反推 VOC 格式。xml 里存的是绝对坐标结构长这样annotation filenameabc123.jpg/filename size width1280/width height720/height /size object namecar/name bndbox xmin320/xmin ymin210/ymin xmax580/xmax ymax400/ymax /bndbox /object /annotationname是类别名bndbox是框的左上角和右下角绝对坐标。Faster R-CNN 的很多实现比如 torchvision 的参考代码直接读这种格式。4.2 从 txt 反推 xml 的转换脚本如果你手上的版本只保留了 txt但临时要切到 VOC 管线可以自己转。核心逻辑是读图片尺寸把归一化坐标乘回去import os import cv2 from xml.etree.ElementTree import Element, SubElement, ElementTree # 类别映射顺序必须和训练时一致 CLASSES [pedestrian, car, bus, rider, motorcycle, truck, bicycle] def yolo_to_voc(img_path, txt_path, xml_path): img cv2.imread(img_path) h, w img.shape[:2] # 拿到图片真实宽高 root Element(annotation) SubElement(root, filename).text os.path.basename(img_path) size SubElement(root, size) SubElement(size, width).text str(w) SubElement(size, height).text str(h) with open(txt_path, r) as f: for line in f.readlines(): parts line.strip().split() if len(parts) ! 5: continue # 跳过空行或异常行 cid, xc, yc, bw, bh map(float, parts) # 归一化坐标还原成绝对像素 xmin int((xc - bw / 2) * w) ymin int((yc - bh / 2) * h) xmax int((xc bw / 2) * w) ymax int((yc bh / 2) * h) obj SubElement(root, object) SubElement(obj, name).text CLASSES[int(cid)] box SubElement(obj, bndbox) SubElement(box, xmin).text str(max(0, xmin)) SubElement(box, ymin).text str(max(0, ymin)) SubElement(box, xmax).text str(min(w, xmax)) SubElement(box, ymax).text str(min(h, ymax)) ElementTree(root).write(xml_path)CLASSES列表的顺序必须和 txt 里class_id的语义完全一致错一位整个数据集的类别就全乱了。max(0, xmin)和min(w, xmax)是防止坐标越界YOLO 标注偶尔会有框超出图片边缘的情况不裁剪的话某些框架会直接报错。转换完建议抽几张用labelImg打开看一眼确认框的位置和类别都对。4.3 训练集/验证集/测试集切分的注意事项这份数据集已经切好了 train/val/test但你要清楚它的切分比例和随机种子是固定的。如果你要做交叉验证或者调整切分比例得自己重新划分。重新划分时有个血泪经验同一个视频序列的连续帧不能同时出现在训练集和验证集里否则验证指标会虚高因为模型见过几乎一样的画面。BDD100K 原始数据是按视频采集的虽然这份整理版可能已经打散了但如果你发现验证集 mAP 高得离谱比如 0.95 以上先怀疑是不是数据泄漏。5. 避坑排查训练不收敛、标签错位、显存爆炸的六个真实案例5.1 现象loss 一直是 nan 或者不下降原因通常有三个。第一yaml 里的nc和实际类别数不一致比如你只保留了 3 类但 yaml 还写着 7模型输出维度对不上。第二txt 标签里有空文件或者格式错误的行YOLO 解析时产生异常值。第三学习率设太大前几个 batch 就把权重跑飞了。解决办法先用脚本扫一遍所有 txt统计每个文件的类别 id 范围确认没有超出nc-1的值再检查有没有 0 字节的标签文件学习率用默认的lr00.01起步不要一上来就调大。5.2 现象训练正常但推理框全错位原因基本锁定在 yaml 的names顺序和 txt 的class_id语义不匹配。比如 txt 里0是pedestrian但 yaml 里0写成了car模型学到的映射就是错的。解决办法抽 10 张训练图用下面的脚本把框画出来人眼确认类别和位置import cv2 img cv2.imread(images/train/xxx.jpg) h, w img.shape[:2] with open(labels/train/xxx.txt) 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), (0, 255, 0), 2) cv2.putText(img, str(int(cid)), (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imwrite(check.jpg, img)画出来一看便知类别 id 和实际目标对不上就改 yaml。5.3 现象训练到一半 CUDA out of memory原因不一定是 batch 太大。YOLOv8 在训练过程中会缓存验证集的预测结果如果验证集图片分辨率不一致某些 batch 会突然占用更多显存。另外workers设太高每个 worker 都会预加载数据到内存间接影响显存。解决办法先把batch降到 8 试还爆就把imgsz从 640 降到 512。如果都不行加cacheFalse关掉数据缓存。长期方案是统一把所有图片 resize 到同一分辨率再训练。5.4 现象验证集 mAP 很高但测试集一塌糊涂这是典型的数据泄漏或者过拟合。先检查训练集和验证集有没有重复图片用 md5 去重再检查验证集是不是太小。15807 张图如果按 8:1:1 切验证集大概 1500 张左右这个量级是够的。如果验证集只有几百张指标波动会很大不能作为选模型的依据。5.5 现象某些类别完全检测不到rider、motorcycle、bicycle这三类在 BDD100K 里样本量天然比car少很多。如果训练完发现这几类 mAP 接近 0先统计一下每类的标注框数量# 统计每个类别出现的次数 cat labels/train/*.txt | awk {print $1} | sort | uniq -c如果某类只有几十个框模型学不到是正常的。解决办法是用copy_paste或者mosaic增强或者在 yaml 里给这类加权重YOLOv8 支持cls_pd之类的损失权重调整具体看版本。5.6 现象解压后文件名乱码或者路径带中文项目正文里列出的文件名是类似c3a18207-504667c7.txt这种哈希串说明原始文件可能是用 UUID 命名的。解压到 Windows 上如果路径带中文OpenCV 读图会失败返回 None进而导致训练时报assert img is not None之类的错误。解决办法是把数据集放到纯英文路径下比如D:/datasets/bdd100k/别放在桌面或者「我的文档」里。6. 进阶技巧用子集快速验证管线再全量开训6.1 为什么要先跑子集15807 张图全量训练一轮在单卡上也要不少时间。如果你只是想验证「数据管线通不通、yaml 写得对不对、标签有没有问题」完全没必要等全量跑完。我的习惯是先从训练集里抽 500 张图建一个 mini 子集跑 5 个 epoch看 loss 有没有正常下降、验证能不能出结果。这一步能把 90% 的配置错误提前暴露出来。import os import random import shutil src_img bdd100k_person_car/images/train src_lbl bdd100k_person_car/labels/train dst_img mini/images/train dst_lbl mini/labels/train os.makedirs(dst_img, exist_okTrue) os.makedirs(dst_lbl, exist_okTrue) files [f for f in os.listdir(src_img) if f.endswith(.jpg)] random.seed(42) # 固定种子保证可复现 sample random.sample(files, 500) # 抽 500 张 for f in sample: shutil.copy(os.path.join(src_img, f), os.path.join(dst_img, f)) lbl f.replace(.jpg, .txt) lbl_path os.path.join(src_lbl, lbl) if os.path.exists(lbl_path): shutil.copy(lbl_path, os.path.join(dst_lbl, lbl))random.seed(42)是为了让每次抽的子集一样方便对比不同配置的效果。抽完记得同步改一份 mini 版的 yaml把train和val都指向 mini 目录跑通后再换回全量。6.2 用 TensorBoard 看训练过程YOLOv8 训练时默认会把指标写到runs/bdd/exp1/下可以直接用 TensorBoard 打开tensorboard --logdir runs/bdd浏览器打开localhost:6006重点看metrics/mAP50(B)和train/box_loss两条曲线。正常的训练曲线是 mAP 稳步上升、loss 稳步下降中间有波动是正常的。如果 mAP 在某个 epoch 突然掉到 0 又弹回来通常是那一个 batch 的数据有问题去查对应的图片和标签。6.3 一个我踩过的坑验证集指标选模型YOLO 默认保存best.pt和last.ptbest.pt是按验证集 mAP 选的。但如果你后面要换测试集评估别直接用best.pt的验证集指标当最终结果一定要在测试集上重新跑一遍val。我有一次汇报时用了验证集 mAP被问到测试集表现时才发现差了 5 个点原因是验证集和测试集的类别分布不完全一致。从那以后我每次选模型都强制在测试集上再跑一遍yolo detect val splittest确认没有过拟合才敢用。这份 BDD100K 人车识别数据集的完成度在于它把格式转换和切分这些脏活都做完了你拿到手只需要选对格式、配好 yaml、跑通管线。如果你正在做人车检测相关的项目或者课程设计直接拿它当 baseline 能省掉至少两天的数据整理时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表