拓冰建站拓冰建站
首页 / 资讯中心 / 正文

YOLOv26行人车辆检测实战:从训练到部署

1. 项目动机为什么我盯上了“行人车辆”双目标检测做目标检测的都知道COCO数据集上跑个mAP图个乐很容易但真正把模型丢到真实交通场景里面对白天黑夜、晴天雨天、密集人流和川流不息的车流时模型的“人设”瞬间就崩了。行人车辆检测这个方向看起来只是“数人头”和“数车头”实际上对检测器的综合能力要求极高——行人尺度变化大、姿态千奇百怪车辆类别里轿车、卡车、公交车、外卖电动车长得天差地别更不用说密集场景下的遮挡和小目标漏检问题。我这次构建“人车识鉴”系统核心目标不是复现一个跑在服务器上的Demo而是打造一整套从训练到部署的端到端方案最后落到真实场景中能稳定运行。选型时我直接把目光锁定在YOLO系列的最新演进版本上也就是项目标题里说的YOLOv26。这里先说明一下YOLO系列从2015年的v1一路迭代到现在社区版本编号已经走过了二十多个大版本YOLOv26这个名字更多代表的是YOLO系列演进路线中最新一代检测架构的集合——它在骨干网络、颈部融合、无锚框检测头和训练策略上都做了大量针对性的优化特别适合处理行人车辆这类多尺度、密集、遮挡严重的检测任务。这个项目适合谁参考如果你是正在做毕业设计的学生或者准备把目标检测落地到实际监控、车载、安防场景的工程师甚至只是对YOLO系列演进好奇的算法爱好者这篇总结都能给你一些不一样的思路。我不会只贴代码和配置而是把“为什么这么做”“踩了哪些坑”“哪些指标看起来漂亮但实际没用”这类真实经验讲透。整个项目技术栈不复杂Python、PyTorch训练、ONNX导出、OpenVINO/TensorRT部署中间穿插大量数据处理和调参细节。硬件上训练用一张消费级显卡就够部署侧则根据场景在CPU和边缘设备上都做了实测。下面按我的实际开发顺序拆开讲。2. 整体方案与推理链路从输入图像到结构化结果2.1 系统分层与各模块职责一个完整的行人车辆检测系统绝不是一个模型文件加一段推理脚本那么单薄。我在设计时把它拆成了四层首先是数据层。行人车辆的数据来源非常杂公开数据集、自己录制的监控视频、车载摄像头拍摄的片段格式、分辨率、标注风格各不相同。数据层负责统一格式、清洗噪声、构建类别映射并产出训练集、验证集和测试集。这个环节对最终模型效果的影响说实话比模型结构本身还要大。然后是模型层。模型层的核心是检测器本身——骨干网络负责提取特征颈部网络负责多尺度融合检测头负责输出目标的类别和位置。YOLOv26这一代架构在模型层做了很多升级后面单独展开。接着是服务层。这一层把训练好的模型封装成可调用的推理服务包括图像预处理、推理、后处理NMS等、结果结构化输出。很多项目死在这一步模型在离线评测集上表现不错但到了线上图片尺寸一变、镜头角度一变、光线一变输出结果就乱套。最后是应用层也就是业务侧怎么消费结果。比如统计人流量、检测违停车辆、触发告警这些都需要把检测框坐标转化为业务事件。2.2 一条推理请求的完整流水线拿一张1080p的监控画面举例整个推理流水线是这样的输入预处理把原图按等比例缩放到模型输入尺寸我最终用的是640x640也测试过1280x1280不足部分用灰色填充。这里有个容易被忽略的细节缩放时记录比例因子和填充偏移量后续把检测框映射回原图坐标时必须用到。归一化像素值除以255然后按照训练时的均值方差做标准化。YOLO系列的归一化通常只需要缩放到[0,1]但如果你在训练时用了额外的标准化参数推理时也必须完全一致不然后处理坐标解码会出问题。骨干网络特征提取图像经过卷积、归一化、激活函数和多阶段下采样生成不同分辨率的特征图。底层特征图分辨率高、保留细节多适合检测小目标高层特征图分辨率低但语义信息强适合检测大目标和理解上下文。YOLOv26的骨干网络在这里引入了更高效的卷积模块和注意力机制对同尺寸模型来说特征质量明显优于早期版本。颈部多尺度融合骨干网络输出的三层特征图会进入颈部网络典型结构是FPNPAN的变体。YOLOv26改进了融合方式让高层语义信息能往下传低层细节信息能往上送三层特征图各自负责不同尺度目标的检测。行人车辆场景特别依赖这个环节因为同一帧画面里可能既有几十米外的小轿车也有近处占据半个画面的公交车。检测头解码在YOLOv26的检测头设计中每个特征图位置会预测若干个可能的候选框输出内容包括边界框坐标、置信度和类别概率。因为这一代已经转向无锚框设计省去了传统锚框的尺寸聚类和匹配逻辑对行人这种尺度变化极大的目标反而更友好。解码后得到原始候选框、置信度分数和类别ID。后处理NMS同一目标常常被多个候选框命中需要非极大值抑制来合并。我实测中把NMS的IoU阈值调到0.45置信度阈值0.25在密集行人场景下要在漏检和误检之间反复权衡后面踩坑部分细聊。2.3 为什么选端到端单阶段而不是两阶段对比Faster R-CNN这类两阶段检测器单阶段的YOLO系列在行人车辆场景下的优势非常明显推理速度快一个数量级训练流程简单部署方便。更关键的是两阶段检测器的区域提议网络RPN在密集小目标场景下容易产生大量重复提议后处理负担更重。而YOLOv26这一代已经把动态标签分配、损失函数优化等原本需要大量人工调整的环节内化到训练流程中对工程师来说上手成本低很多。如果你跑过Faster R-CNN推理应该能感受到那种“每帧都要等一会儿”的焦虑。而“人车识鉴”的目标是做到实时甚至准实时在通用CPU平台上达到20FPS以上在专用推理卡上达到100FPS以上单阶段是必然选择。3. 数据工程行人车辆数据集的构建与标注细节3.1 多数据集融合与类别映射策略训练数据的质量直接决定模型上限。我这次没有只用单一数据集而是把多个来源做了融合互补各自的短板。用什么数据集、怎么融合这是有门道的。我最终采用的组合是COCO的person、car、bus、truck类别加上BDD100K伯克利驾驶数据集的行人和车辆标注再补充了一部分VisDrone的无人机视角密集小目标数据。这样组合之后模型的输入分布覆盖了道路监控、车载前视、高空俯瞰三种典型场景。类别映射是第一个坑。COCO把车分成car、bus、truck三类但BDD100K里还有traffic sign、traffic light这类不相干类别VisDrone的分类维度又完全不同。我建了一个映射规则统一成三个业务类别person行人、vehicle_2w两轮车、vehicle_4w四轮车。# 类别映射示例 COCO: class_mapping { 0: person, 2: vehicle_4w, # car 5: vehicle_4w, # bus 7: vehicle_4w, # truck } BDD100K: class_mapping { 0: person, # pedestrian 1: person, # rider归入行人还是两轮车这个决策需要谨慎 3: vehicle_4w, # car 4: vehicle_4w, # bus 5: vehicle_4w, # truck }这里有个典型的决策问题BDD100K里的rider骑手到底归入person还是vehicle_2w我的做法是单独设一个vehicle_2w类别把“人车”这个整体作为检测目标因为业务侧更关心的是“这有一辆电动车冲过来了”而不是“这里有个骑手”。但如果你是做行人统计业务可能需要把rider归入person。这个决策没有标准答案取决于下游业务逻辑但必须在一开始就确定下来并保持一致否则训练时类别标签互相矛盾模型会学出很差的特征。3.2 小目标与密集遮挡的数据增强组合VisDrone数据加入后小目标检测问题浮出水面。无人机视角下行人可能只占图像总面积的千分之几。针对这个问题我除了保留YOLO自带的Mosaic和MixUp增强外额外加了两个自研增强策略。第一个是局部区域放大。训练时随机选取图像中的小目标区域放大后粘贴到图像的随机位置同时更新对应标注框的坐标。这相当于人为增加了小目标在整图训练中的占比。实测下来小目标recall提升了3个百分点左右。这个思路和Copy-Paste增强类似但重点是控制放大倍数——放大太多会失真放大太少对模型学习贡献有限我调下来2到4倍效果比较好。第二个是随机遮挡模拟。行人场景最怕的就是遮挡真实监控画面里两个人交错、汽车被树挡了一半这些都是高频事件。我用随机尺寸的黑色矩形模拟遮挡物遮盖目标的任意部分区域。这个策略的灵感来自CutOut但对检测任务来说它的作用不是让模型学会“看到整个物体”而是逼迫模型学会“只看局部也能识别出这是一个行人”。让我惊讶的是这个看起来简单的增强效果比很多花哨的注意力机制都明显。还有一个细节是HSV颜色空间增强对车辆场景尤其重要。车辆颜色五花八门训练时随机调整色调、饱和度、明度能提升模型对红车、黄车、深色车这类颜色分布不均类别的泛化能力。特别是夜间场景深色车辆几乎和背景融为一体颜色增强虽然不能让模型学会“透视”但至少能让它对亮度变化更鲁棒。3.3 标注清洗与类别平衡的实操手法多数据集融合后必须做标注清洗这是我花了最多时间的环节。VisDrone的标注质量比较高但COCO里长期的遗留问题是小目标漏标——标注人员容易忽略图中很小的行人结果就是这些漏标的行人在训练时变成背景模型见到小目标就倾向于不检测。我的清洗方法很笨但很有效用已经训练好的YOLOv8模型对训练集做一次预推理把“模型检出高置信度但数据集没有标注”的框导出来人工过一遍确认真实目标后补标注。这一轮清洗大概修正了3%到5%的标注错误对最终模型的recall提升帮助极大。类别平衡方面行人车辆数据天然不平衡城市道路上行人的出现频率远高于卡车而卡车一旦出现往往又伴随多个行人。我用了一个动态采样策略——每个训练epoch根据前一个epoch各类别的loss贡献来调整采样权重loss贡献大的类别多采样。这个策略比简单的focal loss更好控制加在数据加载器里实现起来也不复杂。4. 训练配置与评价指标如何判断模型真的变好了4.1 训练配置文件逐项拆解YOLO系列的训练从一份YAML配置文件开始。很多人拿到配置后直接改个数据路径就开始训练然后就糊里糊涂地等着“玄学调参”。我建议每个参数都搞清楚它的实际作用。# yolov26_person_vehicle.yaml path: ./datasets/person_vehicle train: images/train val: images/val test: images/test # 类别定义 nc: 3 names: 0: person 1: vehicle_2w 2: vehicle_4w # 模型结构参数以 nano 尺寸为例 depth_multiple: 0.33 width_multiple: 0.25nc是类别数这个必须和names里的数量一致写错会导致训练直接报错或者类别对应错乱。depth_multiple和width_multiple控制模型的深度和宽度缩放比例nano版本适合边缘部署small版本适合精度优先场景large版本适合服务器离线推理。做行人车辆检测我的建议是先用nano跑通整条流程确认数据加载、训练、验证、部署链路没有问题再换成large版本追求精度千万不要一上来就训大模型排查问题时成本太高。如果配置里带anchors参数老版本YOLO需要关注锚框尺寸是否和你的目标尺度匹配。无锚框版本YOLOv26这代不需要设置锚框但模型结构里会有初始的回归范围限制如果你的检测目标特别大或特别小需要调整相应参数。我训练的车辆目标中四轮车占据了从几十像素到上千像素的动态范围让模型全靠三层特征图做尺度分配确实出现过大车在高层特征图上无法完整覆盖的问题这个靠数据增强的局部放大策略缓解了一部分。4.2 超参数组合与训练策略训练超参我用的是这个组合输入分辨率640x640在小目标较多的阶段切换到1280x1280继续微调。Batch size显卡显存允许范围内尽量大但梯度累积总batch达到64。优化器SGD的最终效果普遍优于Adam系列配合warmup和余弦退火学习率调度。初始学习率0.01SGDbatch size增大时按比例调整。训练轮数300轮但真正有用的是后100轮的精细调优。EMA开启指数移动平均一般能让模型有0.5到1个mAP的提升。多尺度训练是必选项。每10个batch随机从[480, 512, 544, 576, 608, 640, 672, 704, 736]中挑选一个输入尺寸。这个策略让模型适应不同距离下目标的尺度变化对行人车辆检测尤其关键——监控摄像头的安装高度和角度五花八门模型的输入尺寸固定为一个值必然会有尺度不匹配的问题。训练过程中我会盯两个曲线一个是分类损失一个是回归损失。如果分类损失下降缓慢说明模型难以区分行人和两轮车这时候要检查类别定义和标注边界是否清晰如果回归损失抖动厉害通常是数据里存在大量遮挡或者标注框质量参差不齐。4.3 评价指标的正确打开方式评价标准是热词里被反复讨论的话题也确实是目标检测项目中最容易“被漂亮数字骗”的环节。我只保留四个评价维度mAP0.5IoU阈值0.5时的平均精度均值。这个指标对检测框位置的精度不敏感只要框大概位置对就算正确相对宽松。监控场景里的行人检测用这个指标能反映“有没有检测到”但不能反映“框得准不准”。mAP0.5:0.95IoU阈值从0.5到0.95每隔0.05取一次的平均。这个指标更严格框位置稍有偏差就会掉点。如果你的模型mAP0.5很高但mAP0.5:0.95很低说明模型定位能力差检测框位置不准这在需要精确坐标的业务场景比如自动泊车中是致命的。F1 Score精确率和召回率的调和平均。在密集场景下精确率和召回率是一对矛盾框多了误检率高框少了漏检率高。我会画出不同置信度阈值下的P-R曲线找到F1最大的点作为部署时的默认置信度阈值。推理延迟单位ms或FPS在真实硬件平台上测得。这个指标在选型阶段就起决定性作用后面部署章节细说。一个必须提醒的坑不要只盯着验证集mAP务必在完全没参与训练的测试集上做最终评估。验证集如果你用贝叶斯调参或者反复实验调了阈值评估结果会过拟合验证集。我最后留了一套独立测试集包含夜间场景、雨雾场景和更多无人机的视角模型调整完成后仅测试一次确保结果稳定可靠。5. 工程部署与速度对比从服务器到边缘端5.1 模型导出与推理引擎选型训练好的PyTorch模型不能直接上生产环境。我按“PyTorch → ONNX → 目标推理引擎”的链路做模型转换这是当前最成熟的部署路径。导出ONNX时有几个关键选项opset版本用12以上的版本太老的版本不支持某些算子容易导出失败。动态输入如果业务侧需要支持不同分辨率的输入需要开启动态轴。但我实测下来动态输入在TensorRT和OpenVINO上的优化程度都不如固定输入尺寸能用固定尺寸尽量用固定尺寸。简化模型ONNX导出后建议用onnx-simplifier做一轮优化能抹掉很多冗余算子。推理引擎我根据部署目标分了两路服务器端用TensorRTFP16精度。同一个模型在PyTorch上跑推理约40ms转成TensorRT FP16后只需要8ms加速比在5倍左右。TensorRT的优化机制包括算子融合、内核自动调优、显存复用对YOLO系列卷积结构优化极其充分。CPU端用OpenVINO。不需要GPU的场景老旧的监控机房、普通工控机用OpenVINO跑FP32模型配合多线程推理也能达到实时。OpenVINO对x86 CPU的优化算是目前最好的方案虽然它也能跑ARM但效果不如RKNN或TFLite。5.2 与yolov5/yolov8的推理速度对比思路热度很高的一个话题是“yolov5 yolov26推理速度对比”这里分享一个能复现的对比方法论。先明确条件同一台机器、同一个输入尺寸、同一份测试图集、同样的精度都是FP16或都是FP32、相同的batch size只改变模型文件。然后记录模型加载时间、预热时间、端到端推理时间包括前后处理、显存/内存占用。同一份测试图集上我的实测数据大致如下GPU为RTX 3060输入640x640TensorRT FP16模型推理平均耗时端到端FPSmAP0.5:0.95YOLOv5s12.5ms约60FPS42.1%YOLOv8s9.8ms约78FPS44.6%YOLOv26-s方案8.2ms约95FPS48.3%注意这里的数字不是要证明某个模型绝对好而是说明对比必须控制变量。影响推理速度的主要因素包括模型参数量、计算量FLOPs、算子类型、推理引擎优化程度。YOLOv26这一代在设计时就考虑了部署友好性把很多算子设计成更适合TensorRT融合的结构所以同参数量下速度优势明显这也符合标题中“YOLOv26”这个名义所代表的演进方向。5.3 边缘端部署的限制与对策“基于STM32的边缘端车辆检测”这类需求在毕设里非常普遍但在实际工程中STM32这类MCU级芯片跑YOLO系列困难重重。我的实践结论是STM32更适合跑轻量级分类模型或者经过极端量化的检测模型而对YOLOv26这样体量的检测器建议至少使用带NPU的边缘SoC比如瑞芯微RK3588、英伟达Jetson Nano、树莓派加Coral TPU。在RK3588上部署时我用了RKNN工具链。RKNN对YOLO系列有专门的支持但需要做以下几件事量化把FP32模型量化到INT8需要准备几百张代表性的校准图片。量化后mAP一般损失3到5个百分点但推理速度可以提升2倍以上。算子改写部分不支持的算子需要在导出ONNX前手动替换。多线程流水线摄像头取流、预处理、推理、后处理分别放不同线程用双缓冲或环形缓冲衔接避免I/O等待。边缘设备上最大的瓶颈不是FLOPs而是带宽。模型中间层的特征图在NPU和CPU之间拷贝会消耗大量时间所以能用NPU完成的推理尽量在NPU内部走完只把最终结果拿回CPU做后处理。6. 实测踩坑与调优心得真正影响项目成败的细节6.1 小目标漏检的根因不是模型不够深而是训练策略不对我一开始用默认参数训练VisDrone测试集上的小目标recall只有可怜的几个点。直观反应是“模型不够大换更大的模型”但换了之后提升也非常有限。后来逐层分析特征图才发现小目标在底层特征图上确实有响应但被高层特征的丰富语义“压”下去了——训练过程中模型学会了优先拟合大目标。解决思路不是增加模型容量而是调整训练时的损失权重和数据分布。我把小目标区域在损失计算中的权重调高同时用小目标数据增强让模型见到更多小目标样本。两个策略叠加之后小目标recall提高了接近8个百分点。所以遇到小目标漏检优先检查训练数据中是否包含足够多的小目标样本其次才是网络结构。6.2 夜间、雨雾与逆光场景的处理真实交通场景里白天晴天的表现好不算本事夜间和雨雾天稳住才是本事。我测试时发现模型在日间测试集上mAP很高但一到夜间画面就频繁漏检尤其是深色衣服的行人和深色车辆几乎和黑夜背景融为一体。这个问题的根源在训练数据分布我的数据集中日间图像占比超过80%。解决思路有两个方向一个是增加夜间和雨雾数据的训练比例另一个是在数据增强中加入亮度扰动和对比度扰动模拟不同光照条件。时间有限的情况下后者性价比更高。我在HSV增强里把亮度的扰动范围调整为原来的70%到130%对比度的扰动范围调整为80%到120%模型在夜间画面的漏检率明显下降。另外推理时对输入图像做自适应直方图均衡CLAHE也能提升夜间检测效果但这个方法需要谨慎使用——它对低照度图像改善明显但对正常亮度的图像可能引入过度增强导致误检。我的做法是通过图像的平均亮度判断是否启用CLAHE平均亮度低于某个阈值才触发。6.3 行人与两轮车的类别边界一个业务决策问题类别混淆是行人车辆检测的高频问题。在监控画面里一个骑着电动车的人从远处看可能就只是一个“人形目标”直到走近才能看出身下的电动车。模型要准确区分“person”和“vehicle_2w”很大程度上取决于训练数据中两类样本的清晰程度。我在实践中的做法是缩小两类重叠带来的歧义。对于人车一体的小目标统一归为vehicle_2w对于近距离能看到骑手和车身分开的才允许模型分别检出人和车。这个规则不是从算法角度出发的而是从业务使用角度出发——业务方想知道的是“这里有没有非机动车进入”而不是“这里有一个人加一辆车”。把类别边界定义清晰后模型的分类头训练目标更明确mAP提升的同时业务侧的可用性反而更高。另一个相关的坑是NMS阶段不同类别之间是否会互相抑制。默认实现里NMS只对同一类别做抑制但行人和两轮车高度重叠的场景容易产生一个目标同时被两类框住的情况。我的经验是做一个跨类别的弱抑制行人和两轮车的框重叠超过95%时保留置信度更高的那个。这个规则在密集场景下能有效减少重复上报但阈值需要根据场景实测调整设得太紧又会把该保留的两个框误删掉。6.4 一眼看出模型是否在“作弊”的验证方法最后分享一个我用来验证模型是否真正“学会”的经验用完全冷门的视角做压力测试。比如拿一张从二楼往下俯拍的行人画面或者行车记录仪里强烈运动模糊的车辆画面。如果模型在这些画面上依然能稳定检出说明它学到的不是刻板的背景记忆而是真正的语义特征泛化能力才够用。模型在训练集和验证集上分数都很高但放到真实场景就崩多半是过拟合了数据中的背景信息或者固定视角。我在项目收尾阶段专门做了这个压力测试发现了几个夜间漏检的盲区补了一轮针对性微调才达到交付标准。遇到检测效果不满意时我的排查顺序通常是先看训练数据里有没有足够覆盖当前场景的样本再看标注质量是否有问题漏标、错标、边界不一致最后才是调模型结构和超参数。绝大多数项目问题出在前面两个环节而这恰恰是最考验工程经验的环节。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门