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 团队
英文版本稍后补充。
#RK3588 #NPU #离线OCR #PP-OCRv4 #PaddleOCR #RKNN #INT8量化 #端侧推理 #西安铂傲

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 det4.5 MB2.6 MB INT8INT8, 480×480选用
PP-OCRv4 server det108 MB204 MB FP16FP16, 960×960备选(已淘汰)
PP-OCRv4 mobile rec10.4 MB6.8 MB FP16FP16, 48×320选用
PP-OCRv4 server rec86 MB45 MB FP16FP16, 48×320备选(已淘汰)
PP-OCRv5 mobile det4.6 MB3.8 MB FP16FP16, 480×480备选(已淘汰)
PP-OCRv5 mobile rec9.8 MB FP16FP16, 48×320备选(已淘汰)

3.2 选型核心数据

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 @ 96087.9% → 89.5% ❌模型在 480 尺度训练,放大后特征失配
FP16 mobile @ 96087.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只支持枚举 shapePython API 硬限制
C API 动态输入放大无用模型设计尺度决定

4.3 4 条关键教训

  1. 更大 ≠ 更好:CNN 检测模型有”设计尺度”,在训练尺度附近效果最佳
  2. INT8 的 480 固定不是瓶颈:INT8 量化损失 < 2%,换来 3× 速度
  3. 识别不是瓶颈,检测才是:Mobile Rec 与 Server Rec 质量相当,瓶颈在检测框的”准”和”全”
  4. RKNN Python API 不支持真正动态 shapedynamic_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 测试集

6.2 整体指标

指标数值说明
字符错误率 (CER)27.1%编辑距离 / 总字符数
文本行匹配率59.0%整行字符串相等占比
字符级准确率67.8%1 − CER
Mobile Det 耗时144 msINT8 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 INT86.8 MB FP1627.1%170 ms9.4 MB
Mobile INT8@480 + Server Rec2.6 MB INT845 MB FP1685.6%1,800 ms47.6 MB
Server FP16@960 + Mobile Rec204 MB FP166.8 MB FP1689.5%4,400 ms211 MB
v5 FP16@480 + v5 Rec3.8 MB FP169.8 MB FP16≈ 100%1,800 ms13.6 MB

七、为什么这些”更好”的方案都失败了

7.1 Server Det @ 960(204 MB,4.4 s)

7.2 v5 mobile(13.6 MB,1.8 s)

7.3 Server Rec(45 MB)

7.4 RKNN dynamic_input

八、真正有效的提升方向

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

关键术语

为方便非专业读者理解,先对本文高频出现的术语作简要定义。

常见问题(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 还能再快吗?

可以。三个方向:

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.pyppocr_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%)。

参考资料

本文涉及的技术细节、模型规格、性能数据与失败实验结论,均可追溯至以下权威来源(按引用频次排序)。

官方仓库与文档

  1. rknn_model_zoohttps://github.com/airockchip/rknn_model_zoo — 瑞芯微官方预转换 RKNN 模型库,含 PP-OCR Det/Rec 可直接部署的 .rknn 文件
  2. PaddleOCR 开源仓库https://github.com/PaddlePaddle/PaddleOCR — 百度 PP-OCR 系列模型的官方代码、训练脚本与配置文件
  3. rknn-toolkit2https://github.com/rockchip-linux/rknn-toolkit2 — 瑞芯微官方 RKNN 模型转换与 Python 推理 API 工具链
  4. rknpu2 驱动https://github.com/rockchip-linux/rknpu2 — RK3588 NPU Linux 内核驱动源码

厂商与生态

  1. 瑞芯微(Rockchip)官网https://www.rock-chips.com/ — RK3588 处理器规格、NPU 算力、合作伙伴生态
  2. PaddlePaddle 飞桨官网https://www.paddlepaddle.org.cn/ — 百度飞桨深度学习框架官方主页
  3. FastDeploy GitHubhttps://github.com/PaddlePaddle/FastDeploy — 百度推理部署框架,C++ 部署提速 30-50% 的来源

数据基准来源

关联阅读


复现声明:本文所有测试数据、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量化 | 端侧推理 | 西安铂傲