拓冰建站拓冰建站
首页 / 资讯中心 / 正文

YOLOv5+TT100K交通标志识别实战:数据集转换与模型训练全流程

简介本资源是一个基于YOLOv5实现的交通标志牌识别高分项目面向人工智能、自动化、电子信息等专业的在校学生、教师及工程实践者适用于毕业设计、课程设计、项目立项演示及深度学习入门进阶学习。项目完整复现了TT100K数据集上的检测流程涵盖数据预处理、模型训练、验证评估与推理部署全链路代码经实测可直接运行配套文档详述环境配置、参数调优与结果分析。压缩包共149个文件含56个Python脚本核心训练/推理/可视化逻辑、49个YAML配置文件数据集定义、模型结构与超参设置、6个Shell脚本一键训练/测试/打包、6个Markdown文档含使用指南与答辩要点以及Dockerfile系列支持CPU/ARM64多平台部署整体仅1.12MB轻量易用。已有79人下载学习提供从零跑通到二次开发的完整支撑包括缓存机制、引用规范CITATION.cff、工程化目录结构与多环境适配方案。 做交通标志牌识别这个方向我最初是被一堆公开数据集勾起来的。当时正好要交一个计算机视觉相关的项目看了下市面上的方案YOLOv5 和 TT100K 这个组合非常成熟网上资料也相对多但真正自己动手的时候还是踩了不少坑。比如数据集解压之后不知道从哪下手、标注格式和 YOLO 要求的格式对不上、训练完检测效果差得离谱等等。所以这篇博客我打算把这个项目从头到尾完整拆一遍包括方案选型、环境搭建、数据集整理、训练评估、问题排查以及最后怎么从一个普通训练Demo 变成一个能交差、能答辩、能拿得出手的“高分项目”。无论你是刚接触目标检测的初学者还是准备做毕业设计、课程设计这篇内容都能直接给你一套可以复现的操作路径。1. 方案选型为什么是 YOLOv5 TT100K1.1 YOLOv5 的生态优势先说说我为什么选 YOLOv5而不是 Faster R-CNN、SSD或者更先进的 YOLOv8、YOLOv9。YOLOv5 虽然名字里有个 v5但它至今依然是社区最成熟、资料最全的目标检测框架之一。它的核心优势倒不是指标上碾压谁而是“上手成本极低坑基本都被前人踩平了”。Ultralytics 官方把数据格式、训练脚本、验证脚本、模型导出脚本全都整合成一个命令行工具初学者只需要准备数据和配置文件敲几行命令就能跑起来。这一点对课程设计、毕业设计来说远比多几个百分点的 mAP 更重要。其次是它的部署生态。训练完的模型可以导出成 ONNX、TensorRT、OpenVINO 等格式后续如果要做 Web 端、树莓派、Jetson 上的实时识别都有现成方案。对项目而言这意味着你有充分的后期扩展空间不会被框架卡死。从模块化角度看YOLOv5v7.0 版本的代码结构非常清晰backbone、neck、head 分层明确改模型、替换注意力机制、加检测头都大有人做过。有一次我需要把模型改成单通道红外图像输入社区里早就有现成的修改教程省了很多事。1.2 TT100K一套更“本土化”的交通标志数据集TT100KTsinghua-Tencent 100K是由清华大学和腾讯联合发布的交通标志数据集名字里的 100K 指的是包含约 10 万张街景图像。它从腾讯街景全景图中截取覆盖了国内真实道路场景包含晴天、阴天、逆光、夜晚和不同天气状况下的交通标志。这个数据集的特殊性在于它和国内道路环境高度匹配。如果你想用 GTSRB德国交通标志数据集训练模型再去识别国内道路上的标志效果往往会打折扣因为标志样式、颜色、字体、甚至磨损程度都不一样。TT100K 就解决了这个问题在中国场景下做交通标志识别它就是最合适的选择之一。数据集自带 3 万张训练图像部分版本给出更多和 1 万张测试图像标注采用 JSON 格式每个目标包含类别名称和 bbox 框。不过这里有个必须提醒的坑官方标注里类别非常多原论文分类有 221 类很多类别的样本数量极少。常规做法是只保留出现频次较高的一部分类别比如限速标志 i2/i4/i5、禁止驶入 p10、停车让行等标志做一次类别筛选而不是一股脑全训。1.3 这个组合适合哪些场景YOLOv5 加 TT100K 的组合非常适合这些实际场景课程设计、毕业设计里的“目标检测落地项目”智能驾驶辅助系统中的交通标志识别模块原型自动驾驶仿真环境下的感知算法验证移动端或嵌入式设备上的交通标志检测对于参赛或者毕设来说这个组合的意义在于“真实数据 主流算法 有明确的应用价值”答辩的时候故事线也容易讲。你不需要自己拉无人机去拍路牌也不需要手工标注几万张图省掉的精力全部可以放在模型调优和系统化封装上。2. 动手前的准备环境搭建与数据集格式化2.1 用最少的时间装好 YOLOv5 环境网上很多人一上来就推荐用 Anaconda、CUDA、cuDNN、PyTorch 一条龙但实际我建议先做一个“最小可运行”环境把流程跑通再回头补性能优化。我的建议是Python 用 3.8 或 3.9PyTorch 用官方推荐的稳定版本。如果是 GPU 环境先确认自己的显卡驱动支持哪个 CUDA 版本再去安装对应 PyTorch。一个更省事的做法是直接用 YOLOv5 仓库里的 requirements.txtgit clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt如果是在国内服务器或者本地机器上安装速度慢可以给 pip 换国内镜像源比如清华源、阿里源。装完之后不要急着跑训练先跑一次官方自带的检测脚本确认环境没问题python detect.py --source data/images/bus.jpg --weights yolov5s.pt能输出一张带检测框的图片说明整个链路是通的。这一步千万不能省很多人后面训练出问题最后发现是 PyTorch 和 CUDA 版本不匹配导致 Tensor 运算异常。依赖安装阶段最常见的报错主要来自这几个包opencv-python、pycocotools、thop。pycocotools 在 Windows 上经常需要编译如果装不上可以考虑安装pycocotools-windows或者直接跳过YOLOv5 只有在计算 COCO 数据集指标的时候才强制需要它。2.2 TT100K 标注转 YOLO 格式的关键脚本TT100K 的原始标注是 JSON而 YOLOv5 要求每张图片对应一个同名 txt 文件每行一个目标格式是class_id center_x center_y width height其中center_x center_y width height全部是相对于图片宽高的归一化值取值范围 0 到 1。TT100K 的 JSON 结构大致是{ imgs: { 00000.jpg: { objects: [ { category: i2, bbox: { xmin: 123, ymin: 456, xmax: 200, ymax: 520 } } ] } } }不同版本解析细节可能略有差异但核心就是拿到 category 和 bbox。下面是我自己写的转换脚本可以直接参考import json import os import shutil from pathlib import Path # 配置路径 ann_file annotations.json # TT100K 标注文件 img_root train # 图片目录 out_img_root images/train # 输出图片目录 out_label_root labels/train # 输出标注目录 # 类别筛选与映射只保留出现次数较多的类别 selected_classes [i2, i4, i5, p10, p26] class_dict {name: idx for idx, name in enumerate(selected_classes)} os.makedirs(out_img_root, exist_okTrue) os.makedirs(out_label_root, exist_okTrue) with open(ann_file, r, encodingutf-8) as f: data json.load(f) for img_name, ann in data[imgs].items(): objects ann.get(objects, []) # 过滤出有效目标 lines [] has_valid False for obj in objects: cat obj[category] if cat not in class_dict: continue bbox obj[bbox] xmin float(bbox[xmin]) ymin float(bbox[ymin]) xmax float(bbox[xmax]) ymax float(bbox[ymax]) img_path os.path.join(img_root, img_name) if not os.path.exists(img_path): continue from PIL import Image w, h Image.open(img_path).size # 转 YOLO 格式 cx (xmin xmax) / 2 / w cy (ymin ymax) / 2 / h bw (xmax - xmin) / w bh (ymax - ymin) / h # 过滤掉无效框 if cx 0 or cy 0 or bw 0 or bh 0: continue if cx 1 or cy 1 or bw 1 or bh 1: continue lines.append(f{class_dict[cat]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) has_valid True if has_valid: # 拷贝图片并按 YOLO 目录结构保存 shutil.copy(img_path, os.path.join(out_img_root, img_name)) label_path os.path.join(out_label_root, img_name.replace(.jpg, .txt)) with open(label_path, w, encodingutf-8) as f: f.write(\n.join(lines)) print(转换完成)这段脚本里有几个细节值得注意。第一个是过滤掉没有有效目标的图片TT100K 里不少图片没有目标框如果不过滤训练时这些图片会被当作背景虽然不算严重错误但会让数据分布变怪。第二个是必须跳过超界框有些标注框边缘超出图片范围如果不处理会导致训练报错或者 loss 异常。2.3 训练集与验证集的划分策略TT100K 官方给的 train 和 test 划分主要是按场景区分的。实际做项目时我建议把官方 train 里再切出一部分验证集比如取 15% 到 20% 作为 val官方 test 留作最终测试。这样划分的原因很简单训练过程中你需要频繁看模型在验证集上的表现如果直接拿官方 test 来做这件事会慢慢把 test 的统计特性“泄漏”到调参决策里最后报出来的测试指标就不那么可信了。划分完以后整体目录结构应该是datasets/ ├── tt100k/ │ ├── images/ │ │ ├── train/ │ │ └── val/ │ └── labels/ │ ├── train/ │ └── val/YOLOv5 在训练时会自动根据tt100k.yaml里的配置找到images和labels目录并且默认要求 labels 和 images 在同级目录下。这个规则很多人会漏掉如果标签放错位置训练时会出现 “No labels found” 的警告模型会在纯背景上瞎学效果自然一塌糊涂。3. 训练与评估核心实操全流程3.1 编写数据配置文件YOLOv5 训练需要一份 YAML 格式的数据配置文件告诉框架去哪找图片、目标类别有哪些。在yolov5/data/目录下新建一个tt100k.yaml内容如下path: /path/to/datasets/tt100k # 数据集根目录 train: images/train # 训练图片相对路径 val: images/val # 验证图片相对路径 nc: 6 # 类别数必须和实际筛选出的类别数一致 names: [i2, i4, i5, p10, p26, p27] # 类别名顺序要和脚本里的 class_dict 一致nc和names这两个字段必须和转换脚本里class_dict的类别顺序严格对应否则训练出的模型类别名称就是错乱的。我一开始没注意这个写反了两类训练指标一切正常推理时却把限速标志识别成停车标志排查了半小时才找到问题。3.2 选择模型和超参数YOLOv5 有n/s/m/l/x五个缩放版本参数量和精度依次递增。我建议第一轮训练直接用yolov5s它速度快、显存占用小一轮跑下来也就几十分钟特别适合验证数据集整理得对不对。如果数据集已经有几十万张图或者你是冲着刷新精度去的可以后续再换yolov5m或yolov5l。但如果是课程设计先用 s 版本把整个流程打通再在 s 版本的权重上继续微调效率最高。基础训练命令如下python train.py \ --data data/tt100k.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --device 0 \ --project runs/train \ --name tt100k_exp几个关键参数说明一下--img 640是输入图片的尺寸。TT100K 里很多标志在原始街景图中只占几十个像素如果显存允许建议用 960 甚至 1280 训练小目标检测效果会明显改善。--batch 16按你的显卡显存调整。8G 显存跑 640 输入配 batch 16 基本没问题如果爆显存就降到 8。--weights yolov5s.pt会加载 COCO 预训练权重做迁移学习。对交通标志这种与 COCO 类别差异较大的任务预训练模型依然能提供基础特征提取能力收敛速度明显更快。数据增强方面YOLOv5 默认在hyp.scratch-low.yaml里已经配置了 Mosaic、随机翻转、HSV 扰动等策略。交通标志通常颜色和形状特征比较强可以稍微调低 HSV 扰动强度避免因为颜色偏移太厉害导致模型学不到标志的颜色特征。这个可以在训练后看验证集表现再决定要不要调。3.3 训练过程查看与断点恢复训练开始后终端会实时输出每个 epoch 的 loss 和指标。除此之外runs/train/tt100k_exp/目录下会保存results.png、weights/best.pt和weights/last.pt。best.pt是验证集 mAP 最高的权重last.pt是最后一个 epoch 的权重。如果训练到一半中断了直接用last.pt恢复训练python train.py \ --data data/tt100k.yaml \ --weights runs/train/tt100k_exp/weights/last.pt \ --img 640 \ --batch 16 \ --epochs 50 \ --resume加--resume参数时YOLOv5 会自动读取上次训练的状态包括优化器状态和当前 epoch 数相当于无缝续跑。这里有个小技巧如果你想调整学习率、数据增强参数后重新训练不要直接--resume而是复制一份新的权重文件再改参数避免把旧优化器状态带进去。3.4 结果评估看懂 mAP 和 PR 曲线训练完成后第一件事是跑验证集python val.py \ --data data/tt100k.yaml \ --weights runs/train/tt100k_exp/weights/best.pt \ --img 640 \ --task val输出里最关键的几个指标是 mAP0.5、mAP0.5:0.95、Precision、Recall。mAP0.5 表示 IoU 阈值为 0.5 时的平均精度这是目标检测最常用的指标交通标志这类小目标任务一般要求达到 0.8 以上才算是能用的模型。mAP0.5:0.95 是一个更严格的综合指标从 0.5 到 0.95 每间隔 0.05 计算一次平均对框的位置精度更敏感。Precision 代表检测结果里真正正确的比例Recall 代表所有真实目标里被找出来的比例。如果 Precision 高、Recall 低说明模型“宁可少检也不错检”通常可以在推理时适当降低--conf-thres阈值来提升召回。如果两个指标都低往往不是参数问题而是数据问题要去检查样本数量、标注质量、类别分布。runs/train/tt100k_exp/confusion_matrix.png里的混淆矩阵也很有用。它可以直接显示哪些类别之间容易互相混淆比如“限速 40”和“限速 50”这类外观相似的标志。如果混在一起可以考虑增加对应类别的数据增强或者检查标注本身是不是标错了。4. 经典问题排查与精度优化实战4.1 数据集“看着能训”但效果差的典型原因我见过很多人在这一步卡住数据集按教程转好了命令也能跑通训练 loss 也在下降但验证集 mAP 就是上不去。做个自查清单标签是否真的对应上了图片仔细检查 labels 下有没有空的 txt、图片是否损坏。类别是否严重不平衡TT100K 中“禁止停车”这类标志样本可能特别多而某些特殊警告标志样本很少模型会倾向于预测高频类别。解决方式是筛选类别或者对少样本类别做在线增强复制粘贴、旋转、加噪声。是否所有图片都参与了训练如果 train.txt 里的路径写错模型等于在训练别人的数据集。打开日志确认一下train.py输出的 “train: Images xxx” 数量和你的图片数是否一致。另外一个很低级但常见的坑是TT100K 的图片文件名重复。它的测试集和训练集里可能有同名的图片只是内容不同。如果直接把 train 和 test 放在同一个目录下做划分会有一部分图片被 “腾挪” 覆盖而不自知。所以拆分数据时我强烈建议先把图片复制到统一目录并用shutil.copy而不是shutil.move。4.2 环境与运行时报错速查这里整理一份我在实际跑项目中遇到的典型问题速查表现象原因解决办法训练时提示 “No labels found”labels 目录结构和 images 不一致或标签文件为空检查目录是否按images/train和labels/train对应重新跑转换脚本训练几轮后 loss 变成 NaN学习率过大、混合精度问题、数据含异常框尝试降低--lr0或者加--no-amp关闭混合精度显存 OOM输入尺寸或 batch 过大降低 batch、降低 img 尺寸或者开启--cache减少数据加载压力推理结果中所有框都用同一个类别数据配置文件names顺序与标签索引不一致检查tt100k.yaml的names是否与转换脚本的class_dict完全一致图像里有目标但检测不到目标太小或推理阈值太高使用更大输入尺寸img 960/1280或降低--conf-thresCPU 推理速度太慢模型复杂度大于算力换yolov5n或yolov5s导出 ONNX 模型用 ONNXRuntime 推理这些坑的排查思路其实都很朴素先确认数据没问题再确认配置没问题最后才去怀疑模型本身。4.3 把精度再往上提的几种实操手段如果你训练完发现 mAP 只有 0.6 出头不用急着怀疑人生。以下手段按投入产出比排序可以逐个尝试。第一招提高输入分辨率。TT100K 数据集中交通标志在原始图像中的像素占比很小。把--img 640改成--img 960通常能带来 3 到 5 个百分点的提升。缺点是显存占用和训练时间都会涨你需要根据显卡调整 batch。第二招使用切片辅助推理SAHI。SAHI 的核心思想是把大图切成多个小图分别做检测再把结果合并。对于街景大图里的小路牌效果立竿见影。你可以在推理阶段用 SAHI 对训练好的模型做增强不需要重新训练from sahi.model import Yolov5DetectionModel from sahi.predict import get_sliced_prediction model Yolov5DetectionModel( model_pathbest.pt, confidence_threshold0.4, devicecuda ) result get_sliced_prediction( test_image.jpg, model, slice_height256, slice_width256, overlap_height_ratio0.2, overlap_width_ratio0.2 )第三招调整置信度阈值和 NMS 参数。交通标志往往多个目标靠得很近或者目标之间遮挡严重。推理时可以把 NMS 的 IoU 阈值从默认值调低一点减少相近框被合并的可能性。第四招训练时开启 TTATest Time Augmentation推理时用多尺度翻转预测再平均。YOLOv5 内置了--augment参数推理时开启它通常会带来 mAP 提升代价是推理时间变长。对于演示型项目这个方案非常划算python val.py \ --data data/tt100k.yaml \ --weights best.pt \ --img 960 \ --augment第五招如果以上手段都用完了再考虑模型升级。yolov5s换yolov5l是最后一张牌它能带来一定提升但训练时间和部署成本也都上去了。对课程设计来说s 版本配合前面四招已经足够拿到一个不错的成绩。5. 从模型到“高分项目”交付物包装与扩展思路很多同学跑通了模型就止步了但我认为“项目”和“训练Demo”之间有两步距离。第一步是做一个能演示的界面或交互入口。最简单的做法是用 Flask 搭建一个 Web 页面上传图片后返回带检测框的结果图。YOLOv5 官方仓库本身就提供了detect.py支持图片输入你要做的只是把这个逻辑封装成一个接口。也可以把模型导出成 ONNX再用 FastAPI 部署体验更接近于真实项目。第二步是一份能讲清楚设计思路的文档。我在交付项目时常用的文档结构是项目背景、数据分析和预处理、算法选型对比、实验过程与结果分析、局限与改进方向。这里最有分量的是“实验对比”比如做一组有无迁移学习的对比做一组不同输入尺寸的对比把这些实验结果用表格展示出来比写几百字“我测试了模型”要有说服力得多。如果时间充裕还可以把推理脚本改造成支持视频流输入比如用 OpenCV 读取本地视频逐帧检测把检测结果叠加到画面上。这样的效果在答辩现场展示时冲击力远大于静态图片。最后再分享一个小技巧训练完之后把results.png、混淆矩阵、验证集上随机抽样的检测结果图单独整理到一个文件夹这些素材不仅方便自己复盘也是项目报告中最重要的可视化证据。我在做类似项目时还会顺手写一个 README把训练命令、评估命令、推理命令都记下来方便两个月后的自己快速回忆。项目可以不用很复杂但流程完整、逻辑闭环、结果可视化这三点做好了就已经超过大半同类型项目了。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门