news 2026/9/12 21:56:04

YOLOv5交通标志检测:从数据预处理到ONNX部署完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLOv5交通标志检测:从数据预处理到ONNX部署完整指南

简介:YOLOv5交通标志物检测完整工程包,面向计算机相关专业正在准备课程设计、期末大作业的学生,以及需要完整项目进行实战练习的深度学习学习者。项目以YOLOv5为检测框架,整合了源代码、训练好的权重模型、标注数据与训练配置,覆盖从数据整理、模型训练、效果评估到单张/视频推理的完整链路,能够直观展示目标检测在实际交通场景中的应用方式。压缩包共266个文件,体积423MB,文件类型以Python脚本、YOLO系列配置、模型权重、图像样本为主,同时包含训练日志、指标统计和Docker部署文件,兼顾二次开发与部署实践需求。目前已有362人学习浏览,项目源码经过严格调试,下载后按照说明即可直接运行,免去复杂的环境搭建与数据集准备流程。对需要完成课程报告或答辩演示的同学来说,包内训练记录、结果曲线和模型性能数据都是现成的支撑材料,适合作为高分项目参考或在此基础上做算法优化。

1. 拿到YOLOv5交通标志物检测项目包后,先确认这三件事

这种“源码+训练好的模型+全部数据”的压缩包看似一步到位,但最常见的问题不是模型不收敛,而是你拿到手就直接双击 train.py,结果在数据加载阶段就抛异常。解压之后我会按三步走:先确认目录是不是自包含的,weights、data、models、runs 这些关键目录是否齐全;再确认权重文件是完整 checkpoint 还是只用于推理的 stripped 模型,前者能接着训练,后者只能做推理;最后检查数据集标注是不是 YOLO 的 txt 格式,而不是 VOC 的 xml 或 COCO 的 json。

交通标志检测和通用目标检测不太一样。标志在画面里往往只占几十个像素,而且数据集之间的类别定义差异很大,TT100K 有 45 类,CCTSDB 只有 3 类,直接拿别人训练好的模型跑你的测试图,很可能类别名对不上、mAP 跌一半。所以先搞清楚这个包里的数据分布和标签结构,比急着复现训练更重要。这个项目通常用于课程设计、毕业设计或小规模道路巡检验证,正确打开方式是把模型、数据和代码三个部分分别校验一遍。

2. YOLOv5交通标志物检测的网络结构和数据集格式

2.1 从CSPDarknet到三尺度检测头,YOLOv5网络结构如何服务小目标

要真正用好 YOLOv5,不能只会跑命令。YOLOv5 的网络结构分成三块:Backbone 是 CSPDarknet,Neck 是 PANet,Head 是三个不同尺度的检测头。CSP 模块把特征图沿通道分成两路,一路做卷积提取,一路通过 short-cut 直连,既减少计算量又保住梯度流。PANet 在 FPN 的基础上增加了一条自下而上的路径,让高层语义信息和小目标的细节纹理双向融合,这对交通标志这种小目标尤其关键。

Head 部分在 80x80、40x40、20x20 三个特征层上输出预测框。80x80 的网格负责捕捉小目标,感受野小;20x20 的网格负责大目标。交通标志在 1080p 路面上可能只有 20x20 像素,如果输入图像被缩得太小,小目标特征直接丢光。所以做交通标志物检测时,我一般会把输入尺寸从默认的 640 提到 1280,或者至少开 multi-scale 训练。YOLOv5 的 anchor 是在训练时基于你的数据集重新计算的,换数据集后如果还沿用 COCO 的 anchor,前几个 epoch 会明显不稳定。

2.2 数据集目录结构和 YOLO txt 标签格式

拿到项目包后,先看 data 目录是不是这样的结构:

project/ ├── data/ │ ├── images/ │ │ ├── train/ │ │ └── val/ │ ├── labels/ │ │ ├── train/ │ │ └── val/ │ ├── classes.txt │ └── traffic.yaml ├── weights/ │ ├── best.pt │ └── last.pt ├── models/ └── scripts/

如果 labels 目录是空的,那数据还需要预处理。YOLO 的标签每一行是五个浮点数:类别索引、归一化后的中心点 x、中心点 y、宽度、高度。比如图像宽 1920 高 1080,一个限速标志落在 (100, 200) 到 (160, 280),标签行就是:

0 0.06771 0.22222 0.03125 0.07407

类别索引对应 classes.txt 里的顺序,0 表示第一类,不是中文名称。这里有个常见的脏数据:标注框坐标越界,x2 比图像宽度大几十像素。YOLOv5 在训练时会报坐标警告,不致命但会影响框回归精度。我习惯先写一个脚本统计缺失标签的图片:

import os img_dir = 'data/images/train' label_dir = 'data/labels/train' missing = 0 for name in os.listdir(img_dir): stem = os.path.splitext(name)[0] if not os.path.exists(os.path.join(label_dir, stem + '.txt')): print('missing label:', name) missing += 1 print('missing count:', missing)

这个脚本的逻辑很简单:图片文件名和标签名必须一致,只是后缀不同。缺失标签要么是数据整理时漏拷了,要么是这张图本身没有目标。如果没有目标的图片也放在 train 目录,最好单独清掉,否则 YOLOv5 会把它当成背景训练,影响 recall。

2.3 把 VOC XML 转成 YOLO 标签,避免手动标注浪费时间

项目如果给的标注是 Pascal VOC 的 xml,转换代码可以这样写:

import xml.etree.ElementTree as ET def voc_label_to_yolo(xml_path, out_txt, classes): root = ET.parse(xml_path).getroot() w = int(root.find('size/width').text) h = int(root.find('size/height').text) lines = [] for obj in root.iter('object'): name = obj.find('name').text if name not in classes: continue box = obj.find('bndbox') x1 = float(box.find('xmin').text) y1 = float(box.find('ymin').text) x2 = float(box.find('xmax').text) y2 = float(box.find('ymax').text) x_c = (x1 + x2) / 2.0 / w y_c = (y1 + y2) / 2.0 / h bw = (x2 - x1) / w bh = (y2 - y1) / h cls_id = classes.index(name) lines.append(f'{cls_id} {x_c:.6f} {y_c:.6f} {bw:.6f} {bh:.6f}') with open(out_txt, 'w') as f: f.write('\n'.join(lines))

使用前把 classes 列表按训练数据集的类别文件顺序填好。转换时如果 x2 比 w 大,要先 clip 再归一化,否则生成的 width 会大于 1,YOLOv5 对这类标签的过滤策略不一定每次都报错。

2.4 不同交通标志数据集的类别映射不要混着用

常见的交通标志检测数据集差异很大,训练前先看项目里的 classes.txt:

数据集类别数典型类别
TT100K45i100, p26, pl100 等标志编号
CCTSDB3prohibitory, warning, mandatory
GTSDB43各类限速、禁行、提示标志

如果压缩包里的权重是用 CCTSDB 训练的,模型输出层就是 3 个类别,拿去做 TT100K 的 45 类评估,结果一定很差。所以训练自己的数据前,先确认 dataset.yaml 里的 nc 和 names 跟标签里的类别索引对齐。这一步比调学习率重要得多。

3. 本地复现YOLOv5交通标志物检测:环境、权重和推理

3.1 安装依赖并跑一次最小推理命令

解压项目后,先建虚拟环境装依赖。不要用系统 Python 直接装,YOLOv5 的依赖版本敏感,torch 和 torchvision 版本不匹配会直接报错。

cd YOLOv5交通标志物检测源码目录 python -m venv venv source venv/bin/activate pip install -r requirements.txt

requirements.txt 里通常包含 torch、torchvision、opencv-python、numpy、matplotlib、PyYAML、tqdm 等。如果机器是 NVIDIA GPU,按你装的 CUDA 版本选择对应的 torch 版本;如果是 CPU 机器,直接装 CPU 版即可,交通标志检测用 CPU 也能跑推理,只是训练会很慢。

环境装好后,先用模型对单张图片做推理:

python detect.py \ --weights weights/best.pt \ --source data/images/val/00001.jpg \ --conf-thres 0.25 \ --img-size 640 \ --save-txt

其中--source可以是单张图片、文件夹、视频文件或摄像头编号。--conf-thres是置信度阈值,低于 0.25 的框会被过滤掉;交通标志小目标置信度普遍偏低,可以降到 0.2 试一下。--save-txt会把每个框的类别和归一化坐标写入 runs/detect 目录,方便后面核对标注位置。

3.2 detect.py 关键参数表与交通标志场景推荐值

参数默认值交通标志场景建议
--weightsyolov5s.pt换成项目自带的 best.pt
--source单张图片先用一张图跑通,再跑视频
--conf-thres0.250.2 到 0.3 之间,低了误报多,高了漏检
--iou-thres0.45标志密集时降到 0.3
--img-size640小目标场景用 1280 或 1280 的倍数
--devicecpu有 GPU 时指定 0
--save-txt建议开启,方便检查坐标
--projectruns/detect管理多次实验输出

--img-size是推理时缩放到输入尺寸,不是原图尺寸。交通标志检测建议不要低于 640,否则远端小标志会被压缩成几个像素,检测器再强也识别不出。代价是推理速度变慢,可以用 TensorRT 或 ONNX Runtime 缓解。

3.3 先检查权重文件再推理,避免加载出空模型

很多 zip 里的 best.pt 是训练中途保存的完整 checkpoint,包含模型结构、优化器状态、epoch 和类别名;但也有的被剥成 deploy 版本,只能推理。用一个小脚本看权重结构:

import torch ckpt = torch.load('weights/best.pt', map_location='cpu', weights_only=False) print(ckpt.keys()) if 'model' in ckpt: model = ckpt['model'].float().eval() print('names:', model.names) print('stride:', model.stride) else: print('no model key, only state_dict')

如果输出里names是字典,说明模型自带类别名;如果为空,需要你在调用 detect.py 时补一个 dataset.yaml。stride是三个检测头的下采样倍数,正常是 [8, 16, 32],看到这个值说明模型结构加载完整。忽略这一步直接跑,容易把类别数量不一致的模型当成可用权重,推理结果全是 0 个目标。

3.4 推理阶段最常见的三个错误

第一个是报Label class N exceeds nc=N_cfg in data/yaml,这不是推理问题,是训练标签写错了,后面训练章节会细说。第二个是CUDA out of memory,模型本身不大,但输入图开到 1280 后显存占用会成倍增加,先检查是不是真的用到了 GPU 和 batch size。第三个是图片路径含中文,OpenCV 默认读取不了,把测试集改成英文路径。

提示:如果 detect.py 输出了框但全标成无关类别,先检查 weights 和 dataset.yaml 是否属于同一个数据配置。跨数据集的模型耦合在类别列表上,路径、文件名对不上最典型的表现就是“检测到东西但全是错类”。

4. 用YOLOv5训练自己的交通标志数据集和超参数调优

4.1 写好 traffic.yaml,类别数和标签强相关

训练自己的数据集,第一步是建 dataset.yaml:

path: ./data train: images/train val: images/val nc: 3 names: 0: prohibitory 1: warning 2: mandatory

path是相对 dataset.yaml 所在目录的根路径,YOLOv5 会把 path、train、val 拼接成最终目录。nc必须和标签文件里最大类别索引 +1 相等。如果 names 里写了 3 个类别,但某个标签第 6 个数据是3 0.5 0.5 0.2 0.2,训练会直接报类标签越界。

检查标签越界可以跑一条命令:

python - <<'PY' from pathlib import Path for p in Path('data/labels/train').glob('*.txt'): for line in p.read_text().strip().splitlines(): if line and int(line.split()[0]) >= 3: print(p, line) PY

这个脚本用 heredoc 方式执行 Python,逻辑是遍历所有 txt,把第一列类别索引不小于 3 的行打印出来。输出有内容就先修数据,不要带着脏标签训练。

4.2 train.py 训练命令和参数说明

训练命令我一般写成这样:

python train.py \ --data data/traffic.yaml \ --weights yolov5s.pt \ --cfg models/yolov5s.yaml \ --img 640 \ --batch-size 16 \ --epochs 100 \ --hyp data/hyps/hyp.scratch-low.yaml \ --project runs/train \ --name traffic_exp

--weights yolov5s.pt使用 COCO 预训练权重做迁移学习,交通标志这种小数据集从零训练容易欠拟合,用预训练权重能明显加快收敛。--cfg指定模型结构文件,必须和--weights对应,yolov5s.pt 配 yolov5s.yaml,不能拿 yolov5m 的结构去加载 s 的权重。--hyp是超参数文件,交通标志场景推荐 hyp.scratch-low.yaml,因为数据量通常不大,过强的数据增强反而让模型学不到特征。

4.3 超参数怎么调:从lr0到mosaic

关键超参数我列在表里:

超参数默认值调整建议
lr00.01数据集小于 5000 张时降到 0.005
lrf0.01最后学习率是初始学习率的 1%,一般不动
warmup_epochs3.0前 3 个 epoch 用低学习率热身
mosaic1.0小目标占比高时保持 1.0
mixup0.0类别少且相似时不要开
fl_gamma0.0背景多、正样本少时调到 1.5

mosaic是拼接四张图训练,对提升小目标召回有奇效,但交通标志之间形态差异大,拼接太猛会导致上下文失真。如果你的训练 loss 一直震荡,先看lr0是不是太大,而不是持续加训练轮数。

4.4 训练过程异常排查和指标验证

训练过程中实时看runs/train/traffic_exp/results.csv,这个文件每轮都会写入 loss 和 mAP。用 pandas 快速看尾部数据:

import pandas as pd df = pd.read_csv('runs/train/traffic_exp/results.csv') print(df[['epoch', 'train/box_loss', 'val/box_loss', 'metrics/mAP50', 'metrics/mAP50-95']].tail())

正常情况是 box_loss 和 cls_loss 下降,mAP50 上升。如果 mAP50 一直在零附近,优先检查 labels 是否有内容、类别编号是否对、train 和 val 是否重叠。

训练结束后用 best.pt 跑验证集:

python val.py \ --weights runs/train/traffic_exp/best.pt \ --data data/traffic.yaml \ --task val \ --conf-thres 0.001 \ --iou-thres 0.6

验证时把置信度阈值设到 0.001,是为了画 PR 曲线时覆盖所有置信度区间,这样才能得到完整的 mAP。如果直接用推理时的 0.25 阈值做验证,mAP 会被截断,看起来偏低。

5. 导出ONNX并在本地验证交通标志检测模型

5.1 用 export.py 导出静态尺寸 ONNX

PyTorch 模型直接部署到端侧不方便,常见做法是先导出 ONNX。命令:

python export.py \ --weights runs/train/traffic_exp/best.pt \ --include onnx \ --opset 12 \ --img-size 640 640 \ --simplify

--img-size 640 640固定成静态输入,导出的 ONNX 在 CPU 设备上运行更稳定。--simplify会用 onnx-simplifier 做一些常量折叠和算子合并,减少模型体积。对交通标志检测这种小目标场景,不建议同时开--dynamic,动态 shape 会导致端侧显存分配不确定,流量大时延迟抖动很明显。

5.2 用 onnxruntime 做一次推理

导出后写一个最小推理脚本,验证 ONNX 输出是否正常:

import cv2 import numpy as np import onnxruntime as ort session = ort.InferenceSession('runs/train/traffic_exp/best.onnx', providers=['CPUExecutionProvider']) input_name = session.get_inputs()[0].name def preprocess(img): img = cv2.resize(img, (640, 640)) img = img[..., ::-1].transpose(2, 0, 1) img = np.ascontiguousarray(img, dtype=np.float32) / 255.0 return img[None] image = cv2.imread('data/images/val/00001.jpg') outputs = session.run(None, {input_name: preprocess(image)})[0] print(outputs.shape) # (1, 25200, 8)

输出形状里的25200是三个尺度的 anchor 总数,8 是四个坐标、一个目标置信度、三个类别概率。YOLOv5 的 ONNX 输出默认是不带解码的裸 tensor,后面还需要做 decode、conf 过滤和 NMS。如果你不想手写后处理,可以直接用项目里自带的 detect.py 验证 PyTorch 模型,把 ONNX 推理作为部署阶段的对齐参考。

5.3 部署前检查指标差距

一个容易被忽略的技巧是检查 ONNX 和 PyTorch 的输出差异。如果项目版本支持对 ONNX 直接跑 val.py,就对比 mAP50;如果不支持,就抽三张图逐框对比坐标和置信度。允许的差距很小,正常情况差在 0.1% 以内;如果差得明显,通常是预处理逻辑不一致,比如 BGR/RGB 顺序、归一化系数、letterbox 补边方式。拿一张训练集和验证集里都没出现过的路段照片,把 ONNX 输出的检测框画回原图,确认限速标志、禁行标志的框位准确,类别名和项目里 classes.txt 一致,再进入端侧部署环节。

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

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

云MySQL与自建MySQL选型决策指南:基于业务场景的四象限模型

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 21:55:18

Android打车源码包导入与运行:从解压到编译全程指南

简介&#xff1a;《我要打车》是一份完整的安卓手机打车项目源码&#xff0c;覆盖乘客端、司机端与服务端交互逻辑&#xff0c;从用户定位、下单到司机接单形成完整业务闭环&#xff0c;适合安卓初中级开发者学习打车类应用架构&#xff0c;也可作为毕业设计或快速构建同类产品…

作者头像 李华
网站建设 2026/9/12 21:51:39

Electron+Vue3桌面应用架构迁移实战:从VSCode插件到独立应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 21:46:04

MODIS数据综合处理软件V1.0:从HDF4到NDVI的工程化实践

简介&#xff1a;面向遥感与 GIS 分析人员的 MODIS 数据综合处理软件 V1.0 安装包及配套使用手册&#xff0c;主要解决 NDVI/EVI、ET/PET、LST、LAI、GPP/NPP 等陆面产品批量读取、统计与可视化问题。软件支持多文件批量导入、多核并行计算&#xff0c;能够明显提升大批量时序数…

作者头像 李华
网站建设 2026/9/12 21:36:42

C++与Qt图形开发实战指南

1. C与Qt图形开发概述在桌面应用开发领域&#xff0c;C与Qt的组合堪称黄金搭档。作为一名长期使用这对组合进行工业软件开发的工程师&#xff0c;我见证过Qt如何让原本枯燥的C界面开发变得高效优雅。Qt不仅仅是一个GUI库&#xff0c;它提供了一整套从界面设计到网络通信、数据库…

作者头像 李华