做边缘端人员检测,很多人的第一反应是直接上大算力平台,但真正落到项目里,成本、功耗、安装位置、散热条件每一项都会卡你一下。瑞芯微 RV1126B 配合 EASY EAI 这套板卡平台,是我在智能摄像头和边缘盒子场景里绕不开的一个选择。它本身就是一颗面向智能视觉产品的 SoC,内部集成了 CPU、NPU、ISP 和视频编解码单元,人员检测这种典型的 AI 任务可以直接在设备端跑完,不需要把所有视频流都搬到服务器。
这篇文章会把从方案选型、模型取舍、RKNN 模型转换到板端推理调优的完整路径整理出来。内容基本都是可以直接“抄作业”的实操细节,包括我多次调测中踩过的坑和验证过的参数配置。适合正在做边缘端人员检测/区域人数统计/电子围栏等需求的开发者,也适合刚拿到开发板还不知道怎么把模型跑上 NPU 的同学。
1. 为什么是 RV1126B:边缘端人员检测的算力与成本平衡
1.1 这颗芯片不是通吃型,但目标场景很精准
RV1126B 属于瑞芯微的智能视觉 SoC 系列,在芯片设计上就是冲着 IPC(网络摄像机)、智能门禁、视频分析盒子这一类产品去的。它最值得注意的地方,不是 CPU 本身有多强,而是在一颗芯片里同时集成了 NPU、ISP 和硬件编码器。这意味着人员检测这个任务基本上可以闭环在单芯片上完成:摄像头 Sensor 进来图像,ISP 负责画质处理,NPU 跑检测模型,CPU 跑后处理和业务逻辑,最后编码器还可以直接把视频流推出去。
这颗芯片的 NPU 算力大致在 2 TOPS 级别(INT8)。这个数字放在手机 SoC 或者带独立 GPU 的计算平台面前确实不够看,但在安防、楼宇、零售这类场景里,2 TOPS 恰恰是性价比最舒服的一档。一颗芯片几十元级别,整板功耗可以控制在几瓦,无风扇也能压住温度,部署环境要求低,这些都是做批量产品时非常敏感的指标。相比之下,带高性能 GPU 的通用计算平台虽然算力几十 TOPS,但价格、功耗、体积都会让项目经理眉头一皱。
人员检测模型本质上是检测类模型里最成熟的一类,用轻量化模型加 INT8 量化,在 2 TOPS 算力上完全可以跑出可用的帧率。所以我的结论比较明确:如果你要做的是“人形检测 + 区域计数 + 简单跟踪”这一层业务,RV1126B 这一类平台比大算力平台更贴近真实交付需求。
1.2 一套方案能解决哪些“人”的问题
基于这块板子做人员检测,项目里通常可以衍生出一串功能:室内外的人形识别、指定区域的人数统计、电子围栏触发报警、单人离岗/在岗检测、通行方向判断、门店热区分析等。核心都是“先找人,再叠加业务逻辑”。
我从实际落地角度做一个简单划分:
- 人形检测:模型输出人体框和置信度,这是基础能力;
- 目标跟踪:加上简单的 IoU 跟踪或客户端跟踪算法,可以实现计数和轨迹,不需要很大的算力开销;
- 业务判定:比如检测到人后判断是否进入某个 ROI 区域,或者持续 5 秒无人时触发告警,这些用 CPU 做完全够用;
- 端侧录像/推流:RV1126B 自带编码器,可以把检测画面叠加框线后编码存储。
这套方案的直接价值就是“数据不出端”。视频流在设备端完成分析,只上传结构化结果或告警消息,网络带宽压力和隐私合规压力都会小很多。这在园区监控、门店管理、工地安全等场景里是非常现实的需求,也是我最终选择它而不是把视频全传后台的原因。
2. 硬件平台与开发环境搭建
2.1 EASY EAI 平台和配套模块
EASY EAI RV1126B 开发板是我用的这套硬件载体,它的设计思路就是面向算法验证和产品原型快速打样。板卡整体比较规整,核心是 RV1126B 主控,常见的配置会带几十到上百毫秒级启动的存储方案,外设上基本把项目里需要的接口都留出来了:MIPI CSI 摄像头接口、千兆/百兆网口、USB、串口、TF 卡槽等等。
实际使用中我建议先把摄像头和网络接口确认好。MIPI 摄像头最好选板卡适配过的型号,驱动和设备树已经配好了,插上就能出图,省去很多调驱动的麻烦。如果是 USB 摄像头,虽然也能用,但有些型号对 ISP 通道的适配不完整,画质和帧率会打折扣。做人员检测这种强依赖图像质量的任务,我更推荐优先用 MIPI 接口的 Sensor。
电源部分要特别留意。板卡标称功耗不高,但接上摄像头、WiFi 模块、编码推流同时跑的时候,瞬时电流会拉高,最好是选一个电流裕量充足的电源适配器,别用一个输出刚好卡在边缘的充电器凑合。我见过好几个“推理一会儿就死机”的案例,最后查下来都是供电不稳。
2.2 开发工具链和板端连接
RV1126B 的模型转换主要依赖瑞芯微的 RKNN-Toolkit2 工具链。这个工具链在 PC 上完成模型转换、量化、仿真,在板端则通过 RKNN Runtime 加载运行。开发机上建议用 Ubuntu 20.04/22.04 这类成熟系统,Python 环境单独建一个虚拟环境,避免和日常开发库互相污染。安装 RKNN-Toolkit2 直接通过 pip 装:
pip install rknn-toolkit2版本匹配是个容易出问题的地方。PC 端 RKNN-Toolkit2 的版本和板端 RKNN Runtime 的版本必须保持兼容,否则会出现“模型加载失败”“算子不支持”之类的报错。我的习惯是每拿到一套新板卡,先查一下官方文档里推荐的对应版本组合,再固定版本号安装,而不是无脑升级最新版。
板端连接一般就是 ADB 或串口。ADB 方便传模型文件和跑 Python 脚本,串口则适合看内核日志和调试启动问题。初次上手时,我会先把板卡系统刷好,然后单独跑一个最简单的 classify 示例,确认 NPU 驱动和 Runtime 都能正常工作,再开始折腾模型。
3. 人员检测模型选型与数据准备
3.1 模型不是越大越好,适配 NPU 才是关键
RV1126B 的算力决定了模型选型只能是轻量化路线。很多人一上来就在 PC 上放了 YOLOv8x 的权重,转换完才发现 NPU 推理一帧要好几百毫秒,根本没法用。这个坑我踩过一次之后,就养成了“先定帧率指标再选模型”的习惯。
我做过一组对比,在相同数据集和量化配置下,不同模型在 RV1126B 上的表现差异很大:
| 模型 | 输入分辨率 | INT8量化后典型耗时(NPU推理) | 整体链路表现 | 适用判断 |
|---|---|---|---|---|
| YOLOv5s | 640x640 | 约 90-110ms | 帧率偏低,后处理压力大 | 不太建议,除非只做低帧率抓拍 |
| YOLOv5n | 640x640 | 约 45-60ms | 帧率可到 20fps 上下 | 优先推荐 |
| YOLOv8n | 640x640 | 约 50-65ms | 帧率和精度均衡 | 可尝试,注意转换兼容性 |
| 轻量化专用检测头 | 416x416 | 约 25-35ms | 帧率较高 | 适合室内近距离场景 |
表格里的数据是实测参考值,不是绝对的,但趋势非常明显:模型参数量的微小增加,在 NPU 上会放大成很大的耗时差异。所以我给大多数项目的建议是:先用 YOLOv5n 或同级别的轻量模型跑通全流程,确认业务效果,再考虑是否换更重的模型。
人员检测用 COCO 预训练的权重通常可以直接起步。COCO 里有 person 这个类别,你可以加载权重后只保留 person 类做 fine-tune,或者干脆先用原权重做验证,跑通部署链路,再针对场景数据迭代。
3.2 数据准备决定了后面 80% 的调试工作量
模型转换前的数据质量,直接决定 INT8 量化后模型精度能不能看。我的做法是,先把目标场景的数据收集起来,至少覆盖这几类情况:
- 不同光照:白天强光、黄昏逆光、夜间红外模式;
- 不同距离:远处小人、近处半身像、镜头边缘被裁切的人;
- 不同姿态:站立、蹲下、弯腰、人群中部分遮挡;
- 不同视角:平视、俯视(很多室内场景的摄像头是高处俯视安装)。
公开数据集可以做底座,但一定要从目标场景里抽一批真实图像出来。我见过一个项目,用纯公开数据训练,检测效果在演示视频里挺好,一装到现场就大量漏检,原因是现场摄像头安装角度偏高,人物在画面中偏小,而且有大量俯视角度。后来补了几天现场数据,重新训练和量化,误检漏检才明显降下来。
标注层面有一点容易被忽略:人员检测并不需要标注得特别精细,但边界框的一致性很重要。如果同一个人的框一会儿紧贴身体,一会儿包含大量背景,模型学出来的框回归逻辑会很混乱,量化后更容易掉点。标注时尽量统一标准:框住人体的可见部分,头部和脚部边缘适度留一点余量。
4. 模型转换与 RKNN 部署全流程
4.1 从 PyTorch/ONNX 到 RKNN 的转换细节
模型选好之后,第一步是把训练框架里的模型导出成 ONNX,再用 RKNN-Toolkit2 转换成 RKNN 格式。整个流程的核心就是一段 Python 脚本:
from rknn.api import RKNN rknn = RKNN(verbose=True) # 配置目标平台和预处理参数 rknn.config( target_platform='rv1126b', mean_values=[[0, 0, 0]], std_values=[[255, 255, 255]], optimization_level=3 ) # 加载 ONNX 模型 rknn.load_onnx(model='yolov5n.onnx') # 构建 RKNN 模型,do_quantization 开启 INT8 量化 rknn.build(do_quantization=True, dataset='dataset.txt') # 导出 rknn.export_rknn('yolov5n.rknn')这段脚本里有几个关键点值得单独说:
第一,mean_values 和 std_values 必须和训练时的预处理保持一致。YOLO 系列大多数训练时是把图像 BGR 读入,归一化到 0~1,那么 config 里 mean 填 0、std 填 255 通常是对的。如果训练时用了自定义的归一化参数,这里也要跟着改,不然推理结果干脆是乱的。
第二,dataset.txt 里每行是量化用的参考图片路径。它只用来统计激活值的分布范围,不需要把训练集全部放进去,但一定要“有代表性”。我强调的是把夜间红外图、逆光图、不同亮度下的图都放进去。量化校准图片太少,会让 INT8 模型在局部场景掉点严重。
第三,如果整体 INT8 量化精度掉得太多,RKNN-Toolkit2 还支持混合量化,也就是只量化模型里敏感度低的部分,敏感算子保留浮点。这个策略我后面会详细展开。转换完成后,可以直接用 PC 端仿真接口验证模型的输出,确认没有转换层面的错误,再推送到板端。
4.2 板端推理代码与输出解析
板端推理有两种主流方式,一种是 Python 层面的 RKNNLite,一种是 C API。做原型验证时用 Python 很快:
from rknnlite.api import RKNNLite rknn = RKNNLite() rknn.load_rknn('yolov5n.rknn') rknn.init_runtime() # 输入图像需为模型要求的尺寸和格式 outputs = rknn.inference(inputs=[img]) # 解析 outputs,得到检测框Python 接口的优点是快速验证,缺点是推理后处理如果也用 Python 写,帧率会被拖垮。YOLO 类模型的原始输出是三组不同尺度的特征图,需要做 decode、confidence 过滤和 NMS。这些操作如果在 Python 的 numpy 循环里跑,一帧轻轻松松几十毫秒,比 NPU 推理还慢。
更高效的做法是用 C 写后处理,或者把 NMS 前的 decode 逻辑放到板端 C/C++ 程序里,再或者直接从模型输出层截断,把多尺度输出在板端拼接处理。C API 的调用流程大概是:
rknn_init(); rknn_inputs_set(); rknn_run(); rknn_outputs_get(); rknn_destroy();在实际项目里,我会把输入图像处理(缩放、letterbox、通道转换)放在 CPU 上并行执行,NPU 在处理上一帧的推理时,CPU 同时处理下一帧的图像预处理,这种流水线结构能让整体吞吐量提升非常明显,单纯死盯 NPU 单帧耗时意义不大。
5. 性能调优与实测结果
5.1 影响帧率的不是只有 NPU
很多人在板子上跑通模型之后,第一反应就是“怎么这么慢”,然后开始怀疑 NPU 性能。实际上我在优化人员检测方案时,发现帧率瓶颈经常出现在三个地方:
第一是图像预处理。从摄像头取到的原始图通常是 1080p 甚至更高分辨率,需要缩放到 640x640,还要做 letterbox 保持宽高比。这个操作如果逐像素在 Python 里做,耗时巨大;用板卡硬件缩放或者优化过的 C 代码,可以压到几毫秒内。
第二是后处理。YOLO 的输出层有大量候选框,如果直接在 Python 里做双重循环,帧率直接腰斩。解决思路是先用置信度阈值把明显无用的框过滤掉,再进入 NMS,框数量会少很多,计算量呈平方级下降。
第三是线程模型。板端推理我通常会开三个线程:采集线程只负责取帧,推理线程只负责调用 RKNN 接口,后处理线程只跑解析逻辑,线程之间用环形队列交换数据。这样做的好处是,即使某一帧后处理突然变慢,也不会阻塞采集和推理,整体帧率更稳定。
5.2 一组有代表性的实测表现
我自己在 EASY EAI RV1126B 上做过一组配置对比,前提是:MIPI 摄像头输入,模型为 YOLOv5n,COCO person 类权重直接转换,不做额外 fine-tune。
| 配置 | 输入分辨率 | NPU推理耗时 | 整链路帧率 | 备注 |
|---|---|---|---|---|
| Python后处理 | 640x640 | 约 50ms | 8-10fps | 后处理拖累严重 |
| C后处理 | 640x640 | 约 50ms | 17-20fps | 流水线优化后稳定 |
| C后处理 | 416x416 | 约 30ms | 30fps+ | 小目标能力下降 |
从表格能明显看出来:单看 NPU 推理时间,340 和 640 差距并不夸张,但整链路帧率的提升更多来自后处理和流水线优化。所以在追帧率之前,我强烈建议先写好一个“耗时打点”逻辑,把采集、缩放、推理、后处理每个阶段的时间都打印出来,找到真正的大头再动手优化。
需要说明的是,这些数字受板卡散热、系统负载、摄像头型号影响,不同批次可能有波动,但“后处理必须用 C 优化”“流水线能显著提帧率”这两条结论,在 RV1126B 上几乎不会变。
6. 常见问题排查与实用避坑清单
6.1 高频问题速查表
在实际调测过程中,我整理了一份出现频率极高的问题速查表,遇到问题时可以先对照排查:
| 现象 | 常见原因 | 处理建议 |
|---|---|---|
| 板上推理输出全为 0 或乱码 | 预处理 mean/std 与训练不一致 | 复现训练时的归一化方式 |
| 检测框位置偏移 | letterbox 的填充方式与训练不一致 | 统一使用相同的缩放逻辑 |
| INT8 量化后精度掉得厉害 | 校准图片代表性不足 | 补充夜视、逆光、俯视样本 |
| 模型转 RKNN 报不支持的算子 | 模型版本与 RKNN 工具链不匹配 | 升级 ONNX 导出方式或更换模型 |
| 推理一段时间后变慢或死机 | 散热不足或电源功率不够 | 加强散热,更换电源适配器 |
| 帧率波动大 | 后处理没有分离线程 | 改成生产者-消费者流水线 |
| 多个模型/多次推理时崩溃 | RKNN 并发访问冲突 | 对推理调用加锁或单例化 |
6.2 我踩过的几个比较值得说的坑
第一个坑是关于量化校准集的。有一版模型在 PC 仿真时精度看起来正常,装到板上检测夜间人形时频繁漏检。排查了很久,最后才发现 dataset.txt 里放的全是白天光线充足的图,夜间红外图的激活分布和白天差异太大,INT8 量化后夜间特征被压没了。从那以后,我的 dataset.txt 一定会按场景比例混合图片,而且每加一类新场景都会重新跑一遍量化。
第二个坑是锚框设置。有一段时间我为了提高小目标召回率,手工修改了模型里的锚框尺寸,但只在推理端改了参数,没有重新训练。结果模型输出分布和锚框完全不匹配,检测框大量重叠,轻微调阈值就疯狂误检。锚框不是可以“调一下试试”的参数,它本质上是从训练数据分布里统计出来的,改它之前先确认要不要重训。
第三个坑是后处理优化时机。我最初用 Python 后处理直接跑完了整个流程,花了很长时间优化 Python 代码,效果一般。后来改成 C 后处理后,发现之前几个月的“优化”其实都是弯路的,C 版本一上手帧率就翻倍了。这类板子的算力天花板很低,性能敏感的代码从一开始就别用解释型语言硬扛,早做 C 扩展早省时间。
最后再分享一个小细节:RV1126B 这类带 AI ISP 的芯片,夜间红外模式下图像噪声明显增加,人员检测的精度常常比白天差不少。如果项目里有夜间的场景,务必把夜间图像提前放进训练和量化环节,而不是最后上线了才发现白天光鲜、晚上失效。这个小操作,能给你省下后面大量的误报排查时间。