ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

YOLOv5交通标志检测实战:从训练调优到部署避坑全攻略

YOLOv5交通标志检测实战:从训练调优到部署避坑全攻略 简介YOLOv5交通标志物检测项目是一份97分的期末大作业面向计算机相关专业正在完成课程设计、期末大作业以及需要项目实战练习的学生。资源包含完整的YOLOv5检测源码、已经训练好的模型权重以及配套数据集可直接用于训练、验证和推理交通标志检测任务项目均经过严格调试下载解压即可运行。包体大小约423MB共266个文件其中yaml文件负责模型与数据配置py文件为训练和检测脚本pt文件为现成权重jpg/png等图片为训练测试样本另有Dockerfile、notebook及结果统计文件目录结构清晰便于按需查阅。目前已有362人学习适合希望快速搭建目标检测项目、开展实验对比或学习YOLOv5工程实现的读者。无论是课程报告、答辩演示还是入门深度学习实战都能基于这份资料获得完整可复现的流程。1. YOLOv5交通标志物检测能跑通、能交作业的完整闭环做课程设计最怕的不是模型效果差而是代码在别人机器上能跑、到你手里就崩。这份YOLOv5交通标志物检测项目我拆完第一感受是它把数据、权重、训练日志、Docker环境全给你配齐了属于典型的解压即用型资源。项目基于YOLOv5检测框架训练好的模型可以直接对交通标志限速牌、停止牌、警告牌等做实时识别同时附带完整的训练数据与TensorBoard日志方便你复现整个训练过程。适合三类人正在做期末大作业的在校生、想快速上手YOLO系列检测的初学者以及需要一份干净基线做对比实验的从业者。我在本地Ubuntu环境完整过了一遍从数据集检查到模型推理的流程下面把关键环节和坑位逐一拆开讲。2. 源码包结构从目录看懂训练闭环与存储格式2.1 训练痕迹文件events.out.tfevents 与 results.csv 的读取方式解压后目录里有几个events.out.tfevents.*.0文件这是PyTorch训练时通过TensorBoard回调写入的事件文件。文件名里的数字例如1679055968对应Unix时间戳可以反推训练开始时间chenming是运行训练时系统的用户名这个信息能帮你判断模型是用什么环境训出来的。另一个高频文件是results.csvYOLOv5每次epoch结束都会往里追加一行指标包括训练损失train/box_loss、train/cls_loss、验证损失val/box_loss、val/cls_loss、精确率metrics/precision、召回率metrics/recall和mAP0.5等。读取results.csv最直接的方式是用pandasimport pandas as pd df pd.read_csv(results.csv, comment#) # YOLOv5的CSV首行可能有注释需要跳过 print(df.columns.tolist()) # 查看所有指标列 print(df.tail(5)) # 看最后5个epoch的收敛情况这里有两个细节值得注意第一YOLOv5的results.csv第一行通常是# metrics/...开头的注释直接用pd.read_csv会报错或者把注释行当数据所以必须加comment#参数第二如果你看到train/box_loss持续下降但val/box_loss在第80个epoch后开始反弹说明模型已经过拟合最佳权重应该取验证损失最低的那个epoch而不是最后一个epoch。项目里既然保留了完整的results.csv你可以直接绘图观察这个收敛曲线这比盯着终端输出的loss值直观得多。2.2 setup.cfg 与 Dockerfile环境复现的两条路径setup.cfg是Python包的配置文件YOLOv5原生项目里就有这个文件作用是指定包元数据、entry points等。但真正关键的是Dockerfile——它把整个运行环境固化了。我拉取镜像是这么做的# 在项目根目录下构建镜像 docker build -t yolov5-traffic-sign:latest . # 如果只想跑推理用交互模式挂载目录 docker run -it --gpus all -v $(pwd):/usr/src/app yolov5-traffic-sign:latest bashDockerfile的核心价值在于绕开环境地狱。常见的坑有PyTorch版本与CUDA版本不匹配导致GPU不可用、OpenCV编译缺失依赖、pillow版本过高导致Image.open报错等。在这个项目里如果宿主机CUDA版本和镜像里不一致--gpus all参数可能失效这时退而求其次用CPU推理也能跑只是慢一些。我一般建议如果你只是交作业直接用conda建环境就够了Docker留给需要部署到服务器或者给别人复现的场景。2.3 模型权重与推理脚本拿到手先做一次冒烟测试解压包里应该有best.pt或last.pt这类PyTorch权重文件拿到手第一步不是重新训练而是先跑一次推理验证环境通不通。YOLOv5官方仓库自带的detect.py就够用python detect.py --weights best.pt --source data/images --conf-thres 0.5命令里的--weights指定权重路径--source可以是图片、视频、摄像头设备号或目录--conf-thres是置信度阈值低于这个值的检测框会被过滤掉。如果设备是CPU建议加上--device cpu显式指定否则YOLOv5默认尝试用cuda。跑完看runs/detect/exp目录下有没有生成带框的图片。这一步能同时验证三件事PyTorch能不能正常加载权重、数据集标签格式是否正确、后处理NMS有没有报错。冒烟测试过了再往下做训练或二次开发才有意义。3. 训练复现把模型调到高分作业的水平3.1 数据集组织YOLO格式的目录约定交通标志检测项目的数据集目录结构必须严格遵守YOLO约定否则训练直接报AssertionError: Label not found。标准结构是datasets/ ├── traffic_sign/ │ ├── images/ │ │ ├── train/ │ │ │ ├── 00001.jpg │ │ │ └── ... │ │ └── val/ │ │ ├── 00002.jpg │ │ └── ... │ ├── labels/ │ │ ├── train/ │ │ │ ├── 00001.txt │ │ │ └── ... │ │ └── val/ │ │ ├── 00002.txt │ │ └── ... └── traffic_sign.yaml注意三个铁的约定第一图片和标签的主文件名必须完全一致扩展名不同没关系第二标签文件是纯文本每行格式为类别id x_center y_center width height且坐标必须是归一化后的0到1之间的小数第三traffic_sign.yaml里必须写train和val的路径路径可以是绝对路径也可以是相对项目根目录的路径。我见过不少翻车案例就是Windows下用\分隔路径换到Linux就找不到文件。这个项目的数据如果组织不规范你拿到手第一件事就是写脚本检查命名对应关系。检查标签文件是否异常的脚本很简单import os img_dir datasets/traffic_sign/images/train label_dir datasets/traffic_sign/labels/train for img_name in os.listdir(img_dir): stem os.path.splitext(img_name)[0] label_path os.path.join(label_dir, stem .txt) if not os.path.exists(label_path): print(fMissing label for {img_name}) else: with open(label_path) as f: for line in f: parts line.split() if len(parts) ! 5: print(fBad format in {label_path}: {line})这段代码做的事很朴素遍历所有训练图片检查同名标签是否存在然后逐行校验每行是不是5个数。跑一遍如果没有任何输出说明数据组织是健康的可以进入训练环节。数据这块宁可多花10分钟检查也不要直接开训然后等报错后者浪费时间得多。3.2 训练入口train.py 的关键参数与超参调整YOLOv5的训练入口是train.py数据准备好之后一条典型的训练命令长这样python train.py \ --data traffic_sign.yaml \ --weights yolov5s.pt \ --batch-size 16 \ --epochs 100 \ --imgsz 640 \ --device 0逐项解释参数--data指向数据配置文件--weights是预训练权重yolov5s.pt 是官方在COCO上预训练的模型用它的好处是收敛快、精度高典型的迁移学习做法--batch-size取决于显卡显存6GB显存跑16没问题如果你只有CPU建议调到4甚至2否则OOM是必然的--epochs是训练轮数这个项目既然有100轮左右的训练日志说明作者在合理范围内--imgsz是输入分辨率640是速度和精度的平衡点。训练结束后runs/train/exp目录下会生成weights/best.pt和weights/last.ptbest是验证集指标最好的权重last是最后一轮的权重。做课程设计答辩时用best.pt就对了。超参数配置文件data/hyps/hyp.scratch-low.yaml里有一堆参数但我建议不是调参高手就别动它。唯一值得关注的是mosaic这个增强项默认是1.0开启它把四张图拼成一张训练对小目标检测很有效——交通标志恰好是典型的小目标场景。如果你的数据集图片数量少比如不到500张把mosaic从1.0改成0.5让它交替使用普通增强能减少因为图片拼接导致的语义错乱。这个参数用代码改# 在hyp.scratch-low.yaml中修改 mosaic: 0.5 # 原来默认是1.03.3 评估指标用mAP判断模型真实水平训练过程中的输出的metrics/mAP_0.5是核心指标它表示IoU阈值0.5时的平均精度均值。交通标志检测的难点在于目标小、类别多限速、禁令、指示、警告mAP0.5做到0.8以上就是不错的水平如果低于0.5基本就是数据集标注有问题或训练不充分。除了mAP还要看混淆矩阵confusion matrixYOLOv5在训练结束后会自动生成在runs/train/exp/confusion_matrix.png。我习惯先看这个图它能告诉你哪些类别互相混淆——比如限速30和限速40因为外观相似经常被搞混这时候单纯加大epoch意义不大要么增加对应类别的样本量要么检查标注框是否有偏移。4. 数据增强与类别平衡小目标检测提点的关键操作4.1 交通标志的小目标问题为什么默认增强不够用交通标志在实际场景里占比往往很小假设一张1080p的图片里标志只有80x80像素按640分辨率缩放后只剩下约47x47像素。YOLOv5在 stride32 的检测层上这个目标可能只对应2个左右的grid cell非常容易漏检。默认的mosaic、copy_paste等增强手段对中大型目标效果好但对小目标关键要靠image_weights采样策略和多尺度训练。解决思路有两个方向一是数据层面对包含小目标的图片做过采样二是增强层面开启multi-scale参数让模型在不同输入尺度上训练。后者很简单训练命令加一行python train.py \ --data traffic_sign.yaml \ --weights yolov5s.pt \ --batch-size 16 \ --epochs 100 \ --multi-scale--multi-scale的作用是每10个batch随机从0.5到1.5倍之间缩放输入尺寸。这样模型能看到不同尺度的目标对小目标检测能力有明显提升。代价是训练时间大约增加20%到30%但如果你的交通标志数据集里小目标占比高这个时间花得值。4.2 按类别统计样本量找到你数据集的真实短板很多课程设计的数据集是从网上下载后直接用的类别分布往往不均匀。比如停止标志的图片有500张而禁止驶入只有50张模型学出来肯定偏向前者。写个小脚本统计一下import os label_dir datasets/traffic_sign/labels/train class_count {} for f in os.listdir(label_dir): with open(os.path.join(label_dir, f)) as fh: for line in fh: cls_id int(line.split()[0]) class_count[cls_id] class_count.get(cls_id, 0) 1 print(class_count) # 输出示例: {0: 320, 1: 45, 2: 180, 3: 290}如果发现某个类别的box数量明显偏少有三条路可走。第一去开源数据集找补网上有TT100K腾讯交通标志数据集和德国GTSRB数据集都是交通标志检测常用的公开资源第二做在线增强的加强比如对包含稀有类别的图片加大hsv扰动和旋转角度第三用--hyp参数单独给稀有类别调整loss权重。前两种比较推荐第三种需要改代码容易引入不可控变量课程设计阶段不划算。数据增广只是一种后悔药它能锦上添花但救不了标注错误或样本极度不均衡的烂摊子。5. 避坑排查YOLOv5交通标志训练最常见的六个坑5.1 CUDA OOM 与 batch-size 的玄学现象训练刚跑完第一个epoch程序报RuntimeError: CUDA out of memory。原因不是你的显卡不行而是batch-size乘上imgsz乘上模型参数量超出了显存物理上限。YOLOv5s在640分辨率下一张图大约占2GB内存8GB显卡跑batch-size 16基本就是极限。如果你同时开了TensorBoard、IDE和浏览器显存被其他进程吃掉了一部分那OOM就更早了。解决先降batch-size到4如果还OOM就降到2同时用nvidia-smi查看显存占用确保没有残留的训练进程。还有一个被忽略的点--workers参数默认是8数据加载线程吃的是内存不是显存但如果你内存本来吃紧也会间接影响。设成2试试。如果必须用大batch还有一个折中方案开启梯度累积把batch-size设小但通过--accumulate模拟大批次效果不过这个参数YOLOv5官方train.py里默认根据batch和显存自动算的不建议手动干预。5.2 权重文件加载报错KeyError 与 Unexpected key(s)现象加载预训练权重时报Error(s) in loading state_dict for Model: Missing key(s) in state_dict。原因你下载的yolov5s.pt版本和当前代码版本不匹配。YOLOv5迭代很快v5.0和v6.0的模型定义就有差异v6.0和v7.0的anchors设置也不同。用不同版本的权重加载到当前项目就会出现键不匹配。这个项目里自带的权重如果是从随附代码训练出来的那一定配得上但如果你自作主张从官方GitHub重新下载权重就容易踩这个坑。解决先用项目自带的best.pt做推理别换权重。如果你的确想从官方yolov5s.pt起步迁移学习先去models/yolov5s.yaml里确认当前代码是哪个版本的配置再到对应版本的Release页面下载权重。版本不一致时YOLOv5代码会报明确的警告可以看一眼警告文本里的具体缺失keys来确认差异位置。5.3 标签框全部丢失Label box x centers and widths are zero现象训练一开始就提示大量标签为0或者损失值始终在很大范围震荡不收敛。原因坐标归一化出错。常见的两种第一标注工具导出的是像素坐标比如VOC格式的xmin, ymin, xmax, ymax忘了除以图片宽高做归一化第二数据集中存在纯背景图片即jpg有但txt的内容为空YOLOv5会跳过空标签图但如果所有图片都是空的loss直接崩。解决写脚本统一做归一化下面是VOC格式转YOLO格式的关键片段import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, img_w, img_h, class_map): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text cls_id class_map[name] bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) return lines这个函数做了四件事解析XML、获取物体类别和边界框坐标、将像素坐标转成归一化的中心点坐标与宽高、格式化输出文本。注意边界框坐标如果出现负数或超出图片范围的脏数据也要在这里做截断处理。数据清洗这步没有捷径逐张检查不现实但至少保证所有坐标在0到1之间。5.4 训练正常但mAP非常低且不涨现象loss持续下降但mAP0.5永远停在0.2到0.3之间。原因多半是类别id错位。比如数据集中class 0是限速class 1是停止但配置文件traffic_sign.yaml的names列表顺序和标注文件里的id对不上。还有种情况是验证集的标注文件有大量错误验证loss失真导致best.pt选在了错误的时间点。解决打开traffic_sign.yaml做代码检查确认names顺序和标注id一一对应。如果验证集标注错了最干脆的办法是重新划分验证集——从训练集里随机抽10%到15%的图片用程序和训练标签一起做二次校队。5.5 模型推理速度慢达不到实时现象GPU上推理一张图要100毫秒以上或者CPU上根本跑不动视频流。原因模型权重选了YOLOv5l或x系列这类大模型精度高但推理开销大也可能是--imgsz分辨率设得太高比如1280。课程设计通常不需要那么高的精度速度和效果的平衡最关键。解决换用自带或者重新训练YOLOv5s然后把推理脚本里的--imgsz降到416或320。交通标志本身是简单目标YOLOv5s配合416分辨率就能跑出不错的准确率而且速度能到实时。另外推理时可以开半精度# detect.py中的模型加载部分 model torch.load(weights_path, map_locationdevice)[model].float() # 改为 model torch.load(weights_path, map_locationdevice)[model].half()半精度推理会快30%左右。只有新的GPU架构对half支持不好才可能出问题建议推理前先跑几张图确认结果正常。实测下来最稳妥的方式还是直接把模型转成TensorRT或ONNX不过课程设计阶段没必要走到这一步。5.6 数据增强过头增强后标注框错位现象训练集上loss降得很低但验证集效果很差或者目测检测框位置偏了半个身位。原因增强参数设置得太激进尤其是旋转角度、剪切、透视变换。比如degrees: 45训练时图片被旋转45度标注框也跟着转但如果是矩形标注框旋转后必须重新计算否则框和目标的贴合度变差。解决检查hyp.*.yaml把degrees调回10以内shear回到2以内perspective回到0.0005左右。交通标志不存在倒挂的场景旋转增强角度本来就该保守一点。我习惯是先关掉所有增强训一个baseline确认模型能正常收敛再逐项打开增强看指标变化。这样能定位到具体是哪个增强拉低了验证集效果。6. 部署与二次开发把模型跑进摄像头和自定义场景训练完模型最终要落到实际场景里验证。最实用的做法是接摄像头做实时检测YOLOv5的detect.py直接支持python detect.py --weights best.pt --source 0 --conf-thres 0.5--source 0表示打开本机默认摄像头。跑起来之后你会很快发现交通标志的检测好不好光照和运动模糊是两大杀手。这时有两个技巧可以临时救场一是适当降低--conf-thres到0.3允许更多低置信度候选框进入NMS阶段二是开启跟踪功能YOLOv5的detect.py支持--track参数需要额外安装跨帧保持目标ID能明显减少漏检带来的闪烁感。如果想把模型集成到自己的程序里比如做成一个Streamlit标注工具或者安卓端检测应用直接调YOLOv5的库接口更干净import torch model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt, sourcelocal) # 推理单张图片 img test.jpg results model(img) results.show() # 可视化 # 结果里包含boxes、labels等结构化数据 boxes results.pandas().xyxy[0] print(boxes[[xmin, ymin, xmax, ymax, confidence, class, name]])torch.hub.load的sourcelocal参数很关键它告诉PyTorch从项目本地加载YOLOv5源码而不是联网拉取官方仓库——后者会自动下载最新版YOLOv5和你训练时的代码版本可能不一致导致权重无法加载。别问我是怎么知道的这个坑我踩过不止一次。我当时做另一个检测项目时就是被模型加载搞到头皮发麻。从那以后我每次都强制走一遍固定检查流程先看权重文件的修改时间再用项目自带detect.py跑冒烟测试最后才动torch.hub.load。这三步顺序不能乱任何一步有问题就停下来查原因绝对不带着疑问往下走。希望这份拆解能帮你把这个项目顺利跑通尤其是那些准备拿它交作业的朋友——少走弯路一次过审。本文还有配套的精品资源点击获取
返回列表