泰山派 RK3566 部署 NCNN 极速推理实践
在立创·泰山派(RK3566, 4 核 Cortex-A55, 2GB 内存)这类嵌入式 Linux 开发板上部署深度学习模型时,CPU 算力与内存带宽往往是最大掣肘。
很多开发者默认使用 ONNX Runtime CPU 模式作为落地兜底方案,但在泰山派上运行标准的 PP-OCRv4 ONNX 模型时,耗时通常长达 1.5 ~ 2 秒,且模型总体量达 90MB,内存占用极高。
而在开源项目 tspi-ocr-web 的研发过程中,我引入了腾讯开源的高性能移动端推理框架 Tencent/ncnn 与百度 PaddlePaddle/PaddleOCR 移动端轻量模型。通过开启 ARM NEON FP16 汇编加速 与 pnnx 动态尺寸图优化,将整图 OCR 识别速度直接提升至 120~180ms(性能提升近 10 倍),同时模型体量骤降至 11MB!
本文提取项目中关于 NCNN 的核心实践,系统整理“架构优势 $\to$ 模型来源与下载 $\to$ 模型转换 (pnnx) $\to$ Python 板端推理 $\to$ 性能对比与避坑”的完整落地方法论。
一、为什么选择 NCNN?
在边缘 ARM 嵌入式设备上,主流推理框架主要有 ONNX Runtime、TFLite 以及硬件专用的 NPU 工具链(如 RKNN)。但在实际工程落地中,NCNN 展现出了极其独特的不可替代性:
| 评估维度 | ONNX Runtime (CPU) | 瑞芯微 RKNN (NPU) | 腾讯 NCNN (ARM CPU) |
|---|---|---|---|
| 依赖与体积 | 依赖较重(动态库庞大) | 强依赖专有 NPU 内核驱动 | **极简纯 C++**,零第三方库依赖 |
| 模型算子兼容 | 兼容性极强 | 需模型量化,部分动态算子受限 | 算子全面,图优化成熟 |
| 模型体积 (PP-OCR) | 约 90MB | 约 15MB | 仅 11MB(FP16 压缩) |
| RK3566 整图耗时 | ~1500ms(慢) | ~80ms(极快) | ~150ms(极快,接近 NPU) |
| 跨硬件通用性 | 通用 | 仅限瑞芯微指定芯片 | 通用(任意 ARMv8/A55/A72/A76) |
核心加速秘密:ARMv8.2-A NEON FP16 指令
RK3566 的 CPU 核心基于 ARM Cortex-A55 架构,支持 ARMv8.2-A 指令集中的 FP16 矢量运算。
- 传统 ONNX Runtime 大多运行在 FP32 单精度下,不仅计算量翻倍,更严重的是在 2GB 开发板上受限于 L2/L3 缓存与 DDR4 带宽瓶颈;
- NCNN 针对 ARM NEON 手写了深度的汇编优化内核(Kernel),计算时以 16 位半精度浮点(FP16)直接加载并执行 FMA(乘加)向量指令;
- 双重红利:内存带宽占用直接减半,浮点吞吐率翻倍,彻底释放 4 核 A55 的硬件潜能。
二、模型来源与资源清单(Hugging Face 开源仓库)
项目中所采用的 NCNN 与 ONNX 模型均来自于开源社区并经过轻量化验证,详细开源出处与文件清单如下:
2.1 PP-OCRv5 NCNN 优化版(开箱即用推荐,总计约 11MB)
- 开源仓库出处:Hugging Face 开源项目 qefro/pp-OCRv5-6-ncnn
- 国内镜像加速:https://hf-mirror.com/qefro/pp-OCRv5-6-ncnn
- 包含文件与映射:
- 文本检测:
PP_OCRv5_mobile_det.param/PP_OCRv5_mobile_det.bin(约 3.0 MB) - 文本识别:
PP_OCRv5_mobile_rec.param/PP_OCRv5_mobile_rec.bin(约 7.9 MB) - 方向分类器:
PP_LCNet_x0_25_textline_ori.param/PP_LCNet_x0_25_textline_ori.bin(约 0.3 MB) - 字典文件:
ppocr_keys_v5.txt(映射为dict.txt)
- 文本检测:
该套模型是针对移动端与嵌入式平台优化后的 PP-OCRv5 结构,相比 v4 识别精度提升的同时参数量进一步压缩,完美适配 NCNN 的 NEON 汇编计算核心。
2.2 PP-OCRv4 ONNX 原版(对比基准与转换源模型,约 90MB)
- 开源仓库出处:Hugging Face 仓库 monkt/paddleocr-onnx
- 国内镜像加速:https://hf-mirror.com/monkt/paddleocr-onnx
- 包含文件:
detection/v3/det.onnxlanguages/chinese/rec.onnxpreprocessing/textline-orientation/PP-LCNet_x1_0_textline_ori.onnx
2.3 自动化下载脚本
在 tspi-ocr-web 项目中,可通过内置脚本 scripts/download_models.py 一键拉取上述模型(支持自动走 hf-mirror.com 国内加速):
1 | |
三、模型转换实战:ONNX $\longrightarrow$ NCNN (基于 pnnx)
NCNN 早期使用的是 onnx2ncnn 工具,而目前官方主力推荐的是经过彻底重构的 pnnx(PyTorch/ONNX Neural Network eXchange)。pnnx 能自动完成算子融合、冗余消除以及动态尺寸定义。
在 tspi-ocr-web 项目中,转换逻辑封装在 utils/ncnn_converter.py 模块中。
3.1 安装转换工具链(建议在 PC 端执行)
虽然 pnnx 可以通过 pip 安装,但官方的 pip install pnnx 往往会强行绑定安装 500MB+ 的 PyTorch。为了保持环境纯净,可从 pnnx GitHub Releases 直接下载独立的 C++ 预编译二进制文件。
1 | |
3.2 文本检测模型(DBNet)转换
文本检测模型输入通常为动态大图,若未指定输入维度,转换工具往往无法正确推导动态算子形状。需使用 inputshape 与 inputshape2 显式预设多级动态分辨率:
1 | |
optlevel=2:启用全局算子融合与图结构裁剪;fp16=1:权重大幅压缩至原大小的 50%,并在运行时开启半精度推理;- 产物:生成
det.ncnn.param(网络拓扑)与det.ncnn.bin(权重参数)。
3.3 文本识别模型(CRNN / SVTR / LCNet)转换
文本识别模型的特点是:图像高度固定(如 48px),而文本行宽度随字符数量动态可变:
1 | |
通过指定不同宽度的 inputshape,pnnx 能够推导出任意步长的动态宽度拓扑,使得模型在板端能够直接接收变长文本切片推理。
四、板端 Python 极速推理实战
在 RK3566 开发板端(建议使用此前搭建的 Python 3.12 虚拟环境),安装编译好的 Python 绑定:
1 | |
4.1 初始化与网络加载
基于 tspi-ocr-web 中 PPOCRv5NCNNEngine 的核心实现,网络初始化与线程调优如下:
1 | |
4.2 动态 Blob 名称自适应
经过 pnnx 优化后的网络,输入输出 Blob 节点名有时会由 input/output 重命名为 in0/out0。为了增强兼容性,可在加载后动态自省匹配:
1 | |
4.3 执行前向推理(Extractor)
NCNN 的设计思想是无状态的网络拓扑(Net)搭配有状态的提取器(Extractor),Extractor 负责单次前向的数据绑定与计算执行:
1 | |
4.4 资源释放
在长周期驻留的服务中,当网络不再使用或需要重载时,显式释放底层 C++ 显存与权重:
1 | |
五、RK3566 真实性能对比基准
在立创·泰山派(RK3566 4核 1.8GHz, 2GB LPDDR4, Ubuntu 26.04)上,对一张标准发票图片(包含 18 行文字)进行端到端识别测试:
| 推理引擎 | 计算单元 | 模型体量 (Det + Rec) | 进程常驻内存 | 整图端到端延迟 |
|---|---|---|---|---|
| ONNX Runtime (PP-OCRv4) | CPU 4-Thread (FP32) | 90.4 MB | ~380 MB | 1520 ms |
| NCNN (PP-OCRv5) | CPU 4-Thread (NEON FP16) | 11.2 MB | ~85 MB | 158 ms ⭐ |
| RKNN (PP-OCRv4) | NPU (0.8 TOPS INT8) | 14.8 MB | ~110 MB | 78 ms |
从测试数据可以看出:
- 对比 ONNX Runtime:NCNN 速度直接提升近 10 倍,内存节省超过 **75%**,使得在 2GB 内存板卡上跑复杂视觉服务完全不会发生 OOM;
- 对比 RKNN NPU:NCNN 仅通过 CPU 纯算力就跑出了 150ms 的优异成绩,且完全避开了 RKNN 的 NPU 量化精度损失以及专有内核驱动门槛,非常适合快速落地交付。
六、关键避坑指南
- NumPy 数组连续性问题(C-Contiguous):
在向ncnn.Mat喂入切片数据(如从检测框裁剪文本小图)时,NumPy 切片通常是非连续内存。**必须调用np.ascontiguousarray(...)**,否则可能导致底层 C++ 内存指针越界直接 Core Dump。 - 多线程参数设置(num_threads):
嵌入式多核 CPU 并非线程越多越好。在泰山派 4 核 A55 上,设置为num_threads = 4是吞吐与延迟的最佳平衡点;若设置过高,频繁的线程上下文切换反而会导致性能劣化。 - 输入输出尺寸必须符合网络步长:
检测网络通常包含多级下采样(如 32 倍),输入的宽和高必须预处理为 32 的整数倍,否则在经过 pnnx 算子时会触发维度不匹配错误。
结语与开源资源导航
NCNN 凭借纯粹的底层工程优化与对 ARM 架构的极致压榨,为边缘嵌入式设备提供了一条在 CPU 上实现准实时 AI 推理的高效通路。
本文涉及的所有项目源码、模型与依赖均已开源,欢迎查阅与体验:
1. 项目与代码仓库
- 🔗 tspi-ocr-web 完整项目:https://github.com/bubao/tspi-ocr-web
- 📂 模型转换源码:
utils/ncnn_converter.py - 📂 推理引擎封装:
services/ocr_service.py - 📂 模型自动下载脚本:
scripts/download_models.py
2. 开源框架与模型出处
- 🚀 腾讯 NCNN 官方仓库:https://github.com/Tencent/ncnn
- 🛠️ PNNX 模型转换工具链:https://github.com/pnnx/pnnx
- 📖 百度官方 PaddleOCR 项目:https://github.com/PaddlePaddle/PaddleOCR
- 🤗 Hugging Face PP-OCRv5 NCNN 权重:qefro/pp-OCRv5-6-ncnn(国内镜像:hf-mirror.com/qefro/pp-OCRv5-6-ncnn)
- 🤗 Hugging Face PP-OCRv4 ONNX 权重:monkt/paddleocr-onnx(国内镜像:hf-mirror.com/monkt/paddleocr-onnx)
