首页 / 资讯中心 / 文章详情

轻量级行人检测实战:从模型选型到端侧部署的完整指南

轻量级行人检测实战:从模型选型到端侧部署的完整指南 ★ FEATURED ARTICLE
在嵌入式计算平台上做实时行人检测最头疼的从来不是模型精度不够而是模型太大、推理太慢设备跑不动。几年前我在某边缘设备项目X里做技术调研时PC上跑得好好的检测模型一搬到ARM开发板上帧率直接掉到个位数内存占用还经常把系统挤崩。后来转向轻量级方案才真正把这些坑一个个填平。这篇博文就围绕“基于深度学习的轻量级行人检测”这个主题从模型选型、结构设计、训练细节到端侧部署把我实际踩过、也实际解决的弯路和心得完整记录下来给正在做类似边缘视觉项目的开发者一个可以直接参考的路线图。1. 轻量级行人检测到底要解决什么问题1.1 项目场景与核心需求解读行人检测是计算机视觉里非常经典的方向但“轻量级”这三个字一加上整个问题的性质就变了。传统目标检测关注的是mAP要高、各类别都能识别够准轻量级检测关注的是“在算力有限、内存有限、功耗有限的设备上以尽可能低的延迟把人框出来”。服务端显卡上的重型模型在这里基本不适用YOLOv4、Faster R-CNN等模型动辄上百MB体积、几十G FLOPs边缘设备根本吃不消。我当时的项目X场景是这样的某园区出入口需要部署一台低功耗的边缘计算盒子对过往行人做实时检测用于后续的客流统计和异常徘徊告警。盒子本身的算力大约只有1 TOPS级别内存只有2GB而且视频流要求不低于15 FPS。这种环境下模型必须满足几个硬性指标模型权重文件体积控制在5MB以内方便远程OTA更新。单帧推理延迟在CPU或轻量NPU上不超过80ms。对行人的检出率要尽量高允许一定的误报但不能漏检关键目标。运行内存占用峰值不超过500MB。你会发现这些需求环环相扣。模型小了精度会掉误检漏检变多模型大了帧率就上不去。所以轻量级行人检测本质上是在“体积-速度-精度”这个三角里找平衡点而不是单方面追求某一项指标。1.2 为什么不能直接拿通用检测模型来用很多刚接触边缘部署的朋友第一反应是“我直接用轻量版的YOLO不就行了”。这个思路方向对但直接拿通用模型来用会在真实场景里碰壁。行人和通用物体比如COCO那80类的检测有个很大的不同行人目标在画面里的形态高度一致直立、有头肩结构、宽高比相对固定但也有大量遮挡、截断、行人密集重叠的情况。通用模型为了兼顾各类目标会在特征提取上做较多妥协反而在行人类别上的特征判别力不够精细。另一个问题是很多轻量通用模型为了压缩体积牺牲了对小目标的感受野和浅层细节保留。而行人检测恰恰是典型的多尺度检测任务——远处的人可能只有十几个像素高近处的人能占据大半幅画面。如果直接把网络结构拿过来用而不做适配会出现远距离行人漏检严重、近距离行人框不稳定的现象。我建议的做法是以轻量级网络结构为基础骨架针对行人尺度分布和实际部署硬件重新设计检测头、先验框和输入分辨率。这也是我后面整个实现方案的核心指导原则——不盲目套模型而是把行人检测问题本身作为设计的第一出发点。2. 网络结构设计与模型选型思路2.1 骨干网络选择从MobileNet到轻量自研结构骨干网络是特征提取的核心它的计算量通常占据整个模型的60%~80%。我对比过MobileNetV2、MobileNetV3、ShuffleNetV2以及EfficientNet-Lite这几个主流轻量网络。MobileNetV2的倒残差结构久经考验但深度卷积在高通和瑞芯微等不同平台的优化程度不一样我实测在某些NPU上反而比MobileNetV3更稳。MobileNetV3引入了NAS搜索和SE注意力理论精度更好但它的h-swish激活函数在部分边缘设备的CPU上不是原生支持要额外做算子映射推理反而变慢。ShuffleNetV2的channel shuffle在GPU上还行在CPU上也算友好但受限于分组卷积的组间信息交换代价我在实际项目中并没有感受到比MobileNet系列更强的优势。EfficientNet-Lite则更偏重FLOPs层面的轻量真机部署时可能会遇到算子碎片化的问题需要更多工程适配。最终我在项目X里选择了一个类似MobileNetV3-Small结构但做了三处调整的骨干网络第一层普通卷积的stride从2改为1因为行人检测的输入分辨率一般不超过416x416首层就做大步长下采样会把小目标细节丢得太快。在stage4和stage5各插入一次轻量级注意力模块但只对通道做压缩不做空间注意力控制额外计算量。移除了最后的全局池化和分类头骨干只输出三层不同尺度的特征图直接喂给检测头。这样调整之后骨干网络的理论计算量大约为620M FLOPs参数约1.8M。作为对比原版MobileNetV3-Small是660M FLOPs、2.5M参数左右。算力基本持平但对行人的特征表达针对性更强。2.2 检测头与先验框设定针对行人体态的定制化设计检测头我用的是anchor-based的简化设计。虽然anchor-free的FCOS和CenterNet是当前主流但我在边缘场景里实测下来anchor-based配合合适的先验框收敛更稳、小目标召回更高而且NMS后处理要简单很多——这对部署很友好。核心考量是行人目标不像其他类别的目标那样尺度跨度大只要先验框设计合理anchor-based在小模型里的表现一点也不差。我针对行人的体态特征把先验框设计成高宽比0.41到0.5左右的长条形锚点面积按照输入分辨率416x416来设定覆盖从24x24像素到280x280像素的范围。为了兼顾极小目标我特地在最小特征图上额外增加了一组小尺寸先验框。这里有一个细节如果直接套用PASCAL VOC或COCO里统一的anchor比例比如常见的0.5、1、2三档行人的竖长框会跟猫狗等方形目标混在一起回归分支的收敛压力会变大。特征图方面我用了三层检测头分别来自骨干网络的stage3、stage4和stage5步长分别是8、16、32。这个配置对应到416x416的输入就是52x52、26x26和13x13三张特征图。让较大步长的高层特征图负责大目标低层高分辨率特征图负责小目标。每层设置3个不同尺寸的先验框总共9个anchor相比通用检测模型动辄几十个anchor配置计算量小得多。2.3 为什么我坚持在小模型里保留FPN结构不少轻量化方案为了压缩计算量会直接把特征金字塔去掉只保留最高层特征图做预测。我在前期实验里也试过这个方案效果非常不理想——远处小行人的召回率直接掉了12个百分点。原因不难理解行人本身就属于“细长目标”如果只用高层语义特征预测位置信息已经非常模糊框的定位精度会大幅下降。我在最终方案里选择了一个折衷的轻量FPN——只在相邻两层之间做特征融合不走传统的自顶向下逐层传递。具体来说把stage5的深层语义特征上采样后与stage4的特征逐元素相加staged4和stage3之间做同样的操作。计算量只增加不到18%但小目标的检测精度提升非常明显。这里要给一个实操经验特征融合时通道对齐很重要不同层出来的特征图通道数不一致直接相加是行不通的得先用1x1卷积统一通道数。我测试过用concat再卷积的效果比add更好但计算量几乎翻倍在轻量级场景下性价比不高所以选择了add融合。3. 训练细节与数据策略3.1 数据集准备与难例挖掘训练数据的质量直接决定模型的真实效果。我用的数据集由两部分构成一部分是公开的行人检测数据集另一部分是项目现场自己采集的监控画面。现场数据的价值在于场景光照、机位角度、人群密度和公开数据集差别很大纯靠公开数据训练出的模型拿到现场用效果会打七折。我自己采集的数据大概有20000帧按7:2:1划分训练集、验证集和测试集。为了提升模型的泛化能力我对现场数据做了几个操作随机裁剪和缩放模拟不同距离下的目标尺度变化。对行人区域做随机遮挡模拟行人被路灯杆、招牌、树木遮挡的情况。在画面上叠加模拟噪声让模型对低照度环境更鲁棒。从原图中随机挖除一块区域逼迫模型学习利用上下文信息。难例挖掘在这类任务里极其重要。我第一次训练出的模型误检集中在垃圾桶、石墩这类纹理复杂但形状类似行人的目标上。后面我在损失函数层面做了调整在训练的中间阶段持续把预测置信度在0.3到0.7之间徘徊的候选框作为难例加大它们在损失中的权重。这步操作让误检率下降了将近一半。3.2 损失函数设计与正负样本分配检测头的损失函数我拆成三部分分类损失使用focal lossgamma取2.0alpha取0.25。这个参数组合能有效缓解前景背景类别极度不平衡的问题行人检测里每张图的负样本框数量远大于正样本。回归损失使用CIoU loss而不是原始的Smooth L1。CIoU能同时考虑重叠面积、中心点距离和宽高比对行人这种细长目标的框回归非常友好。我实测同等训练轮数下CIoU比Smooth L1的AP提升约1.8个点。置信度损失还是focal loss让网络对背景区域的预测更保守。正负样本分配我采用的是简化的MaxIoUAssigner。只要anchor与真实框的IoU大于0.5就算正样本小于0.4就是负样本介于两者之间的直接忽略。这个阈值范围比通用检测模型的0.5/0.4更严格因为行人框的标注边界比通用物体更容易产生歧义边缘框经常是“似人非人”的状态。3.3 训练参数与优化器选择训练我分两个阶段进行。第一阶段用输入分辨率320x320训练80轮第二阶段切到416x416再训练50轮。这个多尺度训练策略好处很明显让模型先在低分辨率下快速收敛再通过高分辨率精调细节既省时间又能提升精度。优化器用的是SGDmomentum取0.937weight decay取0.0005初始学习率0.01采用余弦退火衰减到0.0001。这里我踩过一个坑很多人喜欢用Adam但在这个任务里SGD的最终精度普遍高出约1个百分点尤其在边框回归质量上SGD更有优势。Adam收敛快但容易陷入局部平坦区而检测任务的结果对坐标回归精度很敏感。注意weight decay不要作用在bias和BN层参数上这部分参数对正则化没有帮助反而会拖慢收敛。我通过分段param group的方式实现实测能省大约10%的训练时长。4. 端侧部署与推理优化实践4.1 模型转换与算子兼容性排查训练好的PyTorch模型要跑在边缘设备上首先得完成转换。我用的流程是PyTorch导出ONNX再转成边缘设备对应的推理引擎格式。导出ONNX这个环节看似简单坑其实非常多。第一坑是动态尺寸问题。ONNX导出时如果用了动态轴部分推理引擎不认得固定成具体尺寸。我最终输入固定为416x416x3输出层也固定维度这样做还有个额外好处——推理时省去了每帧动态shape推断的开销。第二坑是算子兼容性。模型里的某些操作比如hardswish、某些自定义的注意力实现在部分推理引擎里没有对应的实现要么触发算子回退到CPU要么直接编译失败。我的处理方案是写模型时尽量用卷积、ReLU、sigmoid、add、concat这些基础算子表达所有逻辑避免依赖过于新奇的算子这样在转换时会省下大量调试时间。第三坑是BN层融合。PyTorch模型导出ONNX时BN层是留在图结构里的推理引擎不一定能有效融合。我推荐在导出前先把BN层的参数融合进前一层的卷积权重和偏置中这一步能显著压缩模型体积并提升推理速度。把BN融合后我的模型体积从4.8MB压缩到3.6MB单帧推理时间也缩短了约9%。4.2 半精度量化与INT8量化实战边缘设备的CPU推理如果要跑到15FPS以上通常需要量化。量化分为动态量化和静态量化两种行人检测这种一次性推理的模型建议用静态量化动态量化虽然实现简单但在边缘设备上加速效果有限。INT8量化我用的是训练后量化只需要准备约200张典型场景的校准图片。校准图片不能乱选要包含不同光照、不同行人密度、不同距离的场景否则量化后的模型只在特定场景下表现好换个现场就掉精度。我记录了一组实际测试数据量化方式模型体积平均推理延迟某ARM设备mAP0.5 (验证集)FP323.6MB186ms82.3%FP161.8MB143ms82.1%INT80.9MB68ms78.6%这个结果可以看出INT8量化精度掉了约3.7个百分点但推理速度是FP32的2.7倍在边缘场景里性价比较明显。为了弥补量化带来的精度损失我在训练阶段做了量化感知训练的尝试在训练时通过伪量化节点模拟量化误差。这个方案可以把量化后的精度损失压缩到1.5个百分点以内但因为工程改动较大属于可选优化项。4.3 推理管线优化线程绑定、缓冲池与NMS改写模型本身优化完了工程层和管线层还有大量优化空间。我在部署端做了四件事线程绑定推理库开启4线程推理把线程绑定在不同的物理核心上避免系统调度导致的时间抖动。内存缓冲池输入图像预处理时频繁申请和释放内存会带来不小的开销我预分配了一个循环缓冲池把缩放、归一化后的数据直接写入池中。YUV直接输入摄像头输出的图像通常是YUV格式如果先转RGB再做归一化一次额外的颜色转换开销。我的预处理里直接读取YUV的Y通道做灰度图推理灰度图对行人检测精度影响极小但速度提升约12%。当然这个方案只适合对颜色不敏感的场景。NMS后处理改写为C版本原始opencv的NMS效率不错但考虑到多类别场景我改用针对单类别的简化NMS实现去掉了类别循环直接按分数排序并执行IoU抑制。这几项合起来整条推理管线从原始闭环的约200ms降到了最终的65~75ms稳定跑在15FPS以上。5. 实测效果与常见问题排查5.1 项目X现场测试数据分析部署完成后我在项目X的现场做了一轮完整的实测。测试视频包含白天、傍晚、夜间三种光照条件场景包含出入口通道、广场、停车场。场景平均准确率平均召回率FPS白天出入口89.2%86.4%17.2傍晚广场84.6%81.7%16.8夜间停车场有路灯76.3%72.9%17.0雨天78.5%74.6%16.5这个结果基本满足了项目需求但夜间场景的召回率偏低分析下来主要是行人暗部细节丢失加上运动模糊造成。针对这个问题后续优化方向有两个一是引入多帧时序信息做检测框的轨迹平滑二是做简单的图像增强预处理提升暗部对比度。由于项目排期原因这两个优化没有在当期版本落地但思路已经完全跑通。5.2 常见问题速查表我把项目过程中遇到的高频问题整理成了一张速查表方便后续做类似项目的朋友直接对照。问题现象可能原因解决思路远距离小行人漏检严重输入分辨率过低或浅层特征图信息不足提高输入分辨率调整先验框最小尺寸增加FPN浅层融合夜间误检增多训练数据缺少低照度样本采集夜间现场数据做数据增强模拟暗光增加曝光抖动INT8量化后精度大幅回退校准集场景覆盖不足或敏感层被过度量化扩充校准集逐层分析量化误差对敏感层保留FP16推理时间偶发暴涨NPU/CPU资源争抢线程调度抖动绑定线程到物理核心关掉无关后台服务使用实时调度策略密集人群重叠时漏检NMS阈值过严或特征区分度不足降低NMS阈值到0.45左右增加遮挡数据增强尝试软NMS5.3 轻量模型设计的几个独家心得这个项目做完之后我沉淀了几个判断可能在常规技术文档里看不到但对方案选型很有帮助。第一不要盲目迷信“越小越好”。模型体积压缩到极致往往会带来精度的大幅回落实际部署时宁可多留30%的算力余量给精度。我最初尝试过把骨干换成极致轻量的GhostNet模型体积只有1.2MB但mAP直接掉了7个多点最后反而得不偿失。第二量化和剪枝要在训练阶段就考虑进去而不是训完再压缩。训练时通过伪量化节点模拟量化误差虽然会增加训练复杂度但能极大缓解部署阶段的精度损失。如果项目有时间这步值得做。第三工具链的兼容性比模型结构本身更重要。结构再先进如果推理引擎不支持关键算子最终还是要从头改结构。建议在模型设计阶段就先把目标硬件平台的算子支持列表拉出来逐条核对关键结构的算子是否都在列表里这个前期调研能帮你避开一整个月的返工。第四数据闭环至关重要。现场环境是动态变化的季节、天气、光线都在变模型上线后需要持续收集新样本进行增量训练。我的建议是每两周做一次增量训练每周做一次线上效果回看发现有趋势性的误检漏检就立刻补充对应的难例数据。6. 性能优化后续骨干网络结构再轻量化思考6.1 从工程目标反推模型设计的思路我现在回头看整个项目最有价值的部分其实不是在某个具体网络结构上而是建立了一套“从工程目标反推模型设计”的思维方式。具体来说拿到需求后我先不问“用什么网络”而是先问几个关键问题目标设备算力多少、内存多少、输入分辨率上限多少、能接受的单帧延迟多少、目标的最小检测尺寸大概多少。这些数据定了网络深度、宽度、特征图通道数、anchor配置基本就被框定在一个合理范围内剩下的事情只是在这个范围内做超参数搜索。这个方法也适用于非行人的轻量级检测项目。比如做工业缺陷检测时缺陷通常比较小输入分辨率就得往上调同时浅层特征图的权重就要加大做车辆检测时目标宽高比差异比较大anchor的设计逻辑就又不一样了。核心思路是一致的先搞定边界条件再谈模型结构这样整个工程从第一天起就走在正确的方向上。6.2 后续可扩展的优化方向如果项目有二期我大概会优先考虑以下几个方向知识蒸馏是首选项。用一个大模型比如YOLOX-S或Custom-DLA作为教师模型把中间层的特征蒸馏给小模型。我在实验中发现蒸馏带来的收益在小模型上尤为明显能提升2~3个mAP点。这个大模型只需要在训练时运行部署不用管成本很低。动态推理是另一个有趣的方向。对于画面中行人稀疏的场景可以先用一个极小的分类网络判断当前帧有没有行人没有就直接跳过检测头能省不少算力。实测在空场景下动态跳过策略能额外带来40%的功耗节省。再就是跟踪联动。检测模型如果跟一个轻量的跟踪模块联动同一行人连续多帧的检测结果可以互相验证能有效过滤单帧的误检同时对漏检帧做插值补偿。这个对提升整体检测的稳定性帮助很明显属于在工程层面直接提升体验的做法。总之整个项目走下来我个人最大的体会是轻量级并不意味着能力打折而是一种在资源约束下通过工程和算法的协同把有限算力用在最关键地方的能力。如果有朋友正在做类似的边缘检测项目希望这篇记录能帮你少走几圈弯路。如果你在部署过程中遇到别的坑也欢迎在评论里一起交流我来得及的话都会回复。
阅读完成 · 觉得有帮助?
咨询建站