干货 | 函数详解 OpenVINO Inference Engine SDK
基本介绍
OpenVINO是针对英特尔针对自家现有的硬件平台开发的高性能计算机视觉和深度学习视觉应用的工具套件,支持英特尔自家的 CPU、GPU、FPGA、VPU 等硬件。OpenVINO包含两个大模块:模型转换模块Model Optimizer 和推理模块Inference Engine。本文讲解推理模块常见的 C++、API 函数说明以及使用方法,推理模块 API 也提供 C、Python 接口,笔者安装的OpenVINO版本是 2020.3 版本。
工作流程
推理模块的工作流程一般包含如下步骤:
-
创建推理对象:该推理对象可以支持不同的设备,所有的设备插件自动 通过 Core 来进行管理。Core::SetConfig 来配置设备属性,使用 Core::AddExtension 来注册设备第三方库,增加自定义层实现 -
读取中间表示:使用 Core 对象来读取中间表示文件 Core::ReadNetwork 创建 CNNNetwork 对象,该网络存在于宿主机的内存中 -
设置输入输出:CNNNetwork::getInputsInfo 和 CNNNetwork::getOutputsInfo 函数用于设置输入输出层的精度、数据排列等 -
加载神经网络:CNNNetwork::LoadNetwork 编译并加载网络到设备, 得到ExecutableNetwork 对象 -
设置输入数据:使用 ExecutableNetwork 对象来创建 InferRequest,可以直接将宿主机的内存复制到设备内存 -
执行推理过程:可以选择同步推理 InferRequest::Infer,也可以选择异步推理模式 InferRequest::StartAsync -
获取输出结果:InferRequest::GetBlob 读取推理结果
接口详解
创建推理对象
openvino/inference_engine/ie_core.hpp
,实现文件在openvino/inference_engine/src/inference_engine/ie_core.cpp
。Core 构造函数声明如下所示
explicitCore(conststd::string&xmlConfigFile=std::string());
// xmlConfigFile:指定插件配置文件,如果为空的话加载默认配置
openvino/deployment_tools/inference_engine/lib/intel64/plugins.xml
,默认参数如下所示,
name
表示支持的设备类型名称,
location
表示支持设备对应的库名称。
name="GNA"location="libGNAPlugin.so"> name="HETERO"location="libHeteroPlugin.so"> name="CPU"location="libMKLDNNPlugin.so"> name="MULTI"location="libMultiDevicePlugin.so"> name="GPU"location="libclDNNPlugin.so"> name="MYRIAD"location="libmyriadPlugin.so"> name="HDDL"location="libHDDLPlugin.so"> name="FPGA"location="libdliaPlugin.so">
name=""location=""> location=""> key=""value="">
openvino/blob/master/inference-engine/src/inference_engine
内。可通过
SetConfig
来配置设备的一些属性也就是上面 xml 中的 property 字段,使用
AddExtension
来设置设备外挂第三方库也就是上面 xml 中的 extension 字段,SetConfig 接口函数如下所示:
voidSetConfig(conststd::map<std::string,std::string>&config,conststd::string&deviceName=std::string());
// config:指定配置的参数名称和数值
// deviceName:指定配置设备名称,可选参数,如果不设置可默认为所有注册的设备都更改次配置
openvino/inference_engine/include/ie_plugin_config.hpp
。
voidAddExtension(constIExtensionPtr&extension);
voidAddExtension(IExtensionPtrextension,conststd::string&deviceName);
// extention:已加载的扩展的指针
// deviceName:设备名称
// 使用默认的 plugins.xml 文件 创建 Core 对象
Coreie;
// 设置设备属性
ie.SetConfig({{PluginConfigParams::KEY_CONFIG_FILE,config_file}},device_name);
// 设置设备的外挂第三方库用于支持用户自定义层
IExtensionPtrextension_ptr=make_so_pointer<IExtension>(extension_name);
ie.AddExtension(extension_ptr,"CPU");
// 设置设备的外挂函数用于支持用户自定义层
IExtensionPtrinPlaceExtension=std::make_shared<InPlaceExtension>();
ie.AddExtension(inPlaceExtension);
读取中间表示
CNNNetworkReadNetwork(conststd::string&modelPath,conststd::string&binPath="")const;
// modelPath:中间表示的配置文件
// binPath:中间表示的权重文件,如果为空,则尝试加载 modelPath 同名的权重文件,如果找不到同名文件则不加载权重
CNNNetworkReadNetwork(conststd::string&model,constBlob::CPtr&weights)const;
// model:中间表示的配置文件,权重文件必须与配置文件同名
// weights:共享指针,指向常量 Blob
/** Read network model **/
CNNNetworknetwork=ie.ReadNetwork(modelPath);
设置输入输出
openvino/inference_engine/include/ie_common.h
查询目前支持的输入输出数据 Layout 方式如下:
NCHW=1,//!< NCHW layout for input / output blobs
NHWC=2,//!< NHWC layout for input / output blobs
NCDHW=3,//!< NCDHW layout for input / output blobs
NDHWC=4,//!< NDHWC layout for input / output blobs
openvino/inference_engine/include/ie_precision.hpp
查询,目前支持的精度参数方式如下:
enumePrecision:uint8_t{
UNSPECIFIED=255,/**< Unspecified value. Used by default */
MIXED=0,/**< Mixed value. Can be received from network. No applicable for tensors */
FP32=10,/**< 32bit floating point value */
FP16=11,/**< 16bit floating point value */
Q78=20,/**< 16bit specific signed fixed point precision */
I16=30,/**< 16bit signed integer value */
U8=40,/**< 8bit unsigned integer value */
I8=50,/**< 8bit signed integer value */
U16=60,/**< 16bit unsigned integer value */
I32=70,/**< 32bit signed integer value */
I64=72,/**< 64bit signed integer value */
U64=73,/**< 64bit unsigned integer value */
BIN=71,/**< 1bit integer value */
BOOL=41,/**< 8bit bool type */
CUSTOM=80/**< custom precision has it's own name and size of elements */
};
InputsDataMapinputInfo(network.getInputsInfo());
InputInfo::Ptr&input=inputInfo.begin()->second;
autoinputName=inputInfo.begin()->first;
// 设置精度和数据排列方式
input->setPrecision(Precision::U8);
input->getInputData()->setLayout(Layout::NCHW);
// 设置 BatchSize 大小
ICNNNetwork::InputShapesinputShapes=network.getInputShapes();
SizeVector&inSizeVector=inputShapes.begin()->second;
inSizeVector[0]=1;// set batch to 1
network.reshape(inputShapes);
OutputsDataMapoutputInfo(network.getOutputsInfo());
for(auto&output:outputInfo) {
// 设置精度和数据的排列方式
output.second->setPrecision(Precision::FP32);
output.second->setLayout(Layout::NCHW);
}
加载神经网络
ExecutableNetworkLoadNetwork(
constCNNNetworknetwork,conststd::string&deviceName,
conststd::map<std::string,std::string>&config=std::map<std::string,std::string>());
// network:在步骤二读取中间表示中创建的网络
// deviceName:执行推理的设备名称
// config:设备配置属性,可选参数,该属性也可以通过 SetConfig 来设置所有设备属性
ExecutableNetwork executable_network = ie.LoadNetwork(network, device_name, configure);
plugins.xml
文件中设置的 so 动态库,入口函数为 CreatePluginEngine。
加载神经网络
openvino/inference_engine/sample
中提供了一种通用的数据拷贝方式matU8ToBlob
,首先在宿主机上实现图像的缩放,然后将其拷贝到设备内存,其调用过程如下:
// infer_request 在下面`执行推理过程`时讲述
Blob::Ptrinput=infer_request.GetBlob(input_name);
for(size_tb=0;b<batch_size;b++) {
matU8ToBlob<uint8_t>(image,input,b);
}
openvino/inference_engine/samples/cpp/common/samples/ocv_common.hpp
头文件内,其实现代码如下所示
template<typenameT>
voidmatU8ToBlob(constcv::Mat&orig_image,InferenceEngine::Blob::Ptr&blob,intbatchIndex=0) {
// orig_image:原始图像
// blob:输入数据内存
// batchIndex:批处理的index
// 首先读取网路尺寸
InferenceEngine::SizeVectorblobSize=blob->getTensorDesc().getDims();
constsize_twidth=blobSize[3];
constsize_theight=blobSize[2];
constsize_tchannels=blobSize[1];
if(static_cast<size_t>(orig_image.channels())!=channels) {
THROW_IE_EXCEPTION<<"The number of channels for net input and image must match";
}
T*blob_data=blob->buffer().as<T*>();
// CPU下执行原图的缩放
cv::Matresized_image(orig_image);
if(static_cast<int>(width)!=orig_image.size().width||
static_cast<int>(height)!=orig_image.size().height) {
cv::resize(orig_image,resized_image,cv::Size(width,height));
}
// 获得内存中数据偏移位移
intbatchOffset=batchIndex*width*height*channels;
// 完成数据从宿主机到设备的拷贝过程,仅支持单通道或者三通道输入数据推理
if(channels==1) {
for(size_th=0;h<height;h++) {
for(size_tw=0;w<width;w++) {
blob_data[batchOffset+h*width+w]=resized_image.at<uchar>(h,w);
}
}
}elseif(channels==3) {
for(size_tc=0;c<channels;c++) {
for(size_th=0;h<height;h++) {
for(size_tw=0;w<width;w++) {
blob_data[batchOffset+c*width*height+h*width+w]=
resized_image.at<cv::Vec3b>(h,w)[c];
}
}
}
}else{
THROW_IE_EXCEPTION<<"Unsupported number of channels";
}
}
openvino/inference_engine/include/ie_blob.h
,
网络输入输出数据的传递是通过Blob 类来实现的
。
执行推理过程
InferRequest infer_request = executable_network.CreateInferRequest();
infer_request.Infer();
// 获取网络输出结果
InferRequest::Ptr async_infer_request_curr = network.CreateInferRequestPtr();
InferRequest::Ptr async_infer_request_next = network.CreateInferRequestPtr();
while (true)
{
// 设置下一帧推理数据
frameToBlob(curr_frame, async_infer_request_next, imageInputName);
// 发送下一帧推理请求
async_infer_request_next->StartAsync();
// 获取上一帧推理结果
if (OK == async_infer_request_curr->Wait(IInferRequest::WaitMode::RESULT_READY))
{
// 获取网络输出结果
}
// 交换两个推理指针
async_infer_request_curr.swap(async_infer_request_next);
}
执行推理过程
// 获取输出结果方法一
Blob::Ptr output_blob = infer_request.GetBlob(output_name);
MemoryBlob::CPtr moutput = as(infer_request.GetBlob(output_name)); // 获取输出结果方法二
const float *detections = async_infer_request_curr->GetBlob(output_name)->buffer().as::value_type*>();
写在最后
openvino/inference_engine/sample
中例子程序。
▼
参考链接
-
https://github.com/openvinotoolkit/openvino -
https://docs.openvinotoolkit.org/latest/classInferenceEngine_1_1Core.html -
https://docs.openvinotoolkit.org/latest/_docs_IE_DG_inference_engine_intro.html -
https://docs.openvinotoolkit.org/latest/_docs_IE_DG_Deep_Learning_Inference_Engine_DevGuide.html
评论