OpenVINO Toolkit 系列(三) —— 模型转换与推理加速
OpenVINO™ 是用于优化和部署 AI 推理的开源工具包。1.提升计算机视觉、自动语音识别、自然语言处理和其他常见任务中的深度学习性能2. 使用通过 TensorFlow、PyTorch 等流行框架训练的模型3. 减少资源需求并在从边缘到云的一系列英特尔® 平台上高效部署
简介
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) 来加速推理的方法。
线性操作融合
许多卷积神经网络包括 BatchNormalization
和 ScaleShift
层(例如,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)
后续
喜欢的话可以关注一下我的公众号技术开发小圈,尤其是对深度学习以及计算机视觉有兴趣的朋友,我会把相关的源码以及更多资料发在上面,希望可以帮助到新入门的大家!
更多推荐
所有评论(0)