ARTICLE DETAIL

资讯详情

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

自动驾驶多类车辆检测数据集:从解压到YOLOv8训练避坑指南

自动驾驶多类车辆检测数据集:从解压到YOLOv8训练避坑指南 简介自动驾驶多类交通车辆检测数据集合计一千二百五十一张道路场景图片其中训练集一千一百二十九张、验证集一百一十四张、测试集八张覆盖自行车、公交车、轿车、摩托车、卡车五种交通参与者。所有标注采用YOLO格式的归一化坐标与边界框可直接接入主流检测框架面向自动驾驶感知、智能交通管理、车载安全预警以及计算机视觉算法研究等场景适用于多类别车辆实时检测、交通流量统计与模型对比实验。压缩包内含两千个文件以标注文件与实景图片为主体另附配置文件和数据集说明文档整体压缩后约六十八兆轻量易用。数据经专业团队标注验证类别准确率约百分之九十九点二训练、验证、测试集按科学比例划分能有效支撑模型评估与迭代。当前已有九十八人学习浏览适合需要即用型车辆检测数据、快速验证目标检测算法的工程师与研究人员。1. 自动驾驶多类交通车辆检测数据集拿到zip之后真正的坑才开始“自动驾驶多类交通车辆检测数据集.zip”这个文件名在验收交付、论文复现、找训练数据三种场景里出现的频率都不低。它通常打包了上万张道路图片标注里是小汽车、卡车、公交车、摩托车、自行车这些常见交通参与者格式可能是VOC XML、COCO JSON也可能直接是YOLO txt。对做自动驾驶感知的工程师来说它是训练检测模型的第一份弹药对只跑过demo的新手解压后面对一堆结构不明的目录很容易卡在“下一步干什么”。下面按你拿到zip后的真实顺序展开校验、转格式、训练、避坑、验收每一步都给出能直接抄的脚本和参数。2. 拿到zip先别急着解压校验、目录结构与数据盘点很多人拿到数据集zip的第一反应是双击“全部解压”等解出来发现图片和标注对不上、训练时报路径不存在才回头一点点查。我一般会先花十分钟做三件小事看压缩包清单、测完整性、按需解压。这三步能挡掉后面一半以上的低级问题。2.1 解压前的三道检查清单、完整性、按需解压# 查看压缩包内的文件清单不解压也能摸清目录结构 unzip -l traffic_vehicle.zip | head -60 # 测试压缩包完整性逐个文件做CRC校验 unzip -t traffic_vehicle.zip # 按需解压先只把图片和标注解出来避免解出隐藏坏文件 unzip traffic_vehicle.zip images/* -d ./data unzip traffic_vehicle.zip annotations/* -d ./data第一行unzip -l是看“里面到底有什么”。我习惯先看一眼顶层目录是images/annotations还是JPEGImages/Annotations这决定了后续脚本的路径怎么写。如果文件总数过万列表会很长head -60只看前六十行就够了。第二行unzip -t对包内每个文件做CRC校验拷贝到U盘或硬盘再解压的数据集最容易出现某个文件校验失败——遇到这种情况直接重新获取完整包比补文件快。第三行按需解压是血泪经验有的zip包里打包了解压脚本、README、预训练权重甚至损坏的缩略图全解出来会让训练脚本的glob扫到脏数据先只解图片和标注确认能用再解其余不迟。提示Windows资源管理器的“全部解压”对超长路径和特殊字符文件名支持很差解压失败时换成命令行工具并确认解压工具版本。有条件的话解压前先算一下SHA256和数据集发布页或交付说明里的值比对防止同名zip不同内容。2.2 目录结构与标注格式VOC、COCO、YOLO三种组织方式一次看清这类数据集最让人头大的不是训练是标注格式不统一。目前主流就三种先看表格再细说。格式标注文件坐标表达典型配套工具VOC每张图一个XMLxmin/ymin/xmax/ymax 像素坐标PASCAL VOC 体系、MMDetectionCOCO全部标注一个JSONbbox[x, y, w, h] 像素坐标Detectron2、MMDetectionYOLO每张图一个txtcx, cy, w, h 归一化到[0,1]YOLOv5/v8 系VOC XML里size节点有图宽高每个object节点是一次标注name是类别字符串。COCO JSON分为images、annotations、categories三块靠id关联。YOLO txt最简单每行一个框第一列是类别ID后四列是归一化中心点和宽高。这类zip解压后最常见的是VOC或COCO格式YOLO格式反而少见因为YOLO格式通常会随训练项目一起交付。如果解出来是两种格式混用以内容更完整的那套为准。顺带说一句如果你因此想到BDD100K、KITTI、nuScenes这些公开自动驾驶数据集绝大多数走的是VOC/COCO风格但BDD100K有十类标注KITTI是单目前视视角nuScenes还带雷达。这个zip如果只有2D框标注任务就是水平框多类检测和DOTA、HRSC2016那种遥感旋转框不是一回事模型选择也别混。专做车牌识别的CCPD不在此列CrowdHuman专注密集行人类别结构也完全不同。2.3 类别统计先行不盘点类别就训练等于把数据当黑匣子训练之前必做的一步是统计每类目标数量。不做这个你连“这数据集里摩托车到底有几张”都不知道训练完分析bad case才惊呼“原来摩托车只有两百张难怪AP是0”。import glob import xml.etree.ElementTree as ET from collections import Counter stats Counter() empty_images [] for xml_path in glob.glob(data/annotations/*.xml): root ET.parse(xml_path).getroot() objects root.findall(object) if not objects: empty_images.append(xml_path) continue for obj in objects: name obj.find(name).text stats[name] 1 for name, count in stats.most_common(): print(f{name:12s} {count:6d}) print(f\nempty annotations: {len(empty_images)})这段脚本只针对VOC XMLCOCO JSON改成读取annotations列表里每个category_id的计数逻辑完全一样。if not objects判断的是“有XML但一张图里没有标注”的情况这类图在训练时要单独拿出来要么删掉要么作为纯负样本管理混进训练集会带偏批次质量。看到统计结果后我一般按数量级把类别分成三档单类超过5000的当主类训练500到5000的保留但关注过拟合低于500的要么找补充数据要么干脆在转换时过滤掉。这个分档不是玄学是YOLO默认锚定框和损失权重都不支持极端不均衡。3. 把标注统一成YOLO格式VOC/COCO到txt的转换与四个边界坑训练脚本不关心你标注是XML还是JSONYOLO系列只认“一张图一个txt”的格式。拿到解压后的VOC或COCO标注第一步是统一转成YOLO格式。转换本身不难难在边界处理坐标越界、类别号跳变、空文件、图片宽高读取失败每一条都让训练中途报错。3.1 为什么推荐统一成YOLO格式而不是反过来理由有三条。第一一张图一个txt没有解析XML/JSON的依赖训练时按文件名读取断点续训也稳。第二YOLO用归一化坐标分辨率变化不用改标签从640训练切到1280微调时省一堆事。第三数据增强比如mosaic、随机仿射变换是YOLO系训练效果的重要来源归一化坐标直接跟图片一起变换不需要额外校正。反过来把YOLO转VOC用于可视化倒是常见操作但作为训练主格式YOLO txt最省事。也有例外。如果你打算用MMDetection或Detectron2这类框架跑实验它们原生支持COCO JSON这时候保留COCO格式反而省一次转换。但单人项目用YOLOv8起步统一转YOLO格式是效率最高的选择。后续要上旋转框检测MMRotate是成熟工具但那是另一个任务方向多类交通车辆检测用水平框就够。如果你经常搜“YOLOv8训练自己的数据集”换了多类车辆数据时真正要改的只有三处类别yaml、目录结构、锚定尺寸。3.2 VOC XML转YOLO txt完整脚本与必改参数import os import glob import xml.etree.ElementTree as ET def voc2yolo(xml_path: str, out_dir: str, class_names: list) - None: tree ET.parse(xml_path) root tree.getroot() width int(root.find(size/width).text) height int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_names: continue # 过滤只保留你关心的交通车辆类 cls_id class_names.index(name) box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) cx ((x1 x2) / 2) / width cy ((y1 y2) / 2) / height bw (x2 - x1) / width bh (y2 - y1) / height # 越界框裁剪到[0,1]防止训练时报错 cx max(0.0, min(cx, 1.0)) cy max(0.0, min(cy, 1.0)) bw max(0.0, min(bw, 1.0)) bh max(0.0, min(bh, 1.0)) lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) base os.path.splitext(os.path.basename(xml_path))[0] with open(os.path.join(out_dir, f{base}.txt), w, encodingutf-8) as f: f.write(\n.join(lines)) # 类别顺序决定类别ID训练配置里的names必须和这里完全一致 class_names [car, bus, truck, motorcycle, bicycle] os.makedirs(labels, exist_okTrue) for xml_path in glob.glob(data/annotations/*.xml): voc2yolo(xml_path, labels, class_names)class_names的顺序就是YOLO的类别索引后面data.yaml里必须按同样顺序写否则模型会把人当车。这段代码里的max/min把越界框裁剪回[0,1]是为了避免训练时报“Box corners are out of bounds”但注意这只是兜底如果原标注本身出错裁剪后会掩盖问题。我建议转换时把“被裁剪过的框”单独记录到日志里回头定位是标注低质量还是个别脏数据。VOC里difficult节点标注的模糊目标建议直接跳过这类框参与训练会拉低指标。常见的一个坑是VOC的size/width写的是原图尺寸但有些数据集的jpg碰巧带EXIF旋转信息width/height和实际读出来的宽高是反的按XML算出来的坐标会整体错位解决方法见第5章。3.3 COCO JSON转YOLO注意category_id不连续这个老坑COCO格式的标注全部集中在一个instances JSON里转换时要通过image_id把标注和图片关联起来通过category_id映射到连续编号。import json import os with open(data/annotations/instances_train.json, r) as f: coco json.load(f) # 图片 id - (文件名, 宽, 高)COCO的file_name经常带子目录 img_map {im[id]: (im[file_name], im[width], im[height]) for im in coco[images]} # 类别 id - 连续编号。COCO的category_id通常从1开始且可能跳号 cat_map {cat[id]: i for i, cat in enumerate(coco[categories])} out_dir labels os.makedirs(out_dir, exist_okTrue) for ann in coco[annotations]: cat_id ann[category_id] if cat_id not in cat_map: continue # 过滤未收录类别 image_id ann[image_id] img_name, img_w, img_h img_map[image_id] label_path os.path.join(out_dir, os.path.splitext(img_name)[0] .txt) x, y, w, h ann[bbox] # COCO的bbox是左上角坐标 宽高 cls_id cat_map[cat_id] cx (x w / 2) / img_w cy (y h / 2) / img_h bw w / img_w bh h / img_h with open(label_path, a, encodingutf-8) as f: f.write(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}\n)这段代码里img_map一次性把图片id映射到文件名和尺寸避免在annotations循环里反复扫images列表几万条标注时性能差距明显。COCO的bbox是“左上角x、左上角y、宽、高”和VOC的x1,y1,x2,y2正好差一个右下角换算。cat_map {cat[id]: i for i, cat in enumerate(coco[categories])}直接把原始category_id映射到0开始的连续编号不要直接拿category_id当类别号COCO默认从1开始YOLO类别从0开始差一个数训练出的混淆矩阵会整体错位。注意这段用“a”模式追加写入如果脚本重复运行同一个txt会被追写两遍行数翻倍。更稳的做法是每次运行前先清空输出目录或者改用“w”模式配合缓存。3.4 类别筛选与数据划分只保留交通车辆类的常见做法标题带“多类交通车辆”但实际解压出来往往还混着pedestrian、traffic_light、road_signs这些非车辆类。我的做法是只保留车辆类训练一是减少类别混淆二是让mAP指标聚焦在交通车流上。转换脚本里的if name not in class_names: continue就是干这个的把class_names列表换成你要保留的组合即可。import os import random random.seed(42) keep_classes [car, bus, truck, motorcycle, bicycle] image_files [f for f in os.listdir(images) if f.endswith(.jpg)] random.shuffle(image_files) # 按 8:2 划分训练与验证单机常见做法 split int(len(image_files) * 0.8) with open(train.txt, w) as ft, open(val.txt, w) as fv: for img in image_files[:split]: ft.write(os.path.abspath(fimages/{img}) \n) for img in image_files[split:]: fv.write(os.path.abspath(fimages/{img}) \n)注意这个脚本只做了随机划分如果数据集是按场景连续拍摄的随机切会泄漏同一条路上的相似帧会同时出现在训练和验证里。真正可靠的是按拍摄场景分组划分第5章细讲。4. 用YOLOv8训练多类车辆检测最小可行流程与关键参数格式转换完进入训练环节。YOLOv8是目前跑这类数据最省心的框架之一命令简单、指标可视化完整适合作为基线。下面的流程能直接复现参数给的是单卡12G显存起步的保守配置。4.1 数据目录与data.yaml格式对了训练才不闹脾气YOLO系框架要求的目录结构一般是images/train、images/val、labels/train、labels/val四件套。把上一章转换出来的txt按同样的结构放好。data/ images/ train/ val/ labels/ train/ val/图片和txt必须同名后缀不管jpg还是pngtxt是唯一匹配依据。data.yaml内容如下path: /home/user/traffic_vehicle # 数据集根目录建议写绝对路径 train: images/train val: images/val nc: 5 names: [car, bus, truck, motorcycle, bicycle]path用绝对路径避免相对路径找不到训练文件。train和val是相对path的子目录。nc必须等于names的长度“5”和实际类别数不一致是最常见的报错来源之一。names的顺序必须和转换脚本里的class_names完全一致否则类别ID对不上混淆矩阵会整体错位。4.2 训练命令与核心超参一组能起步的配置yolo detect train \ datadata.yaml \ modelyolov8s.pt \ imgsz640 \ epochs100 \ batch16 \ lr00.01 \ lrf0.01 \ patience15 \ device0用yolov8s.pt做迁移学习权重比从零训练收敛快得多也避免小数据集训不动的尴尬。imgsz640是2D检测的稳妥起点如果数据集里小目标占比高可以上1024或1280但显存和速度代价明显先把640跑通再看指标决定是否加分辨率。batch16看显存12G卡跑不动就降到8。lr00.01是微调常用起始学习率lrf0.01表示训练结束时学习率衰减到初始的1%。patience15表示验证指标连续15轮不涨就早停对“类别多、噪音大”的自动驾驶数据比默认的50更实用能省下大量无效训练时间。device0指第一张GPU卡CPU训练改成devicecpu但多类检测任务CPU一轮要好几个小时真不建议哪怕租卡也合算。数据增强参数默认值对多数场景够用但有两个值得根据数据特点手动调mosaic1.0在少数类样本少时会把目标切碎建议先保持等少数类AP上不去再考虑关掉degrees0.0是旋转增强车辆检测建议保持0车不会倒着开。超参建议值说明modelyolov8s.pt从预训练权重迁移比yolov8n准比yolov8l省显存imgsz640起步用小目标多再提到1024batch16根据显存调整OOM就减半lr00.01迁移学习常用起点loss震荡时降到0.005patience15早停轮数数据噪音大时防止过拟合4.3 训练时盯什么loss曲线与验证mAP的读法训练过程中控制台定期打印一次指标卡关键看五条lossbox_loss、cls_loss、dfl_loss各有train和val两组另有precision、recall、mAP50、mAP50-95。我一般盯三个信号。第一train和val的loss同步下降说明正常train降而val不降或反弹是典型的过拟合先调patience或数据增强而不是加epochs。第二mAP50高而mAP50-95低说明模型“框得大差不差但不够准”常见于小目标、密集场景后面回到imgsz和tile上想办法。第三precision和recall差距过大说明置信度阈值设得不合适。车辆检测场景漏检比误检危险我通常把置信度阈值压到0.1附近做验证看recall上限能到多少再反推部署时的阈值。训练完在weights/下会得到best.pt和last.ptbest.pt是验证指标最优的权重部署只用best.pt别拿last.pt当结果。如果两个文件差距很大说明训练后期过拟合严重回看4.2的patience设置。4.4 显存不足与多卡训练降级方案和参数组合排查12G以下显存跑不动imgsz640, batch16时优先把batch降到4然后改yolov8n.pt再不行把imgsz降到512。顺序不能反先减batch对精度影响最小换轻量模型次之降分辨率影响最大。# 显存不足时的降级命令 yolo detect train \ datadata.yaml \ modelyolov8n.pt \ imgsz512 \ epochs100 \ batch4 \ device0多卡训练直接在命令后加device0,1YOLOv8会自动做分布式数据并行。但多类车辆检测数据集动辄上万张单卡训练一轮也就几十秒到几分钟先单卡跑通再考虑多卡提速不要一开始就上复杂度。5. 避坑这份数据集从解压到上线的5个翻车现场下面这些坑每一个我都亲眼见过别人踩或者自己踩过。按“现象—原因—解决”写方便直接对号入座。5.1 现象训练loss正常下降验证mAP却只有个位数原因图片带EXIF旋转信息。车载相机、手机拍照时会把“方向”写进EXIF很多数据集的jpg实际像素方向没有转正而标注是按视觉方向标的。训练框架读图时忽略EXIF图片被读成横的标签还是按竖的算全部错位。这个现象在VOC转YOLO时特别隐蔽因为XML里的宽高是按未旋转尺寸写的脚本算归一化坐标时完全不会报警。解决转换之前统一转正图片并重存用PIL一次搞定。from PIL import Image, ImageOps import glob for path in glob.glob(data/images/*.jpg): img Image.open(path) img ImageOps.exif_transpose(img) # 根据EXIF自动旋转 # 注意转正后宽高可能互换需重新读宽高再转标注 img.convert(RGB).save(path, quality95)转正后务必重新读一遍图片宽高再算标注不要沿用XML里的size值宽高互换会让坐标在x、y方向整体偏移。5.2 现象训练报错RuntimeError: class index out of range原因txt里类别ID超过了data.yaml的nc范围。典型来源有两个一是转换脚本里class_names顺序和训练yaml不一致二是压缩包里混了个旧版txt没被转换脚本覆盖。解决跑一次类别ID审计。# 检查所有txt里出现的最大类别ID是否小于nc awk {print $1} data/labels/train/*.txt | sort -n | uniq -c看到输出里出现5或更大数字就是类别号越界了。重新转换并清空旧labels目录再训练。数据目录里有零字节txt也要清掉YOLO训练时会把空文件跳过或报warning虽然不是致命错误但会污染日志让你排查时分心。5.3 现象mAP50有0.85mAP50-95只有0.32且bad case集中在同一路段原因数据泄漏。自动驾驶数据集往往是一段段连续视频抽帧得到的随机按8:2划分训练验证时同一辆车几乎一模一样的连续帧同时出现在两边模型靠“背图”刷高mAP50。mAP50-95对精确框位置更敏感于是立即露馅。这也是为什么这种数据集看起来mAP很高换到新路段直接失灵。解决按场景分组划分。常见做法是按采集时间、GPS轨迹或文件名前缀分组同一个场景的帧只进训练或只进验证。如果zip的目录结构已经按场景分了目录直接按目录划分不要随机切文件。交付说明里一般会给出“同一采集序列”的规则照着做最稳。5.4 现象训练提示Box corners are out of bounds然后跳过该图原因标注框坐标超出图片范围比如xmax大于图片宽度、y出现负数。这类越界在开阔路段很少高架桥、切边车辆多的场景很常见标注工具导出时也容易带上小数误差。解决转换脚本里对坐标做clip只是治标真正要做的是把越界严重的样本筛出来人工看。我一般会在转换脚本里统计“越界框数量占比超过50%”的图片把文件名打印出来批量检查是不是标注工具导错了。# 在voc2yolo函数里加一个越界计数 def voc2yolo(xml_path, out_dir, class_names): # ... 原有逻辑 ... clipped_count 0 total_count 0 # 每次执行clip时 clipped_count 1; total_count 1 # 函数返回 clipped_count, total_count少数框越界clip到0到1继续训练没问题但全图一半以上框越界就要回查原始标注了。5.5 现象car的AP是0.92motorcycle的AP一直是0排查一圈发现数据只有200张原因类别不均衡。多类交通车辆数据集的采集天然偏科市区路况卡车不多郊区路况摩托极少。YOLO的损失函数不会因为你是少数类就网开一面mAP是逐类算然后平均少数类直接拉垮整体。解决有三个层次。最省事是调类别权重把少数类损失权重加大第二是在训练配置里关掉对少数类不利的增强比如重度mosaic会切碎小目标第三是把少数类的图做过采样复制粘贴进训练集。如果200张确实太少更实际的路子是补充对应场景的数据而不是硬train一发。这类数据集的价值就在这里类别分布缺口本身就是情报它告诉你该补什么数据。6. 用mAP、混淆矩阵和bad case可视化验收模型是否真的可用训练结束只是开始模型能不能上车是另一回事。验证阶段我习惯三件事跑指标卡、读混淆矩阵、画bad case。6.1 一行命令出指标卡yolo detect val \ modelruns/detect/train/weights/best.pt \ datadata.yaml \ imgsz640 \ conf0.001 \ iou0.5 \ batch32conf0.001是把置信度阈值压到极低目的是看recall上限如果模型在这么低的阈值下recall都不高说明漏检问题不在阈值而在特征学习本身。iou0.5对应mAP50也可以加iou0.05看极端重合容忍度下的表现。6.2 混淆矩阵与PR曲线val结果里会生成confusion_matrix.png和PR_curve.png。混淆矩阵主对角线亮说明分类干净看哪些类互相混truck和bus、motorcycle和bicycle这类外观接近的组机器学习混很正常但如果混得厉害说明这两类的角度和光照分布有明显缺口需要针对性补数据。PR曲线看拐点曲线靠近右上角说明模型在高recall下仍保持高precision车辆检测要的就是这个。6.3 画bad case胜过读十个指标把验证集里置信度最高的误检和漏检框画回原图用best.pt预测一批val图把预测框和GT框一起画出来人工翻一遍。我习惯按类别筛选一次只看一类错检十到二十分钟就能定位是标注问题、类别难分还是小目标丢失。夜间和雨雾场景同样适用直接反哺数据补充策略。说句实在话数据集zip只是起点真正值钱的不是压缩包是你从里面挖出的边界——哪些类能学、哪些类缺数据、哪些场景会让模型翻车。我自己的教训是拿到这类数据集先花半天做数据盘点比蒙头训练一周省心得多。希望帮到你。本文还有配套的精品资源点击获取
返回列表