☰
轻量级行人检测边缘部署实战:从模型选型到性能调优
2026/10/19 9:33:03 网站建设 项目流程

前阵子帮某园区做巡检项目,甲方给了一块算力标称 1T 级别的嵌入式板子,原方案里那套大模型跑起来只有两帧,别说实时预警,连画面流畅都算不上。所以“基于深度学习的轻量级行人检测”就成了那段时间反复调优的头号目标。现在回头看,轻量化从来不是一个单独的模型压缩动作,而是网络结构、训练策略、数据分布、部署推理这几个环节一起调优的结果。这篇文章把这条链路完整拆开讲:轻量级模型怎么选、训练时有哪些容易被忽略的细节、最终怎么落到边缘设备上稳定跑起来,以及我在实际项目中踩过的坑。想动手做边缘端行人检测的同学,可以直接照着这套思路走一遍,至少能少走一半弯路。

1. 轻量级的核心矛盾:为什么不能直接把大模型搬上边缘设备

很多人拿到行人检测任务,第一反应是找一个公开的高精度检测模型,这是典型的服务器端思维。边缘设备并不是“有算力但不够用”这么简单,它更像一个三角约束:算力、内存、功耗三条边互相咬着,你想让模型跑得快,必须同时在三个维度里找可行解。更麻烦的是,行人检测场景本身边界复杂、遮挡严重、目标尺度变化极大,还不能简单套用“检测小物体”的通用方案。所以开始做轻量化之前,得先把这里的核心矛盾聊透。

1.1 算力、内存与访存量的三角约束

先说算力。一块标称 1T 算力的边缘板子,指的是每秒能做 1 万亿次浮点运算,这个数字听起来不小,但实际运行一个卷积网络时,真正能利用的有效算力通常只有标称值的 20% 到 40%。原因是芯片里的计算单元要等数据从内存搬过来,搬运速度跟不上,算力再高也白搭。这个道理很像饭店后厨:厨师翻炒再快,传菜通道一旦堵住,出菜速度就被卡死了。

在轻量化模型设计里,访存量(Memory Access Cost)往往比计算量更关键。有些网络结构 FLOPs 很低,但每一层都要读大量中间特征图,在边缘设备上跑起来依然很慢。我在项目里对比过两个参数量接近的模型,一个 FLOPs 少但特征图很大,另一个 FLOPs 略高但特征图小,实际推理延迟反而是前一个更慢。所以选模型不能只看参数量和 FLOPs,还要考虑内存带宽和特征图尺寸,最好直接在目标设备上跑一遍实测帧率。

内存方面的约束更直白。边缘设备的内存通常只有几百 MB 到 2GB,推理过程中不仅需要保存权重,还要保存每一层的中间特征。如果输入分辨率设得过高,比如 1280x1280,特征图可能直接把内存占满,程序跑到一半就崩了。我的经验是,轻量级行人检测的输入分辨率一般控制在 640x640 左右,既能保证小目标有足够像素,又不会把边缘设备的资源一次性吃光。

1.2 精度与速度的平衡点在哪里

精度和速度之间的取舍,不是简单选个中间点,而是要回到真实需求去定义“好用”。在行人检测场景里,更关键的指标往往是漏报率和误报率,而不是像 COCO 那样盯着 mAP@0.5。比如某园区场景最怕的是漏掉一个人,误报几个背景倒可以靠后置逻辑过滤。理解了这个前提,精度和速度的平衡点就会比想象中宽松很多。

我做过一个对比实验:一个大模型 mAP@0.5 能够到 90% 以上,但推理一次要 300ms;一个参数量只有 1/10 的轻量模型,mAP@0.5 在 87% 左右,推理只需要 30ms。看起来精度掉了 3 个点,但在实际视频流里,误报和漏报的差异并没有 mAP 数字体现得那么明显,因为场景相对单一,背景类别有限。加上一些后处理逻辑,比如跟踪、行人重识别校验,整体效果完全够用。

所以我的建议是:不要一上来就追求最高的精度指标,先定清楚部署设备的算力、可用内存、目标帧率,再反推模型规模和输入分辨率。这个顺序一旦搞反,后面所有训练和优化都会变成无头苍蝇。

2. 模型选型与训练方案:从零搭一个可用的轻量检测器

模型选型是轻量化项目的核心决策点。选型选好了,后面训练、压缩都是锦上添花;选不好,再怎么调参都很难同时满足速度和精度。这一节说一下我实际对比过的几个方案,以及在一套可复现的训练配置下,怎么把轻量模型的精度拉到接近大模型的水平。

2.1 轻量骨干网络怎么选:三个主流方向

现在做轻量检测,骨干网络基本绕不开 MobileNetV3、ShuffleNetV2、EfficientNet-Lite 这几个方向。它们的设计理念各有侧重:

骨干网络特点适合场景
MobileNetV3-Small深度可分离卷积 + SE 注意力,结构成熟,算子简单大多数边缘设备,兼容性好
ShuffleNetV2 0.5x通道重排,设计时显式优化访存量内存受限、带宽吃紧的板子
EfficientNet-Lite0深度、宽度、分辨率综合缩放,结构调整空间大想做精度和速度的精细权衡

我最后在项目里用的是结构上接近某开源轻量检测实现的一套组合:骨干网络以深度可分离卷积为主,参数量压到 1.8M 左右,计算量在 1.2G FLOPs 上下。选它的原因很直接:所有算子都是深度可分离卷积、普通卷积、激活函数这些基础操作,导出到推理引擎或者做 INT8 量化时,兼容性问题最少。很多花哨的结构在服务器上精度好看,一到边缘设备就各种算子不支持,这个坑我踩过不止一次。

2.2 训练配置里的几个关键细节

轻量模型精度能不能撑起来,训练策略比模型结构影响更大。我用的一套可复现配置是这样的:

  • 输入分辨率 640x640,训练时多尺度采样 480 到 800;
  • batch size 128,初始学习率 0.01,配合前 3 个 epoch 的 warmup;
  • 学习率调度用余弦退火,训练 160 个 epoch;
  • 优化器用带动量的 SGD,权重衰减 5e-4;
  • 开启混合精度训练,但不降低最终精度;
  • 全程使用 EMA 指数移动平均,收敛更稳。

损失函数上,分类用带 focal 项的 BCE Loss,回归用 CIoU Loss。行人检测最典型的问题是正负样本极度不平衡:一张图里可能只有两三个行人,背景锚点却有几千个。如果不做采样,模型很快就会偏向把所有框都预测成背景。我在每个训练 batch 里都会做正负样本采样,把正负比例控制在 1:3 左右。

数据增强方面,Mosaic、HSV 抖动、随机仿射变换是默认组合,但有一个细节必须强调:Mosaic 四张图拼接时,行人经常会被裁成半截,模型容易学到“半个身体也能算行人”的错误特征。所以我在项目里把 Mosaic 概率控制在 0.3 左右,不全程开启。宁可让背景多样性少一点,也别让目标特征被切坏。

2.3 知识蒸馏:用小模型蹭大模型的判断力

轻量模型直接从头训练,精度上限通常比大模型低一截。知识蒸馏是把这个差距补回来最有效的手段之一。思路很简单:先训练一个精度不错但不算太大的教师模型,然后让轻量学生模型去学习教师模型的输出分布,而不仅仅是真实的标注框。

在目标检测里,蒸馏不能只对齐最后的分类和回归结果,那样信息太稀疏。更实用的做法是同时蒸馏特征图:取教师和学生模型的 Neck 层输出,在对应空间位置上做 L2 距离约束,让学生的中间特征尽量向教师看齐。分类头的蒸馏用 KL 散度,回归头可以继续用原始 Loss,避免教师框本身的误差被放大。

我在这套轻量模型上做过直接训练和蒸馏训练的对比。同样的参数量、同样的训练轮数,蒸馏后 mAP@0.5 大概提升了 1.5 到 2 个点,漏检率下降尤其明显。这说明小模型不是学不会,而是缺少一个有效的目标函数指引。蒸馏相当于给了一个“标准答案参考”,能让小模型把更多容量用在真正的难例上。

3. 数据准备与标注:行人检测项目的隐藏成本

模型结构选完,训练策略定了,真正决定项目能不能过验收的反而变成数据。很多人低估了这个环节,觉得拿公开数据集训练一下就够了,但真实场景里光照、视角、行人穿着、遮挡方式千差万别,公开数据集覆盖不了全部情况。这一节聊聊数据侧最容易出问题的几个地方。

3.1 数据集选型和自采数据的重要性

起步阶段可以用公开数据集做预训练,比如 COCO、CrowdHuman、CityPersons 这类常见数据集。它们的优点在于类别覆盖广、样本量充足,能让模型先学到通用的行人特征。但直接拿这些模型部署到园区,效果一定会打折扣,因为园区里的摄像头是俯视视角,行人密度、背景纹理、光线变化和公开数据集里多数标注场景差异很大。

我当时的做法是:先用公开数据集预训练一轮,然后到现场采集三到五天的视频,按帧抽图,人工挑选出有代表性的画面,大概积累了两三千张场景图片。重点覆盖早晚逆光、夜间低照度、雨天玻璃反光、部分遮挡、密集排队这些典型情况。没有这些真实场景数据,后面的所有调优都像是在盲人摸象。

说到标注,最容易引起争议的是行人框到底怎么画。同样一个行人,不同标注员可能画出的框差异很大,有的喜欢紧贴轮廓,有的喜欢多留背景。这会导致模型学到不稳定的框预测。我们后来定了一套简单明确的规则:只标注可见部分,如果遮挡超过一半且无法判断方向,就标成难例而不是行人框;框的边界精确到能看到的最小外接矩形。规则清晰之后,标注一致性问题减少了很多。

3.2 数据增强的隐藏风险:Mosaic 不是万能的

数据增强可以提高模型泛化能力,但用过头了反而会伤害轻量模型。行人检测场景里,最典型的问题就是前面提到的 Mosaic 拼接。Mosaic 能让模型看到更多上下文,但也容易把行人切成碎块,导致模型学到错误模式。另一个问题是随机裁剪增强幅度太大,行人目标被裁到只剩一只脚,模型只能靠想象补全。

我建议控制两个参数:一是 Mosaic 的开启概率,二是在 Mosaic 合成时对行人目标做一个保护逻辑,如果目标经过拼接后被切掉超过 30% 的可见面积,就把他所在的子图放在边缘而不是中间,必要时干脆跳过这张拼接图。这样既保留了 Mosaic 的多样性,又不会牺牲目标的完整性。其他增强手段也一样,核心原则是增强后的图像必须仍然像一个真实场景,不能为了多样性把图像搞得不像自然画面。

3.3 小目标行人:一个容易被 mAP 掩盖的问题

行人检测里的“小目标”一般指高度小于 32 像素或者面积占比很小的行人。这类目标在监控画面里很常见,尤其是远距离的走廊尽头、园区外围。如果只看整体 mAP,小目标的影响很难被察觉,因为整体指标被大量中大型目标拉高了。但实际部署时,漏掉几个远距离行人可能直接导致事件没有被发现。

针对小目标,我试过三种有效方案。第一是多尺度训练,输入分辨率在 480 到 800 之间随机变化,相当于让模型适应不同缩放尺度。第二是 Copy-Paste 增强,把小行人剪切出来,复制粘贴到画面不同位置,增加小目标样本数量。第三是推理时做多尺度测试,但这个方法在边缘设备上通常不现实,因为计算量会翻倍,所以一般只作为离线分析手段。真正部署时,我更倾向于固定输入分辨率,但确保训练数据里小目标样本占比不低于 20%。

4. 模型压缩与导出:从训练框架到边缘设备的最后一公里

训练好的模型还是留在 PyTorch 里的浮点权重,离真正跑在边缘设备上还有很长的路。剪枝、量化和算子兼容环节,每一步都可能让前面辛苦攒下的精度和速度归零。这一节记录一下我踩过的坑和最终跑通的压缩部署流程。

4.1 剪枝、量化的分工与顺序

模型压缩不是把一堆手段堆上去就行,顺序和分工很重要。我的流程是这样:

  1. 先正常训练到收敛;
  2. 做稀疏化训练,给 BatchNorm 的缩放系数加 L1 正则,让一部分通道的系数趋近于零;
  3. 按通道剪枝,把缩放系数很小的通道直接删掉;
  4. 剪完以后做几十个 epoch 的微调,恢复精度;
  5. 最后做 INT8 量化。

剪枝和量化是两个不同层面的优化:剪枝是从结构上把模型变瘦,量化是把每个权重和中间激活值从 32 位浮点变成 8 位整数。如果你不剪枝直接量化,模型还是那么大,内存没有实质性下降。如果你只剪枝不量化,推理速度提升通常也只有 20% 左右,因为计算单元仍然在按 32 位精度运转。

关于顺序,我给一个很明确的结论:先剪枝再量化,不要反过来。量化的误差会对剪枝后的模型结构选择产生误导,而先剪枝再量化,每一步的误差来源更可控。剪枝后如果精度掉得多,不要急着调量化参数,先检查是不是剪过头了,把某个关键通道删掉了。

4.2 ONNX 导出时的算子兼容坑

从训练框架到推理引擎,最常用的中转格式是 ONNX。导出这一步非常容易翻车,最常见的几个问题:

  • 动态尺寸到处都是。很多检测模型前处理里有放缩、填充、堆叠等操作,如果不固定输入尺寸,导出的 ONNX 会包含大量动态 shape 节点,推理引擎解析起来又慢又容易出错。我在部署版本里直接固定输入为 640x640,也固定 batch size 为 1。
  • 上采样算子冲突。部分版本的 PyTorch 导出的上采样节点,推理引擎不支持,需要用 ONNX 重写为固定模式。
  • 后处理节点要不要打进模型里。我的选择是:NMS 坚决不放进模型,交给推理引擎或外部代码处理。因为 NMS 的算子兼容性和动态逻辑都太复杂,强行塞进模型只能换来一堆不稳定因素。

导出后建议用工具做一遍模型简化,再把 ONNX 的输出和原始 PyTorch 模型的输出做一致性比对,最大绝对误差控制在 1e-4 以内才算过关。很多部署后精度突然掉很多的问题,其实在比对这一步就能提前发现。

4.3 量化与边缘设备上的实测性能

量化是轻量级模型在边缘设备上实现实时推理的关键一步。INT8 量化能把模型体积缩小到原来的 1/4,推理速度提升 1.5 到 2 倍。但量化需要一个正确的校准流程:选择 500 到 1000 张覆盖典型场景的图片,统计各层激活值的分布,然后确定量化缩放系数。校准集如果只选几张图,或者全是白天画面,夜间场景的激活分布就会和校准分布偏差很大,导致推理时精度突然崩塌。

我在那台 1T 算力级别的边缘板子上记录过一组实测数据:

模型状态推理延迟内存占用mAP@0.5 精度
FP32 原始模型46ms约 900MB87.5%
FP16 半精度33ms约 500MB87.4%
INT8 量化后21ms约 260MB86.8%

从数据看,INT8 相比原始 FP32 精度只掉了 0.7 个点,延迟却从 46ms 降到 21ms,大约能跑到 47 帧每秒,已经完全满足实时要求。内存也只剩原来的三分之一左右,给其他业务模块留下了充足空间。

量化后如果精度掉得过多,一般先检查校准集,再考虑是不是某个特定层对量化特别敏感。我遇到过一种情况:个别层用逐层量化误差很大,但改成逐通道量化之后,误差明显减小。所以量化不是一锤子买卖,调几层再试几次很正常。

5. 常见问题与排查经验

整个项目做下来,最难的不是模型训练,也不是部署,而是现场出现的各种“看起来正常但实际不好用”的问题。我这里整理了几类典型问题,基本覆盖了边缘行人检测项目里最容易踩的坑。

5.1 场景误检:背景比行人更像行人

园区场景里误检率最高的几类背景:工地的支架、围栏、假人、玻璃反光里的影子。这些目标在形状上和行人有相似之处,模型很容易给出高置信度。单纯降低置信度阈值会漏掉真目标,提高阈值又压不住难背景。

我的排查思路是分层处理。首先收集现场误检样本,专门做一轮 hard negative 挖掘,把这些背景当成训练数据重新微调。其次在模型输出之后接一层跟踪过滤:同一位置的检测框如果连续几帧只在偶发帧出现,多半是误检,直接丢掉。最后用一些简单的场景规则,比如检测框宽高比异常、长宽比过大或过小、高度超过画面高度的 80%,都直接判定为无效框。这套组合拳打下来,误报率下降了 60% 以上。

5.2 帧率不稳定:一烤机就掉速

边缘设备最容易被忽略的问题是散热降频。实验室里测试的时候帧率稳定在 45 帧,拿到室外连续跑两个小时,帧率可能会掉到 30 帧以下。原因是芯片温度升高后主动降频,算力缩水,推理延迟自然变大。这个现象不是模型本身的问题,而是部署环境造成的。

我在项目里处理这个问题主要靠三招:第一,在推理层面做异步流水线,采集和推理重叠,减少单帧等待;第二,设置帧率上限,比如限制到 25 帧,让设备有更多空闲时间降温;第三,在代码里加一个温度监控,如果持续超过阈值,自动降低输入分辨率一个级别,等降温后再恢复。这些策略保证了全天的帧率波动控制在 5 帧以内,现场不会再出现“上午流畅、下午卡顿”的情况。

5.3 框忽大忽小:标注标准不统一的连锁反应

有的项目里模型精度看起来不错,但检测框会莫名其妙地忽大忽小,尤其在不同距离上特别明显。排查下来往往不是模型结构问题,而是训练数据的标注标准不统一。有人标注时喜欢把行人整体轮廓框进去,有人只框身体不框头发,还有人把半遮挡目标也硬标成一个完整框。模型学到的不是统一的“行人外接框”,而是一个混乱的折中结果,真实目标越远,框偏差越明显。

这个问题的根源在标注环节,只能回去重审数据集。我后来整理了一套傻瓜式标注规范:可见部分全部框进去;目标被遮挡超过一半或者边缘严重模糊时标为 ignore;相邻两个行人挨得太近时,如果无法区分边界,也标为 ignore,不给模型传递错误信息。重新标注并清洗之后,框的稳定性有了明显改善,后续训练出问题的概率低了很多。

5.4 量化后漏检变多:校准数据根本不代表真实场景

INT8 量化后经常出现的一种现象是:正常光照画面完全没有问题,一到夜间或者逆光场景,大量行人突然漏检。很多人第一反应是模型训练数据里夜间样本不够,但还有一种可能:量化校准集全部是白天图像,夜间图像在网络中间层的激活值分布与校准集统计的分布相差巨大,量化后的缩放系数完全失去了代表性。

我去检查部署前用的校准图,确实全是白天场景。后来重新从全天候视频里均匀抽取了 800 帧,白天、傍晚、夜间、雨天各占四分之一,重新校准之后,夜间漏检率下降了一半以上。所以校准集的选择不能随便挑几张“看着清晰”的图,必须覆盖部署现场可能出现的所有光照和天气条件。

6. 做完这个项目后的一些体会

最后想分享一点个人经验。轻量化不是把一个大模型通过各种手段强行压缩成小模型,更像是在一开始就站在部署设备的角度去设计整个方案。先明确设备能提供多少算力、多少内存、需要多高帧率,再选模型结构和训练策略,顺序不能反。顺序反了,后面所有优化都会变成在错误的框架里打补丁。

另一个比较深的体会是:检测精度这类模型指标,和现场真正关心的“好不好用”之间,存在一段不小的距离。mAP 高不代表误检率低,框架稳定不代表全天候稳定。做这行久了就会发现,项目里最后拼的往往不是模型有多花哨,而是数据清不干净、标注规不规范、现场环境的边界情况有没有考虑到。

如果后续继续在这个方向深入,我会把检测和跟踪、行人属性分析放到同一个模型里做多任务。边缘设备资源有限,多任务共享骨干网络比跑三个独立模型要省太多资源。这个思路比较适合轻量级方向,也值得继续在真实场景里折腾。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询