基于YOLO26的电瓶车与自行车检测系统开发实践
1. 项目整体设计与技术选型1.1 为什么做电瓶车与自行车检测这个项目的出发点其实很直接我接到了一个模拟园区安防系统的需求对方需要在监控画面里自动识别电瓶车和自行车用来做非机动车流量统计和指定区域闯入预警。翻了一圈现成的算法方案通用检测模型虽然能框出目标但在实际场景里有两个绕不开的问题——一是电瓶车和摩托车外观高度相似默认模型经常把这两类混在一起二是监控场景里目标尺度变化大小目标漏检率很高。换句话说通用模型解决的是“有没有东西”但这个项目要解决的是“这东西到底是什么、是不是需要关注的对象”。电瓶车和自行车这两类目标在真实场景中的检测难点是具体且琐碎的骑行者姿态变化大骑行、推行、停车、目标之间互相遮挡、雨天雾天画面模糊、夜间只有车灯可见等等。这些细节决定了直接套用预训练权重效果不理想必须走完整的“数据构建—针对性训练—工程化部署”流程。除了园区安防这类两轮车检测系统还能用在不少场景路口非机动车违章行为分析、停车场非机动车位占用检测、小区电动车禁入电梯预警、共享单车停放区域调度统计等。每个场景的数据分布不同但核心的算法框架和工程链路是一致的这也是我决定把整套流程完整记录下来的原因——让后面做类似需求的朋友有迹可循。1.2 目标检测框架的选型逻辑目标检测领域有两条主流技术路线。一条是两阶段检测代表是 Faster R-CNN 系列先选出候选区域再逐区域分类和回归精度确实高但速度往往快不起来在实时视频流场景里很难满足监控系统对流畅度的要求。另一条是单阶段检测代表就是 YOLO 系列把分类和定位放在同一个网络里直接回归牺牲了一小部分精度上限换来了显著的推理速度优势。项目最终选择 YOLO26核心原因是它在精度、速度和工程生态三者的平衡上最符合落地需求。前面几代 YOLO 在不同阶段解决过不同问题有的侧重骨干网络轻量化有的引入无锚框机制提升收敛速度有的在特征融合层面做文章。以 YOLO26 为代表的新一代框架把这些优化整合得相当成熟在基准测试上的精度表现已经不输很多复杂的两阶段模型同时推理帧率依然保持实时水平这是做监控类产品最看重的指标。更重要的是生态层面的成熟度。YOLO 系列的开源社区非常活跃从标注工具适配、训练脚本封装到部署时需要的模型导出工具链都形成了完整的配套方案。做工程项目的人会懂算法效果是基础但“能不能顺利部署到目标设备上”往往是更现实的问题。YOLO26 在这方面省了很多事支持常见的训练推理框架、可以导出多种部署中间格式、文档和社区案例相对丰富这些都是在项目排期压力下非常宝贵的优势。我也对比过其他方案。基于 Transformer 的检测模型在精度上很有竞争力但训练成本高、部署依赖复杂在算力有限的边缘设备上跑起来困难重重。SSD 系列推理速度可以但特征提取能力相对有限遇到电瓶车这种细节差异大、区分度要求高的任务效果往往差一口气。综合评估下来YOLO26 虽然不是所有场景的最优解却是这次项目里最稳妥的现实解。1.3 系统整体架构与核心设计思路整个系统的架构可以拆成四层来看。最底层是数据层负责图像和视频流的接入包括本地文件、USB 摄像头、RTSP 网络摄像头三种来源中间是推理层也是系统的核心负责图像预处理、YOLO26 模型推理、结果后处理再往上是业务逻辑层负责检测结果的过滤比如置信度阈值、特定区域规则、计数统计、告警判断最顶层是展示层用 PyQt5 实现可视化界面实时显示检测框、类别标签、FPS 和统计信息。四层结构的设计主要基于三个考量。第一是解耦模型推理逻辑和界面交互逻辑完全分离后续如果要把 PyQt5 界面换成 Web 端或者接入其它平台只需要替换展示层推理层的代码不用动。第二是并发界面渲染和模型推理各自跑在独立线程里避免推理阻塞主界面操作。第三是部署灵活性各个层之间的接口都定义得很薄便于以后把推理层嫁接到不同的硬件加速设备上。从实际开发顺序来看我建议先打通推理层再做界面层。先用脚本方式验证模型能够正常检测确认检测结果稳定可靠之后再开始设计 GUI。这样有个好处界面开发过程中遇到问题排查范围能明确锁定在交互层不会出现算法和界面问题混在一起互相干扰的情况。我见过一些新手项目一上来就搭界面结果模型效果不稳界面调试和算法调试纠缠在一起进度非常被动。2. 数据集构建与预处理细节2.1 数据来源与类别定义目标检测模型的效果上限很大程度上由训练数据决定。这个项目的检测类别比较特殊只有两类bicycle自行车和 ebike电瓶车/电动车。类别的定义看着简单实际操作中需要把边界理清楚否则标注人员会凭直觉标注最后模型学到的特征就乱了。我最终的分类规则是这样的脚踏板结构明显、以人力蹬踏为主的算自行车电动驱动、有电池仓、无脚踏板或脚踏板仅为装饰的算电瓶车。可能有人会问共享电单车算哪类我把它归到电瓶车因为外观特征和电瓶车更接近模型在这种数据上的区分能力也能得到加强。需要强调的是规则一旦定下来所有数据都要严格执行同一标准这是数据集质量的第一道防线。数据来源这块我做了组合搭配。一类是用公开基准数据集里已有的自行车和摩托车类别数据做底座这类数据量大、场景多样能提供充足的背景多样性。一类是针对项目实际场景自采的数据用监控摄像头在园区不同位置、不同时段拍摄画面覆盖了白天、傍晚、夜间、雨天等光照条件。第三类是从公开视频片段里截帧获得的数据补充一些特殊视角和运动模糊样本。三部分加起来初步筛掉重复帧和严重模糊帧之后保留了大约八千多张有效图片。数据划分遵循严格的互斥原则训练集、验证集、测试集按 8:1:1 划分并且确保同一个视频来源的帧不跨集合。这一点很多人容易忽略如果划分不严格同一个场景的相似帧同时出现在训练集和验证集里验证指标看起来很漂亮但模型一旦部署到全新场景效果立刻现原形。2.2 标注规范与质量把控标注是数据构建中最消耗精力的环节也是性价比最高的环节。我用的标注工具是常见的图形化标注软件支持导出 YOLO 格式的 txt 标注文件。YOLO 格式的每一行内容为类别id 中心点x 中心点y 宽度 高度所有坐标都归一化到 0~1 区间。标注规范上我定了几个硬性标准。首要原则是完整目标必须完整标注只要目标可见面积超过整体的30%就必须标注不能漏。遮挡情况下按可见部分标注框住看得见的区域即可不要凭想象去框被遮住的部分。类别归属不明的模糊目标宁可不标也不乱标样本噪声对模型的伤害远大于样本数量不足。质量控制分三步走。第一轮是标注员自检标注完成后浏览一遍标注效果修掉明显不准的框。第二轮是抽检我按10%的比例随机抽图检查框的贴合度、类别错误、漏标。第三轮是训练前的数据体检用预训练模型在这些数据上做一次推理找出模型强烈预测但未被标注的目标这些往往是漏标的高发区。三轮下来大约有3%的图片需要返工这个返工率在可接受范围内。2.3 数据增强策略让模型适应真实场景数据增强的目标很直白在不改变语义信息的前提下人为制造数据的多样性降低模型对特定背景、光照、角度的过拟合。YOLO26 框架自带了比较完整的增强管线但参数需要按实际情况调整不能用默认值一路跑到底。训练阶段我启用了以下几类增强。Mosaic 增强是最有效的手段之一把四张图片随机裁剪拼接成一张新图模型在训练中能看到更丰富的上下文信息也间接实现了尺度增强。随机仿射变换负责提供旋转、缩放、平移的变化帮助模型适应不同视角和距离。HSV 色彩空间扰动模拟不同光照条件下的色偏对白天夜晚、阴天晴天这种自然光照变化很有帮助。随机擦除模拟目标被遮挡的情况增强模型在部分目标不可见时的鲁棒性。参数设置上有一条经验值得分享增强幅度不是越大越好。比如 Mosaic 的拼接图如果裁剪太狠会产生大量残缺目标标签与视觉内容严重不匹配反而把模型学歪。我使用的缩放范围是 0.5~1.5旋转角度不超过15度HSV 色相偏移控制在±20以内。目标检测的增强参数有一个逻辑前提——所有变换必须保证人工看过去仍然能认出目标类别如果增强后的图片连人类都难以辨认模型也不可能学到有效特征。另外小目标问题需要单独考虑。监控画面中远处的电瓶车可能只有几十个像素大小直接训练时这类小目标对损失函数的贡献远小于大目标。除了依靠 Mosaic 增强天然带来的尺度多样性我还在预处理阶段把输入图像的分辨率从默认的640分辨率提升到了项目自定的1280相当于给模型更多像素来辨析细节后面会详细说这个参数选择。3. 模型训练的关键参数与过程记录3.1 环境配置与依赖清单训练环境的搭建不算复杂但版本匹配是个容易踩坑的地方。我用的核心依赖如下Python 3.10、PyTorch 2.x带 CUDA 支持、CUDA 11.8 运行环境、OpenCV-Python、NumPy、Pillow以及 YOLO26 框架对应的训练工具包。GPU 用的是单张消费级显卡显存24G属于训练检测模型比较典型的入门配置如果显存小于12G建议把批次大小和输入分辨率同步调低。依赖安装建议使用独立的虚拟环境不要和日常开发的 Python 环境混在一起。我在这一步踩过坑之前直接往全局环境里装深度学习依赖结果某个包版本冲突把其他项目的运行环境都污染了排查花了半天。后来所有实验项目都强制使用虚拟环境依赖冲突问题再也没有犯过。顺带记录一个细节图像解码库的选择会影响训练读取速度。默认的 OpenCV 图像解码在大量小文件场景下会成为数据读取瓶颈可以考虑开启框架自带的预读取和缓存机制或者把数据预处理成 LMDB 这类格式加速访问。实际测试中开启数据预读取后GPU 利用率从70%左右提升到了90%以上训练总耗时缩短了将近三分之一整个训练阶段能节约不少时间。3.2 训练超参数的选择与计算逻辑超参数是整个训练过程中变数最大的部分。我直接给出一套自己验证过相对稳定的配置再讲讲背后的调整逻辑。首先是输入分辨率。这个参数直接决定模型能看到多少细节我最终选择了1280像素作为训练和推理的输入尺寸。原因很简单监控场景里小目标占比高640分辨率下远处的电瓶车可能只有十几个像素特征信息严重不足。提高分辨率能显著改善小目标的检测精度代价是显存占用增加、推理速度下降。我的显卡配置下1280输入配合合适的批次大小可以稳定训练如果算力不够建议采用“训练用大分辨率、推理用小分辨率”的分阶段策略。批次大小和显存紧密相关。在1280分辨率下我设置的批次大小是16显卡显存恰好吃满。批次大小的选择要保证每个批次内的正样本数量足够如果类别少且小目标多批次太小会导致梯度估计噪声大训练不稳定。在数据类别只有两类、目标数量相对密集的情况下批次16在本次项目中表现稳定损失曲线平滑下降。学习率策略上我采用了前三个轮次预热加后续余弦衰减的组合。预热阶段学习率从0.0001逐步上升到初始学习率0.01目的是让模型在前期避免因为梯度方向剧烈变化而震荡。YOLO26 框架默认的优化器在自带的基础学习率下就能跑出不错的效果但不同数据集的最优学习率差异很大。判断学习率是否合适的初步方法是看前几十个迭代的损失值变化损失如果在下降且没有明显震荡说明学习率量级基本可行。训练轮次方面我设置了300轮但实际上用到约220轮就触发了早停条件。训练过程中框架会持续监控验证集指标如果连续多个轮次验证集 mAP 不再提升早停机制自动终止训练并保留历史最优权重。这个机制能有效避免无效的算力消耗也能防止后期过拟合。3.3 训练过程曲线解读与调优训练过程不是一路顺风的中间有一段损失下降得特别慢验证集 mAP 在0.65左右徘徊了将近30个轮次。当时第一反应是数据出了问题后来逐项排查才发现是数据增强参数过强——随机擦除的擦除比例设得太大大量目标被大面积抹掉模型根本没有足够的信息学会识别。调低擦除比例后验证集 mAP 在两个轮次内迅速突破到0.75后面稳步上升到0.87左右。这个经历让我意识到一个问题当模型卡在某个平台期不上不下时首先应该怀疑的不是网络结构而是数据或者增强参数。模型训练像做饭火候太大太小都会糊锅增强参数就是那把火要拿捏在刚好能增加多样性又不破坏语义信息的程度。最终评估结果汇总如下。验证集 mAP0.5 达到0.87mAP0.5:0.95 为0.63这个精度在两类近景远景混合的任务里算表现不错。类别单独看自行车的召回率略高于电瓶车主要原因是电瓶车的部分样本特别是夜间的与摩托车外观接近模型会产生一定混淆。推理速度方面1280分辨率输入在消费级显卡上单帧推理耗时约22毫秒对应45帧左右的实时检测能力部署到 CPU 环境时单帧耗时1.2秒左右只能用于离线处理实时场景必须依赖 GPU 或加速推理框架。4. PyQt5 界面设计与推理部署4.1 界面功能设计与交互逻辑界面是整个系统与用户对话的窗口功能设计要围绕使用者的真实操作习惯来组织。通过访谈目标用户园区安保人员、系统管理员我梳理出几个核心使用场景查看实时视频、回放检测结果、了解某个时段的车辆数量统计、调整告警灵敏度。PyQt5 在桌面端 GUI 开发中是个很成熟的选择控件丰富与 Python 生态无缝衔接开发效率高。界面布局采用左侧控制区、中部实时视频区、右侧统计信息区的三段式结构。左侧从上到下依次布置视频源选择本地视频文件、USB摄像头、RTSP网络流、连接与断开按钮、置信度阈值滑块、IOU阈值滑块、检测开关。中部是主显示区域使用 QLabel 控件实时刷新带检测框的画面。右侧显示当前统计数据自行车数量、电瓶车数量、总目标数、当前 FPS以及历史数量变化的折线简图。交互逻辑上做了一个重要设计置信度阈值和 IOU 阈值都做成可实时调节的滑块。这两个参数对检测结果影响立竿见影——阈值调高误检减少但漏检增加阈值调低检测更激进但可能出现误报。实际使用中园区白天光线充足时阈值可以设置在0.5左右夜间或雨天画面噪声大时适当调高到0.6以上更合适。让使用者自己调节能显著提升系统在不同环境下的适应能力。4.2 推理引擎封装与线程设计把模型推理逻辑封装成独立的 Detector 类是工程化的重要一步。这个类负责模型加载、图像预处理、推理、后处理全链路对外只暴露一个推理接口输入原始图像输出检测框列表、类别标签和置信度。PyQt5 界面层完全不知道模型内部做了什么只管把结果画到界面上。线程设计是界面流畅运行的关键。如果在主线程里直接执行模型推理界面会在每帧推理期间卡死按钮点了没反应视频画面一顿一顿的体验很糟。我的方案是启动一个专门的工作线程运行视频解码和推理循环通过自定义信号把带检测结果的图像传给主线程主线程只负责刷新界面。这种“生产-消费”模式在实践中非常稳定。为了让界面响应更加灵敏还有一个容易被忽略的细节图像从工作线程传到主线程时传递的是检测结果的副本而不是大尺寸图像本身。实际操作中工作线程把检测框坐标、置信度、类别传给主线程主线程再基于原始画面绘制检测框。这样做避免了多线程同时访问大内存对象的锁竞争问题界面刷新也更加流畅。线程生命周期管理也得注意。工作线程在窗口关闭时必须正确停止否则会出现关闭程序后后台进程仍然占用摄像头或模型显存资源的情况。我在停止逻辑里增加了超时机制向线程发送停止信号后最多等待若干秒超时则强制终止避免某些阻塞在视频流读取操作上的线程永远无法退出。4.3 模型导出与部署优化模型训练完成后要进入实际部署阶段首先需要把 PyTorch 格式的权重导出为更适合部署的中间格式。我导出 ONNX 格式时遇到过一个典型问题模型包含的一些动态尺寸运算在导出图上被固定为训练时的1280输入尺寸导致部署后只能处理固定分辨率图像。后来通过在导出命令中显式设置动态输入输出维度问题解决模型可以接受任意尺寸输入使用灵活度大大提升。ONNX 是最通用的开放格式兼容性最好但在推理速度上相比专用加速格式仍有差距。项目里我做了两档部署方案。第一档是 GPU 部署在 ONNX 基础上进一步转换为 TensorRT 加速引擎。转换完成后在消费级显卡上单帧推理耗时从22毫秒降低到11毫秒左右提升接近一倍同时显存占用也有明显下降。需要注意的是TensorRT 引擎与具体 GPU 型号绑定换机器需要重新生成引擎。第二档是 CPU 部署使用 ONNX Runtime 的 CPU 后端直接推理虽然速度有限但胜在环境要求低、兼容性最好。部署中还做了精度校准。导出和加速过程中由于算子融合和优化检测精度会有微小波动。我在转换后用测试集数据做了精度对比TensorRT 引擎与原模型的 mAP 偏差控制在1%以内属于可接受范围。如果发现精度下降超过预期要优先排查中间格式导出的算子在目标设备上的支持情况某些不支持的算子会导致低效回退甚至错误计算。选择合适的部署设备需要结合项目预算和现场条件。园区监控场景如果已有 GPU 服务器建议直接使用 TensorRT 方案能获得接近实时的处理能力。如果条件受限只能使用普通 PC 机CPU 方案也可以满足离线批量检测和低帧率实时检测的基本需求但要明确其算力天花板。5. 常见问题与排查技巧实录5.1 训练阶段的典型问题与对策训练阶段最常遇到的问题之一是 loss 前期不下降。我第一次跑的时候前几十次迭代损失几乎纹丝不动后来排查发现是批次大小太小导致每次梯度更新的样本代表性不足。把批次从8调整到16后损失立即进入健康下降通道。如果你遇到同样问题可以按优先级依次排查检查数据标注是否有大面积错误、检查学习率是否过小或过大、检查增强参数是否过强。顺序很重要因为数据问题对训练的影响最根本排查成本也最低。类别不均衡是另一个高发问题。我的数据里电瓶车样本明显多于自行车样本早期训练结果中模型对自行车的召回率比电瓶车低了将近15个百分点。解决办法很直接对自行车类别进行复制增强并适当调整损失权重让模型在训练时更重视样本少的类别。经过调整后两类的召回率差距缩小到5个百分点以内效果明显。还有一个隐蔽的坑是锚框匹配。如果数据集中目标尺度分布偏极端比如大量超小目标模型默认的锚框匹配策略可能无法给这些小目标分配足够正样本。YOLO 框架支持自动计算合适锚框我在训练前开启了自动锚框计算让框架基于数据重新生成锚框小目标的检出率因此提高了约6个百分点。5.2 界面与部署阶段的典型问题部署阶段第一头疼的问题是打包发布。用打包工具把 Python 应用打成 exe 时深度学习框架的依赖体积巨大打出来的包动辄几个GB。而且容易漏掉一些隐含的依赖文件导致程序在目标机器上启动时报缺 DLL。我的经验是打包前先用静态分析工具梳理动态链接库依赖把缺失的依赖项手动添加到打包配置里。另外目标机器必须要安装对应版本的显卡驱动和计算平台运行环境这一步无法通过打包解决需要在部署文档里明确写清楚。界面卡顿问题在实测中也很高频。如果排除了线程堵塞的原因后界面仍然不流畅常见原因有两个。一个是图像只在主线程绘制时发生了频繁的内存拷贝我的解法是使用预分配的缓冲区重复利用避免每帧都新建大数组。另一个是界面刷新频率过高超过显示器的刷新率实际上是性能浪费我把刷新间隔限制为约50毫秒即约20帧的显示频率画面观看体验与实际刷新效率达到了不错的平衡。摄像头打开失败也是现场部署时经常碰到的问题。不同摄像头对解码格式的支持不尽相同我在程序中增加了摄像机常见编码格式的自动探测和切换逻辑。如果打开失败会自动尝试其他编码格式重新建立数据流。这个细节在真实设备上非常重要因为不同厂商的摄像头兼容性差异很大稍微处理不好用户看到的就是一个黑屏界面。5.3 效果调优的几个额外心得一套系统部署完效果往往还有提升空间而且是性价比极高的提升。我在项目后期做了两件事都带来了可感知的改善。一件事是收集现场真实运行中产生的误检和漏检样本定期追加到训练数据集中做增量训练让模型持续适应场景里的特殊分布。另一件事是为常见场景生成预设的检测参数白天模式的置信度阈值、夜间模式的阈值等用户一键切换场景配置省去手动调参的过程。追加数据的增量训练要注意控制新旧数据比例。旧数据占比不能过低否则模型会遗忘之前学习的知识。通常我把新旧数据按7:3到8:2比例混合训练实测效果最稳定。这种方法在真实项目中的价值怎么强调都不过分——一个持续迭代的模型永远比你一次性训练后丢在那里不管的模型可靠。对检测框后处理也有人容易忽略非极大值抑制的判定阈值要结合场景调整。如果监控场景中目标密集、互相遮挡严重IOU 阈值可以适当调低如0.4减少重叠目标的框被压抑的概率目标稀疏的场景则把阈值调高如0.6更激进地合并冗余检测框。这都是很小的细节但对画面上的实际表现影响很直接。我个人实际操作下来最大的体会是目标检测系统做到上线并不难难的是长期稳定地运行下去。算法工程本质上是数据、参数、部署环境三方持续博弈的过程没有一劳永逸的配置只有不断根据现场反馈调整优化。这套基于 YOLO26 的两轮车检测系统目前还预留了扩展空间可以把判断规则扩到更多类别比如摩托车、三轮车也可以结合目标跟踪算法做跨帧轨迹分析和停留时长统计。基础打得稳后面往上加什么功能都相对顺手。