首页 / 资讯中心 / 文章详情

YOLO交通标志识别数据集:三种标签格式与训练避坑指南

YOLO交通标志识别数据集:三种标签格式与训练避坑指南 ★ FEATURED ARTICLE
简介这份资源面向计算机视觉入门与进阶开发者、自动驾驶或智能交通方向的学生与工程师提供一套可直接用于YOLO系列目标检测训练的交通标志识别数据集。数据均来自真实道路场景覆盖多种光照与视角标注质量较高并同时给出voc、coco和yolo三种格式标签分别存放于独立文件夹便于在不同框架间切换使用。压缩包共约2000个文件以1985个xml标注文件为主另含少量txt、html与py脚本整体约807.7MB。资源附带数据集划分脚本可按需生成训练集、验证集与测试集并配套Windows与Linux环境搭建、训练案例教程帮助读者快速跑通从环境配置到模型训练的全流程。目前已有801人学习下载适合希望省去数据采集与格式转换环节、专注模型调优与实验对比的读者参考使用。1. 从一张被漏标的限速牌说起这套交通标志数据集到底能干什么去年帮一个做辅助驾驶 demo 的团队看模型验证集 mAP 卡在 0.62 上不去可视化一拉出来限速 80 的牌子十张里有三张框是歪的还有两张压根没标。问数据哪来的答曰网上随手扒的。这就是交通标志识别最真实的痛点——模型结构抄来抄去就那几套真正拉开差距的是标注质量。今天拆的这套 YOLO 交通标志识别数据集3000 张真实道路场景图用 labelImg 逐张标过同时给了 VOC 的 xml、COCO 的 json 和 YOLO 的 txt 三种标签格式还配了划分脚本和 Linux/Windows 双平台的训练教程。它解决的不是有没有数据的问题而是数据能不能直接喂进 YOLO 且不用返工的问题。适合谁正在做交通标志检测课程设计的学生、要快速搭 baseline 的算法工程师、以及被格式转换折磨过的从业者。下面按是什么 → 怎么用 → 坑在哪的顺序把这份资源拆开讲透。2. 三种标签格式的取舍VOC、COCO、YOLO 到底该用哪个拿到数据集第一件事不是急着训练而是搞清楚三种格式各自的坐标系和适用边界。选错了格式后面转换脚本能让你怀疑人生。2.1 三种格式的坐标定义差异VOC 格式用 xml 存储坐标是绝对像素值bndbox里是xmin/ymin/xmax/ymax左上角为原点。COCO 格式用 json 存储bbox是[x, y, width, height]同样是绝对像素但注意它是宽高不是右下角坐标这个差异坑过不少人。YOLO 格式用 txt 存储每行class_id x_center y_center width height全部是归一化到 0~1 的相对值且中心点坐标而非左上角。格式文件类型坐标类型表示方式典型用途VOCxml绝对像素xmin,ymin,xmax,ymax传统检测框架、labelImg 原生输出COCOjson绝对像素x,y,w,h多任务、实例分割、COCO 预训练权重YOLOtxt归一化相对值cx,cy,w,hYOLOv5/v8/v11 直接训练为什么这套资源三种都给因为实际项目里你经常要在不同环节切换。比如用 COCO 预训练权重做迁移学习就得先有 COCO 格式用 labelImg 补标新数据出来的是 VOC最终训练 YOLO 又要转成 txt。三种格式齐备等于省掉了中间所有转换环节。2.2 用 Python 校验三种格式是否对齐拿到数据先别信简介自己写个脚本抽查同一张图在三种格式下的框是否一致。这是我最推荐的第一道质检。import os import xml.etree.ElementTree as ET import json # 以一张图为例校验 VOC 与 YOLO 标签是否对齐 img_name traffic_0001 img_w, img_h 640, 480 # 替换为实际图片尺寸 # 读 VOC xml_path fVOC/Annotations/{img_name}.xml tree ET.parse(xml_path) root tree.getroot() voc_boxes [] for obj in root.findall(object): bnd obj.find(bndbox) xmin float(bnd.find(xmin).text) ymin float(bnd.find(ymin).text) xmax float(bnd.find(xmax).text) ymax float(bnd.find(ymax).text) voc_boxes.append((xmin, ymin, xmax, ymax)) # 读 YOLO反归一化回绝对像素 yolo_path fYOLO/labels/{img_name}.txt yolo_boxes [] with open(yolo_path) as f: for line in f: cid, cx, cy, w, h map(float, line.split()) xmin (cx - w / 2) * img_w ymin (cy - h / 2) * img_h xmax (cx w / 2) * img_w ymax (cy h / 2) * img_h yolo_boxes.append((xmin, ymin, xmax, ymax)) # 逐框比对容差 1 像素 for vb, yb in zip(voc_boxes, yolo_boxes): diff max(abs(a - b) for a, b in zip(vb, yb)) print(fVOC {vb} vs YOLO {yb} - max diff {diff:.2f}px)这段脚本的逻辑是把 YOLO 的归一化坐标反算回绝对像素再和 VOC 的绝对坐标逐框比对。参数上img_w和img_h必须换成图片真实尺寸否则反算全错。容差设 1 像素是因为标注工具保存时可能有四舍五入。如果 diff 超过 2 像素说明三种格式不是同一批标注导出的得警惕。2.3 类别映射表要先固定下来交通标志的类别数因数据集而异常见的有限速、禁止、警告、指示几大类。这套资源用的是 labelImg 标注类别名写在classes.txt或predefined_classes.txt里。训练前必须确认 YOLO 的data.yaml里names列表顺序和 txt 里的class_id严格对应。我一般会先跑一遍统计from collections import Counter import glob counter Counter() for txt in glob.glob(YOLO/labels/*.txt): with open(txt) as f: for line in f: cid int(line.split()[0]) counter[cid] 1 for cid in sorted(counter): print(fclass {cid}: {counter[cid]} boxes)跑完你会得到每个类别的框数量。如果某个类别只有个位数基本可以判定是长尾或者误标训练时要么过采样要么直接合并。这一步不做后面 mAP 低了你都不知道是模型问题还是数据问题。3. 划分脚本怎么用train/val/test 三分的正确姿势数据集划分看着简单实则是最容易埋雷的环节。随机切分导致同一场景的图片同时出现在训练和验证集验证指标虚高上线就翻车——这种血泪经验我见过太多次。3.1 三个划分脚本的分工资源里给了三个脚本别混用各管各的训练集、验证集、测试集划分脚本图片标签划分写入新文件夹.py三分把图片和标签复制到 train/val/test 三个新文件夹适合从零开始整理。训练集、验证集划分脚本图片标签划分写入新文件夹.py二分只分 train/val适合数据量不大、不单独留测试集的场景。split_train_val生成ImageSets下txt文件划分脚本.py不移动文件只在ImageSets/Main/下生成train.txt、val.txt等索引文件适合 VOC 风格的数据管理。选哪个取决于你的训练框架。YOLOv5/v8 默认读images/和labels/目录用前两个脚本直接分文件夹最省事如果你用的是 PASCAL VOC 那套评估流程用第三个生成索引。3.2 按比例划分并固定随机种子以三分脚本为例核心逻辑是打乱后按比例切分。关键参数是随机种子必须固定否则每次跑结果不一样实验没法复现。import os import random import shutil random.seed(42) # 固定种子保证可复现 img_dir images label_dir labels out_dir dataset_split train_ratio, val_ratio, test_ratio 0.7, 0.2, 0.1 imgs [f for f in os.listdir(img_dir) if f.endswith((.jpg, .png))] random.shuffle(imgs) n len(imgs) n_train int(n * train_ratio) n_val int(n * val_ratio) splits { train: imgs[:n_train], val: imgs[n_train:n_train n_val], test: imgs[n_train n_val:] } for split, files in splits.items(): os.makedirs(f{out_dir}/{split}/images, exist_okTrue) os.makedirs(f{out_dir}/{split}/labels, exist_okTrue) for img in files: shutil.copy(os.path.join(img_dir, img), f{out_dir}/{split}/images/{img}) txt os.path.splitext(img)[0] .txt src_txt os.path.join(label_dir, txt) if os.path.exists(src_txt): shutil.copy(src_txt, f{out_dir}/{split}/labels/{txt}) else: print(f警告{img} 没有对应标签)逻辑说明先random.shuffle打乱再按 7:2:1 切。random.seed(42)是后悔药保证你明天再跑一次结果完全一样。参数上比例可以根据数据量调3000 张的话 7:2:1 比较稳测试集留 300 张够评估了。代码里那个else分支打印缺失标签的图片跑完一定要看输出有图无标签的样本混进训练集就是纯噪声。3.3 划分后必须做的两项检查第一确认没有图片同时出现在两个 split 里。第二确认每个 split 的类别分布大致均衡。第二项尤其重要如果验证集里某个类别一个框都没有那这个类别的 mAP 就是 0白评估。# 检查各 split 的类别分布 for split in [train, val, test]: counter Counter() label_path f{out_dir}/{split}/labels for txt in os.listdir(label_path): with open(os.path.join(label_path, txt)) as f: for line in f: counter[int(line.split()[0])] 1 print(split, dict(sorted(counter.items())))如果发现 val 里某类为 0常见做法是手动从 train 里挪几张过去或者改用分层抽样stratified split。交通标志数据集里限速类通常占大头警告类偏少分层抽样能明显改善小类评估的稳定性。4. 环境搭建与训练Linux 和 Windows 两条路资源里给了两套环境搭建和训练教程Linux 和 Windows 各一份。别跳过环境直接跑训练CUDA 版本和 PyTorch 对不上是新手最常见的翻车点。4.1 Linux 下的环境搭建要点Ubuntu 环境下先确认显卡驱动和 CUDA 版本。教程里给的是标准流程我补充几个容易忽略的点。# 查看显卡和驱动 nvidia-smi # 确认 CUDA 版本驱动支持的版本不是已安装的 nvcc --version # 创建虚拟环境避免污染系统 Python conda create -n yolo python3.9 -y conda activate yolo # 安装 PyTorch注意 cu118 要和你的驱动匹配 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 验证 GPU 可用 python -c import torch; print(torch.cuda.is_available())参数说明python3.9是 YOLOv5/v8 兼容性最好的版本3.10 以上偶尔有依赖冲突。cu118对应 CUDA 11.8如果你的驱动只支持到 11.6就换成cu116。最后那句验证必须输出True输出False说明 PyTorch 装成了 CPU 版训练会慢到无法接受。4.2 Windows 下的差异与注意Windows 教程的流程类似但有两个坑。一是路径分隔符脚本里写/还是\要统一混用会报FileNotFoundError。二是num_workers参数Windows 下多进程 DataLoader 容易卡死建议设成 0 或 2Linux 下可以设 8。# Windows 下训练时建议加的参数 python train.py --data data.yaml --weights yolov5s.pt --epochs 100 --batch-size 16 --workers 2--workers 2就是针对 Windows 的妥协牺牲一点数据加载速度换稳定。--batch-size 16是 8G 显存的安全值显存够可以往上加但要注意 batch 变了学习率最好同步调。4.3 用案例配置改自己的数据集教程里给的是案例配置改成自己的数据集主要动三个地方data.yaml里的train、val路径和nc、names模型配置里的类别数以及预训练权重的选择。# data.yaml 示例 train: ../dataset_split/train/images val: ../dataset_split/val/images test: ../dataset_split/test/images nc: 4 # 类别数按你的实际类别改 names: [speed_limit, prohibition, warning, indication]nc必须和names长度一致且顺序要和标注时的class_id对应。改完先跑 1 个 epoch 看看 loss 有没有正常下降别一上来就 100 epoch浪费时间。5. 避坑与排查那些让 mAP 莫名掉点的细节这一章是我踩过的坑合集每条都按现象 → 原因 → 解决写照着排查能省不少时间。5.1 训练 loss 正常但 mAP 极低现象训练 loss 稳定下降但验证 mAP 一直在 0.1 以下。原因data.yaml里的names顺序和标注class_id不一致模型学的是错位的类别。解决跑一遍第 2.3 节的类别统计脚本把names按class_id顺序重排重新训练。5.2 图片和标签文件名不匹配现象训练时报No labels found或者大量图片被跳过。原因图片是001.jpg标签是001.txt但中间多了空格或大小写不一致。解决写个批量重命名脚本统一小写并去空格或者用os.path.splitext严格配对后再划分。5.3 验证集指标虚高现象验证集 mAP 0.9换一批新图测试掉到 0.5。原因划分时没打乱或者同一段视频抽帧的图片同时进了 train 和 val数据泄漏。解决划分前先按场景或视频来源分组组内不跨 split再在组间随机分。5.4 显存溢出OOM现象训练几个 batch 后报CUDA out of memory。原因batch-size太大或者图片分辨率没统一个别大图撑爆显存。解决先把batch-size降到 8 试同时检查图片尺寸训练前统一 resize 到 640。YOLO 默认会 letterbox但原图过大仍会占内存。5.5 中文路径导致读取失败现象Windows 下训练报编码错误或找不到文件。原因数据集放在中文命名的文件夹里OpenCV 或 PIL 读取时编码不兼容。解决把数据集移到纯英文路径下这是最省事的办法别去改源码里的编码。6. 进阶技巧用 ONNX 导出验证数据集质量训练完不是终点导出 ONNX 做一次跨框架推理能反过来验证数据集和模型是否真的可靠。这一步很多人跳过但它是发现标注问题的最后一道关卡。6.1 导出 ONNX 并检查输出维度import torch # 加载训练好的模型 model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/exp/weights/best.pt) model.eval() # 导出 ONNX torch.onnx.export( model.model, torch.zeros(1, 3, 640, 640), traffic_sign.onnx, opset_version12, input_names[images], output_names[output], dynamic_axes{images: {0: batch}, output: {0: batch}} ) print(ONNX 导出完成)opset_version12是兼容性较好的选择dynamic_axes让 batch 维度可变方便部署时按需调整。导出后用onnxruntime跑一张测试图对比 PyTorch 和 ONNX 的输出差异如果框的位置差很多说明导出有问题。6.2 用 ONNX 推理反查漏标把 ONNX 模型在测试集上跑一遍挑出那些模型置信度很高但标注里没有对应框的图片。这些大概率是漏标样本。import onnxruntime as ort import numpy as np import cv2 sess ort.InferenceSession(traffic_sign.onnx) img cv2.imread(test.jpg) img cv2.resize(img, (640, 640)) img img[:, :, ::-1].transpose(2, 0, 1) # BGR-RGB, HWC-CHW img np.expand_dims(img, 0).astype(np.float32) / 255.0 outputs sess.run(None, {images: img}) preds outputs[0] # 筛选高置信度预测 high_conf preds[preds[:, 4] 0.7] print(f高置信度预测数{len(high_conf)})逻辑说明preds[:, 4]是置信度列阈值 0.7 是经验值交通标志场景可以设高一点减少误报。把高置信度预测和标注框做 IoU 匹配IoU 低于 0.3 且置信度高于 0.7 的基本就是漏标。我一般会把这类图挑出来人工复核一遍补标后重新训练mAP 通常能再涨 2~3 个点。6.3 一个我坚持了很久的习惯从那以后我每次拿到新数据集都强制走一遍格式校验 → 类别统计 → 划分检查 → 导出 ONNX 反查这四步不管简介写得多漂亮。这套交通标志数据集三种格式齐备、脚本和教程都给了底子是不错的但数据质量最终得靠自己的流程兜底。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站