OpenVINO分为转换与部署两个部分,如下图所示
在转换步中,需要将输入模型序列化后传入OpenVINO的
MO
Model Optimizer工具对模型进行优化,以得到
IR
Intermediate Representation中间表示,详细的内部行为可以参考
Model Optimizer Developer Guide
。接着,在部署步中,我们使用OpenVINO提供的Python或者CPP的api,进行编程以达到我们想要的结果:1) 载入ir文件, 2) 建立
ie
Inference Engine推理引擎, 3) 生成执行对象ExecutableNetwork, 载入不同的plugin,以支持特定的硬件(CPU、GPU等等),详细行为可参考
Inference Engine Developer Guide
。
对于转换步,针对"输入模型序列化"我就产生了疑问,OpenVINO所使用的序列化后进行ir转换的模型,它是一个类似静态图的东西,序列化后我再转换,那岂不就是我只能支持输入静态分辨率了?要使用OpenVINO化的模型进行推理,任意输入就得按照序列化时的分辨率来推理,岂不是很僵硬。难道,OpenVINO的推理,就得先插值,再推理,最后再插值回原分辨率?
这里就直接给结论了,OpenVINO是支持动态输入的,并且在它的手册里,也有相应的段落
Using Shape Inference
,乍看起来很简单,但实则暗藏坑点,这里我也直接给出坑点来,CPP api是无法全面支持OpenVINO reshape操作的:
-
Python api
全面支持reshape操作,不会出错
-
CPP api
某些简单网络支持,我推测还是scale的精度问题,参考我之前的日志
PyTorch转ONNX之F.interpolate
,从4到9,python搞得定,cpp估计就搞不定了,例如就会报如下的错,也是网络内部的upsample的问题,所以可以在2) 建立ie引擎的时候,加入resize层,也就是在ir外部添加一个处理,而不是reshape整个ir
那么,下面就是两部分的详细说明
由于Python不像CPP,在精度和内存分配上,我们都不需要担心,所以完全可以使用OpenVINO自带的reshape操作,将整个ir调整到适合的输入分辨率。
这里需要注意两点,一是在使用mo工具进行ir转换的时候,需要使用
--keep_shape_ops
,二是在部署的时候,需要在"3) 生成ExecutableNetwork对象"前使用reshape。
--keep_shape_ops
[ Experimental feature ] Enables `Shape` operation
with all children keeping. This feature makes model
reshapable in Inference Engine
详细地,可以参考When to Specify --keep_shape_ops Command Line Parameter,mo工具会保留内部的分辨率变化的图结构,实话说这部分保留了什么样的图结构,我不清楚,我猜是像onnx那样的scale值,onnx是通过scale值来计算输入与输出的分辨率大小,有可能,--keep_shape_ops
取消了原本scale的const类型?
这里我给一个示例代码,这里也是修改自OpenVINO提供的deployment_tools/inference_engine/samples/python
里面的,我把注释和提示信息打印了出来,方便大家理解。
model_xml = 'your_model.xml'
model_bin = 'your_model.bin'
print("Creating Inference Engine...")
ie = IECore()
print("Loading network files:\n\t{}\n\t{}".format(model_xml, model_bin))
net = ie.read_network(model=model_xml, weights=model_bin)
supported_layers = ie.query_network(net, "CPU")
not_supported_layers = [l for l in net.layers.keys() if l not in supported_layers]
if len(not_supported_layers) != 0:
print("Following layers are not supported by the plugin for specified device {}:\n {}".
format('CPU', ', '.join(not_supported_layers)))
print("Please try to specify cpu extensions library path in sample's command line parameters using -l "
"or --cpu_extension command line argument")
sys.exit(1)
assert len(net.inputs.keys()) == 1, "Sample supports only 1 input topologies -> {}".format(len(net.inputs.keys()))
required_input_keys = {'input'}
assert required_input_keys == set(net.inputs.keys()), \
'Demo supports only topologies with the following input keys: {}'.format(', '.join(required_input_keys))
assert len(net.outputs) == 2, "Sample supports only single output topologies"
required_output_keys = {'boxes', 'scores'}
assert required_output_keys.issubset(net.outputs.keys()), \
'Demo supports only topologies with the following output keys: {}'.format(', '.join(required_output_keys))
n, c, h, w = net.inputs['input'].shape
print("input_blob NxCxHxW is {}x{}x{}x{}".format(n, c, h, w))
input_size = cv2.imread("your_input_image.png").shape[:-1]
net.reshape({'input': (1, 3, input_size[0], input_size[1])})
n, c, h, w = net.inputs['input'].shape
print("input_blob NxCxHxW is resized to {}x{}x{}x{}".format(n, c, h, w))
print("Loading model to the plugin")
exec_net = ie.load_network(network=net, device_name='CPU')
print("Starting inference in synchronous mode")
for j in range(len(img_list)):
img_path = img_list[j]
ori_img = cv2.imread(img_path)
img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2RGB)
img = np.array(img, dtype=np.float32)
img = img.transpose((2, 0, 1))
img = img[np.newaxis, :, :, :]
print('[{}/{}]'.format(j, len(img_list)))
res = exec_net.infer(inputs={'input': img})
boxes = res['boxes']
scores = res['scores']
这里说明下“注册”是个啥意思,就是输入输出层的名字,实际上静态图里面,各层都是有类似“conv35”——“层类型-层的id”这样的名字,如果在IR转换的时候不规定,就是默认“conv35”的名称,规定层的名称,就是“注册”,我感觉这样来形容更加贴切一点。
模型转换那里是一样的,因此就不再赘述。
按理说,流程应该与“Python api推理”的流程是一致的,在文档Using Shape Inference的Usage of Reshape Method中提到CPP的流程如下所示:
InferenceEngine::Core core;
CNNNetwork network = core.ReadNetwork("path/to/IR/xml");
cv::Mat image = cv::imread("path/to/image");
auto input_shapes = network.getInputShapes();
std::string input_name;
SizeVector input_shape;
std::tie(input_name, input_shape) = *input_shapes.begin();
input_shape[0] = batch_size;
input_shape[2] = image.rows;
input_shape[3] = image.cols;
input_shapes[input_name] = input_shape;
network.reshape(input_shapes);
...
std::string device = "CPU";
ExecutableNetwork executable_network = core.LoadNetwork(network, device);
虽然会报之前讲到的错,因此我觉得这条reshape
路是不容易走通的,那么是不是就卡关了呢?实际上是有解的,OpenVINO提供在"3) 生成ExecutableNetwork对象"前添加一个类似resize层的东西,这样就不会变动IR结构,而且使用OpenVINO提供的内建的resize操作,比自己在输入OpenVINO前进行自己的resize操作,我感觉应该是要快一点,如果画成图的话,就如下图所示,我们可以使用OpenVINO优化后的resize操作。
using namespace InferenceEngine;
Core ie;
string cnnNetworkXmlPath;
auto cnnNetwork = ie.ReadNetwork(cnnNetworkXmlPath);
InputsDataMap inputInfo(cnnNetwork.getInputsInfo());
for (const auto & inputInfoItem : inputInfo)
if (inputInfoItem.second->getTensorDesc().getDims().size() == 4)
imageInputName = inputInfoItem.first;
inputInfoItem.second->setPrecision(Precision::U8);
inputInfoItem.second->getInputData()->setLayout(Layout::NCHW);
inputInfoItem.second->getPreProcess().setResizeAlgorithm(ResizeAlgorithm::RESIZE_BILINEAR);
throw std::logic_error("Unsupported " +
std::to_string(inputInfoItem.second->getTensorDesc().getDims().size()) + "D "
"input layer '" + inputInfoItem.first + "'. "
"Only 4D input layers are supported");
std::string device = "CPU";
ExecutableNetwork executable_network = ie.LoadNetwork(network, device);
上述操作就是为前处理添加一个resize操作层,实际上这个PreProcess
是支持很多操作的,例如归一化、减去均值等等,相当于就是在mo转ir的时候,插入的操作,大家可以查看相应的文档InferenceEngine::PreProcessInfo Class Reference看到它支持的各种操作。
好了,以上就是全部内容,在接下来的时间里,我应该会继续更新模型部署的内容,比如ssd的部署啊,trt的量化啊什么的,openvino的量化我也想试一试,奈何经历不够,又要吃饭,又想玩。
OpenVINO整活(一) 输入分辨率OpenVINO分为转换与部署两个部分,如下图所示在转换步中,需要将输入模型序列化后传入OpenVINO的MOModel Optimizer工具对模型进行优化,以得到IRIntermediate Representation中间表示,详细的内部行为可以参考Model Optimizer Developer Guide。接着,在部署步中,我们使用OpenVINO提供的Python或者CPP的api,进行编程以达到我们想要的结果:1) 载入ir文件, 2) 建立ie
ERROR:cannot reshape array of size 181944 into shape(1,22743,4)
出错的原理看这里:https://blog.csdn.net/Netceor/article/details/107330685
但是我实际是转模型的,只能看到这里的报错,print的相关信息已在tu中代码里注释了:
此时报错是第三步骤:
#linux default OpenVINO path
# 1. weights转换成pb模型
python convert_weights
openvino2022部署最新版yolov5v6.1模型demo
openvino 2022.1.0
openvino-dev 2022.1.0
openvino-telemetry 2022.1.1
torch 1.8.1
torchvision 0.9.1
里面命令行参数较多,其中比较重要的参数为:
-input_model: 为输入的训练的模型,如果使用的是caffe训练的模型则应该为XXX.caffemodel
--input_model INPUT_MODEL, -w INPUT_MODEL, -m INPUT_MODEL
Tensorflow*: a file with a pre-trained model (binary or text .pb file after freezing). Caffe*: a model proto file with model weights
Tensorflow *:具有预训练模型的文件(冻结后的二进制或文本.pb文件)。 Caffe *:具有模型权重的模型原
使用anaconda新建一个虚拟环境,假设叫openvino,使用这个虚拟环境
我的选择是这样的,安装命令在最下面,如果出现超时问题,可以再加一个--default-timeout=10000
安装结束后,可以用mo -h检验一下
二、模型下载和转换
以yolox-tiny为例
omz_downloader --name yolox-tiny -o /home/lwd/Downloads
omz_converter --name yolox-tiny -d /hom
接着前面系列博客来讲,这里会来跑下OpenVINO的自带示例,会在多个硬件平台上来测试(包括Intel Movidius Neural Computer Stick 2),神经棒的配置介绍见博主上一篇博客。
Intel Movidius Neural Computer Stick 2使用(PC-Based Ubuntu)_竹叶青lvye的博客-CSDN博客接着博主前面的系列博客继续讲,这篇来介绍上Intel的第二代加速神经棒的使用,主要还是参考官网来配置。前面很多博客也都访问过多家公司的官网,比较下来,I
基于openvino和python环境实现yolox图像检测:踩坑记录
最近看到openvino在Github上开源了一部分openvino_contrib,计划支持ARM架构CPU,就想着学学Openvino,
毕竟买不起NCS,想着单刷树莓派,正好yolox宣称吊打yolo系列,有支持各种加速引擎,果断拿来试试,然后就苦逼
了,但最终填坑,所以想着记录一下,和大家分享一下。
先甩个openvino_contrib和yolox地址:
Github:openvino_contrib
Github:y
OpenVINO是一个深度学习推理框架,可用于将训练好的神经网络模型部署到各种硬件平台上进行推理。下面是在OpenVINO上部署Yolo的一些步骤:
1. 下载和安装OpenVINO Toolkit。在OpenVINO官网下载并安装适合您操作系统的版本。
2. 下载Yolo的权重文件和配置文件。在Yolo官网上下载权重文件和配置文件。
3. 将Yolo模型转换为OpenVINO格式。使用OpenVINO提供的Model Optimizer工具将Yolo模型转换为OpenVINO格式。您需要使用以下命令:
python mo_tf.py --input_model yolov3.weights --tensorflow_use_custom_operations_config extensions/front/tf/yolo_v3.json --input_shape [1,416,416,3] --data_type FP32 --output_dir yolov3_openvino --model_name yolov3
其中,yolov3.weights是您下载的权重文件,yolo_v3.json是一个自定义操作文件,用于告诉Model Optimizer如何处理Yolo模型。--input_shape参数指定输入张量的形状,--data_type参数指定数据类型,--output_dir参数指定输出文件夹,--model_name参数指定模型名称。
4. 运行OpenVINO推理引擎。使用OpenVINO Inference Engine API加载和推理转换后的模型。您需要编写一个Python脚本来完成这一步骤。以下是一个简单的示例:
import cv2
import numpy as np
from openvino.inference_engine import IECore
# Load the OpenVINO model
model_xml = 'yolov3_openvino/yolov3.xml'
model_bin = 'yolov3_openvino/yolov3.bin'
ie = IECore()
net = ie.read_network(model=model_xml, weights=model_bin)
# Load the input image
img = cv2.imread('input.jpg')
# Preprocess the input image
input_blob = next(iter(net.inputs))
n, c, h, w = net.inputs[input_blob].shape
img = cv2.resize(img, (w, h))
img = img.transpose((2, 0, 1))
img = img.reshape((n, c, h, w))
# Run inference
exec_net = ie.load_network(network=net, device_name='CPU')
output = exec_net.infer(inputs={input_blob: img})
# Process the output
output_blob = next(iter(net.outputs))
output = output[output_blob][0]
boxes = output[:, 0:4]
confs = output[:, 4]
class_ids = output[:, 5:].argmax(axis=-1)
# Draw the predicted boxes on the input image
for i in range(len(boxes)):
if confs[i] > 0.5:
x, y, w, h = boxes[i]
cv2.rectangle(img, (int(x), int(y)), (int(x+w), int(y+h)), (0, 255, 0), 2)
# Save the output image
cv2.imwrite('output.jpg', img.transpose((1, 2, 0)))
这个脚本加载了转换后的Yolo模型,读取了输入图像,对图像进行预处理,运行了推理,处理了输出并将结果绘制在输入图像上,最后保存了输出图像。
这些步骤仅仅是一个简单的例子,如果您需要更复杂的操作,您需要仔细阅读OpenVINO文档,并参考OpenVINO的示例代码。
CSDN-Ada助手:
在win的VS2015下编译SuperLU与BLAS的动态库
m0_38075933:
Azure Kinect 使用记录 (一)
麦克斯韦恶魔:
Azure Kinect 使用记录 (一)
EXC0000:
pycharm + ssh 跳板机 + 服务器
天源细雪: