ARTICLE DETAIL

资讯详情

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

智能小车赛道目标检测数据集制作:YOLOV5目录格式与8类指示牌避坑指南

智能小车赛道目标检测数据集制作:YOLOV5目录格式与8类指示牌避坑指南 简介面向智能小车赛道自动驾驶与交通指示牌识别场景这份目标检测数据集按YOLOv5目录格式整理包含左转、右转、红灯、绿灯、人行道等8个类别适合入门计算机视觉或搭建自动驾驶小车的学习者直接投入模型训练。压缩包共2000个文件其中1127个txt标签、872张jpg图片和1个py可视化脚本整体大小约10.31MB训练集含901张图片及对应标签验证集含225张图片及对应标签另有类别字典txt划分清晰无需额外处理。可视化脚本可直接运行随机传入一张图片即可绘制边界框并保存结果便于快速核对标注质量与类别分布。已有151人学习对需要规范格式数据集做算法验证的开发者来说能省去自行标注与格式转换的环节尤其适合课程设计、竞赛练习或自动驾驶项目起步阶段。1. 智能小车赛道数据集为什么 8 类指示牌比 80 类通用目标更难搞一张被运动模糊拖出残影的限速牌从摄像头画面里一闪而过小车的目标检测模型没认出来于是一路直行冲出了赛道——这种翻车在智能小车赛道自动驾驶里太常见了。目标检测数据集YOLOV5目录格式要解决的就是让模型在赛道真实光照、抖动和遮挡下稳定认出交通指示牌。这套数据集的形态很固定图片按 images/train、images/val 组织标注按同名 txt 放进 labels/train、labels/val再配一个 data.yaml 说明 8 个类别。适合谁准备智能车竞赛、自动驾驶课设或者刚接触 YOLOV5 训练自己的数据集的人。接下来我按自己整理赛道数据集的流程把目录、类别、训练参数和避坑一次讲完。2. 拆解 YOLOV5 目录格式从数据组织到首次训练的最小闭环光有图片和标注不算数据集只有把它们按 YOLOV5 目录格式摆好训练脚本才能直接吃。最常见的坑不是标注画得差而是文件夹建好了、images 和 labels 对不上训练时报一堆 warning最后 mAP 全是零。这里先给出一份可以直接对照的目录树。smartcar_dataset/ ├── images/ │ ├── train/ # 训练图片jpg/png 均可 │ └── val/ # 验证图片与训练图片无重叠 ├── labels/ │ ├── train/ # 与 images/train 同名的 txt │ └── val/ # 与 images/val 同名的 txt └── data.yaml # 数据集配置文件这份结构是 YOLOV5 官方训练脚本约定俗成的目录格式train.py只认images和labels两个分支图片与标注靠「文件名相同、后缀不同」关联。比如images/train/frame_001.jpg对应labels/train/frame_001.txt顺序错一位都找不到。我一般会在拿到任何数据集后先跑一遍tree确认没有多套嵌套目录再谈训练。2.1 同名对应规则模型靠什么把图片和标注对上YOLO 的标签文件不是 xml而是纯文本每一行代表一个目标格式是class_id x_center y_center width height四个坐标全部归一化到 0~1。训练脚本读取图片后会在同名路径下找 txt找到就解析出所有框找不到就报 warning 并把该图当背景处理。这里有个容易误解的点images/train和labels/train必须严格同名但图片后缀可以混用 jpg/png。有些同学从网上下载的数据集里图片是 jpg、标注是 txt文件名却带着_aug这类后缀和原图对不上训练时大量目标被静默丢弃。检查方法很简单在数据集根目录执行for img in images/train/*.jpg; do name$(basename $img .jpg) [ -f labels/train/$name.txt ] || echo missing: $img done这段脚本遍历训练图片把不存在的对应 txt 打印出来。正常数据集输出的 missing 列表应为空。如果打印出十几条说明标注文件和图片命名不一致需要先做批量改名而不是急着训练。验证集同样要做一次检查。val 不是可选项YOLOV5 在训练每个 epoch 结束时都要跑一遍验证集来计算 mAP0.5 和 mAP0.5:0.95val 目录为空或图片太少指标曲线会变成一根直线你无法判断模型有没有收敛。2.2 整理散乱数据一个脚本完成 8:2 划分与漏标检查真实项目里很少直接拿到标准目录多数是从视频抽帧得到几千张图标注工具导出成一堆 txt 散在同一个文件夹。我一般会写一个脚本做三类事剔除缺失标签的图片、按 8:2 拆分训练验证、把文件复制进标准目录。注意是复制不是移动保留原始素材方便后续重标。import os import random import shutil from pathlib import Path random.seed(42) img_dir Path(raw/images) # 原始图片目录 label_dir Path(raw/labels) # 原始标注目录YOLO txt train_img Path(dataset/images/train) val_img Path(dataset/images/val) train_label Path(dataset/labels/train) val_label Path(dataset/labels/val) for d in [train_img, val_img, train_label, val_label]: d.mkdir(parentsTrue, exist_okTrue) imgs sorted(img_dir.glob(*.jpg)) random.shuffle(imgs) val_num max(1, int(len(imgs) * 0.2)) missing [] for i, img in enumerate(imgs): txt label_dir / (img.stem .txt) if not txt.exists(): missing.append(img.name) continue if i len(imgs) - val_num: shutil.copy2(img, train_img / img.name) shutil.copy2(txt, train_label / (img.stem .txt)) else: shutil.copy2(img, val_img / img.name) shutil.copy2(txt, val_label / (img.stem .txt)) print(total:, len(imgs)) print(missing labels:, len(missing)) print(missing[:10])逻辑是先把图片路径打乱保证训练验证分布的随机性按 8:2 比例拆分即 80% 进 train、20% 进 val。max(1, ...)保证极端小数据集下至少留一张验证图但说实话智能小车赛道数据若少于 100 张验证集很难有统计意义。missing列表会把缺标注的图片名记下来。这些图如果留在 train 里模型会把它们当背景学习导致批次里有效目标密度降低训练速度慢且容易学到错误特征。这里直接剔除宁可少几张也不要污染训练集。2.3 首次训练前的一分钟自检越界、空标签、类别超范围整理完目录后我强烈建议跑一遍标签自检再开训练。这个脚本不依赖任何第三方库纯标准库就能完成属于典型的低成本高收益动作。它检查三类问题文件是空的、坐标越界、类别 ID 超出你定义的 8 类。from pathlib import Path label_dirs [dataset/labels/train, dataset/labels/val] nc 8 # 本数据集共 8 个类别 for ld in label_dirs: for txt in Path(ld).glob(*.txt): lines txt.read_text().strip().splitlines() if not lines: print(empty label:, txt) continue for line in lines: parts line.split() if len(parts) ! 5: print(bad format:, txt, line) continue cls, x_c, y_c, w, h map(float, parts) if cls 0 or cls nc: print(class id out of range:, txt, cls) if w 0 or h 0: print(zero size bbox:, txt, line) if not (0 x_c 1 and 0 y_c 1): print(center out of [0,1]:, txt, line)YOLO 标签的五个字段缺一不可。len(parts) ! 5能抓出标注工具导出时把类别名写成字符串、或者多了一个空格的脏数据。cls超过 7 说明标注时类别 ID 配置错了这种错误不会让训练崩溃但模型会学到错误的类别映射。空标签文件是另一个隐蔽问题有些自动标注工具对没识别出目标的图片会生成一个空 txt训练脚本默认跳过但 val 的统计里会出现ZeroDivisionError或奇怪的 mAP 跳动。我一般是直接删掉空文件再训练。顺手用 Git 记录一份文件列表后续想找回误删的标注还有后悔药。3. 定义 8 个交通指示牌类别标注规范与工具选型目录格式解决的是「文件放哪」类别定义解决的是「模型学什么」。智能小车赛道自动驾驶场景里8 个类别听起来比 COCO 的 80 类简单得多但类别之间长得很像、视角又低标注稍有不统一模型就会学到错误边界。3.1 8 类别映射表赛道标志与标签 ID 的一一对应我按智能车赛道的常见路线把交通指示牌分成 8 类。这张表的顺序即 data.yaml 里 names 的顺序也直接决定 txt 第一列的数字训练中途改顺序等于全部重来。class id类别名指示牌含义赛道位置0stop停车等待起跑线前、路口停止线1left左转左弯道前2right右转右弯道前3straight直行直道入口4speed_limit限速需要减速的路段前5pedestrian人行横道斑马线区域6uturn掉头U 型弯道前7finish终点赛道终点线为什么是这 8 个智能小车的控制逻辑本质上是「识别标志 → 执行动作」stop、left、right、straight 覆盖四个基本动作speed_limit 控制速度pedestrian 模拟真实交通场景的避让逻辑uturn 单独列出来是因为它经常和 left 弯道混淆。finish 类用于终点判断很多比赛靠它自动停车。3.2 标注工具选型三个主流工具对比与选择标准标注工具不需要追新关键是能稳定导出 YOLO 格式。我用过的三种方案各有取舍这里直接列对比。工具导出格式自动化程度适用场景LabelImgPascalVOC/自转 YOLO纯手动少量数据、本地离线环境X-AnyLabelingYOLO 直接导出支持预标注辅助长尾难例补充、中等规模数据RoboflowYOLOV5 zip 直接下载云端自动标注团队协作、需要快速迭代选择标准可以浓缩成三问能不能直接导出 YOLO txt能不能批量修改类别 ID标注文件和图片是否自动同名LabelImg 老牌稳定但导出的默认是 VOC 格式需要二次转换多一步就多一个出错点。X-AnyLabeling 这类带自动预标注的工具能省一半时间但预标注结果必须逐框检查赛道指示牌小且形状相似自动框经常偏大。Roboflow 导出方便但前面加了一堆上传下载流程团队用还行单机跑不推荐。3.3 标注边界规则贴边、遮挡和运动模糊怎么处理标注规范比工具更重要。第一个规则是「框贴牌、不贴背景」指示牌外缘就是框的边界允许 2~3 像素误差但绝不能像画通用目标那样留一圈环境冗余。两个牌子同时出现在画面里时只标注更靠近车头的那一个被遮挡超过 50% 的另一个不标。第二个规则是「模糊帧要分两类处理」。智能小车相机帧率低、车速快运动模糊几乎不可避免这些拖影图反而是宝贵的训练样本不要删。但模糊到人眼都无法辨认的帧标注也是噪声剔除更稳妥。对轻微模糊帧我一般会在训练时叠加运动模糊增强让模型提前见过这种退化输入。第三个规则是「不要标背景里的类目标」。赛道上的白色胶带、反光块很容易被误看成指示牌如果标注时手滑把背景圈进去模型会学到一堆假特征val 的 mAP 看着高真正跑赛道时就原形毕露。标注完抽 20 张图自己过一遍专门找「框里内容不像牌子」的样本改掉后再进入下一步。4. 写 data.yaml 并跑通训练500 张图以内的参数配置YOLOV5 的数据集配置全靠一个 yaml 文件。写错路径、类别名不对齐训练脚本不会马上报错而是默默用错误的配置跑几十个 epoch最后你得到一份完全不能用的权重。这章的配置方法按小数据集500 张以内来写也正是 8 类别智能小车赛道数据集的典型规模。4.1 data.yaml 三件套path、train/val、names 的常见坑一份最小可用的 data.yaml 长这样path: ./smartcar_dataset # 数据集根目录相对本文件所在位置 train: images/train # 训练图片相对路径 val: images/val # 验证图片相对路径 nc: 8 # 类别数量 names: # 类别名列表顺序与 labels 的 class id 一致 0: stop 1: left 2: right 3: straight 4: speed_limit 5: pedestrian 6: uturn 7: finishYOLOV5 的路径解析逻辑是path与train/val拼接成完整目录。path我推荐用相对本文件的路径数据集整体移动后不用改配置如果你把数据集放在别的盘符直接写绝对路径更省心但要记住改配置时别漏掉盘符。nc和names是两个最容易翻车的地方。nc: 8表示模型输出 8 个类别的预测概率如果 labels 里出现 class id 为 8 的标注训练不报错但这类目标永远不会被正确学习。names列表的索引和 txt 第一列数字严格对应顺序一旦写错你标注的「left」会被模型当作「right」去学那就是灾难。提示val 路径写错时训练脚本只会输出一行 warning 后跳过验证loss 曲线照常下降。等到你觉得训练好了才发现 mAP 从没被计算过白白浪费时间。启动前先确认 yaml 里路径真实存在。4.2 启动训练的命令img、batch、epochs 在 500 张图以内的取值训练命令是我日常用得最多的这一行不同参数组合应对不同硬件这里按「8G 显存、500 张内赛道图」给出组合python train.py \ --data data.yaml \ --cfg models/yolov5s.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --device 0--data指向刚写的 yaml--cfg选择模型结构yolov5s是对精度和速度的折中--weights用官方预训练权重做迁移学习这是 500 张小数据集能收敛的前提。如果只想验证流程可以先用--epochs 10跑一次 smoke test确认 loss 在下降再拉满。--img 640是输入分辨率。赛道指示牌在画面里通常只有 30×30 像素左右降到 480 会明显掉召回但 640 也有代价显存占用高、训练慢。--batch 16在 8G 显存下比较稳显存不够先降 8单卡别盲目上 32。--epochs 100对 500 张图来说是常见起步值我观察 val mAP 一般在 60~80 个 epoch 时稳定只训练 30 个 epoch 就上车的等于没把数据喂饱。参数还有一个隐性关联图片总量越少batch 对过拟合影响越大。500 张图用 batch 32 训练loss 会快速降到很低但 val 指标反而波动大模型把训练图背下来了。所以小数据集我更推荐 batch 16 搭配 100 epoch留出验证集观察泛化。注意如果你用的不是官方仓库而是二次修改版训练脚本参数名可能有差异比如--img-size先跑python train.py --help看一眼再执行别抄完命令直接回车。4.3 超参数调整从默认值出发的小步快跑YOLOV5 的超参数文件里和自动驾驶小数据集关系最大的是翻转、马赛克和学习率。默认的hsv_h: 0.015表示色相随机偏移 1.5%fliplr: 0.5表示水平翻转概率 50%mosaic: 1.0表示每张训练图都做马赛克拼接。智能小车赛道场景里fliplr有个专属问题水平翻转后「左转」牌子会变成「右转」的样子如果标注没跟着翻转模型会把左右类学反。YOLOV5 的数据增强会自动同步翻转标注但检测左右转的同时牌子上的文字方向也被翻转部分赛道标志设计是「箭头文字」翻转后外观和另一类真标志很接近。我遇到过 val mAP 不低、上车后左右不分的情况最后关掉 fliplr 才解决。mosaic在训练最后 10 个 epoch 会自动关闭这是官方设计好的不需要手动干预作用是最后阶段精修真实尺度下的检测框。至于学习率出现 loss 震荡或微调崩了的情况先把lr0从默认 0.01 降到 0.001 试一个 epoch看曲线是否变稳。超参数调整不是玄学一次只动一个变量用 val mAP 对比决定取舍而不是凭感觉叠加改动。5. 智能小车赛道数据集避坑指南5 个让模型翻车的高频原因数据集的坑不在目录结构就在你看不见的细节里。下面 5 条是智能小车赛道自动驾驶里最常见的问题每一条都是现象、原因、解决三步按优先级排。5.1 训练 mAP 很高一上车就漏检现象验证集 mAP0.5 达到 0.95模型在仿真或离线视频上都表现正常装到小车上跑第一圈就漏检 stop 牌。原因训练图片的拍摄视角和数据采集方式脱节。最常见的是用手机在赛道上方俯拍采集再手动裁剪出指示牌而小车摄像头高度只有 15~20 厘米视角是贴地斜视。模型学到的是「俯视角下的牌子外观」一旦视角变成低矮斜视特征分布偏移精度立刻消失。这属于典型的「采集分布」问题不是网络结构能解决的。解决把摄像头固定在小车上以真实安装高度和姿态录制赛道视频再按 10 帧抽 1 帧的方法抽取训练图。同一赛道至少录三圈取不同车道线和光照条件。如果已经有俯拍数据别直接丢把它作为辅助增强——用透视变换把俯拍图压低视角模拟小车视角但注意变换后的标注框也要用同一变换矩阵重算。5.2 标签自检全过loss 就是不降现象2.3 节的脚本跑完没有报任何错误训练时 loss 前 10 个 epoch 降了 20%后面就横盘不动。原因数据集类别不平衡且背景占主导。智能小车赛道里 stop 和 finish 通常只在固定位置出现一整个视频抽帧后这两类的目标数量可能只有 left/right 的十分之一。模型把大部分注意力放在容易学的类别上困难类别的梯度贡献太小loss 曲线看起来还在降其实只是背景和易分类别在刷指标。解决先看每个类别的目标框统计标出数量最少的类。对少于 50 个框的类别回原始视频专门截取该标志出现的片段补标如果实在难以补充考虑复制该类目标做实例增强把指示牌以不同尺寸贴到赛道背景图上。补数据优先于调损失函数这是最直接的解决路径。管用后再观察 loss 是否开始下降。5.3 「直行」与「限速」互相误检现象混淆矩阵里straight 和 speed_limit 两个类别的交叉格数值很高模型反复把限速牌识别成直行牌。原因这两类指示牌的形状和宽高比接近尤其当拍摄距离远、分辨率低时细节特征被压缩模型只能依赖轮廓判断。另一个推手是标注框的边界不统一有人把框贴在牌面内圈有人把框贴到外沿加边框导致同类目标的宽高统计方差被拉大类间可分性变差。解决先把这两类的全部标注抽查一遍统一框贴牌面外缘的规则去掉框内明显包含背景的噪声样本。然后看这两类在画面中的真实差异——如果只是长宽比略有不同可以通过提高输入分辨率到 640 以上保留细节让模型有足够像素去区分牌面图案。若仍无法区分检查一下是不是类别定义本身有歧义赛道里「限速」标志如果画的是数字应裁剪到包含完整数字而不是只框圆边。5.4 验证集 mAP 曲线像心电图现象每一轮 epoch 的 val mAP 剧烈抖动0.9 到 0.4 之间来回跳训练集 loss 却很平滑。原因划分训练验证时同一视频的连续帧被随机散落到两边。赛道视频连续相邻帧几乎一样验证集和训练集内容高度重复模型在训练时已经见过验证帧的近似副本指标虚高换到真正的测试环境又打回原形。解决按「视频片段」而不是「单帧」划分数据。把同一圈视频的全部抽帧放到同一个组里整组进 train 或整组进 val验证集至少单独保留 50 张来自不同片段的图。同时固定随机种子保证每次实验的划分一致。改完划分后重新训练你会看到 val 曲线平稳得多那个数字才是真实泛化性能。5.5 中断训练后报缓存错误现象训练中途断电手动终止再次运行时报错提示内容类似AttributeError: NoneType object has no attribute shape但代码和参数都没动过。原因YOLOV5 会在labels目录下生成.cache文件这是一个二进制缓存保存了标注文件的解析结果用于加速下次读取。训练中断时缓存文件可能只写了一半再次加载时解析失败报错的位置根本不在数据代码里很容易被误判成环境问题。解决删除数据集labels目录下所有.cache文件后再启动训练。这个操作安全无损缓存可以在下次训练时自动重建。顺带养成的习惯是每次数据集内容更新后都在训练前清一次.cache否则旧缓存会和新的标注文件不一致你会被莫名其妙的指标变化骗到。6. 验证部署一条龙混淆矩阵、ONNX 导出与数据集版本管理训练完成后先别急着上车用混淆矩阵定位类别短板再导出轻量模型最后给数据集做版本管理这三步直接决定现场表现。6.1 先看混淆矩阵再决定补哪类数据训练输出目录runs/train/exp/下会生成confusion_matrix.png对角线上的数字越高越好。重点看对角线外的高亮格比如 5.3 里 straight 和 speed_limit 的交叉值。如果背景类 background 与某个类别之间误检严重说明框偏大把指示牌周边背景也包进去了这时候不补数据而是回到标注端修正框边界。补数据优先级永远按「混淆矩阵误检最严重」来排。6.2 导出 ONNX从 PyTorch 权重到小车推理的落地点部署到树莓派这类边缘设备前把权重转成 ONNX 是常见做法。YOLOV5 自带导出脚本一条命令完成python export.py \ --weights runs/train/exp/weights/best.pt \ --include onnx \ --img-size 640 \ --batch-size 1--batch-size 1导出静态 batch 模型在 onnxruntime 或 TensorRT 加载时省去动态形状的解析麻烦推理更稳定。导出完成后用一行 Python 验证输出形状import onnxruntime as ort sess ort.InferenceSession(best.onnx) out sess.run(None, {images: __import__(numpy).zeros((1, 3, 640, 640))}) print(out[0].shape) # 期望 (1, 8, 8400)输出形状第一维是 batch第二维是 (类别数 4) × 每个网格的预测数8正好对应本数据集的 8 个类别8400是 640 分辨率下三个尺度的 anchor 总数。实际部署时NMS 等后处理逻辑在 ONNX 导出时默认不带需要在推理代码里自行实现或使用对应 runtime。6.3 版本管理给数据集装一个后悔药我自己的血泪经验是刚做完数据集的 v1为了追 mAP 直接修改原标注文件结果 5.1 和 5.3 的问题串在一起查了三天才发现是验证集被自己改动了。从那以后我定了两个规矩第一每次批量标注或修正都复制一份目录打上 v2 标记验证集永远锁死不动第二训练前用脚本记录文件数量和总标注框数数字对不上就不启动训练。这个习惯看起来笨但比训练后追悔高效得多。智能小车赛道数据集的价值不在类别多而在分布贴合实际场景把目录格式、类别定义和版本管理做扎实后面所有训练和部署才有地基。希望帮到你。本文还有配套的精品资源点击获取
返回列表