• 使用OpenVINO实现飞桨版PGNet推理程序


    作者:杨雪峰 英特尔物联网行业创新大使

    1.1 OpenVINOTM 简介

       OpenVINO™ 工具包2022.1版于2022年3月22日正式发布,根据官宣《OpenVINO™ 迎来迄今为止最重大更新,2022.1新特性抢先看》,OpenVINO™ 2022.1将是迄今为止最大变化的版本,并可以直接支持读取飞桨模型。

    1.2 PGNet简介

            任意形状文本的识别(例如,弯曲文本)受到越来越多的研究关注,而应用也愈发广泛(例如,广告牌识别、印章识别等),如下图所示。

            AAAI 2021会议上发表的百度自研的端到端场景文本识别PGNet[1]算法,有效的满足了上述需求,其典型特点有:

    • PGNet是一种新颖的、端到端的、的任意形状的文本检测识别器框架
    • 不需要字符级别的标注,NMS操作以及ROI操作[2]
    • 提出预测文本行内的阅读顺序模块和基于图的修正模块来提升文本识别效果
    • 识别精度和运行速度堪称SOTA

    *上图引用自PNGet论文[1]

            另外,飞桨版PGNet的工程化和文档化做的极好,没有任何基础的人,都可以在不到半天的时间内完成PGNet的开发环境搭建、模型训练、ONNX模型导出。

    PGNet的文档链接:https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/algorithm_e2e_pgnet.md

    1.3 准备PGNet的OpenVINO推理程序开发环境

            要完成PGNet的OpenVINO推理程序开发,需要安装:

    pip install openvino-dev[onnx]

    1.4 下载PGNet预训练模型

            PaddleOCR已提供PGNet预训练模型,请自行下载并解压,如下图所示。

    PGNet预训练模型下载链接:https://paddleocr.bj.bcebos.com/dygraph_v2.0/pgnet/e2e_server_pgnetA_infer.tar
    下载完毕后,运行PaddleOCR自带的预测程序 tools\infer\predict_e2e.py

    # 如果想使用CPU进行预测,需设置use_gpu参数为False

    python3 tools/infer/predict_e2e.py --e2e_algorithm="PGNet" --image_dir="./doc/imgs_en/img623.jpg" --e2e_model_dir="./inference/e2e_server_pgnetA_infer/" --e2e_pgnet_valid_set="totaltext" --use_gpu=False

    运行结果,如下图所示,说明PaddleOCR和PGNet预训练模型都准备好了。

    从图中可见,运行的平均时间是5.09s。

    1.5 用OpenVINOTM读取PGNet预训练模型

            如前所述,OpenVINOTM支持直接读入飞桨模型。使用下面的代码,可以快速测试OpenVINOTM读入PGNet模型的效果。

    1. from openvino.runtime import Core
    2. # 指定PGNet模型路径
    3. pgnet_path = ".\e2e_server_pgnetA_infer\inference.pdmodel"
    4. # 创建Core对象
    5. core = Core()
    6. # 载入并编译PGNet模型
    7. sess = core.compile_model(model=pgnet_path, device_name="CPU")
    8. # 输出PGNet模型输入&输出信息
    9. print(sess.input)

    运行效果如下图所示,说明OpenVINOTM直接读取飞桨版PGNet模型成功。

    1.6 使用OpenVINOTM开发PGNet的推理程序

            基于上述代码,结合PGNet的数据前处理和后处理代码,即可开发出完整的PGNet推理程序。

     1.6.1 升级PaddleOCR自带预测程序,支持OpenVINO推理

            由于PaddleOCR自带的预测程序 tools\infer\predict_e2e.py,已经实现了PGNet的数据前处理和后处理代码,所以,只需要稍微修改:

    • tools\infer\predict_e2e.py
    • tools\infer\utility.py

            添加OpenVINO的推理代码,即可升级PaddleOCR对OpenVINO的支持。

          上述代码,可以从PGNet OpenVINO Inference: Do the PGNet inference based on OpenVINO 下载。下载后,请并替换同名文件。

            OpenVINO支持代码如下所示,所有修改处都添加了“# OpenVINO Support Here”:

    1. # OpenVINO Support Here
    2. elif self.use_openvino:
    3. outputs = self.predictor([img])
    4. out_layers = self.predictor.output
    5. preds = {}
    6. preds['f_border'] = outputs[out_layers(0)]
    7. preds['f_char'] = outputs[out_layers(1)]
    8. preds['f_direction'] = outputs[out_layers(2)]
    9. preds['f_score'] = outputs[out_layers(3)]

    替换完同名文件后,使用命令:

    python tools\infer\predict_e2e.py --e2e_algorithm="PGNet"

    --image_dir=.\doc\imgs_en

    --e2e_model_dir=ov_infer\e2e_server_pgnetA_infer\inference.pdmodel

    --e2e_pgnet_valid_set="totaltext"

    --use_gpu=False

    --use_openvino=True

    运行效果如下所示:

            从运行结果可以看到,使用了OpenVINO的推理程序,运行的平均时间是1.33s;没有使用OpenVINO的推理程序,运行的平均时间是5.09s。OpenVINO极大的提升了模型在CPU上的推理计算效率

     1.6.2 借鉴PaddleOCR的前处理和后处理代码,实现OpenVINO推理程序

            直接使用ppocr中自带的前处理和后处理代码,可以轻松实现PGNet的OpenVINO推理程序:pgnet_ov_infer.py · PPOV_NUC/PGNet OpenVINO Inference - Gitee.com

    1. from openvino.runtime import Core
    2. from ppocr.data import create_operators, transform
    3. from ppocr.postprocess import build_post_process
    4. import cv2
    5. import numpy as np
    6. import time
    7. # 指定PGNet模型路径
    8. pgnet_path = "./e2e_server_pgnetA_infer/inference.pdmodel"
    9. # 创建Core对象
    10. core = Core()
    11. # 载入并编译PGNet模型
    12. pgnet = core.compile_model(model=pgnet_path, device_name="CPU")
    13. # 创建preprocess_op
    14. pre_process_list = [{
    15. 'E2EResizeForTest': {
    16. 'max_side_len': 768,
    17. 'valid_set': 'totaltext'}
    18. }, {
    19. 'NormalizeImage': {
    20. 'std': [0.229, 0.224, 0.225],
    21. 'mean': [0.485, 0.456, 0.406],
    22. 'scale': '1./255.',
    23. 'order': 'hwc'
    24. }
    25. }, {
    26. 'ToCHWImage': None
    27. }, {
    28. 'KeepKeys': {
    29. 'keep_keys': ['image', 'shape']
    30. }
    31. }]
    32. preprocess_op = create_operators(pre_process_list)
    33. # 创建postprocess_op
    34. postprocess_params = {}
    35. postprocess_params['name'] = 'PGPostProcess'
    36. postprocess_params["score_thresh"] = 0.5
    37. postprocess_params["character_dict_path"] = "./ic15_dict.txt"
    38. postprocess_params["valid_set"] = 'totaltext'
    39. postprocess_params["mode"] = 'fast'
    40. postprocess_op = build_post_process(postprocess_params)
    41. def clip_det_res(points, img_height, img_width):
    42. for pno in range(points.shape[0]):
    43. points[pno, 0] = int(min(max(points[pno, 0], 0), img_width - 1))
    44. points[pno, 1] = int(min(max(points[pno, 1], 0), img_height - 1))
    45. return points
    46. # 定义filter_tag_det_res_only_clip函数
    47. def filter_tag_det_res_only_clip(dt_boxes, image_shape):
    48. img_height, img_width = image_shape[0:2]
    49. dt_boxes_new = []
    50. for box in dt_boxes:
    51. box = clip_det_res(box, img_height, img_width)
    52. dt_boxes_new.append(box)
    53. dt_boxes = np.array(dt_boxes_new)
    54. return dt_boxes
    55. # 载入图像数据并实现预处理
    56. image_path = 'img623.jpg'
    57. image = cv2.imread(image_path)
    58. data = {'image': image}
    59. data = transform(data, preprocess_op)
    60. img, shape_list = data
    61. img = np.expand_dims(img, axis=0)
    62. shape_list = np.expand_dims(shape_list, axis=0)
    63. starttime = time.time()
    64. # Do the inference by OpenVINO
    65. outputs = pgnet([img])
    66. out_layers = pgnet.output
    67. preds = {}
    68. preds['f_border'] = outputs[out_layers(0)]
    69. preds['f_char'] = outputs[out_layers(1)]
    70. preds['f_direction'] = outputs[out_layers(2)]
    71. preds['f_score'] = outputs[out_layers(3)]
    72. post_result = postprocess_op(preds, shape_list)
    73. points, strs = post_result['points'], post_result['texts']
    74. dt_boxes = filter_tag_det_res_only_clip(points, image.shape)
    75. elapse = time.time() - starttime
    76. print(f"Predict time: {elapse}s")
    77. import utility
    78. src_im = utility.draw_e2e_res(points, strs, image_path)
    79. cv2.imshow("PGNet infer by OpenVINO", src_im)
    80. cv2.waitKey(0)
    81. cv2.destroyAllWindows()

    运行结果,如下图所示:

    1.7 总结:

            飞桨版的PGNet是一个易学易用、文档化和工程化做的非常好的[3]、端到端的、可以检测弯曲文字的模型。

            由于从OpenVINO™ 2022.1版本开始,OpenVINO™ Runtime已经支持了直接读取飞桨模型,且OpenVINO™的API简单易用,所以,可以很容易的升级PaddleOCR自带的预测程序 tools\infer\predict_e2e.py支持OpenVINO™推理计算,或者从零开发OpenVINO™推理程序。

            经过OpenVINO™优化后,PGNet的CPU推理计算效率大大提升,平均运行时间从5.09s,提升到1.33s,效率提升非常明显。

            注意:运行时间,仅供参考,在不同CPU上,运行的时间会不一样。

    参考资料

    [1] PGNet: Real-time Arbitrarily-Shaped Text Spotting with Point Gathering Network, https://www.aaai.org/AAAI21Papers/AAAI-2885.WangP.pdf

    [2]PaddleOCR FAQ: https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/FAQ.md#13

    [3] PGNet repo: https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/algorithm_e2e_pgnet.md

  • 相关阅读:
    Prompt进阶系列1:LangGPT(从编程语言反思LLM的结构化可复用提示设计框架)
    C语言内功修炼【整型在内存中的存储】
    Vue的computed和watch的区别是什么?
    stm32、IO口、中断、串口、定时器讲解
    【Overleaf】解决LaTeX Error: Something‘s wrong--perhaps a missing \item.
    阿里云OSS简单应用
    手把手教你用 Jenkins 自动部署 SpringBoot
    分布式数据库Apache Doris HA集群部署
    流量背后的生意经,“达人营销”能否带来捷径?
    【MySQL进阶】SQL性能分析
  • 原文地址:https://blog.csdn.net/gc5r8w07u/article/details/126387999