ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLOv5交通标志识别毕设项目:数据标注、训练部署与避坑指南

YOLOv5交通标志识别毕设项目:数据标注、训练部署与避坑指南 简介这套YOLOv5交通标志识别检测资源面向毕业设计、期末大作业与课程设计场景提供从数据集、训练代码到预训练模型的完整闭环代码带详细注释新手也能读懂并快速部署。包体为ZIP压缩包共266个文件约423MB其中yaml负责模型与数据配置py为训练/推理脚本pt为已训练权重jpg/jpeg为标注图像txt为标签文件png为示例或可视化结果结构清晰、覆盖完整流程。压缩包内同时包含训练日志、评估指标CSV及Dockerfile支持复盘训练过程、查看指标变化并完成容器化部署方便在本地或服务器环境复现。资源已有112人学习项目经严格调试可稳定运行曾被导师高度认可属于手打98分的高分项目系统界面美观、操作简单、功能齐全下载后简单部署即可直接使用非常适合作为毕设或大作业的落地项目参考。1. 从 98 分毕设说起为什么 YOLOV5 交通标志识别值得你直接拿来复现如果你的毕业设计被「既要能跑、又要能讲、还要有数据支撑」卡住过那你一定知道最后那个月的滋味别人已经在改汇报 PPT你还在跟 CUDA 报错搏斗。这个 YOLOV5 交通标志识别检测项目把数据集、带注释的源码、训练好的模型权重一起打包了还附带了训练过程中的 TensorBoard 日志与 results.csv。简单说解压、配环境、跑一次 detect.py一个能演示的识别流程就能起来。适合两类人——一类是拿它交毕设或期末大作业、想省时间但要有底气另一类是产品里需要识别限速牌、禁行标志想借现成数据和权重快速验证效果。下面这篇笔记把它的数据构成、部署步骤、训练参数和常见坑一次讲完让你能放心用起来。2. YOLOV5 交通标志识别项目拆解数据标注、模型结构与训练产物怎么对应2.1 数据集目录结构与 YOLO 标注格式拿到资源后先别急着跑训练把 datasets 目录的结构摸清楚是第一步。YOLOV5 系列项目的数据集惯例是 images 与 labels 两套文件夹图片按 train/val 划分标签是跟图片同名的 txt 文件。这个项目遵循的正是 YOLO 通用的归一化标注格式txt 文件名与图片名一致每行代表一个目标框。txt 里一行的五个数字依次是类别 id、目标中心的 x 坐标归一化到 0-1、目标中心的 y 坐标、目标框宽度 w、目标框高度 h。拿0 0.4567 0.3456 0.1234 0.0897举例类别是 0中心点在图像横向 45.67%、纵向 34.56% 的位置宽高分别占整张图的 12.34% 和 8.97%。类别 0 具体代表哪个标志要看 data.yaml 里的 names 列表顺序不能乱。字段位置含义取值范围第 1 个类别 id对应 data.yaml 的 names从 0 开始第 2、3 个框中心点 x、y归一化坐标0.0-1.0第 4、5 个框宽、框高归一化值0.0-1.0交通标志识别场景有个共性标志牌在 1080p 画面里往往偏小一个限速牌可能只占几十个像素归一化后的宽高通常落在 0.05-0.15 之间。所以看到标注框数值偏小不要慌不是数据坏了真正要留神的是重复标注和重叠框它们会让模型收敛时反复跳变后面排查章节会专门处理。2.2 YOLOV5 模型结构Backbone、Neck、Head 与交通标志的匹配度YOLOV5 是单阶段检测架构主体由三块组成CSPDarknet53 作为 Backbone 提取图像特征PANet 作为 Neck 把不同尺度的特征融合起来最后 YOLO Head 在三个下采样倍率的特征图上输出预测框和类别。跟 Faster R-CNN 这种两阶段检测器比它没有先画候选框再二次分类的流程检测直接在特征图上回归出来所以速度优势明显代价是极小目标的召回不如两阶段对超远距离的小标志确实会漏。YOLOV5 的三个预测尺度分别对应 8 倍、16 倍、32 倍下采样特征图其中 8 倍下采样那层感受野最小专门承担小目标预测。只要训练和推理时 imgsz 不低于 640模型就能在 80x80 的特征图上覆盖原图 8x8 像素范围这种设计对交通标志类小目标比较友好。这也是我建议毕设选 YOLOV5 而不是追新的 YOLOV8 的核心原因YOLOV8 的 anchor-free 设计对数据规模更挑剔而 YOLOV5 的参数配置稳定预训练权重和社区踩坑记录都成熟答辩讲原理也好讲。训练产物里如果同时有 best.pt 和 last.pt 两个权重记住一个默认操作优先加载 best.pt。它是训练过程中在验证集上 mAP 最高的那一轮权重last.pt 只是最后一轮的结果通常不如 best 稳。2.3 训练产物文件解读events.out.tfevents、results.csv 与 Dockerfile解压后你会看到若干个 events.out.tfevents 打头的文件、一个 results.csv、setup.cfg 和 Dockerfile。这些不是冗余文件它们把「能跑的模型」直接变成「能写进论文的训练记录」。events.out.tfevents 是 TensorBoard 的原始日志里面保存了每个 step 的 loss、learning rate、mAP 等标量。文件名中间的秒级时间戳代表启动时刻时间不同的多个文件一般是同一任务中途重开或者换参数再训留下的按时间排序就能还原训练过程。results.csv 是每次训练结束自动导出的表每一行对应一个 epoch列包含 train loss、val loss、mAP_0.5、mAP_0.5:0.95、Precision、Recall。论文和答辩 PPT 里需要训练曲线图时直接读这个文件画就行不需要自己手动记数字。setup.cfg 和 Dockerfile 则体现了发布者对环境一致性的考虑setup.cfg 声明包依赖与工程配置Dockerfile 能把 Conda 环境完整固化成镜像。对只想交作业的同学Dockerfile 可以暂时忽略如果导师要求可复现环境这两个文件就是很好的佐证材料。提醒一句events 日志如果被多个训练任务混在一起TensorBoard 会把它们全部叠到一张图上看起来特别乱。最佳做法是每个训练任务一个独立目录比如 runs/train/traffic_v1方便回看和提交。2.4 类别不平衡在交通标志数据集里几乎必然存在打开 labels 统计一下每个类别出现次数你会发现交通标志数据集普遍存在类不平衡限速牌数量可能占总量四成施工警告牌不足 5%。这不影响模型跑起来但直接影响 mAP 和答辩评价。原因是单阶段检测器的正负样本比例天然失衡占比少的类别训练时很难被喂饱。统计方式很简单遍历所有 label txt累计每个 class id 出现次数即可# 按类别 id 统计训练集里的目标框总数结果按 id 排序 awk {count[$1]} END {for (id in count) print 类别, id, 数量, count[id]} \ datasets/train/labels/*.txt | sort -nawk 的 count 数组以类别 id 为下标逐行累加最后循环输出sort -n 让结果按 id 排序方便对照 data.yaml 里的 names。如果发现某类框数量只有几百后面训练时就要单独盯着它的 recall不要只看总 mAP。处理办法有两个一是给这个类别在损失函数里加大惩罚二是对这类数据做复制增强或翻转增强。YOLOV5 官方没有像 RetinaNet 那样直接在 loss 里做类别加权所以最省事的做法是数据层面补齐不要硬改 loss 公式否则控制变量不一致答辩时容易被人追问。3. 本地部署与首次推理conda 环境、detect.py 参数与 TensorBoard 日志3.1 conda 配置 YOLOV5 环境PyTorch 与 CUDA 的搭配顺序YOLOV5 依赖包很多但真正要小心的是 PyTorch、CUDA 与显卡驱动的三角关系。我的安装顺序是先建 conda 虚拟环境再装 PyTorch最后装 requirements.txt避免 pip 反手把 torch 版本换掉。项目里虽然有 setup.cfg但每台机器的驱动版本差异大环境配置还是手动来更稳。conda create -n yolov5 python3.9 -y conda activate yolov5 # 有显卡且驱动支持 CUDA 11.8选对应 torch 版本 pip install torch2.0.1 torchvision0.15.1 \ --index-url https://download.pytorch.org/whl/cu118 # 没独显或显存小于 4G换成 CPU 版 torch流程照样能跑通 # pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu cd yolov5-traffic-sign pip install -r requirements.txtconda 环境把项目依赖跟系统 Python 隔离后面 pip 不管怎么装都不会污染机器上的其他环境。PyTorch 版本建议选 1.13 或 2.0.x跟 YOLOV5 官方仓库兼容性最好。装完先验证一下环境再继续python -c import torch; print(torch.__version__, torch.cuda.is_available())第二个值输出 True才说明 PyTorch 真正用上了显卡。很多人自认为装了 CUDA实际 torch 跑在 CPU 上这一步立刻就能暴露问题省得后面训练慢到怀疑人生。requirements.txt 里还有一个容易翻车的点numpy 版本经常被其他包顶掉。装完依赖后如果出现 Numpy 相关报错用pip install numpy1.23.5固定一次版本再重新装 requirements是目前最省事的解法。低显存机器也不用被训练劝退后面避坑章节会讲 4G 显存下的具体跑法。3.2 用训练好的模型做推理detect.py 参数详解环境没问题接下来就是跑推理。项目自带的检测脚本是 detect.py命令行参数不多但每个都直接影响输出效果。我用交通标志场景最常用的一组参数示范python detect.py \ --weights runs/train/traffic_v1/weights/best.pt \ --source datasets/test/images \ --imgsz 640 \ --conf-thres 0.4 \ --iou-thres 0.45 \ --project runs/detect --name demo01参数含义--weights 指向模型权重文件--source 可以是单张图片、图片目录、视频文件或者摄像头端口--imgsz 是推理分辨率必须和训练时一致或接近默认 640--conf-thres 是置信度阈值低于它的框会被扔掉--iou-thres 是 NMS 去重阈值两个框重叠超过它只保留分数高的那个--project 与 --name 决定结果输出到 runs/detect/demo01 下。阈值选择有点玄学但可以给个经验值conf-thres 在交通标志上建议 0.4 到 0.5不要用默认的 0.25。道路场景背景干扰多阈值太低会出现大量误检框答辩演示时满屏方框很尴尬太高又会导致远处小标志识别不到。iou-thres 保持 0.45 即可对密集小目标这个值已经能避免重叠框叠加。参数作用交通标志建议值conf-thres置信度阈值0.4 - 0.5iou-thres重叠框去重阈值0.45imgsz输入分辨率640 或 768跑完后一定到输出目录看一眼结果图确认框确实画出来了。如果图片上什么都没有多半是权重路径写错但代码没报错detect.py 会默默用随机权重跑完这个坑我踩过一次输出图一片空白查了很久才发现是路径失效。3.3 用 TensorBoard 查看训练日志比 results.csv 更直观想直观看到 loss 曲线和 mAP 曲线的走势用 TensorBoard 最快tensorboard --logdir runs/train --port 6006跑完终端会提示本地访问地址默认是 http://localhost:6006。左侧 Scalars 标签页可以勾选 loss、mAP、Precision、Recall 等指标右侧还能调平滑系数。项目根目录里散落的 events.out.tfevents 文件把它们归到 runs/train 某个项目目录下再启动 TensorBoard 就能合并看到历次训练曲线。答辩演示时把损失下降曲线和 mAP 上升曲线贴进汇报材料比任何文字描述都直观。如果提示找不到 tensorboard说明依赖没装全。YOLOV5 训练时通常会自动带上但手动建环境后偶尔会漏补一条pip install tensorboard即可。3.4 视频与摄像头检测的参数变化如果答辩时要展示实时检测效果把 --source 换成摄像头端口就行python detect.py \ --weights runs/train/traffic_v1/weights/best.pt \ --source 0 \ --imgsz 640 --conf-thres 0.5 --iou-thres 0.45 \ --project runs/detect --name camera_demo--source 0 表示读取系统默认摄像头如果是视频文件就把 0 换成视频路径。实时场景里我习惯把 conf-thres 再往上调到 0.5因为视频相邻帧会连续出现同一个目标置信度偏低的识别结果会产生抖动的框视觉上会暴露模型判别力不足。演示阶段的原则是宁可少检出也不要错检出。4. 用自己的数据重训模型data.yaml、训练参数与 results.csv 收敛判断4.1 data.yaml 的写法路径、类别名与顺序如果你想扩一批自己拍摄的交通标志图进去或者想改类别定义第一件事就是编辑 data.yaml。YOLOV5 训练时所有路径都以这个文件为入口写错一个路径train.py 会在启动时直接报错。# data.yaml 示例 path: datasets/traffic # 数据集根目录 train: images/train # 训练图片目录 val: images/val # 验证图片目录 # test: images/test # 有测试集则去掉本行注释 names: 0: speed_limit 1: no_entry 2: yield 3: pedestrian 4: constructionnames 的 id 顺序必须与标注 txt 第一列的类别数字一一对应错位会导致整个训练白跑。path、train、val 三者组合出的最终路径是 datasets/traffic/images/train检查你实际的目录层级能否对上。类别多的时候不要在这里纠结先保证数据能读入类名后面可以再改。4.2 train.py 训练命令epochs、batch-size、imgsz 与 hyp 文件直接用项目自带的 train.py 训练命令大体长这样python train.py \ --data data.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --imgsz 640 \ --hyp hyp.scratch-low.yaml \ --device 0 \ --project runs/train --name traffic_v1--weights yolov5s.pt 是官方 COCO 预训练权重训练时会自动下载用于迁移学习如果已有训练好的 best.pt也可以把它填在这里继续微调。--epochs 先给 100实际可能 50 轮就收敛后面看验证集 mAP 不再涨就提前停。--batch-size 取决于显存16G 显存可以试 328G 显存建议 16再低就 8。--imgsz 用 640 最稳如果训练图本身是 1280 以上分批试 768 会更适配。--hyp 是数据增强超参数配置文件我一般选 hyp.scratch-low.yaml对中小数据集更保守。常用的增强参数调法打开 hyp.scratch-low.yaml找到 hsv_h、hsv_s、hsv_v 三个键。把 hsv_h 从 0.015 调到 0.02hsv_s 从 0.7 调到 0.8保存后训练脚本会重新读取配置。不要一次给太大颜色被完全改掉会让模型学到错误的不变特征。这里也不要盲目上 hyp.scratch-high.yamlhigh 配置里 mosaic、mixup 概率更高适合大而杂的数据集交通标志背景相对干净增强过猛反而破坏标志的形状和颜色。4.3 训练前的数据完整性检查与 results.csv 收敛判断训练之前先检查图片和标签是否一一对应。YOLOV5 对缺标签只打 WARNING、不中止但你会发现 loss 曲线一直在正常下降验证集 mAP 却起不来因为模型根本没见过这些图的目标。# 检查每一张训练图片是否有同名 txt 标签 for img in datasets/train/images/*.jpg; do labeldatasets/train/labels/$(basename ${img%.jpg}.txt) [ -f $label ] || echo 缺标签: $label done逻辑很简单遍历 images 目录里的 jpg把文件名后缀换成 .txt跟 labels 目录对比存在则通过不存在则打印。实际执行时如果输出很多行说明数据整理阶段有遗漏优先补标签或把对应图片移出训练集。训练结束后用一小段脚本看 results.csv 的尾部数据import pandas as pd df pd.read_csv(results.csv) df df.dropna(axis1, howall) # 去掉全空列 # 注意 YOLOV5 的列名前面带空格按实际列名取 col_map {c: c.strip() for c in df.columns} df df.rename(columnscol_map) print(df.tail(10)[[epoch, mAP0.5, mAP0.5:0.95, precision, recall]])这段代码读取训练日志去掉空列打印最后 10 轮的 mAP 与 precision、recall。怎么判断收没收敛mAP0.5 连续 10 轮不再上升说明模型学得差不多了如果训练 loss 还在降但验证 mAP 停滞说明开始过拟合早停比继续跑划算precision 高 recall 低说明模型很保守、漏检多推理时要把 conf-thres 调低再看反过来 recall 高 precision 低说明误检多推理时调高 conf-thres。如果要把曲线放进论文用 matplotlib 读同一个文件画折线图更正规import matplotlib.pyplot as plt import pandas as pd df pd.read_csv(results.csv) df df.rename(columns{c: c.strip() for c in df.columns}) plt.plot(df[epoch], df[mAP0.5], labelmAP0.5) plt.xlabel(epoch) plt.ylabel(mAP) plt.legend() plt.savefig(mAP_curve.png, dpi150)画完的图分辨率足够直接插入论文没问题。这样做的好处是数据来源可追溯答辩被问到时还能打开 results.csv 指出具体哪一轮达到峰值。5. 交通标志识别训练常见问题排查四个翻车现场与解决步骤前面说的是顺利路径下面这部分是血泪经验。我把这个项目落地过程中最容易碰到的四个问题按「现象 - 原因 - 解决」写出来遇到直接照着处理。5.1 现象loss 在 20 轮后突然变成 nan训练直接中断最常见的原因是学习率过高导致梯度爆炸或者标注文件里出现宽或高小于等于 0 的非法框loss 计算时产生除零或对数负值。交通标志数据自动采集后人工校正时偶尔有人把框拖到图片外面就潜伏着这种坏标注。解决分两步先把 hyp 文件里的 lr0 和 lrf 调低一个数量级比如 lr0 从 0.01 改成 0.001同时跑一段脚本把损坏标签筛掉import os label_dir datasets/train/labels for f in os.listdir(label_dir): if not f.endswith(.txt): continue path os.path.join(label_dir, f) lines [] for raw in open(path).readlines(): parts raw.strip().split() if len(parts) ! 5: continue _, _, _, w, h map(float, parts) if w 0 or h 0: continue lines.append(raw) open(path, w).writelines(lines)这段代码逐行读取标签文件字段数不为 5 或宽高非法的行直接丢弃。它不会报错处理后如果某张图片剩余 0 个框训练时会自动跳过。跑完再训练nan 基本消失。5.2 现象训练时 torch.cuda.OutOfMemoryErrorbatch-size 减半仍然溢出显存溢出不只是 batch-size 一个变量说了算。输入分辨率 imgsz 是平方增长的640 和 1280 的显存占用差 4 倍。如果你在 4G 显存机器上把 imgsz 拉到 1280batch-size 减到 1 也白搭。另一个隐藏因素是数据加载多进程 worker 占用的缓存也会把显存边缘堆爆。正确的抢救顺序是先把 imgsz 降回 640batch-size 设在 8再给 train.py 加 --workers 0 关闭数据加载多进程。下面这条是 4G 显存下能跑起来的基准命令python train.py --data data.yaml --weights yolov5s.pt \ --batch-size 8 --imgsz 640 --workers 0 --epochs 50这条命令基本能把训练跑通。如果显卡驱动装完依然识别不到 GPU回到第 3 章用 torch.cuda.is_available() 那个命令排查不要继续在 train.py 参数上使劲。低显存跑通的要点就是分辨率优先降workers 开关优先关batch-size 最后动。5.3 现象推理时把红色圆边框的限速牌识别成禁止驶入很多交通标志都是红底白字圆形限速牌和禁止驶入的区别在很细节的纹理上。当标注框里的目标只占 3%-5% 像素面积时backbone 下采样后这个差异已经被特征提取抹平模型只能靠「红色圆边框」这个粗特征判断自然张冠李戴。解决首选提高输入分辨率把 imgsz 从 640 提到 768 或 896把细节保留住其次是补数据专门把限速牌和禁行标志的近景图混在一起做增强。我一般还会对这两类单独算混淆矩阵确认误检方向到底占多少再决定补哪一类样本。这里不建议调低 conf-thres调低只会让更多错误框冲出来。5.4 现象加载权重报 model.0.conv.weight 等 key 对不上权重文件可能是在旧版本 YOLOV5 里保存的或者保存时包了 nn.DataParallel 的 model 前缀而你用的是新版本代码或直接 torch.load 读取。YOLOV5 自带的 attempt_load 函数在加载时会自动兼容这些差异所以不要手动 torch.load。统一用项目代码里的加载方式from models.experimental import attempt_load model attempt_load(best.pt, devicecpu) # device 换 0 表示 GPU如果还报错就在保存端处理加载 checkpoint 后state_dict 里去掉 model 前缀再另存一次。这类问题基本都是新旧代码混用导致的保持代码和权重来自同一份项目包就不会出现。6. 从「能识别」到「能答辩」模型导出、推理封装与验证技巧如果毕设要求里含一套独立系统光在终端里调用 detect.py 显然不够。答辩前我会再把权重导出成 ONNX封装一个十几行的推理入口这样演示时不用依赖完整训练环境现场稳定性高很多。# 把 best.pt 导出为 ONNXCPU 机器也能跑推理 python export.py --weights best.pt --include onnx --imgsz 640 --opset 12# 封一个极简验证入口输入 BGR 图片直接拿到预测结果 import cv2 import numpy as np import onnxruntime as ort class TrafficSignDetector: def __init__(self, onnx_path, imgsz640): self.sess ort.InferenceSession(onnx_path) self.imgsz imgsz def detect(self, bgr_img): img cv2.resize(bgr_img, (self.imgsz, self.imgsz)) img img[:, :, ::-1].transpose(2, 0, 1) # BGR 转 RGBHWC 转 CHW img np.ascontiguousarray(img, dtypenp.float32) / 255.0 out self.sess.run(None, {self.sess.get_inputs()[0].name: img[None]}) return out[0] # 形状形如 (1, 25200, 5类别数)前 5 位是坐标与目标置信度代码逻辑读取 ONNX 模型把 BGR 图片 resize 到 640转 RGB、CHW、归一化然后跑一次推理。输出的第一个数组就是全部预测框后面按导出格式自行解析。ONNX 推理的好处是不再需要 PyTorch 环境现场机器只要能装 onnxruntime 就能跑。实时视频演示时把 conf-thres 设到 0.5画面干净读验证集时调回 0.25证明召回率再用 results.csv 里某几轮数据做对比曲线放进论文。别把测试集 mAP 反复美化答辩老师追问时说不出细节就尴尬了。现在我再拿到类似的 YOLOV5 资源都会强制自己走一遍「推理 → 重训 → 封装」的完整链路确认每个环节都能跑过才开始动代码。这个顺序很笨但绝大多数问题都出在你想跳过的那一步上。希望这些笔记能帮你在毕设里少熬一个夜。本文还有配套的精品资源点击获取
返回列表