使用 OpenVINO™ 实现飞桨版 PGNet 推理程序 | 开发者实战
【慧聪教育网】OpenVINO™ 工具套件2022.1版于2022年3月22日正式发布,根据官宣OpenVINO™ 迎来迄今为止最重大更新,2022.1新特性抢先看!,OpenVINO™ 2022.1将是迄今为止最大变化的版本,并可以直接支持读取飞桨模型。
PGNet 简介
任意形状文本的识别(例如,弯曲文本)受到越来越多的研究关注,而应用也愈发广泛(例如,广告牌识别、印章识别等),如下图所示。
AAAI 2021会议上发表的百度自研的端到端场景文本识别 PGNet1 算法,有效的满足了上述需求,其典型特点有:
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
准备 PGNet 的 OpenVINO™ 推理程序开发环境
要完成 PGNet 的 OpenVINO™ 推理程序开发,需要安装:
PaddleOCR 运行环境,参考:
安装 PaddleOCR 运行环境
克隆 PaddleOCR 到本地,并安装第三方库
OpenVINO™ 开发套件:
pip install openvino-dev[onnx]
下载 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参数为Falsepython3 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。
用 OpenVINO™ 读取 PGNet 预训练模型
如前所述,OpenVINO™ 支持直接读入飞桨模型。使用下面的代码,可以快速测试 OpenVINO™ 读入 PGNet 模型的效果。
from openvino.runtime import Core
# 指定PGNet模型路径pgnet_path = ".\e2e_server_pgnetA_infer\inference.pdmodel"
# 创建Core对象core = Core()# 载入并编译PGNet模型sess = core.compile_model(model=pgnet_path, device_name="CPU")# 输出PGNet模型输入&输出信息print(sess.input)
运行效果如下图所示,说明 OpenVINO™ 直接读取飞桨版 PGNet 模型成功。
使用 OpenVINO™ 开发 PGNet 的推理程序
基于上述代码,结合 PGNet 的数据前处理和后处理代码,即可开发出完整的 PGNet 推理程序。
01
升级 PaddleOCR 自带预测程序,
支持 OpenVINO™ 推理
由于 PaddleOCR 自带的预测程序:
tools\infer\predict_e2e.py
已经实现了 PGNet 的数据前处理和后处理代码,所以,只需要稍微修改:
tools\infer\predict_e2e.py
tools\infer\utility.py
添加 OpenVINO™ 的推理代码,即可升级 PaddleOCR 对 OpenVINO™ 的支持。上述代码,可以在下方链接下载。下载后,请并替换同名文件。
https://gitee.com/ppov-nuc/pgnet-openvino-inference
OpenVINO™ 支持代码如下所示,所有修改处都添加了“# OpenVINO™ Support Here”:
# OpenVINO Support Here elif self.use_openvino: outputs = self.predictor([img]) out_layers = self.predictor.output preds = {} preds['f_border'] = outputs[out_layers(0)] preds['f_char'] = outputs[out_layers(1)] preds['f_direction'] = outputs[out_layers(2)] 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 上的推理计算效率。
02
借鉴 PaddleOCR 的前处理和后处理代码,
实现 OpenVINO™ 推理程序
直接使用 ppocr 中自带的前处理和后处理代码,可以轻松实现 PGNet 的OpenVINO™ 推理程序:
https://gitee.com/ppov-nuc/pgnet-openvino-inference/blob/master/pgnet_ov_infer.py
from openvino.runtime import Corefrom ppocr.data import create_operators, transformfrom ppocr.postprocess import build_post_processimport cv2import numpy as npimport time
# 指定PGNet模型路径pgnet_path = "./e2e_server_pgnetA_infer/inference.pdmodel"
# 创建Core对象core = Core()# 载入并编译PGNet模型pgnet = core.compile_model(model=pgnet_path, device_name="CPU")
# 创建preprocess_oppre_process_list = [{ 'E2EResizeForTest': { 'max_side_len': 768, 'valid_set': 'totaltext'} }, { 'NormalizeImage': { 'std': [0.229, 0.224, 0.225], 'mean': [0.485, 0.456, 0.406], 'scale': '1./255.', 'order': 'hwc' } }, { 'ToCHWImage': None }, { 'KeepKeys': { 'keep_keys': ['image', 'shape'] } }]preprocess_op = create_operators(pre_process_list)
# 创建postprocess_oppostprocess_params = {}postprocess_params['name'] = 'PGPostProcess'postprocess_params["score_thresh"] = 0.5postprocess_params["character_dict_path"] = "./ic15_dict.txt"postprocess_params["valid_set"] = 'totaltext'postprocess_params["mode"] = 'fast'postprocess_op = build_post_process(postprocess_params)
def clip_det_res(points, img_height, img_width): for pno in range(points.shape[0]): points[pno, 0] = int(min(max(points[pno, 0], 0), img_width - 1)) points[pno, 1] = int(min(max(points[pno, 1], 0), img_height - 1)) return points# 定义filter_tag_det_res_only_clip函数def filter_tag_det_res_only_clip(dt_boxes, image_shape): img_height, img_width = image_shape[0:2] dt_boxes_new = [] for box in dt_boxes: box = clip_det_res(box, img_height, img_width) dt_boxes_new.append(box) dt_boxes = np.array(dt_boxes_new) return dt_boxes
# 载入图像数据并实现预处理image_path = 'img623.jpg'image = cv2.imread(image_path)data = {'image': image}data = transform(data, preprocess_op)img, shape_list = datAImg = np.expand_dims(img, axis=0)shape_list = np.expand_dims(shape_list, axis=0)starttime = time.time()
# Do the inference by OpenVINOoutputs = pgnet([img])out_layers = pgnet.outputpreds = {}preds['f_border'] = outputs[out_layers(0)]preds['f_char'] = outputs[out_layers(1)]preds['f_direction'] = outputs[out_layers(2)]preds['f_score'] = outputs[out_layers(3)]
post_result = postprocess_op(preds, shape_list)points, strs = post_result['points'], post_result['texts']dt_boxes = filter_tag_det_res_only_clip(points, image.shape)elapse = time.time() - starttimeprint(f"Predict time: {elapse}s")import utilitysrc_im = utility.draw_e2e_res(points, strs, image_path)cv2.imshow("PGNet infer by OpenVINO", src_im)cv2.wAItKey(0)cv2.destroyAllWindows()
运行结果,如下图所示:
总结
飞桨版的 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 上,运行的时间会不一样。