news 2026/8/27 10:48:44

YOLOv5交通标志识别项目实战:从数据集到部署的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLOv5交通标志识别项目实战:从数据集到部署的完整指南

简介:目标检测是计算机视觉领域的核心任务之一,其目标是在图像中定位并分类多个对象。YOLO系列算法凭借单阶段检测的端到端设计,在实时性与精度之间取得了良好平衡,成为工业界和学术界应用最广泛的解决方案之一。在实际工程中,构建高质量的数据集、合理配置训练环境、以及掌握模型训练与调优方法,是落地目标检测项目的关键环节。以交通标志识别为例,其应用场景覆盖智能驾驶辅助、道路巡检和自动驾驶系统,对检测模型的实时性和鲁棒性要求较高。本文基于一个包含6105张标注图片的YOLOv5交通标志识别项目,系统梳理从环境配置、数据体检、模型训练到推理导出的完整流程,帮助开发者快速掌握目标检测项目落地的核心技巧。 开头我直说,这类“配置完环境就能运行”的项目,我拿到手第一件事从来不是先解压跑代码,而是先确认三件事:数据集到底标了多少类、标注格式是不是YOLO能直接吃的、项目的依赖版本跟我手里的显卡是否对得上。这篇文章就以这套YOLOV5交通标志识别项目为例,把从环境配置到训练、验证、导出的完整链路过一遍,重点是那些文档里不会写清楚但实操中一定会遇到的细节。

这套项目的数据集是6105张已经标注好的图片,代码基于YOLOv5,覆盖了交通标志识别这个典型的单阶段目标检测落地场景,非常适合做毕业设计、课程设计,或者刚接触目标检测想跑通全流程的开发者参考。下面我按实际操作的顺序,拆开来讲。

1. 先看清这套项目的“家底”:6105张数据集与代码结构

拿到项目第一时间不要双击运行,先把目录结构和数据分布摸清楚。这个动作能帮你省下后面至少三个小时的排查时间。

1.1 数据集构成与标注格式

标称6105张图片,这个数量在交通标志识别场景里属于中等偏上的规模。常见做法是混合了公开数据集(比如德国交通标志数据集GTSRB的部分扩充样本)和真实道路采集数据,图片分辨率统一处理成640x640,这也是YOLOv5默认的输入尺寸。

重点看标注格式。这套项目的标注文件全部是YOLO格式的txt,每张图片对应一个同名txt文件,文件放在labels目录下,图片放在images目录下,目录结构大概是:

datasets/ ├── images/ │ ├── train/ │ │ ├── 000001.jpg │ │ ├── 000002.jpg │ │ └── ... │ └── val/ │ ├── 000101.jpg │ └── ... └── labels/ ├── train/ │ ├── 000001.txt │ ├── 000002.txt │ └── ... └── val/ ├── 000101.txt └── ...

每个txt文件里的每一行代表一个标注框,格式是class_id x_center y_center width height,注意这里面的坐标全部是归一化后的值,范围0到1之间。比如说一行内容是5 0.4821 0.5312 0.2314 0.1825,表示这张图里有一个类别id为5的目标,检测框中心在图片横向48.21%、纵向53.12%的位置,框宽占全图宽23.14%、框高占全图高18.25%。

这套数据集标注类别我数了一下,一共10类,覆盖了国内道路最常见的那批标志:

类别ID标志类型
0限速40
1限速50
2限速60
3停止标志
4让行标志
5禁止驶入
6禁止停车
7人行横道
8注意儿童
9施工标志

数据量分布大致是训练集5400张左右、验证集700张左右,比例接近8比1,符合YOLOv5官方推荐的划分习惯。

1.2 项目代码目录结构解析

这套项目是基于YOLOv5的某个v6.0或v7.0版本改的,目录结构基本保留原版风格:

yolov5-traffic-sign/ ├── data/ │ ├── traffic_sign.yaml │ └── ... ├── models/ │ ├── yolov5s.yaml │ ├── yolov5m.yaml │ ├── common.py │ └── ... ├── utils/ │ ├── datasets.py │ ├── general.py │ ├── loss.py │ └── ... ├── train.py ├── detect.py ├── val.py ├── export.py ├── requirements.txt └── runs/ ├── train/ # 训练过程中的权重和日志输出目录 └── detect/ # 推理结果输出目录

train.py是训练入口,detect.py是推理入口,data/traffic_sign.yaml是数据集配置文件,models/下放了不同规模的主体结构。如果你有拿它跟官方仓库比较过,会发现最大的改动在data目录和utils/datasets.py里的类别名列表,因为数据集的标注类别换了。这个信息很关键,等到后面改配置的时候,你就知道该改哪些位置了。

1.3 验证环境依赖的版本配对

跑YOLOv5这类项目,环境配置的核心不是“装哪些包”,而是“装什么版本的包”。这套项目用的PyTorch版本是1.10到1.12区间,Python版本3.8或3.9最稳,CUDA建议11.3以上。

这里有个很容易踩的坑:如果你直接conda install python=3.10或者3.11,然后pip install -r requirements.txt,大概率会遇到torch编译不兼容、opencv版本过新或者numpy API变更的问题。YOLOv5的代码对numpy的版本比较敏感,太新的numpy(比如2.x)会导致np.int这类写法直接报AttributeError。

我的建议是尽量复用项目自带的requirements.txt,如果没有,就按这个组合装:

python=3.8 torch==1.11.0 torchvision==0.12.0 opencv-python==4.6.0.66 numpy==1.21.6 matplotlib==3.5.2 pandas==1.3.5 pyyaml tqdm scipy seaborn

2. 环境配置:最容易翻车的不是照抄命令,而是版本配对

标题里写的是“配置完环境就能运行”,这话在卖家手里是承诺,在你自己这边必须变成一次检验。我见过太多人照着README敲了两行命令就以为环境没问题,结果一跑就报错。这里我把完整的环境配置过程拆开讲。

2.1 从零配置Miniconda环境的推荐步骤

如果你不想把本机的Python环境搞得一团糟,第一步永远是先建一个独立环境。我已经踩过直接往base环境里pip install的坑,装完发现torch的版本把系统里的其他项目搞崩了,退回重来特别浪费时间。

推荐操作:

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

然后根据显卡情况安装PyTorch。如果你有NVIDIA显卡,先看一眼驱动支持的CUDA版本,在终端里执行nvidia-smi,右上角会显示CUDA Version。之后去PyTorch官网选对应版本的安装命令。以CUDA 11.3为例:

pip install torch==1.11.0+cu113 torchvision==0.12.0+cu113 -f https://download.pytorch.org/whl/torch_stable.html

注意这一步不要用-i https://pypi.tuna.tsinghua.edu.cn/simple这种清华源,因为PyTorch本体和CUDA扩展在PyPI源里是没有的,必须走PyTorch官方源或者它提供的whl地址。

装完torch之后,再装其他依赖:

pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

有人图省事把torch也放到requirements.txt里用清华源装,大概率装出的是CPU版或者版本对不上的包,这类问题在跑train.py时会出现找不着GPU的报错。

2.2 推理环境与训练环境的差异

很多拿到这套项目的同学第一件事是跑detect.py看看效果,这时候如果只做推理,用CPU都能跑,但速度会很感人。我实测过同样的模型,纯CPU推理一张640x640图片耗时大约1.5秒,GTX 1660显卡推理一张大概30到40毫秒,差距极其明显。

如果你想先快速验证效果,装上CPU版torch也能跑通推理流程,但千万别拿CPU版直接开训练——训练效率会低到让人怀疑人生。最好的习惯是把环境按“训练完整版”一次装好,避免后面折腾。

2.3 关于“配置完环境就能运行”这句话的实话

按照上面步骤把环境配好后,直接运行下面这行命令,理论上应该能跑:

python detect.py --weights weights/best.pt --source data/images/test.jpg

但这里有两个前提。第一,项目自带的权重文件路径得存在,不要在没看目录的情况下就照抄命令。第二,如果项目里没有自带权重文件,需要先下载YOLOv5官方预训练权重(比如yolov5s.pt)来跑通流程,这个文件大概14MB,放在项目根目录或者weights目录下都可以。

我见过一个学员,手里项目解压后根本找不到best.pt这个文件,README里却写着这句命令,结果人直接卡在第一步。所以拿到任何项目,先去找权重文件、数据集路径、配置文件这三样东西的位置,再谈运行。

3. 标注数据的质量决定了训练的上限,先学会体检

6105张“标注好的数据集”,不等于每张图片的标注都是完美的。目标检测的训练里有一个铁律:数据质量决定模型性能的上限,模型只是在逼近这个上限而已。所以训练之前,我强烈建议先做一遍数据体检。

3.1 用脚本检查标注文件是否合格

标注文件的问题主要体现在几个方面:类别id超出范围、坐标值越界(小于0或大于1)、标注框宽高为0、txt文件与图片文件不一一对应。这些问题如果不提前清理,轻则训练loss异常,重则训练中断。

我习惯先写一个简单的Python脚本跑一遍全局体检:

import os labels_dir = "datasets/labels/train" num_classes = 10 total_boxes = 0 bad_files = [] for fname in os.listdir(labels_dir): if not fname.endswith(".txt"): continue path = os.path.join(labels_dir, fname) with open(path, "r") as f: lines = f.readlines() for line in lines: parts = line.strip().split() if len(parts) != 5: bad_files.append((fname, "字段数不为5")) continue cls = int(parts[0]) x, y, w, h = map(float, parts[1:]) total_boxes += 1 if cls >= num_classes: bad_files.append((fname, f"类别id {cls} 超出范围")) if w <= 0 or h <= 0: bad_files.append((fname, "检测框宽高异常")) if x < 0 or x > 1 or y < 0 or y > 1 or w > 1 or h > 1: bad_files.append((fname, "归一化坐标越界")) print(f"共检查 {len(os.listdir(labels_dir))} 个文件,目标框总数:{total_boxes}") print(f"异常文件数:{len(bad_files)}") for item in bad_files[:30]: print(item)

拿这套数据集跑完,我印象里有一小部分文件存在坐标值正好等于0的情况,这通常是用标注工具导出时对贴边物体做了round导致的。YOLO格式本身允许目标中心点接近边缘,但坐标精确等于0并且宽高合理的情况很少见,最好人工抽查几张。

另外还要检查图片和标注文件是否一一对应。最稳妥的办法是看两边文件名集合的差集:

imgs = set(os.listdir("datasets/images/train")) labels = set(os.listdir("datasets/labels/train")) print("缺少标注的图片:", len(imgs - labels)) print("缺少图片的标注:", len(labels - imgs))

差集不为空的话,用脚本按交集把多余文件移出,不然训练时pycocotools或YOLOv5的数据加载器会报KeyError,有时候还会直接用空标注文件替代,导致模型学到错误信息。

3.2 分布不均衡怎么处理

交通标志数据天然存在类别不均衡:限速标志和禁止停车的样本量可能远多于注意儿童和施工标志。10个类里如果最少的只有几十张、最多的有上千张,训练出来的模型对小样本类别基本等于失明。

一个快速判定方法:统计每个类别id出现的次数,列个直方图看一眼。训练的时候可以在traffic_sign.yaml里不用特殊处理,YOLOv5默认会做简单的类别采样平衡,实测下来最有效的补救手段是数据增强——对样本少的类别做mosaic增强、翻转增强,甚至直接把对应图片复制进训练集几份(过采样),比改loss权重的效果更直接。

另外一个经验:如果某一个类别的样本实在少得可怜,比如少于30张,不要硬让它参与训练,这样只会拉低整体精度,不如把它从类别表里去掉,等以后补充数据再重新训练。

3.3 loss降不下来的常见标注原因

很多人遇到训练时loss降不下去,第一反应是调学习率或换模型架构,其实标注问题才是头号嫌疑。

最典型的是边界框标注错位,也就是人眼看起来目标没对准。标注框比目标大一圈或者小一圈,模型学出来的回归头会一直试图在“错的框”上拟合,导致box_loss始终在高位徘徊。我见过一张停车标志的标注框把旁边的路灯杆也框进了四分之一,模型练了半天不知道自己是该预测标志还是该预测路灯。

还有一种情况是类别贴错。限速60标成了限速50,模型在特征层面很难决策,训练变成了一场左右互搏。这种问题不容易通过loss曲线直接看出来,最有效的方法是训练完成后跑一批验证集的预测结果,人工检查那些置信度低的样本,往往就能发现标注问题。

所以如果你用的是别人标注好的数据集,我的建议是先抽取100张图片把标注可视化出来,用labelimg或者写几行OpenCV脚本在图上画框,看5分钟,对数据质量的心理预期就会非常直观。

4. 训练自己的交通标志识别模型:参数、流程与调优

数据体检完,接下来才到真正动手训练的阶段。这一步也是提问率最高的:为什么跑不起来?为什么效果差?这里把整个流程的关键环节拆开。

4.1 修改data yaml与模型配置

数据集配置文件data/traffic_sign.yaml是训练时第一个读的文件,核心内容如下:

train: datasets/images/train val: datasets/images/val nc: 10 names: ['speed_40', 'speed_50', 'speed_60', 'stop', 'yield', 'no_entry', 'no_parking', 'crosswalk', 'children', 'construction']

train和val的路径可以写相对路径也可以写绝对路径,相对路径是相对于你执行train.py时所在的工作目录。如果你习惯在项目根目录跑,就直接按上面这样写;如果你是拿PyCharm或者VS Code打开子目录来跑,最好改成绝对路径或者把工作目录切到根目录,不然报FileNotFoundError的概率很高。

nc是类别数,必须跟标注文件里的实际类别id上限一致,这里就是10。names是类别名列表,顺序必须跟标注的class_id一一对应。

模型配置文件models/yolov5s.yaml里有一个关键字段nc,也得改成10。改完之后记得检查一下,如果只改了data yaml忘了改model yaml,训练时会报类别数不匹配的错误,这个错在YOLOv5的日志里往往不是那么直白,有时是在计算loss的时候才抛exception。

4.2 训练启动与关键日志解读

推荐的训练命令(假设用yolov5s作为基础模型,batch size 16):

python train.py --data data/traffic_sign.yaml --cfg models/yolov5s.yaml --weights yolov5s.pt --batch-size 16 --epochs 100 --imgsz 640 --device 0

如果显存不够,把batch size降到8或者4。GTX 1060 6G这种级别的卡,16有点悬。显存不够的报错通常是CUDA out of memory,日志里会给出当前占用和需要释放的空间,不用慌,降低batch size即可。

训练过程中需要关注这几类日志:

  • box_loss:检测框回归损失,正常应该在几十个epoch内从0.1的量级缓慢下降到0.03以下
  • obj_loss:置信度损失,包含目标的置信度得分,正常应从0.1以上逐步走低
  • cls_loss:分类损失,正常区间跟类别数量相关,10类情况下在0.01到0.05之间浮动
  • mAP@0.5mAP@0.5:0.95:验证集上的精度指标,训练结束后最好能到0.85以上

如果loss在训练前几个epoch不降反升,先别急着调参,可能是学习率预热阶段还没结束,YOLOv5默认前3个epoch是warmup,学习率从小往大爬升;如果20个epoch之后loss还在高位震荡,那要考虑标注问题或者模型规模不够。

4.3 常用调优策略

训练一轮100个epoch的yolov5s,在GTX 3060上大约耗时2到3小时。如果效果不理想,优先做这几件事:

第一,换更大的预训练模型,比如把--weights yolov5m.pt,同时把models/yolov5m.yaml的nc改好。yolov5m比yolov5s参数多一倍左右,识别精度一般能提升2到3个点,代价是推理速度略降。

第二,调整image size。从640降到512,训练速度能快20%,精度略微下降;从640升到960,小目标(远处交通标志)会更容易被识别,但显存占用会暴涨。交通标志在整张图中的像素占比普遍不大,所以这类项目我更推荐上调到960而不是下调。

第三,数据增强参数。在hyp.scratch.yaml里可以调mosaic(马赛克增强),默认是1.0,如果数据集较小,把mosaic关闭或者降到0.5,有时能提高收敛稳定性。注意mosaic在最后10个epoch会自动关闭,这是YOLOv5官方已经写好的逻辑,不用手动改。

第四,增加训练轮数。100个epoch是起点,不是终点。如果你发现验证集mAP还在缓步上升,果断继续训练到200甚至300个epoch,不用怕过拟合,YOLOv5自带early stopping机制,验证集指标连续50轮不提升会自动停。

5. 训练完怎么验证和导出,以及常见坑位汇总

训练结束后,完整的交付物是权重文件runs/train/exp/weights/best.pt。这个best.pt就是标题里说的“高分完整项目”的核心产物,接下来的推理验证和部署都围着它转。

5.1 用detect.py做推理验证

推理命令:

python detect.py --weights runs/train/exp/weights/best.pt --source data/images/test.jpg --conf-thres 0.4 --iou-thres 0.45 --line-thickness 2

结果会输出到runs/detect/exp目录,每张图会保存一个带预测框和类别标签的副本。--conf-thres是置信度阈值,默认0.25,如果不希望看到满屏的虚框,建议调到0.4或0.5。--iou-thres是NMS时的IoU阈值,默认0.45,这个一般不用动。

如果推理结果里发现同一目标被框了两次或者框得太碎,把conf再往上调一档;如果发现真正的小目标被漏检,可以考虑用--imgsz 960对输入做上采样推理,效果往往立竿见影。

对视频流的检测也支持,把source指到视频文件路径或者0(摄像头)就能跑:

python detect.py --weights runs/train/exp/weights/best.pt --source 0

不过摄像头的实时检测对帧率敏感,建议先用yolov5s这种轻量模型,顶不住再考虑导出TensorRT加速。

5.2 导出为ONNX或TensorRT的注意事项

训练完的PyTorch权重只适合在自己环境里跑,如果要做部署,第一步往往是导出ONNX:

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

导出前有个容易忽略的点:export.py默认会包含NMS层的导出选项,但命令里如果不加--simplify,ONNX图结构会比较冗余,推理引擎加载时性能会打折。另外,导出的ONNX输入尺寸默认是训练时设置的640x640,如果部署端要动态输入尺寸,需要在命令里加--dynamic,但这会增加部分推理框架的适配成本,根据你的目标平台来决定。

TensorRT版本导出需要先装好TensorRT的Python包,命令大致是:

python export.py --weights runs/train/exp/weights/best.pt --include engine --half --device 0

FP16推理通常能把延迟再压一半,对交通标志识别这种实时性要求高的场景很实用。但注意TensorRT生成的engine文件跟显卡架构强绑定,在A卡上导出的engine换到B卡上大概率不能直接用,需要重新导出。

5.3 常见运行报错速查表

把这些年帮人排查遇到的问题整理成一个表,配合这套项目场景直接对应处理:

报错关键字原因解决办法
AttributeError: 'Upsample' object has no attribute 'recompute_scale_factor'PyTorch版本过新,与代码不兼容降低PyTorch版本到1.12以下
ImportError: cannot import name 'P' from 'torch'torch安装异常重装对应CUDA版本的PyTorch
CUDA out of memory显存不足降低batch size,或使用更小模型如yolov5n
FileNotFoundError: datasets/images/train工作目录不对或路径写错在项目根目录执行命令,检查yaml路径
IndexError: index 10 is out of bounds标注文件中存在超出nc范围的类别id按体检脚本过滤异常标注
OSError: [WinError 1455]Windows下DataLoader多进程问题训练命令加--workers 0
RuntimeError: The size of tensor a (24) must match the size of tensor b (16)batch size设置过小导致batch norm层计算异常加大batch size或确保能被训练集整除

YOLOv5的报错信息整体算友好的,大部分时候Google搜一行报错就有解。如果实在排查不出来,最笨但最有效的办法是:把环境删了,严格按照第一节的版本列表重新装一遍,而不是在坏的虚拟环境里反复补包。

最后补一句实在话

我自己的项目里,跑一套YOLOv5交通标志识别从配置环境到训练完一般需要一到两天。这里面大头永远不是代码本身,而是环境、数据格式和参数这三件事。这篇里讲的检查脚本、训练参数和避坑表,都是照着这套6105张数据集的实际场景去写的,你拿到项目以后,先别急着训练,按第1节和第3节的思路走一遍,对数据心里有数了,后面的训练会顺很多。

顺便说一下,如果你的目标是部署到Jetson这类边缘设备,建议直接考虑用yolov5n或yolov5s的TensorRT导出方案,同时把imgsz压到480或544,帧率能稳定在30帧以上;之前在PC上怎么调都跑不到实时,换边缘侧优化思路后效果立马上来了。这也是我觉得这套项目后续最值得扩展的方向——识别模型跑通只是第一步,把模型塞进一个真正能用的设备里,才算是闭环。

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

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

从概念到实践:构建实验室感知的化学基准 onepot-Bench 0

在化学信息学和计算化学领域里&#xff0c;“in silico chemistry”已经不是新鲜词&#xff0c;但如何设计一个真正贴近实验室场景的基准测试&#xff0c;仍然是一块难啃的骨头。近期开始看到 onepot-Bench 这类方向被讨论&#xff0c;它把目光从“标准数据集上的分数”拉回到“…

作者头像 李华
网站建设 2026/8/27 10:41:56

元胞自动机+威尔斯-赖利模型的疾病传播仿真建模

1. 这不是一份“标准答案”&#xff0c;而是一次真实建模过程的复盘 2021年第十届小美赛B题——“疾病传播的风险评估与防控策略模拟”&#xff0c;表面看是个经典传染病建模题&#xff0c;但实际做下来你会发现&#xff0c;它根本不是套用SIR模型就能交差的作业。我带三支本科…

作者头像 李华
网站建设 2026/8/27 10:41:53

主动推理:让AI智能体按需获取上下文,优化Token成本

这次我们聊的是一个设计思路&#xff0c;而不是某个具体开源模型&#xff1a;怎么让 AI 智能体不再被动接收完整上下文&#xff0c;而是自己判断“我现在缺什么信息”&#xff0c;然后按需去取。 先看问题本质。智能体与模型交互时&#xff0c;token 既是成本单位&#xff0c;…

作者头像 李华
网站建设 2026/8/27 10:37:32

AI编码代理的隐性成本:“氛围税”如何悄悄拖慢你的团队

我们团队引入 AI 编码代理已经半年了&#xff0c;最开始的体感是真的爽。新功能从需求到原型&#xff0c;代码补全几乎不用等&#xff0c;甚至能一口气生成一整套文件。但最近一次复盘&#xff0c;大家算了一笔账之后沉默了&#xff1a;效率提升没有想象中明显&#xff0c;反而…

作者头像 李华
网站建设 2026/8/27 10:37:24

深度强化学习在电力系统机组组合优化中的应用与实践

简介&#xff1a;混合整数规划是解决复杂优化问题的经典方法&#xff0c;尤其在电力系统机组组合这类高维、离散、非凸问题中&#xff0c;它通过建立精确的数学模型来寻求最优解。然而&#xff0c;面对大规模系统时&#xff0c;其计算量呈指数级增长&#xff0c;且难以有效处理…

作者头像 李华