干貨 | 函數詳解 ?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 構造函數聲明如下所示explicit Core(const std::string& xmlConfigFile = std::string());
// xmlConfigFile:指定插件配置文件,如果為空的話加載默認配置
openvino/deployment_tools/inference_engine/lib/intel64/plugins.xml
,默認參數如下所示,name 表示支持的設備類型名稱,location 表示支持設備對應的庫名稱。<ie>
<plugins>
<plugin name="GNA" location="libGNAPlugin.so">
</plugin>
<plugin name="HETERO" location="libHeteroPlugin.so">
</plugin>
<plugin name="CPU" location="libMKLDNNPlugin.so">
</plugin>
<plugin name="MULTI" location="libMultiDevicePlugin.so">
</plugin>
<plugin name="GPU" location="libclDNNPlugin.so">
</plugin>
<plugin name="MYRIAD" location="libmyriadPlugin.so">
</plugin>
<plugin name="HDDL" location="libHDDLPlugin.so">
</plugin>
<plugin name="FPGA" location="libdliaPlugin.so">
</plugin>
</plugins>
</ie>
<ie>
<plugins>
<plugin name="" location="">
<extensions>
<extension location="">
</extensions>
<properties>
<property key="" value="">
</properties>
</plugin>
</plugins>
</ie>
openvino/blob/master/inference-engine/src/inference_engine
內。可通過 SetConfig 來配置設備的一些屬性也就是上面 xml 中的 property 字段,使用 AddExtension 來設置設備外掛第三方庫也就是上面 xml 中的 extension 字段,SetConfig 接口函數如下所示:void SetConfig(const std::map<std::string, std::string>& config, const std::string& deviceName = std::string());
// config:指定配置的參數名稱和數值
// deviceName:指定配置設備名稱,可選參數,如果不設置可默認為所有注冊的設備都更改次配置
openvino/inference_engine/include/ie_plugin_config.hpp
。 void AddExtension(const IExtensionPtr& extension);
void AddExtension(IExtensionPtr extension, const std::string& deviceName);
// extention:已加載的擴展的指針
// deviceName:設備名稱
// 使用默認的 plugins.xml 文件創建 Core 對象
Core ie;
// 設置設備屬性
ie.SetConfig({{PluginConfigParams::KEY_CONFIG_FILE, config_file}}, device_name);
// 設置設備的外掛第三方庫用于支持用戶自定義層
IExtensionPtr extension_ptr = make_so_pointer<IExtension>(extension_name);
ie.AddExtension(extension_ptr, "CPU");
// 設置設備的外掛函數用于支持用戶自定義層
IExtensionPtr inPlaceExtension = std::make_shared<InPlaceExtension>();
ie.AddExtension(inPlaceExtension);
讀取中間表示
CNNNetwork ReadNetwork(const std::string& modelPath, const std::string& binPath = "") const;
// modelPath:中間表示的配置文件
// binPath:中間表示的權重文件,如果為空,則嘗試加載 modelPath 同名的權重文件,如果找不到同名文件則不加載權重
CNNNetwork ReadNetwork(const std::string& model, const Blob::CPtr& weights) const;
// model:中間表示的配置文件,權重文件必須與配置文件同名
// weights:共享指針,指向常量 Blob
/** Read network model **/
CNNNetwork network = 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
查詢,目前支持的精度參數方式如下:enum ePrecision : 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 */
};
InputsDataMap inputInfo(network.getInputsInfo());
InputInfo::Ptr& input = inputInfo.begin()->second;
auto inputName = inputInfo.begin()->first;
// 設置精度和數據排列方式
input->setPrecision(Precision::U8);
input->getInputData()->setLayout(Layout::NCHW);
// 設置 BatchSize 大小
ICNNNetwork::InputShapes inputShapes = network.getInputShapes();
SizeVector& inSizeVector = inputShapes.begin()->second;
inSizeVector[0] = 1; // set batch to 1
network.reshape(inputShapes);
OutputsDataMap outputInfo(network.getOutputsInfo());
for (auto &output : outputInfo) {
// 設置精度和數據的排列方式
output.second->setPrecision(Precision::FP32);
output.second->setLayout(Layout::NCHW);
}
加載神經網絡
ExecutableNetwork LoadNetwork(
const CNNNetwork network, const std::string& deviceName,
const std::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::Ptr input = infer_request.GetBlob(input_name);
for (size_t b = 0; b < batch_size; b++) {
matU8ToBlob<uint8_t>(image, input, b);
}
openvino/inference_engine/samples/cpp/common/samples/ocv_common.hpp
頭文件內,其實現代碼如下所示template <typename T>
void matU8ToBlob(const cv::Mat& orig_image, InferenceEngine::Blob::Ptr& blob, int batchIndex = 0) {
// orig_image:原始圖像
// blob:輸入數據內存
// batchIndex:批處理的index
// 首先讀取網路尺寸
InferenceEngine::SizeVector blobSize = blob->getTensorDesc().getDims();
const size_t width = blobSize[3];
const size_t height = blobSize[2];
const size_t channels = 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::Mat resized_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));
}
// 獲得內存中數據偏移位移
int batchOffset = batchIndex * width * height * channels;
// 完成數據從宿主機到設備的拷貝過程,僅支持單通道或者三通道輸入數據推理
if (channels == 1) {
for (size_t h = 0; h < height; h++) {
for (size_t w = 0; w < width; w++) {
blob_data[batchOffset + h * width + w] = resized_image.at<uchar>(h, w);
}
}
} else if (channels == 3) {
for (size_t c = 0; c < channels; c++) {
for (size_t h = 0; h < height; h++) {
for (size_t w = 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<MemoryBlob>(infer_request.GetBlob(output_name));
// 獲取輸出結果方法二
const float *detections = async_infer_request_curr->GetBlob(output_name)->buffer().as<PrecisionTrait<Precision::FP32>::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
評論