跳转至

RapidOCR集成PP-OCRv4_server_rec_doc模型记录

该文章主要记录 RapidOCR 如何集成 PP-OCRv4_server_rec_doc 模型的,涉及模型转换,模型精度测试等步骤。

引言

来自 PaddleX官方文档

PP-OCRv4_server_rec_doc 是在 PP-OCRv4_server_rec 的基础上,在更多中文文档数据和 PP-OCR 训练数据的混合数据训练而成,增加了部分繁体字、日文、特殊字符的识别能力,可支持识别的字符为 1.5 万+,除文档相关的文字识别能力提升外,也同时提升了通用文字的识别能力。

来自 MinerU 的官方测试,对该模型的评价:

经验证,PP-OCRv4_server_rec_doc 模型在中英日繁单种语言或多种语言混合场景均有明显精度提升,且速度与 PP-OCRv4_server_rec 相当,适合绝大部分场景使用。

PP-OCRv4_server_rec_doc 在小部分纯英文场景可能会发生单词粘连问题,PP-OCRv4_server_rec 则在此场景下表现更好。

综上所述,该模型在各个场景下均有明显精度提升,尤其是生僻字和一些特殊符号。值得说明的是该模型为 server 版,因此推理速度不是那么快。

以下代码运行环境

  • OS: macOS Sequoia 15.4.1
  • Python: 3.10.14
  • PaddlePaddle: 3.0.0
  • paddle2onnx: 2.0.1
  • rapidocr: 2.0.7

1. 模型跑通

该步骤主要先基于 PaddleX 可以正确使用 PP-OCRv4_server_rec_doc 模型得到正确结果。

该部分主要参考文档:docs

安装 paddlex:

pip install "paddlex[ocr]==3.0.0rc1"

测试 PP-OCRv4_server_rec_doc 模型能否正常识别:

测试用图:

alt text

Tip

运行以下代码时,模型会自动下载到 /Users/用户名/.paddlex/official_models 下。

from paddlex import create_model

model = create_model(model_name="PP-OCRv4_server_rec_doc")
output = model.predict(input="images/1.jpg", batch_size=1)
for res in output:
    res.print()
    res.save_to_img(save_path="./output/")
    res.save_to_json(save_path="./output/res.json")

# 输出以下内容,表明成功:
# {'res': {'input_path': 'images/1.jpg', 'page_index': None, 'rec_text': '绿洲仕格维花园公寓', 'rec_score': 0.9839767813682556}}

2. 模型转换

该部分主要参考文档: docs

PaddleX 官方集成了 paddle2onnx 的转换代码:

paddlex --paddle2onnx --paddle_model_dir models/PP-OCRv4_server_rec_doc --onnx_model_dir models/PP-OCRv4_server_rec_doc

输出日志如下,表明转换成功:

Input dir: models/PP-OCRv4_server_rec_doc
Output dir: models/PP-OCRv4_server_rec_doc
Paddle2ONNX conversion starting...
  warnings.warn(warning_message)
[Paddle2ONNX] Start parsing the Paddle model file...
[Paddle2ONNX] Use opset_version = 7 for ONNX export.
[Paddle2ONNX] PaddlePaddle model is exported as ONNX format now.
2025-05-14 08:21:23 [INFO]      Try to perform optimization on the ONNX model with onnxoptimizer.
2025-05-14 08:21:23 [INFO]      ONNX model saved in models/PP-OCRv4_server_rec_doc/inference.onnx.
Paddle2ONNX conversion succeeded
Done

3. 模型推理验证

该部分主要是在 RapidOCR 项目中测试能否直接使用 onnx 模型。要点主要是确定模型前后处理是否兼容。从 PaddleX官方文档 中可以看到:

PP-OCRv4_server_rec_doc 是在 PP-OCRv4_server_rec 的基础上,在更多中文文档数据和 PP-OCR 训练数据的混合数据训练而成,增加了部分繁体字、日文、特殊字符的识别能力,可支持识别的字符为 1.5 万+,除文档相关的文字识别能力提升外,也同时提升了通用文字的识别能力

以上说明了该模型与 PP-OCRv4_server_rec 模型结构相同,前后处理也相同。唯一做的就是添加了更多数据,扩展了字典个数,从 6623 扩展到 15630 个。因此,可以直接使用 RapidOCR 来快速推理验证。代码如下:

from rapidocr import RapidOCR

model_path = "models/PP-OCRv4_server_rec_doc/inference.onnx"
key_path = "models/ppocrv4_doc_dict.txt"
engine = RapidOCR(params={"Rec.model_path": model_path, "Rec.rec_keys_path": key_path})

img_url = "https://img1.baidu.com/it/u=3619974146,1266987475&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=516"
result = engine(img_path)
print(result)

result.vis("vis_result.jpg")

alt text

4. 模型精度测试

该部分主要使用 TextRecMetric 和测试集 text_rec_test_dataset 来评测。

需要注意的是,PP-OCRv4_server_rec_doc模型更加侧重生僻字和一些符号识别。 当前测试集并未着重收集生僻字和一些符号的数据,因此以下指标会有些偏低。如需自己使用,请在自己场景下测试效果。

相关测试步骤请参见 TextRecMetric 的 README,一步一步来就行。我这里测试最终精度如下:

{'ExactMatch': 0.8097, 'CharMatch': 0.9444, 'avg_elapse': 0.0818}

该结果已经更新到 开源 OCR 模型对比 中。

5. 集成到 rapidocr 中

该部分主要包括将字典文件写入到 ONNX 模型中、托管模型到魔搭、更改 rapidocr 代码适配等。

字典文件写入 ONNX 模型

该步骤仅存在文本识别模型中,文本检测模型没有这个步骤。

详细代码
from pathlib import Path
from typing import List, Union

import onnx
import onnxruntime as ort
from onnx import ModelProto


def read_txt(txt_path: Union[Path, str]) -> List[str]:
    with open(txt_path, "r", encoding="utf-8") as f:
        data = [v.rstrip("\n") for v in f]
    return data


class ONNXMetaOp:
    @classmethod
    def add_meta(
        cls,
        model_path: Union[str, Path],
        key: str,
        value: List[str],
        delimiter: str = "\n",
    ) -> ModelProto:
        model = onnx.load_model(model_path)
        meta = model.metadata_props.add()
        meta.key = key
        meta.value = delimiter.join(value)
        return model

    @classmethod
    def get_meta(
        cls, model_path: Union[str, Path], key: str, split_sym: str = "\n"
    ) -> List[str]:
        sess = ort.InferenceSession(model_path)
        meta_map = sess.get_modelmeta().custom_metadata_map
        key_content = meta_map.get(key)
        key_list = key_content.split(split_sym)
        return key_list

    @classmethod
    def del_meta(cls, model_path: Union[str, Path]) -> ModelProto:
        model = onnx.load_model(model_path)
        del model.metadata_props[:]
        return model

    @classmethod
    def save_model(cls, save_path: Union[str, Path], model: ModelProto):
        onnx.save_model(model, save_path)


dicts = read_txt(
    "models/ppocrv4_doc_dict.txt"
)
model_path = "models/PP-OCRv4_server_rec_doc.onnx"
model = ONNXMetaOp.add_meta(model_path, key="character", value=dicts)

new_model_path = "models/PP-OCRv4_server_rec_doc_with_dict.onnx"
ONNXMetaOp.save_model(new_model_path, model)

t = ONNXMetaOp.get_meta(new_model_path, key="character")
print(t)

托管模型到魔搭

该部分主要是涉及模型上传到对应位置,并合理命名。注意上传完成后,需要打 Tag,避免后续 rapidocr whl 包中找不到模型下载路径。

我这里已经上传到了魔搭上,详细链接参见:link

更改 rapidocr 代码适配

该部分主要涉及到更改 default_models.yamlpaddle.py 的代码来适配。

同时,需要添加对应的单元测试,在保证之前单测成功的同时,新的针对性该模型的单测也能通过。

我这里已经做完了,小伙伴们感兴趣可以去看看源码。

发布新版本

因为这次算是功能新增,按照语义化版本号来看,我们版本号需要从 v2.0.7 → v2.1.0。

我只需要在 github 仓库中,打一个 v2.1.0 的 tag,Github Action 会自动跑所有单元测试,自动发版到 pypi。

写在最后

至此,集成工作就基本完成了。

评论