news 2026/9/12 21:55:06

YOLOv5交通标志检测实战:从数据准备到ONNX部署全流程解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLOv5交通标志检测实战:从数据准备到ONNX部署全流程解析

简介:YOLOv5交通标志物检测完整项目,面向计算机专业正在完成课程设计、期末大作业或需要项目实战练习的学生。项目包含全部源码、训练好的.pt模型权重及配套图像数据与标注文件,经严格调试,下载后可直接运行或继续训练。资源共266个文件,以Python源码(53个py)、YOLO配置(59个yaml)、图像与标注(55个jpg、26个png)为主,另有预训练权重(10个pt)、Docker环境文件、训练结果csv与日志等,整体约423MB,目录结构清晰,便于按模块查阅。目前已有362人学习/浏览,适合入门深度学习和目标检测实战。读者可从中获得一个完整可复现的检测流程,包括数据集组织与标注格式、YOLOv5训练参数配置、模型推理调用与结果记录方式,也可参考其代码结构迁移到其他检测场景。

1. 起步:拿到一份 YOLOv5 交通标志检测源码之后

先看一个反直觉的事实:YOLOv5 交通标志物检测项目能不能跑通,瓶颈往往不在模型,而在数据。课程设计里见过太多人卡在标注格式不一致、训练路径配错、类别数对不上——这三件事随便哪一件出错,train.py 都会在第五个 epoch 前后开始报错或 mAP 全零。这份 97 分的项目打包了源码、训练好的模型和全部数据,等于把最容易出错的三关提前过掉了,解压就能看到data/imagesdata/labels成对存在,训练和推理入口都是现成的。图像处理、深度学习、目标检测三块知识都能从这里找到落点,适合正在做课程设计的学生,也适合想拿一套完整工程复现训练流程的从业者。

2. YOLOv5 网络结构与交通标志的特征提取路线

2.1 骨干网络与 C3 模块

YOLOv5 的骨干网络把 Darknet53 改造成带跨阶段局部连接(CSP)的结构。跨阶段局部连接的核心,是把输入特征图按通道拆成两条路径,一条经过若干 Bottleneck 堆叠,另一条直接向后传递,最后在输出端合并。这样梯度回传时有短路通道,训练更稳定,计算量也不会随深度线性膨胀。这个思想最终被封装成 C3 模块,源码在models/common.py里:

class C3(nn.Module): """CSP Bottleneck with 3 convolutions""" def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, 1, 1) self.cv2 = Conv(c1, c_, 1, 1) self.cv3 = Conv(2 * c_, c2, 1) self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))

cv1 和 cv2 都是 1×1 卷积,先把输入通道压缩到中间维度c_,主路经过n个 Bottleneck 串接,旁路保持原样,最后用 cv3 把拼接后的 2×c_ 通道还原成输出通道。n是 Bottleneck 数量,yolov5s 里为 3,yolov5m 为 6,这直接决定了模型容量和推理耗时的差异。

提示:C3 的shortcut默认 True,只在特征图尺寸不变化时生效;每次下采样后网络会自动绕过残差连接,避免信息冗余。

2.2 PANet 多尺度融合对小目标的意义

交通标志在画面里普遍偏小,一辆车 20 米外拍到的限速牌可能只有 24×24 像素。如果只用单一尺度的特征图,小目标很容易在下采样过程中丢失。YOLOv5 用 FPN 把深层语义传到浅层,再用 PANet 自底向上把细节信息接回来,两条路径汇合后产生三个尺度的检测头。models/yolo.py中的 Detect 层初始化了这些检测头:

m = nn.Conv2d(cv3_out, anchors * (5 + num_classes), 1) self.anchors = torch.tensor(anchors).float().view(self.nl, -1, 2) self.grid = [torch.zeros(1) for _ in range(self.nl)] self.stride = torch.tensor(stride).float()

每个 anchor 输出5 + num_classes个通道,5 对应中心坐标偏移、宽高缩放和置信度,后面的num_classes对应类别概率。stride 表示检测 head 相对原图的下采样倍数,P3 是 8,P4 是 16,P5 是 32,分别对应小、中、大目标。

2.3 三个检测头的分工

检测头下采样倍数特征图尺寸(输入 640×640)合适的目标
P3880×80远处限速牌、警告牌
P41640×40中距离禁令标志
P53220×20近处大尺寸指示牌

三个检测头共用一份 anchor 配置文件,但各自侧重不同尺度的目标。交通标志这种小目标密集的场景里,P3 头承载的压力最大,训练时如果发现小目标漏检严重,优先检查 P3 的输出。

2.4 为什么选 YOLOv5 而不是两阶段模型

Faster R-CNN 这类两阶段检测器在 COCO 上 mAP 略高,但推理时间经常是 YOLOv5 的十倍以上。课程设计答辩现场只有普通笔记本,用 Faster R-CNN 跑摄像头实时检测基本不可行。YOLOv5 把数据加载、Mosaic 增强、自动学习 anchor、EMA 权重平均全部内置,本身就是一个完整训练闭环,改配置就能换数据集,对课程设计和工程验证都很友好。

3. 交通标志数据集:YOLO 标签格式与预处理

3.1 目录组织与数据关联

项目自带的交通标志数据已经按 YOLOv5 约定的目录结构放好,解压后可直接被 train.py 读取。目录如下:

data/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── traffic_sign.yaml

images 和 labels 同级,YOLOv5 在读取标签时通过把images路径替换为labels来定位标注文件。因此 images/train 里的每张img_0001.jpg,必须对应 labels/train 里的一个img_0001.txt,文件名前缀完全一致,否则训练时会静默跳过那个样本。

3.2 标注格式与坐标归一化

YOLO 格式的标签文件每行表示一个目标,格式为:

<class_id> <x_center> <y_center> <width> <height>

五个数值中,坐标和宽高都归一化到 0~1。假如一张 1280×960 图像中有一个边界框,左上角为 (320, 240),宽和高都是 160 像素,x_center = (320 + 160/2) / 1280 = 0.3125,y_center = (240 + 160/2) / 960 ≈ 0.3333,width = 160/1280 = 0.125,height = 160/960 ≈ 0.1667。对应文本行是:

0 0.3125 0.3333 0.125 0.1667

如果标注是 LabelImg 导出的 VOC XML,做一次坐标换算再送入训练。项目里常见做法是写一个转换函数:

def convert_bbox(size, box): dw = 1.0 / size[0] dh = 1.0 / size[1] x = (box[0] + box[1]) / 2.0 * dw y = (box[2] + box[3]) / 2.0 * dh w = box[1] * dw h = box[3] * dh return x, y, w, h

size 是图像的 (width, height),box 按 (left, right, top, bottom) 传入。这里要注意 left/right 的取值顺序,LabelImg 导出的 XML 里是 xmin/xmax/ymin/ymax,对应关系写错会导致标注框反转。

3.3 类别不平衡与增强策略

交通标志的类别分布天然不均衡,“限速”类样本可能是“注意儿童”的十倍。如果直接训练,模型会偏向高频类别,低频类的召回率掉得很快。缓解手段有两类:一类是过采样少见类别样本,另一类是在线增强。YOLOv5 内置的 Mosaic 会把四张图随机拼成一张,等于每个 batch 都引入了更多位置、尺度、光照变化,对交通标志这类小目标数据尤其有效。源码中通过 hyp 配置控制 mosaic 开关:

mosaic: 1.0 mixup: 0.0 copy_paste: 0.0

mosaic=1.0 表示每张训练图都是拼接产物,mixup 和 copy_paste 默认关闭。如果换数据集后出现严重过拟合,可以先把 copy_paste 调到 0.1 试,它能让目标在图像间复制粘贴,进一步丰富背景多样性。

3.4 数据划分与路径配置

训练/验证/测试集的划分建议在文件系统层面完成,不要在训练时动态切分。按 8:1:1 比例分好后,把路径写进 traffic_sign.yaml:

train: data/images/train/ val: data/images/val/ nc: 5 names: ['speed_limit', 'stop', 'warning', 'no_entry', 'crosswalk']

一个容易踩的坑是 train 路径写成data/images/而不是data/images/train/。YOLOv5 的 dataloader 会递归读取子目录,这看似能跑,但会把 test 图也混进训练集,导致验证指标虚高、答辩时被问到说不清。

4. 训练配置、迁移学习与精度平衡

4.1 模型体量选择

交通标志检测对实时性要求高,课程设计通常在一张入门级显卡上完成。项目里常见的模型选择如下:

模型参数量单卡 batch=16 显存占用适用场景
YOLOv5s7.2M约 8GB课程设计/边缘设备
YOLOv5m21.2M约 12GB高精度实验
YOLOv5l47.0M约 24GB线下评测,不适合实时

建议直接用 yolov5s 起步,它精度足够,推理速度也快。显存不够时优先调小 batch 而不是换更小的模型——batch 缩到 8 后仍可正常收敛,只是训练时间变长。

4.2 训练命令与参数解读

python train.py \ --data traffic_sign.yaml \ --cfg models/yolov5s.yaml \ --weights yolov5s.pt \ --epochs 300 \ --batch-size 16 \ --img 640 \ --device 0 \ --patience 50

--cfg指定模型结构,不传时从--weights自动推断;--weights yolov5s.pt是 COCO 预训练权重,用迁移学习可以大幅缩短收敛时间;--patience 50表示验证集 mAP 连续 50 轮不提升就早停,300 轮上限通常 150 轮左右就能触发停止。

提示:如果类别数或数据分布与 COCO 差异较大,训练脚本会在加载权重时自动跳过不匹配的检测头层,不影响训练流程。

4.3 学习率与优化器

YOLOv5 默认优化器是 SGD,配 cosine 学习率衰减。项目 hyp 配置里核心参数为:

lr0: 0.01 lrf: 0.2 momentum: 0.937 weight_decay: 0.0005

lr0 是初始学习率,lrf 是最终学习率相对初始值的比例,0.2 表示最后一个 epoch 学习率衰减到 0.002。这个设置在多数目标检测任务里工作良好。数据量较少时,可以手动把 lr0 调到 0.005 避免震荡。训练中不需要手动修改学习率,scheduler 会按 cosine 曲线自动完成衰减。

4.4 训练日志与 results.csv 分析

训练过程每个 epoch 都会生成 box_loss、obj_loss、cls_loss、mAP@0.5 等指标,并写入 runs/train/exp 下的 results.csv。可以用 pandas 直接读取来观察趋势:

import pandas as pd df = pd.read_csv('runs/train/exp/results.csv') print(df[['epoch', 'metrics/mAP_0.5', 'val/box_loss']].tail())

判断标准很简单:损失平稳下降、mAP 持续上升,说明训练正常。如果验证损失在第 100 轮开始反弹而训练损失还在下降,说明过拟合,此时早期停止已经触发,不需要额外干预。项目里自带的多个 results.csv 相当于几组对照实验,对比不同实验的 mAP 曲线可以反推哪个超参数改动起了作用。

4.5 继续微调与自己的数据迁移

如果训练好的模型要适配新的交通标志类别,直接在 best.pt 基础上进行微调即可。比如新增了一类“施工标志”,把 traffic_sign.yaml 的类别表更新后执行:

python train.py \ --data traffic_sign_custom.yaml \ --weights runs/train/exp/weights/best.pt \ --epochs 50 \ --batch-size 8

训练脚本会根据新类别数自动重置检测头输出维度,预训练 backbone 的特征复用能力保留,只需要少量数据即可达到够用的精度。这种微调方式是课程设计换题目的常用路径。

5. 推理部署:从 PyTorch 权重到 ONNX 工程化

5.1 用训练好的权重跑推理

python detect.py \ --source data/images/test.jpg \ --weights runs/train/exp/weights/best.pt \ --conf-thres 0.4 \ --iou-thres 0.45 \ --project runs/detect \ --name exp_test

--conf-thres 0.4是置信度阈值,只保留高于 0.4 的检测框。调低到 0.25 能减少漏检但误报会变多;--iou-thres 0.45是 NMS 的 IoU 阈值,交通标志重叠较少,按默认即可。--source 0可以切换到摄像头输入,这也是答辩演示最常用的方式。

5.2 导出 ONNX 并用 onnxruntime 加载

把权重导出为 ONNX 格式,可以在没有 PyTorch GPU 环境的机器上部署:

python export.py --weights best.pt --include onnx --simplify

--simplify会用 onnx-simplifier 移除冗余算子,导出后的模型用 onnxruntime CPU 推理:

import onnxruntime as ort import numpy as np sess = ort.InferenceSession('best.onnx') input_name = sess.get_inputs()[0].name output = sess.run(None, {input_name: image_np})

注意导出过程中 YOLOv5 会绑定输入分辨率。如果训练时用的--img 640,推理时输入也需要 letterbox 到 640×640,否则会直接维度报错。ONNX 的输出是原始预测向量,需要自己解码坐标和置信度,项目里 detect.py 的解码逻辑可以直接搬过来。

5.3 兼容摄像头与视频流的工程化处理

视频流推理时要处理采样帧率和帧间对象闪烁问题,直接逐帧跑检测没问题,但输出框会在相邻帧间抖动。我一般保存检测结果时会保留原始帧的 BGR 通道顺序,用 cv2.imwrite 落盘,避免出现红蓝通道对调的人花掉的问题。如果要把检测框叠加回视频,先复用 YOLOv5 的plot_one_box工具函数,再作颜色映射,比从零画要省很多事。从这份源码到线上服务,唯一需要补的是前处理的标准化逻辑——模型导出 ONNX 后输入张量的 BGR/RGB 顺序和归一化方式必须和训练时完全一致,核心的(x/255.0 - mean) / std参数不要拍脑袋改。

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

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

C#离线OCR实践:RapidOCR模型集成与参数调优指南

简介&#xff1a;面向C#开发者的完整光学字符识别示例工程&#xff0c;基于ONNX运行时调用飞桨OCR模型&#xff0c;实现中文文字识别。资源内置可直接运行的演示程序与配套模型文件&#xff0c;适合需要快速集成识别能力或学习C#端模型部署的技术人员&#xff0c;也适合作为课程…

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

S7-200 PLC与组态王智能消防系统实战解析

1. 项目背景与核心需求这套基于S7-200 PLC和组态王的智能楼宇消防控制系统&#xff0c;是我去年为某商业综合体实施的典型方案。现在很多新建楼宇还在用传统继电器控制消防设备&#xff0c;不仅布线复杂&#xff0c;故障排查更是噩梦。这个方案用200SMART PLC组态王上位机&…

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

ESP32-S2/S3 USB MSC实战:从TinyUSB到FatFs实现U盘与调试

先把话放前头&#xff1a;这不是一篇教你“照着敲两行代码就能跑起来”的教程&#xff0c;而是一份完整的USB MSC调试现场记录。我这边说的ESPS&#xff0c;就是大家习惯对ESP32-S2/S3系列的简称。你为什么要折腾USB MSC&#xff1f;很大概率是想让设备插上电脑直接被识别成一个…

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

方言智能转换工具:技术实现与应用场景解析

/* 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:52:16

Pytorch实现FCN语义分割:从数据到训练推理全流程解析

简介&#xff1a;这是一套基于Python与PyTorch实现的FCN语义分割复现项目&#xff0c;面向希望入门语义分割&#xff0c;或将其用于毕设项目、课程设计、工程实训的PyTorch学习者。项目严格按原论文复现了FCN32s、FCN16s、FCN8s与FCNs四种网络结构&#xff0c;并配套完整的PyTo…

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

Linux文件系统详解:从基础概念到高级挂载技巧

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

作者头像 李华