尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

YOLOv5实现交通标志识别:从数据集训练到部署完整指南

YOLOv5实现交通标志识别:从数据集训练到部署完整指南 简介深度学习目标检测技术在智能交通领域扮演着关键角色而YOLOv5作为单阶段检测算法的优秀代表以其高精度和实时性成为交通标识识别任务的热门选择。交通标志检测涉及数据处理、模型训练与推理部署等多个环节需要从数据集构建到特征提取、锚框设计等原理层面的全面理解。掌握YOLOv5的工程实践方法不仅能高效识别限速、禁行等常见标志还能为自动驾驶、辅助驾驶及道路巡检等场景提供可靠的技术支撑。本文围绕YOLOv5展开完整介绍了交通标识识别系统的实现流程包括数据集格式转换、模型训练调参、实时检测与部署优化等关键步骤帮助开发者快速构建可落地的视觉识别解决方案。1. 项目概述与整体技术选型1.1 这个系统的核心价值和应用场景道路交通标识识别放在五年前还是个偏科研向的课题这两年已经成了自动驾驶、辅助驾驶、道路巡检这些方向里绕不开的基础能力。你开车时看到的限速牌、禁止转弯、人行横道预告、施工警告如果能被摄像头实时捕捉并正确分类就能为车辆决策提供关键信息。网上能找到的交通标识识别项目不少但很多要么数据集太老、要么代码结构混乱、要么跑起来一堆依赖报错。我自己在实际工程里反复对比过几个方案最后稳定复现、改起来顺手、部署也方便的还是YOLOv5这套路线。这个项目的核心内容是用YOLOv5算法训练一个针对道路交通标识的目标检测模型配合Python脚本完成从数据集准备、模型训练、评估到实时识别的完整闭环。源码里包含了完整的训练流程、推理接口和可视化工具拿到手之后你可以直接跑通检测效果再根据自己的业务场景替换数据集做二次训练。适合谁来参考如果你是刚入门目标检测的学生想找一个能真正跑起来、能看懂每个环节怎么串起来的项目这个源码很合适如果你是在做辅助驾驶相关的产品原型需要快速验证交通标识识别这个模块的可行性这套东西也能帮你省掉从零搭环境的折腾哪怕你是纯粹对YOLOV5感兴趣想弄明白训练自己的数据集到底要走哪些流程这份源码的工程组织方式也值得过一遍。1.2 为什么选择YOLOv5而不是其他算法交通标识检测这个任务表面上看就是通用目标检测的一个子集但它的特殊性在于目标尺寸往往比较小且经常出现在复杂背景里——比如逆光、雨雾、遮挡、相似形状干扰等。传统目标检测方法如HOG SVM在简单场景下尚可一战一旦面对真实道路环境泛化能力就很难撑住。深度学习方案里大家常用的目标检测算法可以大致归为两类两阶段检测器和单阶段检测器。两阶段的代表是Faster R-CNN系列精度高但推理速度相对较慢单阶段的代表是SSD和YOLO系列速度优势明显精度上近年来也追得很紧。HOGSVM在CPU上跑一帧大概需要几百毫秒识别率还不稳定Faster R-CNN精度确实好但在嵌入式设备或者实时性要求高的场景下帧率上不去相比之下YOLOv5在COCO数据集上的优秀表现以及它在工程落地方面的成熟生态让它成为交通标识识别这类对实时性有硬性要求、同时还要保证精度的任务的合理选择。实际做项目选型时我考虑的不只是“哪个算法mAP高”还会看重三件事第一社区的活跃度和资料丰富程度遇到问题能否快速找到解决方案第二代码的可读性和可扩展性因为交通标识识别通常需要针对特定类别做定制第三推理部署的便利性包括导出ONNX、TensorRT等格式是否顺手。YOLOv5在这三点上表现都比较均衡这也是我在多个项目中反复用它兜底的原因。1.3 完整的技术架构与运行流程整个系统的运行链路可以拆成四段来理解数据层收集/下载交通标识图片完成标注人工标注或借助工具将标注结果整理成YOLO格式的txt文件。预处理层按比例划分训练集、验证集和测试集执行数据增强缩放、翻转、马赛克增强等生成数据集配置文件。训练层加载YOLOv5的预训练权重配置模型结构、超参数在GPU上完成模型训练输出best.pt和last.pt权重文件。推理层读取训练好的权重对图片、视频流或摄像头画面执行检测输出带标注框和类别标签的识别结果。这个链路里的每一段YOLOv5源码都提供了现成的模块和脚本我们要做的事情是理解每个环节的作用把参数调对再把数据集准备好。下面我会按这个顺序逐段展开把我实际操作中的配置过程、踩过的坑和心得一并分享出来。2. 数据集准备与预处理训练一个能用的检测器先过数据这关2.1 交通标识数据集的现状与选择很多新手拿到YOLOv5源码第一反应是赶紧跑训练结果用的还是源码自带的coco128迷你数据集跑完当然也能出图但检测的类目里根本没有交通标识。真要做一个识别交通标识的系统第一步就得解决数据问题。交通标识领域有几个公开数据集可以选TT100K是目前国内用得比较多的交通标志数据集包含数万张包含交通标志的图像标注比较规范涵盖限速、警告、指示等几个大类CCTSDB是国内学者整理的交通标志数据集同样包含训练集和测试集LISA数据集是国外的包含美国的交通标志类别风格和国内差别较大。如果你的业务场景在国内TT100K和CCTSDB的匹配度会高一些。需要提醒的是TT100K这个数据集有它的特殊性数据里涉及几百个标注类别但很多类别只出现几次直接拿全部类别训练会导致严重的类别不平衡。实际操作中我通常会筛选出现频次较高的类别来构建训练集——比如只保留限速标志包括具体的限速数值、禁止通行、禁止驶入、注意行人、施工标志等20个左右的核心类别。宁可类别少一点、每类的样本量均衡一点也不要去强行覆盖几百个类别把模型练废。2.2 标注格式转换与目录结构组织YOLOv5训练所需的标注格式是YOLO txt格式每行代表一个目标内容是“类别id 归一化中心x 归一化中心y 归一化宽w 归一化高h”。坐标值全部相对于图片宽高归一化到0到1之间。但TT100K原始标注是JSON格式CCTSDB是XML格式VOC风格所以拿到数据后的关键一步就是做格式转换。我专门写过一个小脚本做这个转换核心逻辑如下import json import os from PIL import Image def convert_t100k_to_yolo(json_path, img_dir, out_dir, category_map): with open(json_path, r, encodingutf-8) as f: data json.load(f) for img_name, info in data[imgs].items(): img_path os.path.join(img_dir, img_name) if not os.path.exists(img_path): continue with Image.open(img_path) as img: w, h img.size txt_path os.path.join(out_dir, img_name.replace(.jpg, .txt)) lines [] for obj in info[objects]: category obj[category] if category not in category_map: continue cid category_map[category] box obj[bbox] x_min, y_min, x_max, y_max box[xmin], box[ymin], box[xmax], box[ymax] x_center (x_min x_max) / 2 / w y_center (y_min y_max) / 2 / h box_w (x_max - x_min) / w box_h (y_max - y_min) / h lines.append(f{cid} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines))目录结构上我建议严格遵循YOLOv5约定的组织方式datasets/ ├── traffic_signs/ │ ├── images/ │ │ ├── train/ # 训练图片 │ │ └── val/ # 验证图片 │ ├── labels/ │ │ ├── train/ # 与训练图片一一对应的txt标注 │ │ └── val/ # 与验证图片对应的txt标注 │ └── traffic_signs.yaml # 数据集配置文件有个细节特别容易踩坑图片文件名和标注txt文件名必须严格一致包括后缀。YOLOv5读取数据时会通过替换后缀的方式寻找标签文件比如a.jpg对应找a.txt如果文件对不上训练时会出现大量警告“WARNING: No labels found in ...”这时候要立刻回头检查数据文件是否对齐。2.3 数据增强与类别平衡策略YOLOv5自带了比较丰富的数据增强配置默认就包含Mosaic增强、随机透视变换、HSV色域调整、随机翻转等。Mosaic增强是YOLOv5的一个亮点它将4张训练图片随机缩放后拼接成一张新图好处是大大提升了小目标检测的效果因为拼接后每张子图里的目标相对于整图的尺寸进一步缩小模型需要学会在更小的尺度下识别目标——这对交通标识这类中小尺寸目标尤其有利。类别不平衡方面我建议在数据处理阶段就做一次频次统计。比如你用TT100K筛选出的20个类别可以画一个柱状图看每个类别的样本数如果某个类别的样本数特别少低于50要么想办法补充数据要么干脆先放弃这个类别。类别数量差距超过10倍的训练时模型会明显偏向样本量大的类别导致少数类几乎检测不出来。YOLOv5里可以通过调整cls_loss_gain或者给数据做重采样来缓解但这些手段都不如直接从数据源头上平衡来得有效。3. YOLOv5核心原理与本地环境搭建3.1 从原理上说清YOLOv5到底在做什么YOLOv5整体结构可以拆成三个部分Backbone、Neck、Head。Backbone负责提取特征YOLOv5使用的是CSPDarknet结构的变体。CSPCross Stage Partial结构的核心思想是把特征图分成两部分一部分走密集连接层另一部分直接拼接过去这样既减少了计算量又能保持梯度流的丰富性。YOLOv5的Backbone还引入了Focus结构在较新版本中改为6x6卷积用于在保留信息的同时对输入图像做下采样。Neck负责特征融合YOLOv5采用PANetPath Aggregation Network结构。简单理解目标检测需要同时识别不同尺寸的目标深层特征语义信息丰富适合识别大目标但分辨率低对细节位置不敏感浅层特征分辨率高、细节清楚但语义信息不够。PANet做的事就是把深层语义信息和浅层细节信息通过自顶向下和自底向上两条路径进行特征融合然后输出三个不同尺度的特征图。这也是为什么YOLOv5能在同一张图上同时检测比较大的警告牌和比较小的圆形限速牌。Head负责最终的分类和定位YOLOv5采用锚框Anchor机制在三个尺度上分别设定不同尺寸的锚框。模型对每个锚框预测三样东西目标属于每个类别的概率、目标框中心坐标和宽高的偏移量、以及该锚框包含目标的置信度。推理阶段再做NMS非极大值抑制过滤掉冗余的重叠框最终输出每个目标的类别、置信度和位置坐标。理解这个结构的意义在于当你的检测效果不好时能大致判断问题出在哪个环节。比如小目标检测不到重点去检查Neck的浅层特征融合和锚框尺寸设置类别混淆严重重点去看Head的分类分支和样本均衡。3.2 环境搭建与依赖安装含坑YOLOv5的依赖说简单也简单核心就是PyTorch框架加几个辅助库但实操中会踩到各种环境坑。我建议用conda创建独立环境避免和系统Python环境互相污染。conda create -n yolov5 python3.8 conda activate yolov5 # 先装PyTorch务必根据自家CUDA版本选择对应的安装命令 pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu117 # 再安装项目依赖 cd yolov5 pip install -r requirements.txt关于CUDA这里必须多说几句。很多新手一上来就装最新的CUDA和cuDNN结果发现PyTorch版本不匹配运行时直接报“CUDA error: no kernel image is available”。先跑nvidia-smi查看当前显卡驱动支持的最高CUDA版本再去PyTorch官网选一个匹配的版本。以我自己的经验CUDA 11.7搭配PyTorch 1.13是比较稳定的组合跑YOLOv5不会出什么幺蛾子。如果你只有CPU环境也能训练就是速度慢得让人怀疑人生一张500多张图片的迷你数据集CPU训练可能要40分钟以上GPU通常几分钟就搞定。另一个高发的问题是requirements.txt里的opencv-python安装失败。如果遇到这种情况可以分开执行pip install opencv-python-headless这个版本去掉了GUI相关依赖在服务器环境适配性更好。3.3 源码目录结构解析YOLOv5的源码组织得比较清晰拿到项目后我建议先花10分钟把目录结构扫一遍train.py训练入口负责解析训练参数、加载数据、构建模型、执行训练循环。detect.py推理入口加载训练好的权重对图片/视频/摄像头执行检测。val.py验证入口在验证集上计算mAP、Precision、Recall等指标。models/目录存放模型结构定义其中yolov5s.yaml、yolov5m.yaml、yolov5l.yaml等分别对应不同规模的网络配置。data/目录存放数据集配置文件示例比如coco128.yaml、coco.yaml。utils/目录包含各种工具函数比如数据集加载器、损失函数、增强策略、指标计算等。weights/目录用于存放预训练权重和训练输出的权重文件。对新手来说需要改动的文件其实只有几个train.py是入口但你通常不需要动它的源码直接命令行传参就行models/yolov5s.yaml里可以改nc类别数data/目录下新建一个自己的yaml文件指定训练集、验证集路径和类别名称列表。理解每个文件的作用后续调试时才知道去哪里看问题。4. 模型训练实操从命令行到调参心得4.1 训练前的配置文件修改训练之前有两条主线要改一条是数据集配置文件另一条是模型结构文件如果你的类别数跟默认不一样。先看数据集配置文件。在data目录下新建一个traffic_signs.yaml内容如下# 训练集和验证集图片的根路径 train: /path/to/datasets/traffic_signs/images/train val: /path/to/datasets/traffic_signs/images/val # 类别数量 nc: 20 # 类别名称列表顺序必须与标注txt里的类别id一一对应 names: [speed_limit_30, speed_limit_40, speed_limit_50, speed_limit_60, speed_limit_70, speed_limit_80, no_entry, no_parking, yield, stop, pedestrian_crossing, construction, ...]需要特别注意一点names列表的顺序必须和标注文件里类别id的编码顺序一致。比如你的标注里类别id为0对应的是限速30那names[0]必须写speed_limit_30。如果顺序填错模型会正常训练但检测出来的类别名全部错乱而且你很难一眼发现问题。再看模型结构配置。以yolov5s.yaml为例只需要改一个参数nc: 20 # 把默认的80改成你自己的类别数YOLOv5的不同模型规模从上到下依次是yolov5s最小、yolov5m、yolov5l、yolov5x最大。模型越大精度上限越高但训练和推理速度也越慢。我做交通标识识别时主流GPU如RTX 3060以上用yolov5s起步如果有更高的精度要求再往上换。4.2 训练启动与参数选择训练命令的基本写法如下python train.py --img 640 --batch 16 --epochs 100 --data traffic_signs.yaml --weights yolov5s.pt --name traffic_signs_run看到这里可能有人会问为什么这些参数要这样设置我逐个拆解--img 640表示输入图像尺寸为640x640。YOLOv5的输入图像会在保持长宽比的前提下缩放并填充到640x640。调大这个值比如1280有助于检测小目标但会显著增加显存占用和训练时间。交通标识识别场景中许多交通标识在图像中占比并不大如果显存充足并且重点考虑小目标场景可以选1280试一下如果显存有限或者以实时性为主640是比较稳妥的默认值。--batch 16表示批大小。这个参数直接影响训练稳定性、收敛速度以及显存占用。批大小越大越好——它让梯度的估计更准确但显存有限如果显存报错优先降低batch。在RTX 3060 12G上用yolov5s训练batch 16跑640尺寸很从容更大batch就需要更高显存的卡了。--epochs 100表示训练轮数。这个值不是越大越好。模型在几十轮后就可能过拟合在验证集上mAP反而下降。我一般会设个100~150然后根据训练曲线判断是否提前停止。YOLOv5有EarlyStopping机制patience默认100也就是说如果连续100轮验证集指标没有提升训练会自动终止。训练启动后终端会实时打印每一轮的训练损失、验证损失、mAP等指标。关键是观察mAP0.5这个指标表示IoU阈值为0.5时的平均精度一般能到0.9以上就说明模型在验证集上表现相当好了。还要留意训练损失是否持续下降——如果训练损失下不去或者反复震荡很可能是学习率设置有问题或者数据本身就有问题。4.3 训练过程中的监控与评估训练完成后结果会输出到runs/train/traffic_signs_run/目录下。我强烈建议多看几个文件results.png是训练过程的完整曲线图包含train/loss、val/loss、mAP0.5、mAP0.5:0.95、Precision、Recall等指标的曲线。如果你的mAP曲线上升后开始下降说明过拟合了如果还在一路攀升说明可以继续增加训练轮数。confusion_matrix.png是混淆矩阵能直观看出哪些类别之间互相混淆。我做交通标识训练时最常出现的混淆是限速30和限速40——因为两者都是红圈白底黑字外观十分接近如果训练数据里这两个类别的样本量和角度差异不够模型就容易混淆。这种情况下要么补充更多不同角度、距离、光照条件下的样本要么考虑在业务层面对这两个类别做合并处理。val_batch0_labels.png和val_batch0_pred.jpg是训练过程的验证集可视化结果前者显示标注的真实框后者显示模型的预测框。对比这两张图可以直观看到哪些目标没被检出来、哪些目标框位置偏了。还有一个我习惯做的小操作训练结束后用best.pt在测试集上跑一次--task test模式得到更客观的性能评估避免只盯着验证集的指标看。4.4 调参经验分享调参是个经验活每个人的情况不同但有几条通用的经验可以分享。第一数据质量永远比模型参数重要。我见过很多同学训练效果不好第一反应是去调学习率、调锚框但实际上问题出在标注文件错标、漏标太多。训练之前一定要先抽几十张图人工确认标注框是否贴合目标、类别是否准确。一个标注错误的目标在几百个训练样本中可能不算什么但如果在关键类别上错误比例较高对最终检测效果的影响是显著的。第二学习率的设置要参考YOLOv5默认的策略。YOLOv5默认学习率lr00.01训练过程中会采用warmup和余弦退火策略动态调整。新手不建议随便调大lr0否则容易在训练初期就发散如果损失下降得特别缓慢可以尝试按0.002的步长上调边际训练效果提升有限。如果loss出现NaN第一时间检查是否是显存不足导致的内存溢出或者训练数据里有没有问题样本。第三锚框参数的调整要基于数据。YOLOv5有个自动计算锚框的功能在训练时会通过k-means聚类算法根据你的数据集重新计算合适的锚框尺寸。如果你用的是自定义数据集保持默认的--noautoanchor不开启让模型自动算一次会更贴合你的数据分布。我实测过在小目标占主导的交通标识数据上自动计算锚框后mAP大约能提升2到3个百分点这个提升幅度在精细调优阶段相当可观了。第四关于训练轮数和早停很多人有个误区就是“训练越久越好”。其实训练后期模型容易过拟合对真实场景的泛化能力反而下降。我一般会配合训练日志选择在验证mAP达到峰值的那一轮保存的权重不要盲目用最后一轮的权重做测试。YOLOv5的best.pt就是按验证集指标自动挑选的最优权重所以拿best.pt做推理通常比last.pt更合理。5. 推理部署与识别系统的完整实现5.1 加载权重与单张图片检测训练完成后你手里有best.pt这就是咱们训练好的模型权重。接下来要做的是把权重加载进来对图片执行检测。先看最基础的推理方式直接用YOLOv5自带的detect.pypython detect.py --weights runs/train/traffic_signs_run/weights/best.pt --source data/images/test.jpg --img 640 --conf-thres 0.25 --iou-thres 0.45--conf-thres是置信度阈值只有置信度大于该值的目标框才会被保留--iou-thres是NMS的IoU阈值用于过滤重叠的目标框。置信度阈值设得太高会漏检设得太低会有大量误检一般情况下0.25到0.4之间是合理区间。如果你想在Python代码里加载模型做更灵活的定制可以直接用YOLOv5提供的API方式import torch # 加载模型 model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/traffic_signs_run/weights/best.pt, force_reloadTrue) model.conf 0.3 model.iou 0.45 model.classes None # 过滤特定类别时可传入类别id列表如 [0, 1, 2] # 推理 img path/to/image.jpg results model(img) results.print() results.show() # 获取结构化检测结果 detections results.pandas().xyxy[0] # 输出字段xmin, ymin, xmax, ymax, confidence, class, name print(detections)torch.hub.load首次使用时需要联网下载权重和代码离线环境里这步会失败。如果你部署在无外网的环境建议直接从本地目录load即把yolov5仓库clone到本地后用system.path方式导入这样可以避免hub的网络依赖。5.2 视频流与摄像头实时识别交通标识识别系统真正派上用场的场景通常是处理摄像头视频流。YOLOv5的detect.py本身就支持视频输入和摄像头输入只要把--source参数改成视频文件路径或摄像头设备号如0即可。但如果你需要在业务系统里集成实时识别能力就不能直接用命令行方式了得自己写一个视频帧处理循环。下面是一个基于OpenCV读取视频帧、送入模型检测、绘制结果并显示的示例import cv2 import torch model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/traffic_signs_run/weights/best.pt, force_reloadTrue) model.conf 0.3 cap cv2.VideoCapture(0) # 0表示默认摄像头如果读视频文件则传入文件路径 cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) while cap.isOpened(): ret, frame cap.read() if not ret: break results model(frame) # 遍历检测结果并绘制 dets results.pandas().xyxy[0] for _, row in dets.iterrows(): x1, y1, x2, y2 int(row[xmin]), int(row[ymin]), int(row[xmax]), int(row[ymax]) conf row[confidence] name row[name] cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) label f{name} {conf:.2f} cv2.putText(frame, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imshow(Traffic Sign Detection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这段代码是实时识别系统的基础骨架。实际操作中你会发现摄像头画面推流一般是一路视频流模型推理速度是瓶颈。如果要分析多人同时使用的实时性我有两个经验一是把推理分辨率降到416或320会有明显的速度提升检测精度下降幅度通常可以接受二是使用模型导出后的FP16精度权重做推理能进一步降低显存占用和提速。5.3 识别结果的业务化输出检测结果如果只在界面上显示对业务系统的价值有限。更常见的需求是把识别结果对接进上层业务逻辑比如通过MQTT上报到云端、将检测结果写入数据库、触发告警等。我的做法是把检测结果封装成一个统一的结构def format_detections(det_df, source_id): items [] for _, row in det_df.iterrows(): items.append({ source: source_id, timestamp: datetime.now().isoformat(), xmin: int(row[xmin]), ymin: int(row[ymin]), xmax: int(row[xmax]), ymax: int(row[ymax]), confidence: float(row[confidence]), class_id: int(row[class]), class_name: row[name] }) return items拿到这个结构化数据后你可以按任意口径做业务处理。比如在限速识别场景里提取出speed_limit类别的结果和当前车辆速度做对比超速则触发提醒在禁行标志场景里识别到no_entry标志时结合GPS判断车辆是否闯入禁行区域。这些业务规则都与检测模型本身无关属于上层逻辑但底层的识别结果格式一定要设计得干净、可复用。6. 常见问题与排查技巧实录6.1 训练阶段高频问题问题一命令行启动训练后直接报错“AssertionError: Label class ... exceeds nc... in data/xxx.yaml”。这个报错的意思是标注文件里出现了类别id大于或等于你配置的nc值。比如你的nc20但某个标注txt里写了一个数字20的类别id自然就超界了。排查方法是扫一遍所有标签文件找出最大值然后检查数据合并或转换时是否出了问题。我自己有一次就是合并多个数据集时忘了重新映射类别id导致新数据集的类别编号从原来的20开始编号直接越过配置范围。问题二训练时提示“CUDA out of memory”。显存不足在训练中非常常见。优先把batch调小比如从16降到8如果还不行把--img从640降到512或者换更小的模型比如从yolov5m降到yolov5s。还有个小技巧在train.py参数里加--cache ram让数据先缓存到内存里再进GPU也能降低显存压力。问题三训练损失持续不下降。这种情况先检查学习率设置如果自定义过lr0还原默认值试一遍再检查标注文件的正确性随机抽几个标注文件手动解析一下坐标看是否有负值、宽高为0、或者坐标超出图片范围等异常情况。这类脏数据在自定义数据集里非常常见一个宽高为0的标注框就足以让损失在训练初期直接发散。6.2 检测效果不佳的调优方向如果你的模型训练完成但实际检测效果不理想不要急着换模型结构按照下面的优先级排查。第一优先级检查数据覆盖度。检测不到某个类别往往是因为训练数据里该类别的样本太少或者样本形态太单一。比如限速30的标志在训练集里都是正面大图但实际场景中大量出现的是侧面小图那检测效果自然不会好。补充多样性样本比任何调参手段都有效。第二优先级调整置信度阈值和NMS参数。误检多就提高--conf-thres漏检多就降低重叠框多就降低--iou-thres检测框太稀疏就提高。这些参数不需要重新训练实践里改成数值就能生效应该先试这个。第三优先级针对小目标优化。如果你发现漏检的多是远处的小标志可以考虑用更大尺寸的输入图--img 1280重新训练或者把模型从yolov5s升级到yolov5m/yolov5l。后者会增加推理耗时你需要根据自己的硬件情况做权衡。第四优先级考虑类别合并。相似类别如不同数值的限速标志在大部分场景下可以合并成一个“限速标志”类等业务有分类需求时再用一个轻量级分类器做二次分类。这个做法在工程落地里非常实用既能提升检测召回率又不影响最终业务效果。6.3 部署阶段的注意事项如果要把训练好的模型部署到实际环境第一步就是把PyTorch模型导出为更通用的格式。YOLOv5官方提供了export.py脚本python export.py --weights runs/train/traffic_signs_run/weights/best.pt --include onnx --img 640导出为ONNX格式后你可以用ONNX Runtime做CPU推理摆脱PyTorch的依赖推理速度在CPU上有明显提升。如果目标平台是NVIDIA GPU可以考虑导出TensorRT格式进一步优化推理延迟。这里要提醒一下ONNX部署时图像的预处理letterbox缩放、归一化、通道顺序调整要和训练时保持一致否则检测效果会大打折扣。另一个容易被忽视的问题是类别名称映射。部署到生产环境后检测结果通常只有类别id如果id和名称的映射关系只存在于训练配置里下游业务模块拿到的就是一个看不懂的数字。我建议流程上把names列表单独抽出来放到配置中心所有依赖检测结果的模块统一从这个配置中心读取映射关系避免各端自行维护一份“本地字典”导致对不上。还有一个经验是交通标识识别场景中模型推理结果带有天然的不确定性单帧置信度不高或者闪烁变化是正常现象。实际产品做决策时不要依赖单帧结果而是对连续多帧做跟踪或投票。比如连续5帧都识别出同一位置的“限速80”才认为这是一个可信检测结果这样能大幅降低误报率。这也算是一个准入门级的工程优化但效果往往比单纯调模型更明显。最后说一个我在多个项目中反复验证过的体会交通标识识别这类任务真正决定项目成败的往往不是模型本身而是数据的质量和工程细节的把控。YOLOv5给了我们一个很好的起点但怎样把数据集做干净、把参数调合理、把部署链路跑通这些功夫得自己下。这套源码把主线流程都铺好了剩下的就是你在数据上花心思、在调参中积累手感一步步把它打磨成能稳定工作的系统。如果你在实跑过程中卡在某一步建议先回到命令行输出和日志文件里找线索YOLOv5的日志已经标注得很清楚绝大多数问题都能在警告信息里找到方向。祝顺利训练出你自己的交通标识识别模型。本文还有配套的精品资源点击获取
返回列表