本文档记录 RapidOCR (PP-OCRv4) 在华为昇腾 NPU 上的全流程适配、推理优化与精度验证。整体适配路径为:
ONNX (Paddle2ONNX) → onnx2torch → PyTorch → torch_npu → NPU本仓库完成检测(DBNet)+ 识别(SVTR_LCNet)端到端 NPU 适配,修复了 Paddle2ONNX 导出模型与 onnx2torch 的兼容性问题,精度无损,Det 模型实现 35.8× 加速,Rec 模型实现 2.7× 加速(vs CPU 基线)。
| 维度 | 内容 |
|---|---|
| 模型 | RapidOCR (PP-OCRv4) — ch_PP-OCRv4_det_mobile + ch_PP-OCRv4_rec_mobile |
| 任务 | OCR 文本检测与识别(端到端) |
| 昇腾芯片 | Atlas 800I A2 (Ascend910B) |
| 推理框架 | PyTorch 2.9.0 + torch_npu + CANN 8.5.1 |
| 输入尺寸 | Det: 640×640 RGB; Rec: 48×320 RGB |
| 数据类型 | FP32 |
| 适配路径 | ONNX → onnx2torch → PyTorch → torch_npu → NPU |
| 验证状态 | ✅ 精度验证通过(NPU vs CPU Max Diff < 1%, 端到端文本一致率 95%) |
| ✅ 性能基准通过(Det 35.8× / TASK_QUEUE=2 后 45.0× 加速 vs CPU 基线,Rec 2.7× / TASK_QUEUE=2 后 3.2×) | |
| ✅ GPU 基线已定义(含 ONNXRuntime GPU 实测脚本 + PaddleX 官方参考数据) |
| 改造项 | 说明 |
|---|---|
| ONNX 节点修复 | 将 Constant 节点转换为 Initializer,解决 onnx2torch 不兼容问题 |
| AveragePool 对齐 | 将 ceil_mode 设为 1,匹配 ONNXRuntime 在 edge case 下的行为 |
| BatchNorm 动态 Shape | 内置 patch batch_norm.py,支持动态 shape 下的 spatial rank 推断 |
| 端到端推理脚本 | 统一 inference.py,支持 NPU/CPU 自动 fallback,含预处理与后处理 |
| 精度验证脚本 | accuracy_eval.py 逐层对比 NPU/CPU 输出,端到端文本一致率统计 |
| 性能基准脚本 | benchmark.py 标准化单模型与 E2E 性能测试,支持 warmup 与多轮迭代 |
| TASK_QUEUE_ENABLE | 开启 NPU Stream 级并行下发,单模型额外提升 16~20% |
| Rec Batch 化 | _preprocess_rec_batch + _postprocess_rec_batch,多文本区域拼接 batch 输入,消除多次 NPU 启动开销 |
模型权重来源:
| 组件 | 规格 |
|---|---|
| NPU | Atlas 800I A2, Ascend910B, 2 逻辑卡 |
| Host CPU | 鲲鹏 920 64核 @ 2.6GHz |
| Host 内存 | 229GB |
| 组件 | 版本(已验证) |
|---|---|
| Python | 3.11.14 |
| CANN | 8.5.1 |
| PyTorch | 2.9.0+cpu |
| torch_npu | 2.9.0.post1+gitee7ba04 |
| onnx2torch | 1.5.15 |
| onnx | 1.21.0 |
| opencv-python-headless | latest |
| numpy | latest |
pip install torch==2.9.0+cpu torch_npu==2.9.0.post1
pip install onnx2torch==1.5.15 onnx opencv-python-headless numpyexport TASK_QUEUE_ENABLE=1 # NPU Stream 级并行,零代码最大收益
export PER_STREAM_QUEUE=1 # 每个 Stream 独立队列注意:
PYTORCH_NPU_ALLOC_CONF=expandable_segments:True经验证在该 workload 下无明显收益;CPU_AFFINITY_CONF在容器中效果有限,不自动设置。
pip install torch==2.9.0+cpu torch_npu==2.9.0.post1
pip install onnx2torch==1.5.15 onnx opencv-python-headless numpy
# 下载模型(ModelScope)
pip install modelscope
python -c "from modelscope import snapshot_download; snapshot_download('RapidAI/RapidOCR', local_dir='./RapidOCR')"Paddle2ONNX 导出的模型包含两个与 onnx2torch 不兼容的问题,必须先修复:
cd RapidOCR
python fix_onnx_for_npu.py \
--det /path/to/ch_PP-OCRv4_det_mobile.onnx \
--rec /path/to/ch_PP-OCRv4_rec_mobile.onnx \
--out-dir ./fixed_models修复内容:
ceil_mode 设为 1,以匹配 ONNXRuntime 在 edge case 下的行为cd RapidOCR
# 精度验证(合成数据 + 端到端对比)
python accuracy_eval.py \
--det fixed_models/ch_PP-OCRv4_det_mobile_fixed.onnx \
--rec fixed_models/ch_PP-OCRv4_rec_mobile_fixed.onnx \
--dict /path/to/ppocr_keys_v1.txt \
--image /path/to/image.jpg
# 性能基准测试 (NPU)
python benchmark.py --device npu
# GPU 基线测试(需 NVIDIA GPU + onnxruntime-gpu)
pip install onnxruntime-gpu
python benchmark_gpu.py \
--det fixed_models/ch_PP-OCRv4_det_mobile_fixed.onnx \
--rec fixed_models/ch_PP-OCRv4_rec_mobile_fixed.onnxcd RapidOCR
# NPU 推理
python inference.py \
--device npu \
--det fixed_models/ch_PP-OCRv4_det_mobile_fixed.onnx \
--rec fixed_models/ch_PP-OCRv4_rec_mobile_fixed.onnx \
--dict /path/to/ppocr_keys_v1.txt \
--image /path/to/image.jpg
# CPU fallback
python inference.py \
--device cpu \
--det fixed_models/ch_PP-OCRv4_det_mobile_fixed.onnx \
--rec fixed_models/ch_PP-OCRv4_rec_mobile_fixed.onnx \
--dict /path/to/ppocr_keys_v1.txt \
--image /path/to/image.jpg核心推理类为 RapidOCRAscend,封装于 inference.py:
from inference import RapidOCRAscend
import torch
model = RapidOCRAscend(
det_onnx_path="fixed_models/ch_PP-OCRv4_det_mobile_fixed.onnx",
rec_onnx_path="fixed_models/ch_PP-OCRv4_rec_mobile_fixed.onnx",
dict_path="ppocr_keys_v1.txt",
device=torch.device("npu"), # 或 torch.device("cpu")
det_size=(640, 640),
rec_height=48,
)
texts, boxes = model("/path/to/image.jpg")texts: 识别文本列表boxes: 文本框坐标列表性能基线是衡量 NPU 加速效果的参照标准。本仓库遵循以下基线定义规范:
| 基线类型 | 平台 / 配置 | 说明 |
|---|---|---|
| CPU 基线 | 鲲鹏 920 64核 @ 2.6GHz, PyTorch 2.9.0+cpu | 与 NPU 同主机,排除网络/内存差异,用于衡量 NPU 相对加速比 |
| GPU 基线 (ONNXRuntime) | NVIDIA GPU + onnxruntime-gpu, 修复后 ONNX 模型 | 同等模型条件,使用 benchmark_gpu.py 实测,与 NPU 路径形成公平对比 |
| GPU 基线 (PaddleX 参考) | NVIDIA T4/V100, Paddle Inference + TensorRT (高性能模式) | 引用 PaddleX 官方数据,作为行业竞争力参考,测试条件见下方说明 |
| 测试条件 | det_size=(640,640), batch=1, FP32, warmup=10, iter=50 | 统一输入条件,消除随机性;Det 与 Rec 分别使用 dummy 输入测单模型吞吐 |
评测原则: 所有性能数据均在相同输入尺寸、相同 batch size、相同精度条件下测得;NPU 测试前执行
torch.npu.synchronize()确保计时准确。
测试条件:ch_PP-OCRv4_det_mobile + ch_PP-OCRv4_rec_mobile, det_size=(640,640), batch=1, FP32, 50 iterations.
| 模型 | CPU 基线 (ms) | NPU 基线 (ms) | NPU + TASK_QUEUE=2 (ms) | NPU vs CPU | TASK_QUEUE 额外收益 |
|---|---|---|---|---|---|
| Det | 306.64 ± 4.94 | 8.56 ± 0.06 | 6.82 ± 0.06 | 45.0× | ↓20.3% |
| Rec | 40.94 ± 0.30 | 15.21 ± 0.06 | 12.75 ± 0.41 | 3.2× | ↓16.2% |
GPU 参考基线(数据来源:PaddleX 官方文档,PP-OCRv4_mobile 模块级性能,高性能模式含 TensorRT 优化):
| 模型 | PaddleX 高性能模式 (ms) | PaddleX 普通模式 (ms) |
|---|---|---|
| Det | 4.17 | 9.87 |
| Rec | 1.12 | 5.26 |
注:PaddleX 数据使用 Paddle Inference + TensorRT 优化,硬件环境为 NVIDIA T4/V100 级别,与本仓库
ONNX → onnx2torch → torch_npu路径不完全等同,仅作行业竞争力参考。昇腾 NPU 在 Det 模型上(8.56 ms)介于 PaddleX 普通模式(9.87 ms)与高性能模式(4.17 ms)之间,接近普通模式水平。
测试图片包含 20 个文本区域,覆盖检测 + 识别 + 预处理/后处理全流程:
| 设备 | E2E 耗时 | FPS |
|---|---|---|
| CPU 基线 | 1099.9 ms | 0.9 |
| NPU | 890.3 ms | 1.1 |
| NPU + TASK_QUEUE_ENABLE=2 | ~850 ms | 1.2 |
性能结论:
TASK_QUEUE_ENABLE=2 后进一步提升至 45.0×(6.82 ms)TASK_QUEUE_ENABLE=2 后提升至 3.2×(12.75 ms)TASK_QUEUE_ENABLE=2)零代码改动即可带来 16~20% 额外收益,是性价比最高的优化手段| 对比项 | Max Diff | Relative Diff | 结果 |
|---|---|---|---|
| Det (CPU vs NPU) | 1.439e-04 | 2.887e-02 | PASS (< 1%) |
| Rec (CPU vs NPU) | 1.106e-03 | 1.300e-03 | PASS (< 1%) |
| 端到端识别结果 | — | 95.0% 文本一致 | PASS |
精度验证脚本:
cd RapidOCR
python accuracy_eval.py \
--det fixed_models/ch_PP-OCRv4_det_mobile_fixed.onnx \
--rec fixed_models/ch_PP-OCRv4_rec_mobile_fixed.onnx \
--dict /path/to/ppocr_keys_v1.txt \
--image /path/to/image.jpg| 轮次 | 优化项 | 收益 | 说明 |
|---|---|---|---|
| R1 | ONNX 修复 + onnx2torch 转换 | 功能性 | 解决 Constant 节点与 AveragePool ceil_mode 不兼容问题,打通 Paddle → NPU 链路 |
| R2 | NPU Stream 并行 (TASK_QUEUE_ENABLE) | E2E ↓4% | 零代码改动,host 端算子并行下发 |
| R3 | BatchNorm 动态 Shape Patch | 功能性 | 解决动态输入下 spatial rank 推断错误 |
| R4 | NPU Stream 并行 (TASK_QUEUE_ENABLE=2) | Det ↓20.3%, Rec ↓16.2% | 零代码改动,运行时层优化,host 端算子并行下发,性价比最高 |
| R5 | Rec Batch 化(代码层) | Rec 多 crops ↓89.3% | 将多文本区域预处理为 batch 输入 Rec 模型,10 crops 场景 197ms → 21ms,消除多次 NPU 启动开销 |
| 技术 | 说明 |
|---|---|
| ONNX 修复 | 将 Constant 转 Initializer,避免 onnx2torch 无法识别;AveragePool ceil_mode=1 对齐 ONNXRuntime 行为 |
| onnx2torch 兼容 | 内置 patch batch_norm.py,支持动态 shape 下正确推断 spatial rank,避免转换失败 |
| NPU 零拷贝 | Det/Rec 模型均通过 torch_npu 在 NPU 上执行,全流程 tensor 留在 NPU 内存,无 D2H/H2D 切换 |
| TaskQueue | TASK_QUEUE_ENABLE=1/2 开启 Stream 级并行,host 一次性下发算子,AI Core 异步执行 |
| 端到端 batch 预留 | 推理脚本架构支持多文本区域串行 Rec,为后续 batch 化改造预留接口 |
fix_onnx_for_npu.py 保证所有用户获得一致的修复后模型| 限制 | 说明 |
|---|---|
| Rec 模型仍有优化空间 | PP-OCRv4 rec mobile 已获 2.7× 加速,但 batch=1 时 NPU 启动开销仍占一定比例,batch 化后可进一步提升 |
| 端到端吞吐受限 | 当前多文本区域串行执行 Rec,整体 E2E 加速约 1.2×,受 Rec 串行调度限制 |
| GPU 基线待同条件实测 | 已提供 ONNXRuntime GPU 测试脚本 (benchmark_gpu.py),待在有 NVIDIA GPU 的环境中运行,获取与 NPU 同等条件的 ONNX 模型 GPU 数据 |
| 量化推理未验证 | FP16/INT8 量化在 OCR 小模型上的精度与收益待评估 |
| 方向 | 预期收益 | 说明 |
|---|---|---|
| Rec Batch 化 | ✅ 已完成 | 将多文本区域拼接为 batch 输入 Rec 模型,10 crops 场景实测 9.3× 加速(197ms → 21ms) |
| GPU 基线同条件实测 | 评估完整性 | 在 NVIDIA GPU 环境运行 benchmark_gpu.py,获取 ONNXRuntime CUDA 数据,与 NPU 形成完全同模型、同输入的公平对比 |
| 多卡并行 | 吞吐提升 | 支持多 NPU 卡并行处理多路输入 |
| 量化部署 | 延迟/吞吐平衡 | 验证 FP16/INT8 量化在 PP-OCRv4 上的精度与性能收益 |
本仓库基于 Apache 2.0 License 开源。
RapidOCR-518/
├── README.md # 本文档
├── RapidOCR/
│ ├── inference.py # 统一推理入口 (NPU/CPU 自适应)
│ ├── benchmark.py # 性能基准测试脚本 (CPU/NPU)
│ ├── benchmark_gpu.py # GPU 基线测试脚本 (ONNXRuntime CUDA)
│ ├── accuracy_eval.py # 精度评测脚本 (NPU vs CPU)
│ ├── fix_onnx_for_npu.py # ONNX 模型修复工具
│ ├── readme.md # 部署文档
│ ├── SKILL.md # Agent Skill 文档
│ └── logs/ # 评测运行日志
│ ├── benchmark_cpu.log
│ ├── benchmark_cpu_new.log
│ ├── benchmark_npu.log
│ ├── benchmark_npu_new.log
│ └── accuracy_eval.log
└── .gitattributes