资讯动态

自动驾驶多类别交通物体检测数据集7:从数据解析到YOLOv8训练全流程

发布时间:2026/9/23 12:39:11 来源:尧图企业网站定制
简介这份自动驾驶多类别交通物体检测数据集面向从事目标检测算法研发的工程师、高校研究者及参加相关竞赛的选手旨在解决复杂道路场景下多类别交通目标识别与标注数据匮乏的问题。数据集共包含2000个文件以1154个txt标注文件、844张jpg图像为主另附1个yaml配置文件与1份docx说明文档压缩包整体约72.82MB采用YOLO格式标注可直接用于YOLOv12等目标检测模型的训练与验证。数据覆盖动物、垃圾桶、自行车、公交车、汽车、开关车门、自动扶梯、消防栓、人体交通指挥、摩托车、障碍物、行人、杆状物、坑洞、护栏、反光锥、球形路障、楼梯、停车标志、道路标牌、盲道、检票闸机、交通灯、三轮车、卡车、警示柱、斑马线等28类交通与道路目标场景丰富、类别均衡。已有86人学习下载适合用于模型训练、算法对比与自动驾驶感知研究帮助读者快速构建多类别检测实验基线。1. 拆开「自动驾驶多类别交通物体检测数据集7.zip」它到底装了什么能解决哪类问题如果你正在做自动驾驶感知方向的模型训练大概率会遇到一个很现实的问题公开数据集要么类别太少只有车、人、自行车要么标注格式和你的训练框架对不上要么场景单一到模型一上路就翻车。自动驾驶多类别交通物体检测数据集7.zip这个标题核心信息就三块——自动驾驶场景、多类别交通物体、检测数据集。它要解决的不是「有没有数据」的问题而是「类别够不够细、场景够不够杂、能不能直接喂给检测网络」的问题。这类数据集通常面向城市道路与高速混合场景覆盖轿车、卡车、公交车、行人、骑行者、交通锥、摩托车等常见交通参与者部分版本还会纳入红绿灯、交通标志等静态目标。它适合三类人一是刚入门目标检测、想拿真实交通场景练手的新手二是做自动驾驶感知模块、需要补充长尾类别的工程师三是做端到端自动驾驶研究、需要多类别标注做联合训练的研究者。下面我从数据组织、格式转换、训练接入、踩坑排查到进阶技巧把这条路走通。2. 先看清数据组织多类别标注文件与图像目录怎么对应拿到一个检测数据集压缩包最忌讳的就是解压完直接开训。你得先搞清楚它的目录结构、标注格式、类别命名规则否则后面格式转换和类别映射全是坑。这一章先把「数据长什么样」讲透再动手做统计和校验。2.1 典型目录结构与标注格式判断这类数据集常见的组织方式有两种一种是按图像文件夹加独立标注文件夹标注为 XMLPascal VOC 风格或 JSONCOCO 风格另一种是图像和标注同名混放标注为 TXTYOLO 风格。你解压后先跑一条命令看层级# 查看解压后的目录层级限制深度避免输出爆炸 find ./traffic_dataset -maxdepth 3 -type d | head -50 # 统计图像文件数量与格式分布 find ./traffic_dataset -type f \( -iname *.jpg -o -iname *.png \) | wc -l find ./traffic_dataset -type f -iname *.xml | wc -l find ./traffic_dataset -type f -iname *.json | wc -l find ./traffic_dataset -type f -iname *.txt | wc -l逻辑说明先看目录层级判断是「images/labels 分离」还是「混放」再统计图像与标注文件数量如果两者数量不一致说明有图无标注或有标注无图必须进一步定位。参数说明-maxdepth 3控制递归深度避免大目录卡死-iname忽略大小写匹配扩展名。常见做法是图像放images/标注放annotations/或labels/类别名写在classes.txt或categories.json里。判断格式有个快速方法打开一个标注文件看头部。XML 会有annotationobjectname结构COCO JSON 会有images、annotations、categories三个顶层键YOLO TXT 每行是class_id x_center y_center width height且数值归一化到 0 到 1。如果你看到的是绝对坐标像素值那它不是标准 YOLO 格式需要先归一化。2.2 用脚本统计类别分布与标注完整性多类别数据集最怕类别极度不均衡比如轿车几万框、交通锥几十框直接训练会让模型对长尾类别几乎无响应。先写个统计脚本把每个类别的框数和图像数拉出来import os import xml.etree.ElementTree as ET from collections import Counter # 修改为你的标注目录 anno_dir ./traffic_dataset/annotations class_counter Counter() img_with_class Counter() total_imgs 0 for fname in os.listdir(anno_dir): if not fname.endswith(.xml): continue total_imgs 1 tree ET.parse(os.path.join(anno_dir, fname)) root tree.getroot() seen set() for obj in root.findall(object): name obj.find(name).text.strip() class_counter[name] 1 seen.add(name) for c in seen: img_with_class[c] 1 print(总标注图像数:, total_imgs) for cls, cnt in class_counter.most_common(): print(f{cls}: 框数{cnt}, 出现图像数{img_with_class[cls]})逻辑说明遍历所有 XML统计每个类别的总框数和出现该类的图像数。参数说明anno_dir换成你的实际路径如果标注是 COCO JSON改用json.load读annotations列表按category_id聚合。跑完后重点看两个指标框数最少的类别是否低于总框数的百分之一以及某些类别是否只出现在极少数图像里。前者影响损失函数权重设计后者影响你划分验证集时能否覆盖该类。提示如果发现某个类别只有个位数框先别急着删。可以单独把它拎出来做过采样或者在训练时用类别权重补偿。直接删掉会让模型在真实场景遇到该类时完全失效。3. 把标注转成训练框架能吃的格式VOC 转 YOLO 与 COCO 转 YOLO 两条路数据看清楚了下一步就是格式转换。不管你用 YOLOv5、YOLOv8 还是其他检测框架YOLO 格式的 TXT 标注是最通用的入口。这一章给两条转换路径并说清坐标归一化和类别映射的细节。3.1 VOC XML 转 YOLO TXT 的完整脚本VOC 转 YOLO 的核心是把绝对坐标xmin, ymin, xmax, ymax转成归一化的中心点加宽高。直接上脚本import os import xml.etree.ElementTree as ET # 类别列表必须固定顺序训练时类别 id 与此一致 classes [car, truck, bus, person, cyclist, traffic_cone, motorcycle] class_to_id {c: i for i, c in enumerate(classes)} anno_dir ./traffic_dataset/annotations img_dir ./traffic_dataset/images out_dir ./traffic_dataset/labels os.makedirs(out_dir, exist_okTrue) for fname in os.listdir(anno_dir): if not fname.endswith(.xml): continue tree ET.parse(os.path.join(anno_dir, fname)) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in class_to_id: continue # 跳过不在类别表里的目标 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) # 裁剪到图像边界防止越界框 xmin max(0, min(xmin, w)) xmax max(0, min(xmax, w)) ymin max(0, min(ymin, h)) ymax max(0, min(ymax, h)) if xmax xmin or ymax ymin: continue # 跳过无效框 xc (xmin xmax) / 2.0 / w yc (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{class_to_id[name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) out_path os.path.join(out_dir, fname.replace(.xml, .txt)) with open(out_path, w) as f: f.write(\n.join(lines))逻辑说明先读图像宽高再对每个目标做边界裁剪和有效性判断最后归一化写入。参数说明classes列表顺序决定类别 id必须和训练时的data.yaml一致:.6f保留六位小数足够精度且避免浮点误差。常见翻车点是 XML 里size的宽高和实际图像尺寸不一致导致归一化后框偏移。解决办法是在转换前用 PIL 读一次真实图像尺寸做校验。3.2 COCO JSON 转 YOLO 与类别映射的注意点如果标注是 COCO JSON转换逻辑不同COCO 的bbox是[x, y, width, height]绝对坐标且category_id往往不是从 0 连续排列。你需要先建立category_id到连续 id 的映射import json import os with open(./traffic_dataset/annotations/instances.json) as f: coco json.load(f) # 建立 category_id 到连续 id 的映射 cat_ids sorted([c[id] for c in coco[categories]]) cat_id_to_idx {cid: i for i, cid in enumerate(cat_ids)} idx_to_name {i: next(c[name] for c in coco[categories] if c[id] cid) for cid, i in cat_id_to_idx.items()} img_info {img[id]: img for img in coco[images]} out_dir ./traffic_dataset/labels os.makedirs(out_dir, exist_okTrue) # 按图像聚合标注 from collections import defaultdict img_anns defaultdict(list) for ann in coco[annotations]: img_anns[ann[image_id]].append(ann) for img_id, anns in img_anns.items(): info img_info[img_id] w, h info[width], info[height] lines [] for ann in anns: x, y, bw, bh ann[bbox] xc (x bw / 2) / w yc (y bh / 2) / h nw bw / w nh bh / h lines.append(f{cat_id_to_idx[ann[category_id]]} {xc:.6f} {yc:.6f} {nw:.6f} {nh:.6f}) fname os.path.splitext(info[file_name])[0] .txt with open(os.path.join(out_dir, fname), w) as f: f.write(\n.join(lines))逻辑说明COCO 的category_id可能跳号必须先映射成从 0 开始的连续 id否则训练时类别索引越界。参数说明cat_ids排序后映射保证顺序稳定img_anns按图像聚合避免重复打开文件。注意 COCO 的bbox格式是左上角加宽高不是左上右下转换时别搞混。注意转换完成后务必抽查几张图的标注可视化。用cv2.rectangle把 YOLO 框还原画到图上确认框位置和类别都对。这一步能拦住百分之八十的格式错误。4. 接入 YOLOv8 训练data.yaml 配置与首轮跑通命令格式转好了接下来把它接进训练框架。以 YOLOv8 为例这是目前交通物体检测里上手最快、社区资料最多的选择之一。这一章讲清目录划分、配置文件写法和首轮训练命令让你能真正跑起来。4.1 划分训练验证集与编写 data.yamlYOLO 训练要求图像和标签分目录存放且训练集和验证集分开。先按比例划分# 假设图像在 images/标签在 labels/按 8:2 划分 mkdir -p dataset/images/train dataset/images/val mkdir -p dataset/labels/train dataset/labels/val # 用 shell 简单随机划分生产环境建议用脚本固定随机种子 ls traffic_dataset/images/*.jpg | shuf | head -n 800 | while read f; do base$(basename $f .jpg) cp $f dataset/images/train/ cp traffic_dataset/labels/$base.txt dataset/labels/train/ done ls traffic_dataset/images/*.jpg | shuf | tail -n 200 | while read f; do base$(basename $f .jpg) cp $f dataset/images/val/ cp traffic_dataset/labels/$base.txt dataset/labels/val/ done逻辑说明先建目录再按数量切分并复制图像和对应标签。参数说明head -n 800和tail -n 200按你的总量调整shuf做随机打乱但每次结果不同正式实验建议用 Python 固定random.seed。注意标签文件名必须和图像文件名主干一致否则训练时找不到标签。然后写data.yamlpath: ./dataset train: images/train val: images/val nc: 7 names: 0: car 1: truck 2: bus 3: person 4: cyclist 5: traffic_cone 6: motorcycle逻辑说明path是数据集根目录train和val是相对路径nc是类别数必须和names长度一致names的顺序必须和转换脚本里的classes完全一致。参数说明如果类别更多继续往下加编号即可但编号必须从 0 连续。4.2 首轮训练命令与关键超参设置配置写好直接起训练yolo detect train \ data./data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ project./runs/traffic \ nameexp1逻辑说明modelyolov8s.pt用预训练权重做迁移学习比从头训收敛快得多imgsz640是交通检测的常用输入尺寸显存不够就降到 512batch16按显存调整8G 显存建议降到 8lr00.01是初始学习率微调时可以用 0.001patience20表示验证指标 20 轮不提升就早停。参数说明如果类别不均衡严重加cls1.0提高分类损失权重或改用focal loss相关配置。训练启动后重点看三个输出box_loss是否稳定下降、mAP50是否在涨、验证集各类别mAP是否差距过大。如果某个类别mAP一直是 0回去检查该类别的标注数量和转换是否正确。提示第一次训练建议先用小imgsz和少epochs跑通流程确认没有报错再放大。直接上大配置一个格式错误能让你白等几小时。5. 避坑与排查多类别交通数据集训练中最容易翻车的五件事这一章是我自己踩过的坑按「现象 → 原因 → 解决」写清楚。多类别数据集的问题往往不在模型本身而在数据和配置的细节里。5.1 类别 id 错位导致模型学出「幽灵类别」现象训练 loss 正常下降但推理时某些框的类别完全不对比如把卡车标成行人。原因转换脚本里的类别顺序和data.yaml里的names顺序不一致或者 COCO 的category_id没做连续映射。解决把转换脚本的classes列表和data.yaml的names逐行对照确保顺序完全一致COCO 转换时打印cat_id_to_idx确认映射关系。5.2 图像与标签文件名不匹配导致大量样本被跳过现象训练日志显示train: 0 images或实际参与训练的样本远少于预期。原因图像是.jpg标签是.txt但文件名主干不一致比如图像叫frame_001.jpg标签叫frame_001_anno.txt。解决写脚本批量重命名标签去掉多余后缀训练前用ls images/train | wc -l和ls labels/train | wc -l对比数量不一致就排查。5.3 边界框越界导致归一化后坐标异常现象可视化时框跑到图像外面或者宽高出现负值。原因原始标注里xmax超过图像宽度或xmin大于xmax。解决转换脚本里加裁剪和有效性判断如 3.1 节代码所示转换后随机抽 20 张图做可视化确认框都在图像内。5.4 长尾类别被模型完全忽略现象总mAP看着还行但交通锥、摩托车等少数类别的mAP接近 0。原因这些类别框数太少损失被多数类主导。解决对少数类做过采样复制其图像和标签到训练集或在训练配置里提高分类损失权重还可以用copy_paste等数据增强手段增加少数类出现频率。5.5 验证集类别覆盖不全导致指标虚高现象验证集mAP很高但实际路测时某些类别完全检测不到。原因随机划分时验证集里根本没有某些类别的样本模型在这些类别上没被真正考核。解决划分时按类别分层抽样确保每个类别在验证集里都有一定数量的样本划分后统计验证集各类别框数为 0 的类别要补进去。6. 进阶技巧用类别分组评估和难例挖掘把多类别检测做扎实跑通训练只是起点真正让多类别交通物体检测可用的是评估和迭代方法。这一章讲两个我常用的进阶手段按类别分组看指标以及从验证集里挖难例回灌训练。先说类别分组评估。YOLOv8 训练完会输出整体mAP但整体指标会掩盖长尾类别的问题。我一般会单独跑一次验证并导出每类的precision、recall和mAP50做成表格对比类别框数mAP50主要问题car120000.89基本饱和truck32000.76夜间漏检多bus18000.81遮挡场景差person95000.72小目标召回低cyclist21000.65与摩托车混淆traffic_cone3200.41样本太少motorcycle7800.58远距离检测差拿到这张表迭代方向就清楚了traffic_cone和motorcycle要补数据cyclist要做类别区分增强person要加小目标检测层。这比盯着一个总mAP数字有用得多。再说难例挖掘。具体做法是用训练好的模型在验证集上推理把confidence在 0.1 到 0.5 之间、或者预测类别和真实类别不一致的样本挑出来人工复核后把正确标注补进训练集。代码思路如下from ultralytics import YOLO import os model YOLO(./runs/traffic/exp1/weights/best.pt) val_dir ./dataset/images/val hard_cases [] results model.predict(sourceval_dir, conf0.1, saveFalse, streamTrue) for r in results: # 如果最高置信度低于阈值视为难例 if r.boxes is not None and len(r.boxes) 0: max_conf float(r.boxes.conf.max()) if max_conf 0.5: hard_cases.append(r.path) print(难例数量:, len(hard_cases)) with open(hard_cases.txt, w) as f: f.write(\n.join(hard_cases))逻辑说明用低置信度阈值推理把模型「犹豫」的样本收集起来。参数说明conf0.1是收集阈值低于 0.5 的算难例streamTrue避免一次性加载所有结果占内存。收集到难例后人工检查标注是否正确把漏标的目标补上再把这些样本加入训练集重新训练。这个循环做两到三轮长尾类别的指标通常会有明显提升。我自己的习惯是每轮训练后必看类别分组表只要有一个类别的mAP50低于 0.5就先不动模型结构而是回去查这个类别的数据量和标注质量。十次里有八次问题出在数据上而不是网络本身。多类别交通物体检测这件事数据决定了上限模型只是逼近这个上限。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价