英特尔openVINO|【OpenVINO+paddle】OpenVINO核心部署代码讲解-步步打印结果

这个问题是我遇到很多小伙伴问的,这个推理的API难度不大,主要涉及四个步骤:加载模型和硬件、检测输入输出、输入重塑以及执行推理。大致可以参考下面这张图片:英特尔openVINO|【OpenVINO+paddle】OpenVINO核心部署代码讲解-步步打印结果
文章图片

1.用Core()初始化推理引擎

from openvino.runtime import Core ie = Core()

推理引擎可以在设备上加载网络。这里的设备指的是CPU、英特尔GPU、神经计算棒2等。available_devices属性显示系统上可用的设备。get_property()的“FULL_DEVICE_NAME”选项显示了设备的名称。
我的设备上使用的是CPU设备。如果使用集成GPU就改成device_name=“GPU”。注意,在GPU上加载网络会比在CPU上加载慢,但推断可能会更快。
devices = ie.available_devicesfor device in devices: device_name = ie.get_property(device_name=device, name="FULL_DEVICE_NAME") print(f"{device}: {device_name}")

英特尔openVINO|【OpenVINO+paddle】OpenVINO核心部署代码讲解-步步打印结果
文章图片

2.加载模型
在初始化推理引擎之后,首先用read_model()读取模型文件,然后用compile_model()将其编译到指定的设备。
IR模型
一个IR (Intermediate Representation)模型由一个xml文件和一个bin文件组成,其中包含关于网络拓扑的信息,而bin文件则包含权重和偏差二进制数据。read_model()默认是指(bin)weights文件与xml文件位于相同的目录中,文件名相同,扩展名为.bin,那不需要制定,否则就需要指定。
from openvino.runtime import Coreie = Core() classification_model_xml = "model/classification.xml"model = ie.read_model(model=classification_model_xml) compiled_model = ie.compile_model(model=model, device_name="CPU")

ONNX模型
ONNX模型是一个单一的文件。读取和加载ONNX模型的工作方式与读取和加载IR模型的方式相同。model参数指向ONNX文件名。
from openvino.runtime import Coreie = Core() onnx_model_path = "model/segmentation.onnx" model_onnx = ie.read_model(model=onnx_model_path) compiled_model_onnx = ie.compile_model(model=model_onnx, device_name="CPU")

为了用默认设置将ONNX模型导出到IR,也可以使用.serialize()方法。
from openvino.offline_transformations import serializeserialize(model=model_onnx, model_path="model/exported_onnx_model.xml", weights_path="model/exported_onnx_model.bin")

2.检测输入输出和图片
OpenVINO IENetwork实例存储关于模型的信息。关于模型的输入和输出的信息都在模型中。输入和model.outputs。因为现在是支持静态输入,第二个是为了使输入的图形符合输入层,所以需要检测输入输出层。
from openvino.runtime import Coreie = Core() classification_model_xml = "model/classification.xml" model = ie.read_model(model=classification_model_xml) model.inputs[0].any_name

【英特尔openVINO|【OpenVINO+paddle】OpenVINO核心部署代码讲解-步步打印结果】上面的单元格显示所加载的模型需要一个输入,这个输入带有名称输入。如果您加载了一个不同的模型,您可能会看到一个不同的输入层名称,并且您可能会看到更多的输入。
提供对第一输入层名称的引用通常是有用的。对于只有一个输入的模型,使用next(iter(model.inputs))会得到这个名称。
input_layer = next(iter(model.inputs)) input_layer

这个输入层的信息存储在输入中。下一个单元打印输入的布局、精度和形状。
print(f"input precision: {input_layer.element_type}") print(f"input shape: {input_layer.shape}")

注意一下图片中我修改了一下名字,流程是一样的
英特尔openVINO|【OpenVINO+paddle】OpenVINO核心部署代码讲解-步步打印结果
文章图片

这个单元格输出告诉我们,模型期望输入的形状为[1,3,224,224],并且这是在NCHW布局中。这意味着模型期望输入的数据批量大小(N)为1,3个通道?,图像高度(H)和宽度(W)为224。输入数据期望达到FP32(浮点)精度。
模型输入
from openvino.runtime import Coreie = Core() classification_model_xml = "model/classification.xml" model = ie.read_model(model=classification_model_xml) model.outputs[0].any_name

模型输出信息存储在Model .outputs中。上面的单元格显示模型返回一个输出,其名称为MobilenetV3/Predictions/Softmax。如果您加载了一个不同的模型,您可能会看到一个不同的输出层名称,并且您可能会看到更多的输出。
因为这个模型只有一个输出,所以遵循与输入层相同的方法来获得它的名称。
output_layer = next(iter(model.outputs)) output_layer

获取输出精度和形状与获取输入精度和形状类似。
print(f"output precision: {output_layer.element_type}") print(f"output shape: {output_layer.shape}")

英特尔openVINO|【OpenVINO+paddle】OpenVINO核心部署代码讲解-步步打印结果
文章图片

这个单元格输出显示模型返回的输出形状为[1,1001],其中1是批大小(N), 1001是类的数量?。输出作为32位浮点数返回。
3.输入重塑
这里我们把前面的步骤连贯起来执行一次,得到图形的输入输出
from openvino.runtime import Coreie = Core() classification_model_xml = "model/classification.xml" model = ie.read_model(model=classification_model_xml) compiled_model = ie.compile_model(model=model, device_name="CPU") input_layer = next(iter(compiled_model.inputs)) output_layer = next(iter(compiled_model.outputs))

准备工作:加载图像并转换为输入形状
要在网络中传播图像,需要将其加载到一个数组中,调整其大小以满足网络的要求,并将其转换为网络的输入布局。
import cv2image_filename = "data/coco_hollywood.jpg" image = cv2.imread(image_filename) image.shape

该图像的形状为(663,994,3)。它高663像素,宽994像素,有3个颜色通道。我们得到了网络期望的高度和宽度的参考,并将图像的大小调整为该大小。
# N,C,H,W = batch size, number of channels, height, width N, C, H, W = input_layer.shape # OpenCV resize expects the destination size as (width, height) qresized_image = cv2.resize(src=https://www.it610.com/article/image, dsize=(W, H)) resized_image.shape

现在图像的格式是H,W,C格式。我们首先调用np.transpose()将其更改为N,C,H,W格式(其中N=1),然后通过调用np. expand_dimms()将N维相加。使用np.astype()将数据转换为FP32。
import numpy as npinput_data = https://www.it610.com/article/np.expand_dims(np.transpose(resized_image, (2, 0, 1)), 0).astype(np.float32) input_data.shape

英特尔openVINO|【OpenVINO+paddle】OpenVINO核心部署代码讲解-步步打印结果
文章图片

执行推理
既然输入数据的形状正确,那么就进行推断。
result = compiled_model([input_data])[output_layer]

request = compiled_model.create_infer_request() request.infer(inputs={input_layer.any_name: input_data}) result = request.get_output_tensor(output_layer.index).data

这个网络可以返回一个输出,所以我们将对输出层的引用存储在output_layer中。Index参数时,我们可以使用request. get_output_张量(output_layer.index)获取数据。要从输出中获得numpy数组,我们需要加后缀.data。
result.shape

输出的形状是(1,1001),我们看到的是预期的输出形状。这个输出形状表明网络返回1001个类的概率是1.
英特尔openVINO|【OpenVINO+paddle】OpenVINO核心部署代码讲解-步步打印结果
文章图片

以上就是全部推理代码的全流程了。

    推荐阅读