简介

OpenVINO™ 是用于优化和部署 AI 推理的开源工具包。

  • 提升计算机视觉、自动语音识别、自然语言处理和其他常见任务中的深度学习性能
  • 使用通过 TensorFlow、PyTorch 等流行框架训练的模型
  • 减少资源需求并在从边缘到云的一系列英特尔® 平台上高效部署

​ 由于笔者在项目开发的需求是针对YOLOv5的OpenVINO推理加速,所以本文主要针对关于YOLOv5的模型转换和推理加速做具体介绍,对于其他的模型也大同小异。

模型转换

pt To ONNX

​ 使用YOLOv5源码中的export.py脚本,可以很容易地将yolo训练出的pt模型转化成通用的onnx模型。

​ 在yolov5的models文件夹下

python3 export.py --weights 模型路径 --img-size 输入层尺寸

​ 即可直接将pt模型转化成onnx模型。

ONNX To IR

​ OpenVINO推理加速使用的是一种中间表示(IR)模型,其自带的模型优化器中也提供了ONNX模型转换成IR模型的脚本,在deployment_tools/model_optimizer路径下

运行模型转换脚本

cd <INSTALL_DIR>/deployment_tools/model_optimizer/
python3 mo.py --input_model <INPUT_MODEL>.onnx  --output_dir <OUTPUT_MODEL_DIR> --model_name <OUTPUT_MODEL_NAME>

​ 出现SUCCESS则表示转换成功,在对应的路径下会生成.xml和.bin文件,在任何时候,你都需要将这两个模型文件放在统一路径下。

推理加速原理

​ OpenVINO提供了使用不需要模型重新训练的卷积神经网络 (CNN) 来加速推理的方法。

线性操作融合

​ 许多卷积神经网络包括 BatchNormalizationScaleShift层(例如,Resnet*、Inception*)可以表示为一系列线性运算:加法和乘法, 这些层可以融合到以前的 Convolution要么 FullyConnected层。

ResNet 优化(步幅优化)

​ ResNet 优化是一种特定的优化,适用于 ResNet50、ResNet101、ResNet152 等 Caffe ResNet 拓扑和基于 ResNet 的拓扑。该优化的主要思想是将大于 1 的步幅从内核大小 = 1 的卷积层移动到上层卷积层。 此外,模型优化器添加了一个池化层来对齐 Eltwise 层的输入形状。

推理步骤

1. 搭建推理环境

// 创建推理core,管理处理器和插件
InferenceEngine::Core core;
// 读取网络结构和权重
CNNNetReader network_reader;
network_reader.ReadNetwork("Model.xml");
network_reader.ReadWeights("Model.bin");
// 配置输入输出参数
auto network = network_reader.getNetwork();
InferenceEngine::InputsDataMap input_info(network.getInputsInfo());
InferenceEngine::OutputsDataMap output_info(network.getOutputsInfo());
// 配置输入选项
for (auto &item : input_info) {
    auto input_data = item.second;
    input_data->setPrecision(Precision::U8);
    input_data->setLayout(Layout::NCHW);
    input_data->getPreProcess().setResizeAlgorithm(RESIZE_BILINEAR);
    input_data->getPreProcess().setColorFormat(ColorFormat::RGB);
}
// 配置输出选项
for (auto &item : output_info) {
    auto output_data = item.second;
    output_data->setPrecision(Precision::FP32);
    output_data->setLayout(Layout::NC);
}
// 装载网络结构到设备
auto executable_network = core.LoadNetwork(network, "CPU");
std::map<std::string, std::string> config = {{ PluginConfigParams::KEY_PERF_COUNT, PluginConfigParams::YES }};
auto executable_network = core.LoadNetwork(network, "CPU", config);
// 创建推理请求
auto infer_request = executable_network.CreateInferRequest();

2. 执行推理

// 准备输入Data
or (auto & item : inputInfo) {
    auto input_name = item->first;
    /** Getting input blob **/
    auto input = infer_request.GetBlob(input_name);
    /** Fill input tensor with planes. First b channel, then g and r channels **/
    ...
}

// 推理有两种方式可以选择:

// 1. 同步推理
sync_infer_request->Infer();

// 2.  异步推理
sync_infer_request->StartAsync();
sync_infer_request->Wait(IInferRequest::WaitMode::RESULT_READY);

3. 后处理

​ 对于不同的网络模型来说,相应的后处理也不同,这里仅给出大致形式提供参考。

// 结果处理
for (auto &item : output_info) {
    auto output_name = item.first;
    auto output = infer_request.GetBlob(output_name);
    {
        auto const memLocker = output->cbuffer(); // use const memory locker
        // output_buffer is valid as long as the lifetime of memLocker
        const float *output_buffer = memLocker.as<const float *>();
        // process result
        ...
    }
}

参考

Converting a Model to Intermediate Representation (IR)

Model Optimization Techniques

后续

 喜欢的话可以关注一下我的公众号技术开发小圈,尤其是对深度学习以及计算机视觉有兴趣的朋友,我会把相关的源码以及更多资料发在上面,希望可以帮助到新入门的大家!
在这里插入图片描述

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐