\u200E
如何基于OpenVINO加速飞桨模型推理?一个案例带你吃透 | 部署“桨”坛
发布日期:2021-11-12T11:58:00.000+0000 浏览量:42次

部署"桨"坛栏目聚焦AI硬件部署,分享多款厂商硬件部署方案及教程,帮助开发者们实现模型训练与推理的一体化开发和多硬件设备间的无缝切换。(往期文章链接见文末)




OpenVINO是英特尔基于自身现有的硬件平台开发的一种工具套件,主要用于快速开发高性能计算机视觉及深度学习视觉的应用程序和解决方案,从而实现人类视觉模拟、自动语音识别、自然语言处理和推荐系统任务。该工具套件基于最新一代的人工神经网络,包括卷积神经网络、递归网络和基于注意力的网络,可扩展跨英特尔硬件的计算机视觉和非视觉工作负载,从而最大限度地提高性能。基于OpenVINO,可提升应用程序在CPU计算设备上的推理速度。

在飞桨团队和OpenVINO团队的合作推进下,目前OpenVINO已支持直接导入飞桨模型格式进行模型优化转换和部署;而为了给开发者带去更好的体验,我们也正在开展将OpenVINO作为后端引擎向飞桨原生推理框架Paddle Inference以及轻量化推理引擎Paddle Lite的适配集成工作,待正式发布后用户即可亲自感受飞桨模型在OpenVINO上的无缝部署体验。

官方文档请访问: https://docs.openvino.ai/cn/latest/index.html



概述



本文以钢卷捆带检测项目为例(详细案例介绍请看文末),分享如何基于OpenVINO实现飞桨模型的CPU推理加速,主要包括:

  1. Windows及Linux平台下的OpenVINO源码编译;

  2. 如何产出飞桨模型直接用于在OpenVINO部署;
  3. 如何使用OpenVINO工具完成部署模型优化;
  4. CPU环境下的推理加速测试实验。

基于飞桨及OpenVINO进行项目开发的典型工作流程为:

(1)模型训练部分:


(2)模型转换及应用部分




搭建飞桨开发环境及模型训练



为了兼顾效率和精度,在实际案例中采用了PaddleDetection中的YOLOv3模型。PaddleDetection作为成熟的目标检测开发套件,提供了从数据准备、模型训练、模型评估、模型导出到模型部署的全流程。


受篇幅限制,本文只给出搭建飞桨环境的基本流程,请大家在安装以下项目时,详细参考相关官方文档。另外,本文提供了各项目的版本号,建议大家按照提供版本进行安装。



1.配置飞桨框架

安装CPU或GPU版本的飞桨,本文所安装的版本为paddlepaddle-gpu==2.1.3.post112,python版本为3.6.2。

python -m pip install paddlepaddle-gpu==2.1.3.post112 -f https://www.paddlepaddle.org.cn/whl/windows/mkl/avx/stable.html



2.配置PaddleDetection,本文所安装的版本为2.1.0

2.1安装pycocotools

PaddleDetection依赖pycocotools工具,所以需要提前安装。如果使用的是Windows系统,由于原版cocoapi不支持Windows,pycocotools依赖可能安装失败,可采用第三方实现版本,该版本仅支持Python3,本文所安装的pycocotools版本为2.0。

pipinstallgit+https://github.com/philferriere/cocoapi.git#subdirectory=PythonAPI


如果使用的是Python <= 3.6的版本,安装pycocotools可能会报错:
报错信息:distutils.errors.DistutilsError: Could not find suitable distribution for Requirement.parse('cython>=0.27.3'),
可通过先安装cython,如pip install cython解决该问题。

2.2 安装PaddleDetection

官方文档推荐了以下两种方式进行安装,本文采用了方式一。

方式一:通过pip安装,pip安装方式只支持Python3

# pip安装PaddleDetection
pip install paddledet==2.1.0 -i https://mirror.baidu.com/pypi/simple
# 下载使用源码中的配置文件和代码示例
git clone https://github.com/PaddlePaddle/PaddleDetection.git
cd PaddleDetection


方式二:源码编译安装

# 克隆PaddleDetection仓库
cd <path/to/clone/PaddleDetection>
git clone https://github.com/PaddlePaddle/PaddleDetection.git
# 编译安装PaddleDetection
cd PaddleDetection
python setup.py install
# 安装其他依赖
pip install -r requirements.txt




3.模型训练及导出


Paddle Detection的开发套件很完善,因此模型的训练非常方便,官方教程有非常详细的指引。
模型训练可参考官方提供的教程:

“30分钟快速上手PaddleDetection”

https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.1/docs/tutorials/GETTING_STARTED_cn.md

在进行模型训练时,损失函数、mAP等指标的变化情况也可通过VisualDL可视化工具监测。

在模型训练过程中保存的模型文件是包含前向预测和反向传播的过程,在实际的工业部署则不需要反向传播,因此需要将模型进行导出并转换成部署需要的模型格式。在PaddleDetection中提供了 tools/export_model.py脚本来导出模型。

需要注意的是,导出的预测模型包含了以下文件:

├── inference_model/yolov3
│   ├── infer_cfg.yml
│   ├── model.pdiparams
│   ├── model.pdiparams.info
│   └── model.pdmodel

在后文模型转换阶段,我们需要用的就是这个.pdmodel格式的模型文件。



OpenVINO源码编译




在使用OpenVINO前,首先需要以源码编译的形式安装,下面分别介绍Windows及Linux平台的编译过程。 (推荐大家使用Linux平台,因为我在Windows下进行编译配置,遇到了很多坑。)


1.Windows平台编译


可参考官方文档:
https://github.com/openvinotoolkit/openvino/wiki/BuildingForWindows

1.1软件需求

  • CMake 3.13及以上     # 本文使用的版本为3.20。
  • Microsoft Visual Studio 2019, version 16.8 or later,确保C++ Cmake tool for Windows 已安装。
  • (可选项)Intel Graphics Driver for Windows (26.20)。
  • Python 3.6及以上,确保Python已被添加至环境变量。

1.2编译步骤

1)拉取OpenVINO的source安装包

git clone https://github.com/openvinotoolkit/openvino.git

2)进入OV目录

cd openvino

3)下载所需的sub模块

git submodule update --init --recursive

4)创建 build 文件夹

mkdir build

5)进入build目录

cd build

6)创建cmake文件(如果此步失败,重新执行前请务必把build文件夹里的生成文件清除)注意加粗处需修改。

cmake -CMAKE_USE_WIN32_THREADS_INIT=0N -DNGRAPH_PDPD_FRONTEND_ENABLE=ON -DENABLE_SAMPLES=OFF -DENABLE_CLDNN=OFF -DENABLE_PYTHON=ON -DNGRAPH_PYTHON_BUILD_ENABLE=ON -DNGRAPH_ONNX_IMPORT_ENABLE=ON    -DCMAKE_INSTALL_PREFIX="D:\Openvino\openvino\build\install" -DNGRAPH_UNIT_TEST_ENABLE=ON -DNGRAPH_USE_SYSTEM_PROTOBUF=OFF -DPYTHON_EXECUTABLE="D:\Anaconda3\envs\ov\python.exe" -DPYTHON_LIBRARY="D:\Anaconda3\envs\ov\libs\python36.lib" -DPYTHON_INCLUDE_DIR="D:\Anaconda3\envs\ov\include" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DENABLE_GNA=OFF -DENABLE_CLANG_FORMAT=ON  -DENABLE_TESTS=ON -DENABLE_FUNCTIONAL_TESTS=ON -DENABLE_STRICT_DEPENDENCIES=OFF   -DENABLE_MYRIAD=OFF -DENABLE_FASTER_BUILD=ON  -DDNNL_LIBRARY_TYPE=SHARED  -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=Release ..

其中:

-DPYTHON_EXECUTABLE="C:\Users\abc\AppData\Local\Programs\Python\Python36\python.exe"
-DPYTHON_LIBRARY="C:\Users\abc\AppData\Local\Programs\Python\Python36\libs\python36.lib"
-DPYTHON_INCLUDE_DIR="C:\Users\abc\AppData\Local\Programs\Python\Python36\include"

以上需要根据你的python安装路径进行修改为你的路径。

-DCMAKE_INSTALL_PREFIX="C:\openvino\openvino\build\install"

以上需要修改为你的build的文件夹的位置。

若无报错,且显示如下,说明创建CMake文件成功:
- Configuring done
- Generating done

注意:若以上编译方式一直失败,无法解决问题,可尝试使用只加python相关参数进行编译。

   
     
cmake -DENABLE_PYTHON= ON -DNGRAPH_PYTHON_BUILD_ENABLE= ON -DPYTHON_EXECUTABLE= "D:\Anaconda3\envs\ov\python.exe" -DPYTHON_LIBRARY= "D:\Anaconda3\envs\ov\libs\python36.lib" -DPYTHON_INCLUDE_DIR= "D:\Anaconda3\envs\ov\include"  -G  "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=Release ..

7)编译

cmake --build . --config Release --verbose -j8

j后面的数字需要根据自己电脑CPU核数来修改,本文所用电脑为8核。

如果编译过程中遇到中文字符不可识别的报错问题,定位到源码中的相关行,把报错的中文字符行直接注释掉即可。

编译完成后只要是没有报错(红色error),应该就是成功了。编译过程中会有大量的警告(黄色warning),忽略即可。


8)添加至环境变量

将以下路径添加至系统环境变量中,以便OpenVINO能找到他们:

  • <openvino_repo>/inference-engine/temp/tbb/bin
  • <openvino_repo>/inference-engine/temp/opencv_4.5.0/opencv/bin

9)初始化环境变量

进入到scripts/setupvars路径,在cmd中运行setupvars.bat,显示[setupvars.bat] OpenVINO environment initialized,则表示完成环境变量的初始化。

至此,Windows平台下的编译安装就完成了,可以使用OpenVINO了。



2.Linux平台编译

Linux下编译比较简单,建议直接参考官方文档,配置软件需求及进行编译:
https://github.com/openvinotoolkit/openvino/wiki/BuildingForWindows

1)按照官方文档1-4步骤进行

2)编译

按照指引进行操作,当进行到第5步cmake时,替换成如下的cmake参数(不需要自行修改,可直接运行)。

cmake -DNGRAPH_PDPD_FRONTEND_ENABLE=ON -DENABLE_SAMPLES=OFF -DENABLE_CLDNN=OFF -DENABLE_PYTHON=ON -DNGRAPH_PYTHON_BUILD_ENABLE=ON -DENABLE_MYRIAD=OFF -DNGRAPH_ONNX_IMPORT_ENABLE=ON -DCMAKE_INSTALL_PREFIX=`pwd`/install -DNGRAPH_UNIT_TEST_ENABLE=ON -DNGRAPH_USE_SYSTEM_PROTOBUF=OFF -DPYTHON_EXECUTABLE=$(which python3) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DENABLE_GNA=OFF -DENABLE_CLANG_FORMAT=ON -DENABLE_TESTS=ON -DENABLE_FUNCTIONAL_TESTS=ON -DENABLE_STRICT_DEPENDENCIES=OFF \
-DENABLE_FASTER_BUILD=ON \
-DDNNL_LIBRARY_TYPE=SHARED \


3)初始化环境变量
编译工作全部完成之后,进入到openvino/build/install/bin,运行Source setupvars.sh初始化环境变量。
至此,Linux平台下的编译安装也完成了,可以使用OpenVINO了。



模型转换




在Windows或Linux平台下配置好OpenVINO环境后,转换和测试脚本就可以使用了。下面介绍如何将飞桨的.pdmodel模型转换至OpenVINO的IR格式。


IR格式的模型,包含XML和BIN两个文件。
  • .xml  描述网络拓扑结构
  • .bin  包含模型权重及偏差的二进制数据

1.进入到openvino/model-optimizer路径

2.模型转换

目前OpenVINO对飞桨的支持度较好,无需中间格式转换,可通过mo.py脚本直接将飞桨模型转换成IR格式,需要我们做的就是指定模型类型、模型的输入输出、路径等各项参数,整个过程非常地高效和便捷。示例代码如:

python mo.py --model_name yolov3_mobilenet_v1_270e_coco \
--output_dir <PATH_TO_OUTPUT_DIR> \
--framework=paddle \
--data_type=FP32 \
--reverse_input_channels \
--input_shape=[2,3,608,608],[1,2],[1,2] \
--input=image,im_shape,scale_factor \
--output=save_infer_model/scale_0.tmp_1,save_infer_model/scale_1.tmp_1 \
--input_model= < PATH_TO_MODEL_DIR\model.pdmodel>


参数的含义及设置方法请参考:
https://github.com/openvinotoolkit/openvino/blob/master/docs/MO_DG/prepare_model/convert_model/Converting_Model_General.md

执行模型转换脚本mo.py后,输出如下图所示,表示成功生成IR格式的模型,包含XML和BIN两个文件。




推理加速测试




转换后的模型可以通过OpenVINO提供的C++或Python接口实现推理功能,这里提供了一个简单的示例。

import os, sys, os.path
os.environ['Path'] += r'D:\openvino\bin\intel64\Release\python_api\python3.6;'
import numpy as np
import cv2
from openvino.inference_engine import IENetwork, IECore, ExecutableNetwork

import time
import urllib, shutil, json
import yaml
from yaml.loader import SafeLoader

## 图像处理
def image_preprocess(input_image, size):
    img = cv2.resize(input_image, (size,size))
    img = np.transpose(img, [2,0,1]) / 255
    img = np.expand_dims(img, 0)
    ##NormalizeImage: {mean: [0.485, 0.456, 0.406], std: [0.229, 0.224, 0.225], is_scale: True}
    img_mean = np.array([0.4850.456,0.406]).reshape((3,1,1))
    img_std = np.array([0.2290.2240.225]).reshape((3,1,1))
    img -= img_mean
    img /= img_std
    return img.astype(np.float32)

## 绘制矩形框
def draw_box(img, results, label_text, scale_x, scale_y):
    for i in range(len(results)):
        #print(results[i])
        bbox = results[i, 2:]
        label_id = int(results[i, 0])
        score = results[i, 1]
        if(score>0.20):
            xmin, ymin, xmax, ymax = [int(bbox[0]*scale_x), int(bbox[1]*scale_y), 
                                      int(bbox[2]*scale_x), int(bbox[3]*scale_y)]
            cv2.rectangle(img,(xmin, ymin),(xmax, ymax),(0,255,0),3)
            font = cv2.FONT_HERSHEY_SIMPLEX
            label_text = label_list[label_id];
            cv2.rectangle(img, (xmin, ymin), (xmax, ymax), (0,255,0), 2)
            cv2.putText(img, label_text + ":" + str(score) ,(xmin,ymin+50), font, 1.5,(255,255,255), 2,cv2.LINE_AA)
    return img

device = 'CPU'
ie = IECore() 
yolov3_path = r"C:\Users\uzel\Desktop\openvino_workspace\mo_output\yolov3_mobilenet_v1_091511.xml" #指定模型路径
net = ie.read_network(yolov3_path)

exec_net = ie.load_network(net, "CPU")

label_list = []
pdmodel_config = r"C:\Users\uzel\Desktop\openvino_workspace\mo_output\infer_cfg.yml"
with open(pdmodel_config) as f:
    data = yaml.load(f, Loader=SafeLoader)
label_list = data['label_list']

input_image = cv2.imread(r"C:\Users\uzel\Desktop\openvino_workspace\demo\images\Image__2021-05-14__10-28-55.bmp")
test_image = image_preprocess(input_image, 608)
test_im_shape = np.array([[608608]]).astype('float32')
test_scale_factor = np.array([[12]]).astype('float32')

inputs_dict = {'image': test_image, "im_shape": test_im_shape,
               "scale_factor": test_scale_factor}

start_time = time.time() 
output = exec_net.infer(inputs_dict)
end_time = time.time() 
print("time: %.2f ms"  % (1000 * (end_time-start_time)) )
time = str(np.round(1000 * (end_time-start_time))) + "ms"
cv2.putText(input_image, "cost time :" + time ,(20,50), cv2.FONT_HERSHEY_SIMPLEX, 2,(0,0,0), 2,cv2.LINE_AA)

result_ie = list(output.values())
result_image = draw_box(input_image, result_ie[0], label_list,input_image.shape[1]/608*2, input_image.shape[0]/608*2)

cv2.imwrite("test.png", result_image)


检测结果如下图所示:经过OpenVINO加速,基于YOLOv3模型的钢卷捆带监测方案,在推理速度上约有一倍的提升(优化前每batch为~1000ms,优化后可以提升至~400ms),而精度与原始结果也基本持平。



至此,基于OpenVINO实现飞桨模型的CPU推理加速就全部介绍完了。大家可结合自己具体的业务需求,按照上述步骤完成模型转换,并将模型部署至英特尔CPU计算设备上。



案例介绍



"飞桨 x OpenVINO在智慧精整区域整体解决方案及装备中的落地应用 - 机科发展科技股份有限公司"

钢卷自动化拆捆系统主要用于脱碳、拉伸等产线入口的捆带自动化拆除和回收,它能够解决人工拆捆作业危险、耗时久等问题。拆捆的关键是检测捆带位置,我们制定了基于机器视觉和深度学习的技术路线。

主要面向检测任务的PaddleDetection中集成了非常丰富的模型,使机科发展的研发团队能够快速测试,极大地提高了开发效率;Intel OpenVINO也已经能够使用飞桨模型进行部署并支持几乎所有常用的检测模型,多次测试验证也证明上述场景中使用的YOLO v3模型能够满足业务各项指标要求。

在飞桨与OpenVINO的合作赋能下,视觉系统可在约400ms内实现捆带检测,精度和准确率均满足客户需求。这使得单套运算机器的成本得以节省50%。在竞争白热化的今天,这极大的提升我们的投标竞争力。并且基于一次开发任意部署的便捷开发方式,我们可根据客户需求,灵活调整硬件配置,持续提升性价比。


百度飞桨、英特尔OpenVINO团队强强联手,打造高性能推理模型,优化行业机理模型,开发视觉引导拆捆、缺陷检测等产品,助力新一代人工智能技术在头部标杆企业的有效落地。

如有相关AI硬件部署的技术问题,欢迎加入飞桨硬件部署交流群提问交流:609865659 (QQ群)

部署“桨”坛往期回顾:

在即将到来的深度学习领域的顶级盛会——WAVE SUMMIT+ 2021深度学习开发者峰会上,也将设置【智能核芯 生态共赢】论坛,邀请多款硬件产品技术专家莅临分享AI芯片行业的前沿内容,欢迎大家报名参加, 11月27日,我们上海见!

扫码参加,我们在这里等你~