资讯详情

自动驾驶数据集如何转换为YOLOv5目录格式?一文讲清验收与避坑

📅 2026/10/5 11:28:39 | 华诺云谱 👁 阅读
自动驾驶数据集如何转换为YOLOv5目录格式?一文讲清验收与避坑
简介面向目标检测学习者和自动驾驶开发者一份按YOLOv5目录规范整理的大型自动驾驶道路信息检测数据集覆盖卡车、行人、交通信号灯、车辆等11个常见类别训练集与验证集划分完整可直接用于YOLO系列模型训练与评估。压缩包约493MB共计2000个文件其中绝大多数为YOLO格式的txt标注文件1999个另有1个Python可视化脚本无需修改即可随机读取图片绘制并保存边框结果便于快速核查标注质量每个标签对应一张图像中的目标类别与归一化边界框坐标。训练集包含21031张图像的标注验证集包含5266张规模充足目录按datasets-images-train与datasets-images-val分开组织11个类别名称的txt文本文件也一并提供方便对照编号。标注边界框清晰完整覆盖道路、车辆、人员、交通设施等多样场景每幅图像通常包含多个目标适合自动驾驶多目标密集检测研究能省去自行收集、清洗与格式转换的时间。目前已有174人学习下载对入门自动驾驶感知或目标检测实战均具有一定的实用价值。1. 拿到手先别急着训练这个数据集到底能解决什么做自动驾驶目标检测的都知道模型能不能收敛、收敛后能不能落地一半的命都押在数据集上。很多人从网上下载或采购数据集时第一眼只关心“有多少张图”“类多不多”真正把压缩包解开、跑通train.py之后才发现标注格式不对、类别顺序和训练脚本对不上、验证集压根没划分甚至图像的宽高和标注的归一化坐标根本不是一个坐标系。这个标题里写得很清楚的一个点就是“YOLOV5目录格式”——意味着 images 和 labels 已经按 YOLO 的训练习惯排好train/val 也切好了拿过来改一下数据配置就能开跑。11 类别对于自动驾驶道路场景属于中等粒度既不会像 80 类那样稀疏难收敛也不会像“车、人”二分类那样失去工程意义。本文就围绕这套格式讲清楚如何验收它、怎么把它转成标准 YOLOV5 训练目录以及那些最容易「翻车」的细节。2. YOLOV5目录格式到底长什么样从目录树到单行标注2.1 images 与 labels 的镜像结构是第一道门槛YOLOV5 的数据集约定核心是 images 和 labels 两个目录镜像存在。训练时dataset.py会根据图片路径自动找同名的 txt 标注文件如果图片在train/images/0001.jpg标注必须在train/labels/0001.txt。文件同名、后缀不同目录一一对应。大多数打回票的数据集问题就出在“我明明给了标注但训练时一条目标都没读到”十有八九是 labels 目录没和 images 对齐。一个合格的 YOLOV5 目录格式一般长这样dataset/ ├── images/ │ ├── train/ │ │ ├── 0001.jpg │ │ ├── 0002.jpg │ │ └── ... │ └── val/ │ ├── 0001.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── 0001.txt │ │ ├── 0002.txt │ │ └── ... │ └── val/ │ ├── 0001.txt │ └── ... ├── data.yaml └── classes.txt注意这里的data.yaml是训练入口classes.txt是给人看的类别清单。两者必须完全一致类别顺序错一个整个模型的输出头就跟着错位。这个目录结构里最容易忽略的是“同名同前缀”0001.jpg必须对应0001.txt不能出现0001.jpg配0001_label.txt这种情况。如果你拿到手的压缩包解压后是这种命名我是建议写个脚本统一批量改名而不是手动改几十个文件。2.2 单行标注的五个数字类别ID、x/y、宽高各是什么含义YOLO 标注格式每个 txt 文件里有若干行每行五个数字用空格分隔0 0.45 0.35 0.20 0.30从左到右分别是类别 ID、归一化后的中心点 x 坐标、归一化后的中心点 y 坐标、归一化后的框宽、归一化后的框高。所有坐标都是相对于图片原始宽高的比例取值范围在 0 到 1 之间。这是 YOLO 格式与 VOC 的 xmin/ymin/xmax/ymax 最大的区别也是后续所有校验脚本的检查核心。类别 ID 从 0 开始计数不是从 1 开始。标题里说 11 类别那类别 ID 的范围就是 0 到 10共 11 个数字。很多人写data.yaml时习惯把类别写成 1 到 11这会让第一个类别直接被吞掉训练出来所有类别都错位一个索引且 mAP 表现极其诡异。这种错误从 loss 曲线上基本看不出来因为模型能正常收敛但推理输出的框全部对应到错误的类名上属于“最阴间的翻车现场”。我一般拿到数据集后第一件事不是打开图片看标注画得准不准而是写个脚本扫描所有 txt统计每个类别 ID 的出现频次顺便检查有没有超出 01 范围的坐标。这一步能过滤掉大部分低级损坏。2.3 data.yaml 里的类别顺序和训练脚本强绑定YOLOV5 的data.yaml通常长这样train: ./images/train val: ./images/val nc: 11 names: [person, car, truck, bus, motorcycle, bicycle, traffic_light, traffic_sign, road_cone, barrier, others]这里的names列表顺序必须和所有标注 txt 里的类别 ID 严格对应。训练时 YOLO 会自动把第一个名字映射为类别 0第二个映射为类别 1。如果你的标注 txt 里类别 0 实际上代表的是“car”但names列表第一位写的却是“person”模型训练不会报错但所有评估结果都会“张冠李戴”。这个顺序问题常见于从多个数据源拼凑出来的数据集。比如某个数据源的类别顺序是“car, person, bike”另一个是“person, car, bike”两组标注文件混在同一目录下就会出现同一个类别 ID 对应不同语义的灾难。如何避免我的做法是写一个校验脚本从每个标注文件里提取出现过的类别 ID与classes.txt做交叉比对再抽样打开几张图人工确认几个框的语义是否匹配。不要省这一步省了后面全是泪。还有一个细节train和val的路径在data.yaml里建议写绝对路径或者写相对于运行位置的路径。我之前有段时间习惯写绝对路径但数据集迁移到服务器后路径全变了又得改一遍。后来统一改成相对路径train: ./images/train并保证在项目根目录下运行训练命令。这两种方式都可以但建议整个团队统一一个规范不然每次换机器都在改配置文件。3. 大型自动驾驶道路数据集的验收11类别怎么分布才算健康3.1 类别设计合理性先看道路要素覆盖再看平衡性标题里写“大型自动驾驶道路信息检测11类别”。那么在验收时首先要判断这 11 个类别是否覆盖了目标场景的核心要素。自动驾驶道路场景通常关注车辆类小汽车、卡车、货车、公交车、行人类行人、骑行者、道路设施类交通灯、交通标志、路锥桶、护栏、道路边界。这 11 类是否合理很大程度上取决于项目需求——如果你的产品只需要检测红绿灯和行人那 11 类里再多的车辆类别都是噪音如果你做的是辅助驾驶的通用感知那么车辆、行人、骑行者的细分类别就很有必要。判断原则其实很简单这 11 个类别分别对应下游哪个模块每个类别被调用的频率是多少没有下游需求支撑的类别建议直接从训练集里排除或合并否则白白增加模型的输出头数量还可能在推理时产生误检。反过来说如果 11 类里缺少关键要素比如完全没有“行人”这一类别那这个数据集做得再大再“大型”对你的项目也要打个大大的问号。3.2 写脚本统计类别分布识别长尾类别和标注瓶颈数据集验收必须量化不能靠肉眼“看着挺多的”。我常用的验收脚本是一个 Python 脚本遍历所有标注文件统计每个类别出现的框数量与覆盖的图片张数。这个脚本不复杂十几行就能跑出结果import os from collections import Counter label_dir labels/train cls_counter Counter() img_counter Counter() for txt_file in os.listdir(label_dir): if not txt_file.endswith(.txt): continue img_counter[txt_file] 0 with open(os.path.join(label_dir, txt_file), r) as f: for line in f: parts line.strip().split() cls_id int(parts[0]) cls_counter[cls_id] 1 img_counter[txt_file] 1 print(类别 ID 出现次数, cls_counter) print(有标注的图片数, len(img_counter))跑完这个脚本重点看两个数每个类别的框总数、有标注的图片数。如果某一个类别框数量特别少比如只有一两百个而其他类别都有几千个这就是长尾类别。长尾类别会让模型对该类的召回率非常差训练时 loss 会被高频类别主导。我在实际项目里遇到过最典型的例子11 类数据里“交通标志”这个类别框数量占了 43%而“自行车”只占 0.8%。模型训练出来自行车类别在验证集上的 mAP 通常是 0——不是模型不行是数据里这个类别太稀少了。这种情况下的短期解法是给这个类别加重复采样权重长期解法是定向补充该类别的新数据。如果没有补充数据的条件建议把过稀少的类别合并到相近的父类中比如“自行车”和“摩托车”合并成“两轮车”这样模型压力会小很多。3.3 train/val 划分的隐藏规则同一个场景不能同时出现在两边标题里写了“包含训练集、验证集”但切分质量才是关键。很多人只看验证集图片数量够不够却不问一句同一个路口、同一台车同时出没在训练集和验证集里验证指标还有意义吗数据泄漏是目标检测数据集里最隐蔽的坑——如果训练集和验证集里包含同一段视频的相邻帧模型在验证集上的表现会被严重高估部署到新的真实场景时立刻打回原形。判断方法也很直接抽样比对两侧图片的文件名前缀。自动驾驶数据集的图片通常按“路段/时间戳”命名比如road001_0001.jpg、road001_0002.jpg。如果 train 和 val 目录里都大量出现road001_前缀的图片说明划分时是按文件顺序随机切的而不是按场景切分。这个随机切分法在通用目标检测里问题不大但自动驾驶数据的场景相关性太强前后几帧几乎同一个角度泄漏不可避免。我处理自动驾驶数据集时会先按“场景分组”再做划分。把同一路段、同一时间段拍到的图片视作一个 group然后按 group 分配训练和验证——保证同一个 group 的图片要么全进 train要么全进 val。至于 82 还是 91要看数据总量数据量大可以留 20% 做验证数据量小、类别偏长尾我一般留 10%但基础上会配合类别采样。4. 把非标准标注转成YOLOV5目录格式转换脚本与四个边界坑4.1 从 VOC XML 或 COCO JSON 转出来的常见做法虽然这个标题明确说是 YOLOV5 目录格式但实际能直接上手的比例不高。很多时候你下载到的“自动驾驶数据集”原始标注是 COCO JSON 格式一个大的 annotations.json 挂所有图片或者 VOC XML 格式每张图片一个 XML 文件。这时需要先把标注转换成 YOLO 的 txt 格式再把图片和标注拷贝到对应的 train/val 目录下。一个像样的转换脚本核心工作是完成三件事读取原始标注、计算归一化中心点与宽高、按图片所属划分写入目标目录。我常写的 Python 转换脚本大致是这个思路import json import os import shutil def convert_coco_json(json_path, img_root, target_root, split): 把 COCO 格式的标注 JSON 转换成 YOLO 格式 txt。 with open(json_path, r) as f: coco json.load(f) # 建立图片 id - 文件名的映射 img_id2name {} for img in coco[images]: img_id2name[img[id]] img[file_name] # 类别顺序按 JSON 里的 categories 顺序这是必须保持稳定的 cat_id2new_id {cat[id]: idx for idx, cat in enumerate(coco[categories])} for img in coco[images]: img_id img[id] filename img_id2name[img_id] txt_name os.path.splitext(filename)[0] .txt # 原图拷贝到 images/{split} src_img os.path.join(img_root, filename) dst_img os.path.join(target_root, images, split, filename) os.makedirs(os.path.dirname(dst_img), exist_okTrue) shutil.copy(src_img, dst_img) img_w img[width] img_h img[height] lines [] for ann in coco[annotations]: if ann[image_id] ! img_id: continue # COCO 的 bbox 是 [x, y, width, height]左上角坐标系 x, y, w, h ann[bbox] # 归一化中心点坐标 cx (x w / 2) / img_w cy (y h / 2) / img_h # 归一化宽高 nw w / img_w nh h / img_h new_cat cat_id2new_id[ann[category_id]] lines.append(f{new_cat} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}) with open(os.path.join(target_root, labels, split, txt_name), w) as f: f.write(\n.join(lines)) # 同时对 XML 格式的转换做同样的处理注意 XML 的坐标是 xmin/ymin/xmax/ymax。脚本的关键参数有三个json_path指向 COCO JSON 文件img_root指向原图所在根目录target_root指向你要构建的 YOLO 数据集根目录。split参数决定当前处理的是 train 还是 val。4.2 坐标异常的排查负数、超出 1.0、宽高为零转换脚本跑完后不能直接训练。最常见的坐标异常有三类浮点精度误差导致坐标略微超过 1.0、某些框 x/y 为负数、宽或高为零的退化框。这些异常不会让 YOLOV5 训练直接崩溃但会造成极大的 loss 抖动或者模型训练后期反复波动。我的处理方式是加一个校验代码遍历所有生成的 txtdef validate_yolo_labels(label_dir): errors [] for f in os.listdir(label_dir): if not f.endswith(.txt): continue with open(os.path.join(label_dir, f), r) as fh: for line_num, line in enumerate(fh, 1): parts line.strip().split() if len(parts) ! 5: errors.append(f{f}:{line_num} 列数不对: {line}) continue cls, cx, cy, w, h parts cx, cy, w, h map(float, (cx, cy, w, h)) if w 0 or h 0: errors.append(f{f}:{line_num} 宽高小于等于0: {line}) if cx 0 or cx 1 or cy 0 or cy 1 or w 1 or h 1: errors.append(f{f}:{line_num} 坐标越界: {line}) if errors: for e in errors[:30]: print(e) print(f共 {len(errors)} 条异常) else: print(标注文件全部合法)这个脚本有点像一个“体检器”。不要拿全部标注文件体检跑得慢可以随机抽 1000 个文件抽样检查或者全量检查但异常一多就会卡在打印上。我一般先全量跑一遍但把异常数量上限控制住比如每类问题只打印前 10 个用来定位是单个文件的问题还是转换脚本的逻辑错误。4.3 数据集切割时注意保持 train/val 的标注一致性从 COCO 或 VOC 转换时很多人会犯一个错转换脚本只处理了 train 部分的 JSONval 部分没有同步转换导致 val 目录下 images 里有图labels 里却空荡荡。更隐蔽的问题是data.yaml中val路径写的是./images/val但 YOLO 训练时还会检查labels/val/是否存在对应 txt——如果缺失YOLOV5 会跳过这些图片并给出“WARNING: imges without labels”之类提示这种警告刷屏时你很容易误以为数据集很大、很丰富实际进到训练里的有效数据少得可怜。我的习惯是转换脚本无论处理 train 还是 val都走同一套流程跑完后直接统计两边的 txt 文件数量和 jpg 文件数量做一次累计校验每个 split 下images 里的文件数应当等于 labels 里的文件数。如果不相等立即找出缺的是哪一边。这一步能挡住大多数低级错误也能避免训练进度到一半才发现验证集全是空跑。5. 常见翻车与排查自动驾驶数据集训练中最容易出现的问题5.1 类别 ID 错位训练不报错验证结果却全错现象训练 loss 正常下降验证集的 mAP 看起来也有 0.6 以上但打开推理结果图片发现检测出的类别名和框内容完全对不上——明明框着汽车标签却写着“person”框着红绿灯标签却写着“truck”。原因标注 txt 里的类别 ID 与data.yaml里的names顺序不一致。常见于从多来源拼凑的 11 类数据集有的标注从 1 开始编号类别有的从 0 开始。模型只学习“ID 0 对应什么形状”并不知道你期望它叫什么名字。解决写一个脚本将每个类别的代表性图片抽取出来画框人工确认 ID 与语义的对应关系。如果你的标注是从 1 开始的把所有 txt 里的类别 ID 减 1改完再跑一次校验。这个改动一句话但造成的后果非常隐蔽值得在训练前消耗 20 分钟确认。5.2 长尾类别导致验证集 mAP 为 0现象训练结束后模型在训练集上表现很好train 的 loss 也下降到 0.0x 级别但 val 集上某一个或几个不常见类别比如骑行者的 mAP 为 0且无论如何增加训练轮数都不见好转。原因类别不平衡严重该类别在训练集里本身就少见模型把对应的输出头学成了“总是输出背景”。验证集里的该类目标几乎全部漏检。解决先按 3.2 节的脚本跑出每个类别的框数量明确哪个类别是长尾。再通过--hyp参数调整 loss 权重或对长尾类别的数据做过采样。但这些都是权宜之计——最靠谱的做法是给数据集补充大量该类别的新样本。如果补充不了就把它合并到更粗粒度类别里保住整体可用性。5.3 val 目录下标注缺失或为空文件现象训练日志显示数据加载正常但到验证阶段时没有评估结果或者在 eval 时异常退出。打开 val 的 labels 目录发现有一部分 txt 文件大小是 0 字节或者部分图片根本没有对应 txt。原因数据集的验证集是从某个大型数据源切出来的切分脚本只拷贝了 images 分支没有同步拷贝 labels 分支。或者转换脚本在跑 val 时没有执行成功因为某个 JSON 子文件路径错误。解决训练前做一次一致性统计——统计每个 split 下 jpg 与 txt 的文件数并比对同名文件是否一一对应。发现缺失后找到是哪个环节丢文件如果是转换脚本跳过了一批图片查看转换日志里有没有异常报错如果是目录结构问题重新组织目录后重跑转换。5.4 图片分辨率差异过大影响训练稳定性现象训练时 loss 一直偏高模型反复震荡且显存占用波动剧烈。查看数据集发现有的图片是 1920×1080有的是 640×360甚至还有 3840×2160 的大图。原因YOLOV5 默认会做 letterbox 缩放但如果图片之间宽高比差异过大缩放后的有效区域占比会差异很多导致模型每轮看到的物体尺度分布完全不同训练不稳定。解决训练前按最小边长做统计把明显畸形的图片过滤掉。如果目标场景里确实同时存在不同分辨率的摄像头建议在数据增强里加入--cache-images并在hyp.yaml中调整随机尺度范围让模型在多次迭代中适应不同尺寸。最彻底的方法是把分辨率进行分组训练或归一化到统一尺寸但在实际工程中优先保证同一批数据的宽高比不要差两三倍以上。6. 训练前的最后一道验证与关键超参数校准当数据集通过前面的验收、转换和排查之后我通常不会直接开跑完整的训练而是先做一个“冒烟测试”——用很小的图片尺寸、很少的训练轮数快速验证数据链路是否通畅。常见的命令是在单张 GPU 上跑 10 个 epoch看看 loss 是否流畅下降、验证集能否正常评估。python train.py --data data.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 10这轮冒烟测试不追求精度只求“不报错、能收敛、有正常评估输出”。如果连这一步都跑不完问题一定出在数据或环境配置上先把冒烟测试过掉再考虑调优。冒烟测试通过后再进入正式训练。针对这种 11 类自动驾驶数据集我会把hyp.yaml里的几个关键参数做小幅调整hsv_h、hsv_s、hsv_v适当调高因为自动驾驶场景需要适应一天中不同时段的光照变化fliplr默认是 0.5但如果你的场景包含车道通行方向过高的水平翻转会让“靠左行驶”的标志变得不合常理建议对交通标志和红绿灯类别减少翻转概率。角度增强degrees的建议不超过 10过大的旋转会破坏道路目标的基础几何特征。另外验证集的作用不止于评估——我习惯在训练结束后保存每一轮验证集上的 PR 曲线和混淆矩阵用它们来反推数据集的薄弱环节。如果某个类别的混淆主要发生在“行人”和“骑行行人”之间可能意味着这两类的视觉差异本身就不够数据标注的边界判断不一致或者类的定义粒度太细可以尝试把这两个类合并。如果你已经决定长期做自动驾驶感知方向这种基于数据问题的迭代闭环比不停调模型结构重要得多。数据集的验收、清洗、划分、转换这些琐碎的“脏活累活”才是模型精度的真正上限。几年下来我最深刻的教训是拿到手的数据集再大也要在第一天做好目录结构、类别顺序、分布统计这三件事否则后面所有训练、调参、部署都建立在流沙上。希望这篇文章里的步骤和踩坑记录能帮你少走这段弯路。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑