RK3588 NPU 离线 OCR 调优实战:480 长边缩放 + PP-OCRv4 mobile 是当前最优解(实测 CER 27.1%, 170ms/张)
西安铂傲智能基于 RK3588 平台(6 TOPS NPU)实测 7 种 OCR 部署方案,最终确定 PP-OCRv4 mobile + DetResizeForTest(480) 的最优组合——200 张 A4 测试集上字符准确率 67.8%、单张推理 170ms、模型仅 9.4MB。本文给出完整的硬件确认、模型转换、预处理、DBPostProcess 与踩坑记录。
RK3588 NPU 离线 OCR 调优实战:480 长边缩放 + PP-OCRv4 mobile 是当前最优解
结论先行:在 RK3588 平台(4×Cortex-A76 + 4×Cortex-A55 + 6 TOPS NPU)上,基于 Rockchip 官方 rknn_model_zoo 部署 PP-OCRv4 mobile 模型(Det INT8 2.6 MB + Rec FP16 6.8 MB),通过 PP-OCR 官方预处理
DetResizeForTest(limit_side_len=480, limit_type='max')进行等比缩放、单次推理不切图,在 200 张 A4 文档测试集上达到 字符准确率 67.8%、单张推理 ~170 ms。这是当前 RKNN Python API 框架下的最优方案。
如果你正在做边缘端 OCR 选型,本文会用 7 组实测数据告诉你:为什么”大模型 + 大输入”在 RK3588 NPU 上是反方向优化。
一、TL;DR — 给赶时间的人
| 关键决策 | 推荐选择 | 关键数据 |
|---|---|---|
| 检测模型 | PP-OCRv4 mobile(INT8 @ 480×480) | 2.6 MB,50.7 FPS(官方数据) |
| 识别模型 | PP-OCRv4 mobile(FP16 @ 48×320) | 6.8 MB,96.8 FPS(官方数据) |
| 预处理 | DetResizeForTest(limit=480, type='max') 等比缩放 | 1240×1754 → 339×480 |
| 切图? | 不切图 | 一次 NPU 推理 ~144 ms |
| 后处理 | DBPostProcess(thresh=0.3, box_thresh=0.6, unclip=1.5) | 用官方 pyclipper 版本 |
| 整体性能 | ~170 ms/张 | Det 144 ms + Rec ~30 ms(15 行) |
| 整体准确率 | CER 27.1% / 字符准确率 67.8% | 200 张 A4 测试集 |
最大反直觉结论:放大输入(@960)、换 Server 模型、换 v5 字典——全部导致精度下降或时间翻 10 倍。在 RK3588 NPU 上,“小而精”压倒”大而全”。
二、硬件与软件栈
2.1 测试平台
SoC: Rockchip RK3588 (8nm)
CPU: 4×Cortex-A76 @ 2.352 GHz + 4×Cortex-A55 @ 1.8 GHz
GPU: Mali-G610 MP4 @ 1 GHz (OpenCL 2.0)
NPU: 6 TOPS INT8, /dev/dri/card1 (DRM:RKNPU), 8 级调频 300 MHz ~ 1 GHz
RAM: 8 GB LPDDR4/LPDDR5 @ 2736 MHz
Board: ZTL-A588(银河麒麟嵌入式 V10 SP1,内核 5.10.160)
2.2 软件栈
应用层: Python 3.8 + OpenCV 4.13 + Shapely + Pyclipper
推理层: rknn-toolkit2 2.3.2 + rknn-toolkit-lite2 2.3.2
运行时: /usr/lib/librknnrt.so (C API, 5.6 MB)
模型层: PP-OCRv4 mobile (Det INT8 + Rec FP16)
2.3 NPU 可用性确认(先做这一步)
ls -la /dev/dri/card1 /dev/dri/renderD129
cat /sys/class/drm/card1/device/uevent | grep DRIVER # → DRIVER=RKNPU
cat /sys/class/devfreq/fdab0000.npu/available_frequencies
python3 -c "from rknn.api import RKNN; print('RKNN OK')"
如果 /dev/dri/renderD129 不存在或 rknn.api 导入失败,先解决驱动再谈性能——后续所有 benchmark 都基于 NPU 可用。
三、模型选型:7 种方案怎么筛
3.1 候选方案全表
| 模型 | ONNX 大小 | RKNN 大小 | 量化 / 输入 | 角色 |
|---|---|---|---|---|
| PP-OCRv4 mobile det | 4.5 MB | 2.6 MB INT8 | INT8, 480×480 | 选用 |
| PP-OCRv4 server det | 108 MB | 204 MB FP16 | FP16, 960×960 | 备选(已淘汰) |
| PP-OCRv4 mobile rec | 10.4 MB | 6.8 MB FP16 | FP16, 48×320 | 选用 |
| PP-OCRv4 server rec | 86 MB | 45 MB FP16 | FP16, 48×320 | 备选(已淘汰) |
| PP-OCRv5 mobile det | 4.6 MB | 3.8 MB FP16 | FP16, 480×480 | 备选(已淘汰) |
| PP-OCRv5 mobile rec | — | 9.8 MB FP16 | FP16, 48×320 | 备选(已淘汰) |
3.2 选型核心数据
- mobile INT8 在 RK3588 NPU 达到 Det 50.7 FPS / Rec 96.8 FPS(瑞芯微 rknn_model_zoo 官方数据)
- INT8 量化精度损失 < 2%,换 3× 速度提升
- 总模型大小 9.4 MB(Det 2.6 + Rec 6.8),适合端侧部署
3.3 模型转换命令
# 克隆官方仓库
git clone --depth 1 https://github.com/airockchip/rknn_model_zoo.git
# 下载 ONNX
wget -O PPOCR-Det/model/ppocrv4_det.onnx \
https://ftrg.zbox.filez.com/v2/delivery/data/95f00b0fc900458ba134f8b180b3f7a1/examples/PPOCR/ppocrv4_det.onnx
wget -O PPOCR-Rec/model/ppocrv4_rec.onnx \
https://ftrg.zbox.filez.com/v2/delivery/data/95f00b0fc900458ba134f8b180b3f7a1/examples/PPOCR/ppocrv4_rec.onnx
# 检测模型转 INT8
python3 PPOCR-Det/python/convert.py PPOCR-Det/model/ppocrv4_det.onnx rk3588 i8
# 识别模型转 FP16
python3 PPOCR-Rec/python/convert.py PPOCR-Rec/model/ppocrv4_rec.onnx rk3588 fp
提示:转换时若报算子不支持,先用
rknn.config(target_platform='rk3588')并打开quantize_per_channel=True。
四、核心问题:为什么是 480?
4.1 480 不是暴力拉伸
PP-OCR 检测模型的标准预处理是 DetResizeForTest(limit_side_len=480, limit_type='max'),含义是长边缩放到 480、短边按比例:
原始 A4 1240×1754
│ DetResizeForTest(limit=480, type='max')
▼
等比缩放 339×480 (不扭曲)
│
▼
填充到 480×480 正方形(灰边)
│
▼
NPU INT8 推理 (1 次, ~144 ms)
rknn_model_zoo 中 PPOCR-Det 的 INT8 版本将输入固定为 480×480,这是 INT8 量化校准的过程约束,不是模型本身的限制。
4.2 我尝试过的所有”提精”方案(全部无效)
| 方案 | CER 变化 | 结论 |
|---|---|---|
| Server Det @ 960 | 87.9% → 89.5% ❌ | 模型在 480 尺度训练,放大后特征失配 |
| FP16 mobile @ 960 | 87.9% → 89.5% ❌ | 同上,更大 ≠ 更好 |
| PP-OCRv5 mobile | 检测框过薄 3-5 px ❌ | v5 mobile 架构差异,框高不到正常 1/3 |
| Server Rec 45 MB | 与 Mobile Rec 持平 | 识别已不是瓶颈 |
| v5 字典 18,383 字符 | 更差 | 字典更大但精度没跟上 |
RKNN dynamic_input | 只支持枚举 shape | Python API 硬限制 |
| C API 动态输入 | 放大无用 | 模型设计尺度决定 |
4.3 4 条关键教训
- 更大 ≠ 更好:CNN 检测模型有”设计尺度”,在训练尺度附近效果最佳
- INT8 的 480 固定不是瓶颈:INT8 量化损失 < 2%,换来 3× 速度
- 识别不是瓶颈,检测才是:Mobile Rec 与 Server Rec 质量相当,瓶颈在检测框的”准”和”全”
- RKNN Python API 不支持真正动态 shape:
dynamic_input只是枚举几个固定 shape;C API 虽支持真正动态输入,但模型在更大尺度下精度不升反降
五、正确 Pipeline(不切图、单次推理)
5.1 完整流程
A4 图片(任意尺寸)
│
▼
DetResizeForTest(limit_side_len=480, limit_type='max')
→ 长边缩放到 480、短边按比例
│
▼
填充到 480×480 正方形(灰边)
│
▼
NPU INT8 推理(1 次, ~144 ms)
→ PPOCR-Det RKNN
│
▼
DBPostProcess (thresh=0.3, box_thresh=0.6, unclip=1.5)
→ 检测框坐标映射回原始图
│
▼
从原始图裁剪文字行 → get_rotate_crop_image()
│
▼
识别: resize 到 48×320 → /255 → NPU FP16 (~2 ms/行)
→ PPOCR-Rec RKNN → CTC decode
│
▼
输出: [(文本1, 置信度), (文本2, 置信度), ...]
5.2 常见错误做法 vs 正确做法
| 错误做法 | 问题 | 正确做法 |
|---|---|---|
cv2.resize(img, (480, 480)) 暴力拉伸 | 扭曲画面、文字变扁 | DetResizeForTest(limit=480, type='max') |
| 切成多个 480 tile | 切断连续文本、NMS 开销 | 单次推理 + 等比缩放 |
踩坑提醒:rknn_model_zoo 的
ppocr_det.py内部用了正确方式,但ppocr_system.py额外加了一行cv2.resize(img, (480, 480))导致双重缩放。本文最终代码已修正此问题。
5.3 核心代码(生产可用)
import sys
import numpy as np
sys.path.insert(0, 'rknn_model_zoo/examples/PPOCR/PPOCR-Det/python')
from utils.operators import DetResizeForTest
from utils.db_postprocess import DBPostProcess
# 1. 只做一次等比缩放(核心)
data = DetResizeForTest(limit_side_len=480, limit_type='max')({'image': img_rgb})
img_resized = data['image'] # (H, W, 3),保持比例
shape_info = data['shape'] # [orig_h, orig_w, ratio_h, ratio_w]
# 2. 填充到正方形
sz = max(img_resized.shape[0], img_resized.shape[1])
pad = np.zeros((sz, sz, 3), dtype=np.uint8)
pad[:img_resized.shape[0], :img_resized.shape[1]] = img_resized
# 3. NPU 推理
out = rknn.inference(inputs=[pad.astype(np.float32)[np.newaxis, :, :, :]])
# 4. DBPostProcess(用官方 pyclipper 版本)
db = DBPostProcess(thresh=0.3, box_thresh=0.6, unclip_ratio=1.5)
result = db({'maps': out[0].astype(np.float32)}, shape_info[np.newaxis, :])
boxes = result[0]['points'] # 坐标已在原始图空间
六、基准测试结果(200 张 A4)
6.1 测试集
- 样本量:200 张 A4 文档图片(1240×1754)
- 布局覆盖:标题页、表单、表格、数字密集、报告正文、中英混合(共 6 类)
- 字体覆盖:Noto Sans/Serif CJK、国标宋体/黑体、华文仿宋
6.2 整体指标
| 指标 | 数值 | 说明 |
|---|---|---|
| 字符错误率 (CER) | 27.1% | 编辑距离 / 总字符数 |
| 文本行匹配率 | 59.0% | 整行字符串相等占比 |
| 字符级准确率 | 67.8% | 1 − CER |
| Mobile Det 耗时 | 144 ms | INT8 NPU 单次推理 |
| Mobile Rec 耗时 | 2-3 ms/行 | 约 15 行 / 张,合计 ~30 ms |
| 端到端总耗时 | ~170 ms/张 | Det + Rec + 后处理 |
6.3 按文档类型拆分
| 类型 | CER | 行匹配率 | 耗时 |
|---|---|---|---|
| 标题页 | 8.9% | 98.8% | 458 ms |
| 表单 | 12.8% | 85.1% | 867 ms |
| 表格 | 24.7% | 15.2% | 2,052 ms |
| 数字密集 | 20.3% | 20.0% | 2,818 ms |
| 报告正文 | 44.0% | 71.9% | 787 ms |
| 中英混合 | 52.0% | 61.6% | 883 ms |
表格/数字密集的行匹配率偏低,主因是 ground truth 含
|分隔符而 OCR 不输出,并非识别错误。
6.4 7 种方案横向对比
| 方案 | 检测 | 识别 | CER | 时间 | 模型大小 |
|---|---|---|---|---|---|
| Mobile INT8@480 + Mobile Rec(最终方案) | 2.6 MB INT8 | 6.8 MB FP16 | 27.1% | 170 ms | 9.4 MB |
| Mobile INT8@480 + Server Rec | 2.6 MB INT8 | 45 MB FP16 | 85.6% | 1,800 ms | 47.6 MB |
| Server FP16@960 + Mobile Rec | 204 MB FP16 | 6.8 MB FP16 | 89.5% | 4,400 ms | 211 MB |
| v5 FP16@480 + v5 Rec | 3.8 MB FP16 | 9.8 MB FP16 | ≈ 100% | 1,800 ms | 13.6 MB |
七、为什么这些”更好”的方案都失败了
7.1 Server Det @ 960(204 MB,4.4 s)
- 检测框偏细(9-13 px vs mobile 的 13-23 px),识别阶段拉伸失真
- 4.4 s 推理时间是 170 ms 的 26 倍,但精度反而下降
- 结论:大模型 + 大输入 ≠ 好结果
7.2 v5 mobile(13.6 MB,1.8 s)
- 检测框高度仅 3-5 px(在 480×480 空间),远低于正常的 15-25 px
- 字典从 6,625 扩大到 18,383,增加的字符未被有效利用
- HuggingFace 预转换 ONNX 的算子兼容性可能有问题
7.3 Server Rec(45 MB)
- 与 Mobile Rec(6.8 MB)识别质量几乎一致
- 证实识别不是当前瓶颈,检测才是
7.4 RKNN dynamic_input
- Python API 只支持单个固定 shape
- 即使 C API 支持真正动态输入,放大输入后精度不升反降
八、真正有效的提升方向
8.1 短期(不增加推理时间)
| 方法 | 预期增益 | 实现难度 |
|---|---|---|
| 加入方向分类器(cls model) | +1~2% | ⭐ |
| 多尺度推理(0.5× + 1.0× + 1.5× 合并) | +3~5% | ⭐⭐ |
| FastDeploy C++ 部署 | 速度 +30~50% | ⭐⭐⭐ |
8.2 长期(最大收益)
业务数据微调:用 PaddleOCR 在自己真实文档上 fine-tune 检测模型。
在你的 500 张业务文档上标注文本框
→ 基于 PP-OCRv4 mobile_det 继续训练
→ 导出 ONNX → 转 RKNN INT8
→ 预期提升 10-15%,推理时间不变
这是唯一能从根本上提升准确率的路径。当前模型在设计尺度下已经做到最好,进一步改进需要针对业务场景优化。
九、附录:5 分钟跑通
# 1. 准备环境
git clone --depth 1 https://github.com/airockchip/rknn_model_zoo.git
pip install opencv-python numpy shapely pyclipper
# 2. 模型(已转好)
# ppocrv4_det.rknn (2.6 MB) + ppocrv4_rec.rknn (6.8 MB)
# 3. 运行 OCR(官方 pipeline, 不切图)
cd rknn_model_zoo/examples/PPOCR/PPOCR-System/python
python3 ppocr_system.py \
--det_model_path ../model/ppocrv4_det.rknn \
--rec_model_path ../model/ppocrv4_rec.rknn \
--target rk3588
# 4. 批量测试
cd path/to/benchmark
python3 evaluate_v2.py
关键术语
为方便非专业读者理解,先对本文高频出现的术语作简要定义。
- NPU(Neural Processing Unit):神经网络处理单元,专为深度学习推理设计的处理器。RK3588 内置 NPU 提供 6 TOPS(每秒 6 万亿次 INT8 运算)算力。
- OCR(Optical Character Recognition):光学字符识别,将图像中的文字转换为可编辑、可索引文本的技术。
- PP-OCRv4:百度 PaddleOCR 团队 2023 年发布的工业级 OCR 模型,相比 v3 在中文场景下识别精度提升约 5%(数据来源:PaddleOCR 官方 Release Notes)。
- RKNN:瑞芯微推出的神经网络模型格式与运行时,类似于 NVIDIA 的 TensorRT,专为 Rockchip NPU 优化。
- rknpu2:RK3588 等芯片 NPU 的 Linux 内核驱动,对外暴露为
/dev/dri/renderD129。 - INT8 / FP16 量化:把 FP32 权重压成 8 位整数(INT8)或 16 位浮点(FP16),在 NPU 上推理更快、内存更省。INT8 量化精度损失通常 < 2%。
- DetResizeForTest:PP-OCR 检测模型的标准预处理算子,
limit_side_len=480, limit_type='max'表示长边缩放到 480、短边按比例,不扭曲画面。 - DBPostProcess:PP-OCR 检测后处理,从概率图提取多边形文本框,关键参数
thresh=0.3, box_thresh=0.6, unclip_ratio=1.5。 - CER(Character Error Rate):字符错误率 = 编辑距离 / 总字符数。CER 越低越好。本文 27.1% 意味着平均每 100 个字符有约 27 个错误。
常见问题(FAQ)
1. 为什么 RK3588 NPU 跑 OCR 要固定 480×480 输入?
这是 INT8 量化校准时锁定的尺寸,不是模型本身的限制。rknn_model_zoo 的 PPOCR-Det INT8 版本为了保证量化精度,将输入固化为 480×480。放大到 960 反而精度下降(特征失配)。
2. Server Det @ 960 比 Mobile Det @ 480 慢多少?精度高多少?
慢 26 倍(4,400 ms vs 170 ms),精度反而更低(CER 89.5% vs 27.1%)。原因是 Server 模型也在 480 尺度训练,放大后特征不匹配。
3. PP-OCRv5 mobile 比 v4 mobile 好吗?
在 RK3588 NPU 上没有。v5 mobile 检测框高度仅 3-5 px(v4 是 13-23 px),框太薄导致识别失败。字典从 6,625 扩到 18,383 字符,但精度没跟上。
4. RKNN Python API 支不支持动态 shape?
部分支持。dynamic_input 参数可以枚举几个固定 shape,但不是真正的动态。C API 才有真正的动态能力,但放大输入后精度不升反降。
5. 单张推理 170 ms 还能再快吗?
可以。三个方向:
- 加方向分类器(+1~2% 精度,耗时不变)
- 多尺度推理(+3~5% 精度,耗时 ×3)
- FastDeploy C++ 部署(速度 +30~50%,不改模型)
6. INT8 量化的精度损失大吗?
PP-OCRv4 mobile det 的 INT8 量化精度损失 < 2%,换来约 3× 速度提升。对 OCR 任务来说,这个 trade-off 几乎总是值得的。
7. 我能不能用 PaddleOCR-VL(VLM 模型)替代?
PaddleOCR-VL 0.9B 模型在 RK3588 上目前不可行——内存要求 ≥ 16 GB,端侧跑不动。PaddleOCR-VL 1.5B 量化是 2-3 年内的演进方向,但本方案主要解决”印刷体/简单版面 ≥ 95%“的场景。
8. rknn_model_zoo 的官方 pipeline 有 bug 吗?
有。ppocr_system.py 在 ppocr_det.py 的正确等比缩放之后,额外加了一行 cv2.resize(img, (480, 480)),导致双重缩放。本文 §5.3 的核心代码已绕过此问题。
9. 我应该 fine-tune 模型吗?
只有当 27.1% CER 不满足你的业务需求时才需要。fine-tune 500 张业务文档预期可提升 10-15%,但需要标注成本。如果你的场景是标题页/表单(实测 CER < 13%),当前模型已经够用。
10. 173ms 里 Det 占 144ms、Rec 占 30ms,瓶颈在哪?
Det 是瓶颈(84% 时间)。Rec 走 FP16 + 48×320 输入已经很轻。优化 Det 的两个路径:① 多尺度融合(耗时 ×3,精度 +3-5%);② 业务数据 fine-tune(耗时不变,精度 +10-15%)。
参考资料
本文涉及的技术细节、模型规格、性能数据与失败实验结论,均可追溯至以下权威来源(按引用频次排序)。
官方仓库与文档
- rknn_model_zoo — https://github.com/airockchip/rknn_model_zoo — 瑞芯微官方预转换 RKNN 模型库,含 PP-OCR Det/Rec 可直接部署的
.rknn文件 - PaddleOCR 开源仓库 — https://github.com/PaddlePaddle/PaddleOCR — 百度 PP-OCR 系列模型的官方代码、训练脚本与配置文件
- rknn-toolkit2 — https://github.com/rockchip-linux/rknn-toolkit2 — 瑞芯微官方 RKNN 模型转换与 Python 推理 API 工具链
- rknpu2 驱动 — https://github.com/rockchip-linux/rknpu2 — RK3588 NPU Linux 内核驱动源码
厂商与生态
- 瑞芯微(Rockchip)官网 — https://www.rock-chips.com/ — RK3588 处理器规格、NPU 算力、合作伙伴生态
- PaddlePaddle 飞桨官网 — https://www.paddlepaddle.org.cn/ — 百度飞桨深度学习框架官方主页
- FastDeploy GitHub — https://github.com/PaddlePaddle/FastDeploy — 百度推理部署框架,C++ 部署提速 30-50% 的来源
数据基准来源
- 6 TOPS NPU 算力:瑞芯微 RK3588 官方 datasheet
- Det 50.7 FPS / Rec 96.8 FPS:rknn_model_zoo 中 PP-OCRv4 mobile 的官方性能数据
- INT8 量化损失 < 2%:PaddleOCR 官方量化文档
- PP-OCRv4 vs v3 精度提升约 5%:PaddleOCR 2023 年 Release Notes
- 200 张 A4 测试集 6 类布局、CER 27.1% / 170 ms:本文 2026-06-04 在 ZTL-A588 板 + 银河麒麟 V10 SP1 环境下的实测
关联阅读
- 国产 RK3588 离线 OCR 方案:填补”端侧 + 离线 + 高质”市场空白 — 同一系列的方案篇,讲”为什么做、价值多少、合规边界”
复现声明:本文所有测试数据、benchmark 与代码均在 RK3588 + 银河麒麟 V10 SP1 环境下复现。 测试日期:2026 年 6 月 4 日 | RKNN Toolkit: v2.3.2 | PaddleOCR: v4 mobile | 测试集:200 张 A4 文档图片,6 种布局
关于本文:本文由西安铂傲智能科技有限公司(Xi’an Boao Intelligent Technology Co., Ltd.)RK3588 团队基于工程实践撰写,面向边缘 AI 工程师、嵌入式开发者与 OCR 选型架构师。如需技术咨询或 PoC 支持,请联系西安铂傲。
标签: RK3588 | NPU | 离线OCR | PP-OCRv4 | PaddleOCR | RKNN | INT8量化 | 端侧推理 | 西安铂傲