一文带你学会在三大体系中运用OpenVINO布置飞桨模型

开启生长之旅!这是我参与「日新计划 2 月更文应战」的第 16 天,点击检查活动概况

本文介绍如何在在三大体系(Windows、Linux、MacOS)中运用OpenVINO布置飞桨模型。以10种山公的分类为例,练习出飞桨模型,再运用OpenVINO对飞桨模型进行布置。本文目录结构如下:

  • 模型练习
  • 环境装备
  • 模型验证
  • 模型进阶运用

一、模型练习

模型练习部分为10种山公的分类,数据示例如下图1所示。选用ResNet18作为分类模型。

一文带你学会在三大系统中使用OpenVINO部署飞桨模型

  • 知识点:ResNet残差网络介绍

ResNet(Residual Neural Network)由微软研究院的Kaiming He等人提出,经过运用ResNet Unit成功在ILSVRC2015竞赛中获得冠军,在top5上的错误率为3.57%,一起参数量比VGGNet低,作用非常突出。ResNet的主要思想是在网络中增加了直连通道(恒等映射),即Residual Block,如下图2所示。

一文带你学会在三大系统中使用OpenVINO部署飞桨模型

# 导入所需求的库
from sklearn.utils import shuffle
import os
import pandas as pd
import numpy as np
from PIL import Image
import paddle
import paddle.nn as nn
from paddle.io import Dataset
import paddle.vision.transforms as T
import paddle.nn.functional as F
from paddle.metric import Accuracy
import warnings
warnings.filterwarnings("ignore")
# 读取数据
train_images = pd.read_csv('data/data27098/train.csv')
# labelshuffling
def labelShuffling(dataFrame, groupByName = 'label'):
    groupDataFrame = dataFrame.groupby(by=[groupByName])
    labels = groupDataFrame.size()
    print("length of label is ", len(labels))
    maxNum = max(labels)
    lst = pd.DataFrame()
    for i in range(len(labels)):
        print("Processing label  :", i)
        tmpGroupBy = groupDataFrame.get_group(i)
        createdShuffleLabels = np.random.permutation(np.array(range(maxNum))) % labels[i]
        print("Num of the label is : ", labels[i])
        lst=lst.append(tmpGroupBy.iloc[createdShuffleLabels], ignore_index=True)
        print("Done")
    # lst.to_csv('test1.csv', index=False)
    return lst
# 区分练习集和校验集
all_size = len(train_images)
# print(all_size)
train_size = int(all_size * 0.8)
train_image_list = train_images[:train_size]
val_image_list = train_images[train_size:]
df = labelShuffling(train_image_list)
df = shuffle(df)
train_image_path_list = df['filename'].values
label_list = df['label'].values
label_list = paddle.to_tensor(label_list, dtype='int64')
train_label_list = paddle.nn.functional.one_hot(label_list, num_classes=10)
val_image_path_list = val_image_list['filename'].values
val_label_list = val_image_list['label'].values
val_label_list = paddle.to_tensor(val_label_list, dtype='int64')
val_label_list = paddle.nn.functional.one_hot(val_label_list, num_classes=10)
# 界说数据预处理
data_transforms = T.Compose([
    T.Resize(size=(224, 224)),
    T.RandomHorizontalFlip(224),
    T.RandomVerticalFlip(224),
    T.RandomRotation(30),
    T.Transpose(),    # HWC -> CHW
    T.Normalize(
        mean=[0, 0, 0],        # 归一化
        std=[255, 255, 255],
        to_rgb=True)    
])
# 构建Dataset
class MyDataset(paddle.io.Dataset):
    """
    过程一:承继paddle.io.Dataset类
    """
    def __init__(self, train_img_list, val_img_list,train_label_list,val_label_list, mode='train'):
        """
        过程二:完成结构函数,界说数据读取办法,区分练习和测试数据集
        """
        super(MyDataset, self).__init__()
        self.img = []
        self.label = []
        # 借助pandas读csv的库
        self.train_images = train_img_list
        self.test_images = val_img_list
        self.train_label = train_label_list
        self.test_label = val_label_list
        if mode == 'train':
            # 读train_images的数据
            for img,la in zip(self.train_images, self.train_label):
                self.img.append('data/data27098/train/'+img)
                self.label.append(la)
        else:
            # 读test_images的数据
            for img,la in zip(self.train_images, self.train_label):
                self.img.append('data/data27098/train/'+img)
                self.label.append(la)
    def load_img(self, image_path):
        # 实际运用时运用Pillow相关库进行图片读取即可,这儿咱们对数据先做个模仿
        image = Image.open(image_path).convert('RGB')
        return image
    def __getitem__(self, index):
        """
        过程三:完成__getitem__办法,界说指定index时如何获取数据,并返回单条数据(练习数据,对应的标签)
        """
        image = self.load_img(self.img[index])
        label = self.label[index]
        # label = paddle.to_tensor(label)
        return data_transforms(image), paddle.nn.functional.label_smooth(label)
    def __len__(self):
        """
        过程四:完成__len__办法,返回数据集总数目
        """
        return len(self.img)
#train_loader
train_dataset = MyDataset(train_img_list=train_image_path_list, val_img_list=val_image_path_list, train_label_list=train_label_list, val_label_list=val_label_list, mode='train')
train_loader = paddle.io.DataLoader(train_dataset, places=paddle.CPUPlace(), batch_size=32, shuffle=True, num_workers=0)
#val_loader
val_dataset = MyDataset(train_img_list=train_image_path_list, val_img_list=val_image_path_list, train_label_list=train_label_list, val_label_list=val_label_list, mode='test')
val_loader = paddle.io.DataLoader(train_dataset, places=paddle.CPUPlace(), batch_size=32, shuffle=True, num_workers=0)
from paddle.vision.models import resnet18
# 模型封装
model_res = resnet18(pretrained=False, num_classes=10, with_pool=True)
model = paddle.Model(model_res)
# 界说优化器
# scheduler = paddle.optimizer.lr.LinearWarmup(
#         learning_rate=0.5, warmup_steps=20, start_lr=0, end_lr=0.5, verbose=True)
# optim = paddle.optimizer.SGD(learning_rate=scheduler, parameters=model.parameters())
optim = paddle.optimizer.Adam(learning_rate=3e-4, parameters=model.parameters())
# 装备模型
model.prepare(
    optim,
    paddle.nn.CrossEntropyLoss(soft_label=True),
    Accuracy()
    )
# model.load('work/Res2Net50_vd_26w_4s_pretrained.pdparams',skip_mismatch=True)
# 模型练习与评价
model.fit(train_loader,
        val_loader,
        log_freq=1,
        epochs=2,
        # callbacks=Callbk(write=write, iters=iters),
        verbose=1,
        )
The loss value printed in the log is the current step, and the metric is the average value of previous steps.
Epoch 1/2
step 31/31 [==============================] - loss: 1.9038 - acc: 0.3576 - 1s/step         
Eval begin...
step 31/31 [==============================] - loss: 2.1364 - acc: 0.4273 - 1s/step         
Eval samples: 990
Epoch 2/2
step 31/31 [==============================] - loss: 1.8375 - acc: 0.5172 - 1s/step        
Eval begin...
step 31/31 [==============================] - loss: 1.5180 - acc: 0.5232 - 994ms/step        
Eval samples: 990
# 保存模型参数
# model.save('Hapi_MyCNN')  # save for training
model.save('Hapi_MyCNN1', False)  # save for inference

二、环境装备(OpenVINO的装置)

OpenVINO简介

OpenVINO™ 东西套件是用于快速开发使用程序和解决方案,以解决各种使命(包含人类视觉模仿、自动语音识别、自然语言处理和推荐体系等)的归纳东西套件。该东西套件根据最新一代的人工神经网络,包含卷积神经网络 (CNN)、递归网络和根据留意力的网络,可扩展跨英特尔 硬件的计算机视觉和非视觉工作负载,然后最大极限地提高性能。它经过从边缘到云布置的高性能、人工智能和深度学习推理来为使用程序加快。

在最新的OpenVINO2022的版别中,将直接支撑将Paddle的模型读取,不再需求将模型转化为ONNX格局,再转化为IR格局,经过与英特尔工程师的对接,直接读取Paddle模型关于推理时刻与IR格局无任何不同。下面将为我们讲解如何在Ubuntu18.04中装置OpenVINO并跑通Paddle模型的Demo。

官方装置文档

  • Windows10下装置OpenVINO

在Windows10下的装置,需求有如下依靠:

  • Microsoft Visual Studio* 2019 with MSBuild
  • CMake 3.14 or higher 64-bit
  • Python 3.6 – 3.8 64-bit

本教程默认依靠现已装备好。首要下载OpenVINO exe装置文件,按照官方文档中的过程操作即可,需求留意的是,在运用的时候需求激活OpenVINO环境,因为每个人的环境不一样,这儿选用了动态激活的办法,即在命令行模式下运转openvino_2021\bin\setupvars.bat命令激活环境,激活环境后即可。

  • Linux&IOS下装置OpenVINO

在这两个体系中,本文选用源码编译的办法进行装置。

首要下载OpenVINO源代码,

git clone https://github.com/openvinotoolkit/openvino.git
cd openvino
git submodule update --init --recursive
  • For Linux
chmod +x install_build_dependencies.sh
./install_build_dependencies.sh
pip install -r inference-engine/ie_bridges/python/src/requirements-dev.txt
  • For Mac
#install Python Dependencies
pip install -r inference-engine/ie_bridges/python/src/requirements-dev.txt
Compile the source code with Python option enabled.
  • 编译装置
OPENVINO_BASEDIR = `pwd`
mkdir build
cd build
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="${OPENVINO_BASEDIR}/openvino_dist" \
-DPYTHON_EXECUTABLE=$(which python3) \
-DENABLE_MYRIAD=OFF \
-DENABLE_VPU=OFF \
-DENABLE_PYTHON=ON \
-DNGRAPH_PYTHON_BUILD_ENABLE=ON \
..

make -j$(nproc); make install

  • 留意:需求更改为自己的途径,nproc许多指定几个线程,编译装置更快,Cmake版别要对应

三、模型验证(无需转ONNX)

本部分运用OpenVINO读取paddle模型,并对其进行验证。在最新的OpenVINO2022的版别中,将直接支撑将Paddle的模型读取,不再需求将模型转化为ONNX格局,再转化为IR格局,经过与英特尔工程师的对接,直接读取Paddle模型关于推理时刻与IR格局无任何不同,仅仅在初始化的时候会有一些微小差异。

import os
import sys
import numpy as np
import json
import cv2
from openvino.inference_engine import IENetwork, IECore, ExecutableNetwork
from IPython.display import Image
def image_preprocess_mobilenetv3(img_path):
    img = cv2.imread(img_path)
    img = cv2.resize(img, (224,224))
    img = np.transpose(img, [2,0,1]) / 255
    img = np.expand_dims(img, 0)
    img_mean = np.array([0.485, 0.456,0.406]).reshape((3,1,1))
    img_std = np.array([0.229, 0.224, 0.225]).reshape((3,1,1))
    img -= img_mean
    img /= img_std
    return img.astype(np.float32)
# 输出猜测结果
def top_k(result, topk=5):
    result_detec = np.argmax(result[0])
    print(result_detec)
ie = IECore()
net = ie.read_network(r"E:\openvino-paddlepaddle-demo-main\openvino-paddlepaddle-demo-main\model\Hapi_MyCNN1.pdmodel")
# net = ie.read_network(r"E:\openvino-paddlepaddle-demo-main\openvino-paddlepaddle-demo-main\model\test.onnx")
# net = ie.read_network(r"E:\openvino-paddlepaddle-demo-main\openvino-paddlepaddle-demo-main\model\test.xml")
filename = "monkey.jpg"
test_image = image_preprocess_mobilenetv3(filename)
# pdmodel might be dynamic shape, this will reshape based on the input
input_key = list(net.input_info.items())[0][0] # 'inputs'
net.reshape({input_key: test_image.shape})
#load the network on CPU
exec_net = ie.load_network(net, 'CPU')
assert isinstance(exec_net, ExecutableNetwork)
#perform the inference step
output = exec_net.infer({input_key: test_image})
result_ie = list(output.values())
#filter and print the top 5 results
top_k(result_ie)
Image(filename=filename)

四、模型进阶运用(模型转化)

此部分为进阶运用部分,我们能够根据自己的实际情况进行挑选。

  • 知识点:ONNX格局介绍

Open Neural Network Exchange(ONNX,敞开神经网络交流)格局,是一个用于表明深度学习模型的标准,可使模型在不同结构之间进行转移。

也能够对ONNX的模型进行读取:


net = ie.read_network(r"E:\openvino-paddlepaddle-demo-main\openvino-paddlepaddle-demo-main\model\test.onnx")
# paddle2onnx
import os, time
import matplotlib.pyplot as plt
import paddle
from PIL import Image
import numpy as np
import pandas as pd
model_file_path="Hapi_MyCNN1"
model = paddle.jit.load(model_file_path)
paddle.onnx.export(model, 'work')

ONNX2IR

To convert an ONNX* model:

进入 <INSTALL_DIR>/deployment_tools/model_optimizer 文件夹内

运用 mo.py script 对模型进行转化。

python3 mo.py --input_model <INPUT_MODEL>.onnx --output_dir <OUTPUT_MODEL_DIR>

转化之后模型能够经过如下办法读取。

net = ie.read_network(r"E:\openvino-paddlepaddle-demo-main\openvino-paddlepaddle-demo-main\model\test.xml")

留意,途径需求改为自己的模型途径。

总结

本文主要为我们带来了运用OpenVINO布置飞桨模型的一些简略用法。在实际使用中,当模型练习完毕后,上线布置时,就会遇到各种问题,比如,模型性能是否满意线上要求,模型如何嵌入到原有工程体系,推理线程的并发路数是否满意,这些问题决定着投入产出比。只有深入且精确的了解深度学习结构,才干更好的完成这些使命,满意上线要求。实OpenVINO是一个Pipeline东西集,一起能够兼容各种开源结构练习好的模型,具有算法模型上线布置的各种才能,只要把握了该东西,你能够轻松的将预练习模型在Intel的CPU上快速布置起来。此外,在最新的OpenVINO2022的版别中,将直接支撑将Paddle的模型读取,不再需求将模型转化为ONNX格局,再转化为IR格局,经过与英特尔工程师的对接,直接读取Paddle模型关于推理时刻与IR格局无任何不同。

参考资料:

github.com/raymondlo84…