YOLOv9交通标志检测实操:从环境配置到训练部署全流程 简介面向驾驶员视角的道路交通标志检测任务提供一套基于YOLOv9的完整目标检测方案。资源整合了数据集配置说明、模型训练、测试推理与结果可视化全流程并附详细运行教程和参数修改指引适合计算机视觉方向的毕业设计、课程实践以及需要快速落地检测原型的工程入门者。压缩包共187个文件大小74.53MB以83个Python脚本、30个YAML配置、27张JPG样例图、3个PyTorch权重文件和18个Pyc缓存文件为主另含训练指标曲线、XML标注、Shell脚本等模块划分清晰便于对应查找训练、验证、检测等环节所需内容。该资源已有82人学习下载。下载后可直接获得可运行的YOLOv9s交通标识检测系统包含训练好的模型权重、完整源码与测试图片支持按需更换数据集进行自定义训练同时提供环境配置、训练调参与测试输出的详细说明可显著降低上手难度是完成道路标识识别课题的实用参考资料。1. 为什么驾驶员视角交通标识检测值得用 YOLOv9 重新做一遍做过车载视觉项目的人都知道交通标识检测和通用目标检测最大的差别不在模型结构而在数据分布标志小、类别多、不同国家样式差异大而且驾驶员视角下经常出现运动模糊、逆光、遮挡。用 YOLOv9 做这件事不是因为它比 YOLOv8 在 COCO 上刷高了多少分而是它的可编程梯度信息PGI和广义高效层聚合网络GELAN在小目标、遮挡场景下更不容易丢梯度收敛以后对边缘模糊的物体更稳。这套资源里给出的train_dual.py/detect_dual.py双入口设计配合reparameterization.ipynb做推理重构基本覆盖了从训练到部署的完整链路。适合两类人一类是想拿真实数据集做交通标志检测课程设计或毕设的学生另一类是想快速验证 YOLOv9 在自己车载数据上效果的算法工程师。2. 从零配置 YOLOv9 训练环境Anaconda、PyCharm 与 requirements.txt2.1 为什么用 Anaconda 而不是直接装 Python交通标志检测涉及 PyTorch、OpenCV、NumPy、Matplotlib 等一系列包手动装很容易把系统 Python 搞乱。Anaconda 可以创建独立环境后续换项目、换模型版本不会互相干扰。我的习惯是先建一个yolov9环境指定 Python 3.9 或 3.10YOLOv9 官方代码在 3.8–3.10 下表现稳定再在环境内安装依赖。conda create -n yolov9 python3.9 -y conda activate yolov9安装完 Anaconda 后把环境切换好接下来就是装requirements.txt。项目根目录下已经有这个文件里面主要包括torch、torchvision、opencv-python、matplotlib、pandas、tqdm、pyyaml、tensorboard等。pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple-i参数指定清华镜像源国内网络环境下比默认 PyPI 快很多。如果requirements.txt中固定了torch2.0.1之类的版本装的时候注意和本机 CUDA 版本匹配。查看 CUDA 版本可以用nvidia-smi然后在 PyTorch 官网选择对应安装命令。如果只是 CPU 调试直接把torch装成 CPU 版也可以跑通但训练速度会慢得让你怀疑人生。2.2 把 Anaconda 解释器导入 PyCharm这是很多初学者卡的第一步。打开 PyCharm进入File - Settings - Project - Python Interpreter点击齿轮图标选择Add Interpreter - Conda Environment - Existing Environment在列表里找到刚才创建的yolov9环境指定python.exe路径即可。导入以后记得在 PyCharm 的终端窗口里再次确认环境python -c import torch; print(torch.__version__)能正常输出版本号说明环境匹配成功。这一步没做好后面运行train_dual.py时会报ModuleNotFoundError但报错位置可能在第三方库里排查起来很绕。2.3 依赖安装失败后的排查思路pip install -r requirements.txt最常见的失败是torch或torchvision下载超时。这种情况不要反复重试同一命令先单独安装 PyTorch再装其余依赖。pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple另外opencv-python在某些 Linux 服务器上会报 libGL 缺失需要apt-get install -y libgl1 libglib2.0-0Windows 上一般不会遇到。这套资源里作者已经跑通说明依赖锁定得比较准你只要不擅自升级大版本基本不会出问题。3. 数据集准备与 data yaml 配置把交通标志整理成 YOLO 格式3.1 YOLO 标注格式的核心字段YOLOv9 训练用的是基于 txt 的标注文件每一行代表一个目标格式为class_id x_center y_center width height其中坐标是相对于图片宽度和高度的归一化值取值 0~1。一张图片对应一个同名的.txt文件放在标签目录下。比如stop_001.jpg对应stop_001.txt。0 0.5234 0.4123 0.0812 0.0956这行表示一个类别 ID 为 0 的目标中心点在图片横向 52.34%、纵向 41.23% 的位置宽度占整张图片的 8.12%高度占 9.56%。如果你手头的数据是 VOC 格式XML或者 COCO 格式JSON需要先转换。常见做法是写一段 Python 脚本用xml.etree.ElementTree解析 XML再把xmin/ymin/xmax/ymax转成中心点加宽高的形式。转换时注意坐标范围必须用真实像素坐标除以图片宽高否则训练时标签会错位。3.2 交通标志数据集的目录组织参考项目中data/banana_ripe.yaml的结构一个合格的 YOLO 数据集目录应该是这样traffic_sign_dataset/ ├── images/ │ ├── train/ │ │ ├── stop_001.jpg │ │ └── ... │ └── val/ │ ├── stop_256.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── stop_001.txt │ │ └── ... │ └── val/ │ └── stop_256.txt └── traffic_sign.yaml注意图片和标签必须一一对应不能有某张图缺少标签文件背景图可以不标注但建议把空标签文件也放进去否则训练时容易报Image not found或标签缺失的警告。3.3 修改 YAML 文件用你的类别替换默认配置banana_ripe.yaml是作者给的示例里面默认是香蕉成熟度三分类。你只需要新建一个traffic_sign.yaml照葫芦画瓢path: ./traffic_sign_dataset train: images/train val: images/val names: 0: speed_limit_30 1: stop 2: no_entry 3: yield 4: pedestrian_crossingpath是数据集根目录train和val是相对于根目录的路径。names的类别顺序和标注文件里的class_id一致这个顺序一旦开始训练就不要改否则模型学到的类别映射会全部错乱。我见过有人训练到一半在 yaml 里增加类别结果评估时 mAP 曲线直接崩掉。如果你想验证标注是否正确可以做一次可视化检查import cv2 import numpy as np img_path traffic_sign_dataset/images/train/stop_001.jpg label_path traffic_sign_dataset/labels/train/stop_001.txt img cv2.imread(img_path) h, w img.shape[:2] colors [(0, 0, 255), (0, 255, 0), (255, 0, 0)] with open(label_path) as f: for line in f.readlines(): cls, cx, cy, bw, bh map(float, line.split()) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), colors[int(cls) % 3], 2) cv2.imwrite(check_label.png, img)这段代码把标注框画回图片保存成check_label.png。如果框和目标位置明显错位多半是归一化坐标算错了回去检查转换脚本。4. train_dual.py 训练参数逐项拆解以及结果曲线怎么看4.1 通过脚本内参数配置启动训练项目提供的train_dual.py是 YOLOv9 官方的训练入口既可以在 PyCharm 里直接改参数运行也可以用命令行传参。先看最常用的参数python train_dual.py \ --weights yolov9-s.pt \ --cfg models/detect/yolov9-c.yaml \ --data data/traffic_sign.yaml \ --hyp hyp.scratch-high.yaml \ --epochs 100 \ --batch-size 16 \ --device 0 \ --close-mosaic 15各参数含义如下表所示参数示例值作用与建议--weightsyolov9-s.pt预训练权重。小数据集推荐用yolov9-s.pt或yolov9-t.pt显存不够时用 t 版。--cfgmodels/detect/yolov9-c.yaml模型结构配置文件。yolov9-c是 GELAN 的基础结构适合大多数场景。--datadata/traffic_sign.yaml你的数据集配置指向第 3 步写的 yaml 文件。--hyphyp.scratch-high.yaml超参数文件。high版本的数据增强更强适合中等规模数据集。--epochs100训练轮数。交通标志类别少、目标小100~200 轮基本收敛。--batch-size16批次大小。显存不够就降到 8 或 4同时适当降低--img尺寸。--device0GPU 编号。单卡填 0CPU 训练填cpu但不推荐。--close-mosaic15最后 15 个 epoch 关闭马赛克数据增强让模型在真实分布上微调。--close-mosaic这个参数容易被人忽略。YOLO 系列训练后期如果一直用马赛克增强生成图的背景和真实驾驶场景差异太大导致验证集精度不稳。关闭后模型能看到纯真实图最后的precision和recall会更贴近实际部署。4.2 命令行方式与脚本内修改的对比方式一直接改train_dual.py的parse_opt()函数把默认值改掉然后在 PyCharm 里运行。优点是你不需要记参数名但缺点是每次换数据集都要改代码不方便留存实验记录。方式二在项目根目录下打开终端用上面的命令行执行。命令行方式的好处是参数跟着命令走你可以在 shell 历史里看到每次实验的配置。我自己的习惯是把命令写成.sh脚本例如train_ts.sh每次只改--data和--name。python train_dual.py --weights yolov9-s.pt --cfg models/detect/yolov9-c.yaml --data data/traffic_sign.yaml --hyp hyp.scratch-high.yaml --epochs 120 --batch-size 16 --device 0 --close-mosaic 20 --name traffic_sign_run1--name参数控制实验输出文件夹名默认是exp。如果不指定第二次训练会生成exp2、exp3容易把不同实验搞混。建议每次都指定--name配合--project参数可以按项目归类输出目录。4.3 训练过程的监控与指标曲线训练开始后终端会每个 batch 输出一次损失值也可以用 TensorBoard 看曲线tensorboard --logdir runs/train然后在浏览器打开http://localhost:6006能看到train/loss、metrics/precision、metrics/recall、metrics/mAP_0.5等曲线。results.csv文件里也保存了同样的数据如果你想写脚本自动读取分析可以直接用 pandas 读import pandas as pd df pd.read_csv(runs/train/traffic_sign_run1/results.csv) print(df.columns) print(df[[epoch, metrics/mAP_0.5, metrics/mAP_0.5:0.95]].tail())metrics/mAP_0.5是 IoU 阈值 0.5 时的平均精度交通标志检测通常关注这个指标metrics/mAP_0.5:0.95是更严格的综合指标小目标在后者上通常偏低如果你的交通标志普遍小于 32×32 像素不要因为 0.5:0.95 低就急着调参先看 0.5 下的召回率。训练结束后runs/train/traffic_sign_run1目录下会生成best.pt和last.pt。best.pt是根据验证集 mAP 选出的最优权重后面测试和部署都用它。4.4 显存不足与训练崩溃的常见处理如果启动时报CUDA out of memory按优先级做三件事先减小--batch-size从 16 降到 8再减小--img默认是 640可以改成 512最后换更小的模型yolov9-c.pt换yolov9-t.pt。注意改了输入尺寸推理时也必须用同样的尺寸否则检测框会偏移。训练中途崩溃先看错误日志是不是NaN loss。出现NaN通常是因为学习率太大或标签坐标越界。检查数据集的标签文件看有没有width或height大于 1 的值再检查hyp.scratch-high.yaml里的lr0如果用的是默认值0.01在很小的自定义数据集上可以降到0.005试一下。5. detect_dual.py 推理参数与重参数化用 best.pt 做实时检测5.1 单张图片与视频的检测命令训练好模型后用detect_dual.py做推理。核心参数是--weights、--source、--conf-thres、--iou-thres。python detect_dual.py \ --weights runs/train/traffic_sign_run1/best.pt \ --source test_imgs/driver_view_01.jpg \ --conf-thres 0.25 \ --iou-thres 0.45--source可以指向图片文件、视频文件或者一个目录。如果指向目录程序会遍历目录下的所有图片并逐张检测。--conf-thres是置信度阈值低于它的框会被过滤。交通标志检测建议设在0.3~0.4之间因为标志目标小神经网络天然容易给出偏低的置信度阈值太高会漏检。--iou-thres是 NMS 的 IoU 阈值用于去除重叠框一般保持0.45。如果你想处理视频流命令不用变--source直接指向 mp4 文件python detect_dual.py --weights best.pt --source traffic_video.mp4 --conf-thres 0.3 --save-txt加上--save-txt后检测结果除了生成画框的图片还会把每帧的类别、坐标写入 txt 文件后续做轨迹分析可以用。5.2 重参数化把训练模型转为推理结构项目根目录下的reparameterization.ipynb不是摆设。YOLOv9 训练时用了辅助分支和额外的梯度传输路径这些结构在高精度训练中有用但会增加推理开销。重参数化就是把训练模型的这些冗余结构折叠成简洁的推理模型过程类似 YOLOv8 的model.fuse()。在 notebook 里执行的核心代码大致是这样的import torch from models.yolo import Model from utils.torch_utils import select_device # 加载训练权重 ckpt torch.load(best.pt, map_locationcpu) model Model(ckpt[model].yaml, ch3, nc5) model.load_state_dict(ckpt[model].float().state_dict()) # 切换到推理模式并融合 model.eval() model.fuse() # 保存重参数化后的权重 torch.save({model: model.half()}, best_reparam.pt)这里的nc5要和你的数据集类别数一致。model.fuse()会把 Conv2d BatchNorm2d 融合成一个卷积减少层间计算量。重参数化后模型在嵌入式设备或低性能 GPU 上的帧率会明显提升精度损失几乎可以忽略。5.3 小目标漏检的针对性参数调整如果你在验证视频上发现远处的小交通标志经常漏检先不要急着换模型。确认--img-size是否用了和训练一致的 640很多漏检是因为推理尺寸小于训练尺寸。然后检查测试图片中目标的最小像素尺寸。对于小于 20×20 像素的标志可以单独降低--conf-thres到0.2如果产生误检再调高 NMS 阈值到0.5。另外YOLOv9 的训练增强中有--scale超参数它控制随机缩放的范围默认0.9如果数据集中小目标比例高可以在hyp.scratch-high.yaml里把它改大到1.2让模型在训练时多见放大后的目标然后重新训练。这个方法对驾驶员视角的交通标志检测往往比换更大模型更有效。本文还有配套的精品资源点击获取