news 2026/8/31 14:51:16

基于YOLOv5与TT100K的交通标志识别:从数据预处理到模型部署全流程实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于YOLOv5与TT100K的交通标志识别:从数据预处理到模型部署全流程实践

简介:本资源是一个基于YOLOv5实现的交通标志牌识别高分项目,面向人工智能、自动化、电子信息等专业的在校学生、教师及工程技术人员,适用于毕业设计、课程设计、竞赛原型开发与深度学习入门实践。项目完整复现了TT100K数据集上的检测流程,涵盖数据预处理、模型训练、验证评估与推理部署全流程,代码经实测可直接运行,配套文档详述环境配置、参数调优与结果分析方法。压缩包共149个文件,包含56个Python主程序与工具脚本、49个YAML/YML配置文件(定义模型结构、训练超参与数据路径)、6个Shell部署脚本、6个Markdown说明文档,以及Dockerfile(含CPU/ARM64多平台支持)、.gitignore等工程化文件,整体仅1.12MB,轻量易部署。已有79人下载学习,提供从零复现到二次开发的完整支撑,特别适合需要快速构建CV落地案例的学习者与项目开发者。 说实话,这类“基于yolov5的交通标志牌识别项目”我见得太多,但从标题就能看出,它不是一个随便跑跑demo的玩具项目,而是一个能真正落地、拿去交作业甚至写进简历的完整工程。yolov5作为目标检测里上手最快、生态最成熟的一套代码库,配合TT100K这个专门面向中国交通场景的数据集,组合起来的项目价值非常高——无论是毕业设计、课程设计,还是入门实际工程,这条路线都值得认真走一遍。

我这次就结合自己做过的实践,把这个项目从环境搭建、数据转换、模型训练到推理部署的完整链路,全部拆开来讲清楚,顺带把那些文档里不会写、但实操时一定会踩的坑也一并交代了。

1. 项目整体设计与思路拆解

1.1 为什么选yolov5做交通标志识别

选yolov5不是因为它最先进,而是因为它最“够用”。交通标志检测本质上属于中小尺寸目标检测任务,标志牌在画面中往往只占几十到几百像素,对模型的小目标感知能力有一定要求。yolov5提供了s/m/l/x四种规格,s模型只有7M左右参数,在CPU上都能跑出可用的速度,同时精度又不至于拉胯,这对学生项目和嵌入式部署都非常友好。

更关键的是yolov5的生态成熟度。从数据标注格式到训练脚本,从模型量化到TensorRT、ONNX导出,全套工具链都齐了。这意味着你可以把80%的精力花在数据和调参上,而不是去啃一个自研框架的源码。对大多数做毕设或入门工程的人来说,这个选择是性价比最高的。

yolov5本身是一个单阶段目标检测算法,它把目标检测问题拆成了“在特征图上做密集回归”这件事。简单理解就是,输入一张图,网络同时预测出大量候选框的位置和类别,然后通过NMS(非极大值抑制)去掉重复的框,留下最终结果。相比两阶段的Faster R-CNN,yolov5速度更快,结构更简洁,这也是它在工业界被广泛使用的原因。

1.2 TT100K数据集的选型理由

TT100K是腾讯发布的交通标志数据集,全称是Tencent Traffic-Sign 100K,包含10万张街景图像,其中标注了3万多个交通标志实例,覆盖5个大类、45个小类,包括禁令、警告、指示、指路等类型。这个数据集最大的特点是“中国本土化”——里面的标志都是国内道路上真实出现的样式,比如“限速40”“禁止通行”“注意行人”这些,跟国外数据集里的标志风格差异很大。

如果你用国外的GTSRB或者LISA数据集训练模型,拿到国内路况上测试,效果往往会打折扣,因为标志的配色、形状、文字排版都有差异。TT100K直接就是国内的真实街景数据,贴合度很高,这也是毕设和竞赛里它被大量使用的原因。

不过要提醒的是,TT100K虽然名义上有10万张图,但有标注信息的实际只有约1万张,而且这1万张也不是全部都能直接用。光照变化、遮挡、小目标、类别不均衡这些问题在TT100K里都很明显,做数据处理时需要花不少功夫去清洗和筛选。这部分我会在第三章详细讲。

1.3 项目模块划分与资料包结构

一个完整的yolov5交通标志识别项目,通常包含五个核心模块:环境与依赖、数据准备、模型训练、推理验证、文档资料。我在整理自己的项目时,目录结构大概是这样的:

  • yolov5/:核心检测代码库(官方源码,可保持原样)
  • data/TT100K/:数据集存放目录,包括imageslabels
  • tools/:自写的脚本,主要是标注格式转换、数据集划分、类别统计
  • runs/:训练日志、权重文件、检测结果图
  • docs/:项目文档、实验报告、答辩PPT素材

这样的组织方式最大的好处是职责清晰。官方代码库保持原样,后续拉新版本不冲突;自己写的工具脚本单独放,方便复用;训练产出统一进runs目录,出问题排查也方便。很多同学喜欢把所有东西堆在一个文件夹里,结果训练到一半想找某个脚本都费劲,这种坏习惯最好一开始就改掉。

2. 环境搭建:yolov5安装与依赖配套

2.1 yolov5源码获取与环境要求

yolov5的安装流程本身不复杂,但版本兼容问题很容易让人头大。我自己的建议是:不要用最新版,直接用官方v6.0或v7.0版本的稳定分支,因为网上大多数教程、预训练权重和踩坑经验都是基于这些版本积累的,能帮你节省大量排错时间。

下载源码的方式,可以直接从GitHub上clone,也可以下载zip包本地解压。clone的好处是后续可以随时git pull拉更新,但对毕设项目来说意义不大。

环境方面,Python版本建议3.8到3.11之间。PyTorch的安装要和你的CUDA版本对应,这一点特别关键。一般来说,如果你的显卡是NVIDIA的,建议先装CUDA 11.8以上,然后安装对应版本的PyTorch。GPU环境不行的话,CPU版本也能跑,只是训练速度会慢很多,推理勉强能用。

这里要顺带说一句,很多人会忽略requirements.txt里各依赖库的版本关系。yolov5对OpenCV、numpy、matplotlib这些库的版本敏感度其实不高,但torch和torchvision的版本一定要严格匹配,否则会出现_C导入报错之类的问题。

2.2 安装步骤与依赖验证

安装的时候我习惯分两步走。第一步先创建独立的Python虚拟环境,避免污染系统环境,这一步在conda下就是一行命令的事:

conda create -n yolov5 python=3.9 -y conda activate yolov5

第二步进入yolov5目录,安装项目依赖:

cd yolov5 pip install -r requirements.txt

如果CPU版本的PyTorch已经安装好了,这一步只需要装剩下的依赖。如果是GPU环境,建议先手动安装好对应版本的PyTorch,再执行pip install -r requirements.txt,避免依赖自动装上CPU版的torch。

装完之后,验证安装是否成功最快的方式是跑一次官方自带的检测demo:

python detect.py --weights yolov5s.pt --source data/images/bus.jpg

第一次运行会自动下载yolov5s.pt预训练权重,如果能看到输出图像里检测出的公交车和人,说明整个环境就打通了。我习惯跑通这个demo之后再开始下一步,因为后续的训练、推理都依赖这个基础环境的正确性,早验证比晚验证省事得多。

2.3 硬件配置建议与训练规划

关于硬件配置,我的建议非常朴素:有NVIDIA显卡就用GPU,显存8G以上可以比较舒服地训练yolov5s模型,12G以上能尝试yolov5m或更大的模型。没有显卡的话,用CPU训练也不是不行,但要做好心理准备——同样的数据集,GPU跑两个小时,CPU可能要跑两天。

如果条件比较受限,有一个妥协方案:直接用官方预训练权重yolov5s.pt做迁移学习,只冻结backbone层、训练检测头,这样显存和训练时间都能大幅下降。另一个方案是用GitHub Actions或者云GPU平台跑训练,不过对新手来说门槛略高,这里不展开。

3. TT100K数据准备:从原始标注到yolo格式

3.1 TT100K数据格式解析

TT100K的原始标注是JSON格式,这是整个项目里最容易卡住人的一个环节。它的目录结构通常是这样的:

  • train/:训练图片
  • test/:测试图片
  • train.json:训练标注文件
  • val.json:验证标注文件
  • annotations.json:所有标注文件

其中train.json的结构大致是:

{ "imgs": { "0.jpg": { "height": 2048, "width": 2048, "objects": [ { "bbox": [x1, y1, x2, y2], "category": "i100", "id": 1 } ] } } }

注意这里的bbox[左上角x, 左上角y, 右下角x, 右下角y]的格式,跟yolov5要求的[中心点x, 中心点y, 框宽, 框高]不一样,而且数值是像素坐标,没有归一化。如果直接把原始标注拿来训练,模型会直接学崩。所以数据准备的第一步,就是写一个脚本把JSON转成yolov5能识别的TXT格式。

3.2 标注转换脚本的编写要点

转换脚本的核心逻辑其实不复杂,就是把每一张图片的标注信息从JSON里读出来,计算归一化坐标,然后写入到与图片同名的TXT文件中。yolov5对TXT格式的约定是:每行代表一个目标,格式为类别id 中心点x 中心点y 框宽 框高,所有坐标值都是归一化到0到1之间的浮点数。

我写的转换脚本大概长这样:

import json import os def convert_tt100k_to_yolo(ann_file, image_dir, save_dir, class_names): with open(ann_file, 'r') as f: data = json.load(f) for img_name, img_ann in data['imgs'].items(): height = img_ann['height'] width = img_ann['width'] image_id = img_name.split('.')[0] txt_path = os.path.join(save_dir, image_id + '.txt') lines = [] for obj in img_ann['objects']: category = obj['category'] if category not in class_names: continue x1, y1, x2, y2 = obj['bbox'] cx = ((x1 + x2) / 2) / width cy = ((y1 + y2) / 2) / height w = (x2 - x1) / width h = (y2 - y1) / height class_id = class_names.index(category) lines.append(f"{class_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}") if lines: with open(txt_path, 'w') as f: f.write('\n'.join(lines)) if __name__ == '__main__': class_names = ['i100', 'i110', 'p100', 'p130', 'w100'] # 自定义类别列表 convert_tt100k_to_yolo('train.json', 'train', 'labels/train', class_names)

这个脚本里有几个细节值得注意。第一,class_names的顺序决定了类别id的映射关系,一旦确定了就不能轻易改动,否则训练好的模型类别会全乱。第二,如果一张图片里所有目标都不在选定的类别列表里,这张图片和它的TXT文件都会被跳过,后续训练时要注意图片和标签的对应关系。第三,原图是2048×2048的大图,但yolov5训练时会resize到640×640或1280×1280,小目标的标注在resize后可能只剩几个像素,这对检测精度影响很大,后面会专门讲怎么处理。

3.3 数据集划分与类别筛选策略

TT100K的官方划分是训练集和验证集,但实际做训练时,我发现官方验证集的图片数量和标注质量参差不齐,建议自己重新做一次划分。我的做法是:把有标注的图片全部汇总,按照8:1:1的比例随机划分训练集、验证集、测试集,并且保证同一条路段上的图片尽量落在同一个集合里,避免数据泄漏导致评估指标虚高。

类别筛选方面,TT100K全量45个类别里,相当一部分类别的标注数量只有几十个,属于典型的长尾分布。如果全类别训练,模型会对样本量大的类别过拟合,对样本量小的类别基本学不到特征。我的建议是优先保留标注数量最多的前20到30个类别,比如限速标志、禁止通行、注意行人这些高频类别,这样训练出来的模型在实际场景中更有实用价值。

具体筛选时,可以先写个脚本统计每个类别的实例数量,画个柱状图看看分布,再决定保留哪些类别。这一步虽然耗时,但直接决定了模型最终能学成什么样,值得花时间去做。

4. 模型训练与超参数调优

4.1 数据集配置文件(TT100K.yaml)编写

yolov5训练前需要准备一个YAML配置文件,告诉训练脚本去哪里读数据、有多少类别、类别名叫什么。这个文件是训练的入口,写错一个路径或参数,训练就会报错或者跑出一个完全无效的模型。

我常用的配置文件模板:

# TT100K.yaml train: data/TT100K/images/train val: data/TT100K/images/val nc: 20 names: ['i100', 'i110', 'i120', 'p100', 'p130', 'p150', 'w100', ...]

注意这里trainval指向的是图片目录,yolov5会自动在同级目录下找labels文件夹里的TXT标注文件。所以标准的目录结构是:

data/TT100K/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/

如果你的数据集图片和标签不在这个标准结构下,一定记得在YAML里写对路径,或者用软链接把它们组织好。很多同学训练时提示found no labels,90%的情况下都是因为这个目录结构对不上。

4.2 训练命令与关键超参数解析

我在训练时用的命令大概是这样的:

python train.py \ --data TT100K.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 200 \ --device 0 \ --name tt100k_train

逐个参数解释一下:--data指定数据集配置,--weights指定预训练权重,--img指定训练图片尺寸,--batch是批大小,--epochs是训练轮数,--device 0是用第一块GPU,--name是给这次训练起个名字,方便后续在runs/train/目录下区分不同的实验。

超参数里最值得花心思的是--img--batch--img默认是640,对TT100K这种小目标较多的数据集,我建议至少提到1280,这样小标志的细节能保留得更好,代价是训练时间几乎翻倍、显存占用翻倍。--batch受显存限制,24G显存跑yolov5s的1280分辨率,batch大概能开到8到16,如果你的显存不够,可以尝试用--batch 4配合--noplots减少显存占用,或者干脆用yolov5n这个更小的模型。

还有一个很多人忽略的参数是--cache,加上这个参数会提前把图片缓存到内存里,大幅减少训练时读磁盘的开销。如果你的数据集不是特别大,强烈建议加上,实测能提速30%以上。

4.3 训练过程监控与结果分析

训练一旦跑起来,yolov5会自动在runs/train/tt100k_train/目录下记录日志和评估结果。我习惯每隔几十个epoch就打开终端看一下输出,重点看三个指标的变化趋势:box_lossobj_losscls_loss。这三个损失值应该逐步下降,如果某个损失值震荡剧烈或者长时间不降,说明学习率设置不合适,或者数据标注有问题。

训练完成后,weights/best.ptweights/last.pt两个文件会自动保存。best.pt是验证集上mAP最高的权重,last.pt是训练结束时的权重,一般做推理和部署都用best.pt。

另外results.png这张图非常关键,它汇总了训练过程中所有损失和指标的变化曲线,包括mAP_0.5、mAP_0.5:0.95、精确率、召回率等。如果你的mAP_0.5能到0.8以上,说明模型已经相当不错了,放到实际街景里检测常见标志基本够用。

5. 推理实践与工程化部署

5.1 图片、视频与实时检测

模型训练完成后,最直观的验证方式就是用detect.py脚本跑推理。测试单张图片:

python detect.py \ --weights runs/train/tt100k_train/weights/best.pt \ --source test.jpg \ --conf 0.4 \ --device 0

--conf参数控制置信度阈值,默认0.25。交通标志检测建议调到0.4到0.5之间,因为标志牌的纹理相对简单,低置信度的误检会比较明显。--source参数非常灵活,可以传图片路径、视频文件路径,甚至摄像头设备号,比如--source 0就是用第一个摄像头做实时检测。

实际测试的时候,我建议你去找几张TT100K测试集之外的街景图,最好是不同光线、不同天气条件下的,这样可以更客观地评估模型的泛化能力。如果你发现自己训练的数据集上效果很猛,换到真实场景效果暴跌,那大概率是过拟合了,需要回炉做数据增强或者正则化。

5.2 模型导出与嵌入式端部署方向

yolov5最让我满意的一点就是模型导出的便利性。训练好的best.pt可以直接导出成ONNX格式:

python export.py \ --weights runs/train/tt100k_train/weights/best.pt \ --include onnx \ --opset 12

导出ONNX之后,就可以继续转换成各种推理引擎需要的格式。如果是做边缘端部署,现在很多同学会把它部署到瑞芯微RK3568/RV1106这类带NPU的板子上,流程基本是:PyTorch权重 -> ONNX -> RKNN格式,然后调用RKNN的Python SDK做推理。这个过程里最常遇到的问题就是某些算子不兼容,需要回头调整模型结构或者换一个更简单的模型变体。

如果你的项目只是毕设或者演示用,完全不需要走到嵌入式部署这一步,用detect.py做离线推理已经足够展示效果。但如果你想让项目在简历上有更大的亮点,部署到开发板甚至做一个Demo小应用,绝对是个加分项。

6. 常见问题与排查技巧实录

6.1 显存不足与训练中断

显存不足(CUDA out of memory)是训练yolov5最常见的报错之一,我几乎每次带新人都会遇到这个问题。解决策略从优到劣排列:

  • 尝试降低--batch,从16降到8,再降到4,直到能正常跑起来
  • 同时降低--img分辨率,从1280降到640,显存占用大概能降一半以上
  • 如果在1280分辨率下训练小目标太吃力,建议换用多头注意力更好的yolov5m模型而不是强行上大图

如果是长时间训练中断,恢复训练也很简单,找到之前训练保存的last.pt,用--resume参数恢复即可:

python train.py --resume runs/train/tt100k_train/weights/last.pt

6.2 精度低、不收敛怎么办

模型训练出来mAP只有0.3或者损失值震荡不降,这是我被问得最多的问题。排查思路可以参考下面这张速查表:

症状可能原因解决方案
损失值降不下去学习率过大或过小检查训练日志里的lr,尝试降低到0.001或使用warmup
mAP很低但损失正常类别映射错误或标注坐标错误验证TXT标签内容和图片目标的对应关系
小目标完全检测不到训练分辨率太低--img提升到1280,或使用SAHI切片推理
训练集精度高、验证集低过拟合增加数据增强,尝试--hyp自带的增强配置,或降低训练轮数
换场景效果暴跌数据集过拟合增加TT100K之外的补充数据,或者只保留通用性强的类别

这里要特别说一下,很多同学把标注格式转换脚本写完,没有做任何可视化校验直接训练,结果训练完才发现类别框全部偏离目标。我的建议是转换脚本写完之后,一定要用OpenCV或yolov5自带的utils/plots.py把标注框画出来,肉眼检查几组图片确认没问题再开始训练,这个习惯能帮你省下一天的时间。

6.3 标注转换与数据对齐的坑

TT100K还有一个比较隐蔽的坑:原始图片文件名和JSON里的imgs键名可能存在前缀不匹配的问题,比如文件名是0.jpg但JSON里是0。如果这种不一致没有处理好,转换脚本生成的标签就会张冠李戴。我在转换的时候会先打印几个样例,确认键名格式再写正式的转换逻辑。

还有一个问题是图片和标签文件的数量要对齐。yolov5训练时,如果一张图片没有对应的TXT标签文件,它会被直接跳过。如果你发现训练日志里参与训练的图片数量比总数少很多,就去检查是不是标签文件名和图片名没对上。文件名前缀不一致是很常见的原因。

6.4 资料包文档组织建议

既然是“源码+详细文档+全部资料”的形态,文档质量往往比代码本身更影响评估结果。我自己写毕设类文档的习惯是,至少包含六个部分:项目背景与需求分析、技术方案与整体设计、环境搭建与数据准备、模型训练与调优过程、实验对比与结果分析、总结与展望。

其中“实验对比”部分是拉开差距的关键。哪怕你只跑了一组yolov5s的实验,也可以在文档里加入:不同置信度阈值下的检测效果对比、不同天气场景下的检测效果分析、常见误检漏检案例分析。这些内容能充分展示你的工程素养,也方便答辩时应对老师提问。

数据资料方面,建议把数据集样本、标注可视化结果、训练过程截图、检测效果视频整理成独立的附件目录,这些“全部资料”在展示和后续复现时都很加分。

写在最后的一点体会

这个项目我最初做的时候,光是在TT100K标注转换和数据清洗上就花了两天时间,训练调试又花了两天,真正跑通时那种豁然开朗的感觉到现在还记得。回头来看,最大的心得有三条:数据质量比模型结构更重要,任何时候先可视化确认标注不出错再训练;版本锁定很重要,yolov5的代码、PyTorch版本、预训练权重三者匹配能省掉大量排错成本;不要迷恋大模型,yolov5s配合1280分辨率在交通标志识别任务上已经足够惊艳,先把效果打通比追求SOTA指标有意义得多。

如果你拿到类似的资料包,建议不要只停留在跑通Demo,而要按照本文的流程,把数据转换、训练、评估、部署的每一个环节都理解透彻,再试着改一改超参数、换一换模型规模,看看效果差异。做到这一步,你掌握的就不只是一个项目,而是一整套可复用的目标检测工程方法论。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/31 14:50:51

VMware Workstation 虚拟机安装配置全攻略:从下载到网络排错

写 VMware 虚拟机教程最怕遇到两种情况:一是下载时找不到官方渠道,结果装了一堆全家桶;二是装好之后系统能启动,但网络、显示、文件共享各种小问题不断。这篇文章会用一条龙的方式,把 VMware Workstation 下载、安装、…

作者头像 李华
网站建设 2026/8/31 14:50:12

视频点播实战:基于Vue3+HLS.js+Node.js的演唱会点播系统

经典演唱会的长期点播,看起来只是把一个视频文件放到线上。实际上,当用户反复点击播放、拖动进度条、在不同网络环境切换清晰度时,背后涉及视频编码、切片、分发、播放器兼容和内容保护等一系列问题。以《Beyond 1991 生命接触演唱会》这类经…

作者头像 李华
网站建设 2026/8/31 14:49:14

小米手机测试笔试题深度解析:从Android底层到硬件实战

1. 笔试题的命题逻辑与整体考察地图 先说一个很多人对手机测试笔试的误解。不少应届生拿到这种笔试卷,第一反应是“我要把Android源码背下来”或者“我要把所有的测试理论书啃完”,但真实情况是,2019年小米秋招手机测试笔试题(A&a…

作者头像 李华
网站建设 2026/8/31 14:48:30

ONNX Runtime 32位环境部署实战:zip包集成与排错全解析

简介:本资源是专为Windows 32位平台定制的ONNX Runtime C推理引擎开发包(v1.16.2),面向C开发者、嵌入式AI部署工程师及需在x86环境运行轻量级模型的算法工程人员,解决跨框架模型在资源受限Windows设备上的高效集成与低…

作者头像 李华
网站建设 2026/8/31 14:45:50

墨甲机器人背靠奇瑞求上市:机器人公司如何实现独立行走?

这几年机器人赛道最热,但也是最难看懂的一条赛道。一边是资本市场不断给“具身智能”“人形机器人”讲故事,一边是产业链上大量公司还在为“能不能获得一个大客户订单”发愁。就在这种背景下,墨甲机器人带着“背靠奇瑞”的标签走向了上市之路…

作者头像 李华
网站建设 2026/8/31 14:43:33

YOLOv5+CRNN中文车牌识别实战:从数据到部署全流程解析

简介:本资源是一套完整的中文车牌识别高分项目实现,基于YOLOv5实现车牌定位、CRNN模型完成字符识别,面向人工智能、自动化、电子信息等专业学生及初学者,适用于毕业设计、课程设计、项目演示与算法进阶学习。压缩包共92个文件&…

作者头像 李华