【推理技巧】OpenVINO2024 C++ 模型部署技巧合集

学习《OpenCV应用开发:入门、进阶与工程化实践》一书
做真正的OpenCV开发者,从入门到入职,一步到位!

前言

很多人都使用OpenVINO新版的C++ 或者Python的SDK,都觉得非常好用,OpenVINO2022之后的版本C++ SDK做了大量的优化与整理,已经是非常贴近开发的使用习惯与推理方式。与OpenCV的Mat对象对接方式更是几乎无缝对接,非常的方便好用。
在这里插入图片描述

导入头文件

一行代码就获取C++ SDK支持

#include <openvino/openvino.hpp>

创建推理推理请求

总结起来有三种不同方式,针对单个固定输入与输出层的模型,只需要三行代码即可创建:

ov::Core ie;
ov::CompiledModel compiled_model = ie.compile_model(settings.getWeight_file(), "CPU");
infer_request = compiled_model.create_infer_request();

对于支持动态输入的模型,需要首先设置支持动态输入的维度,一般都是图像宽高,加载模型,创建推理请求的方式如下:

ov::Core ie;
auto model = ie.read_model(settings.getWeight_file());
auto inputs = model->inputs();

获取输入格式

// change the input as dynamic shape support
for(auto input_one : inputs){
         auto input_shape = input_one.get_partial_shape();
         input_shape[0] = 1;
         input_shape[1] = 3;
         input_shape[2] = -1;
         input_shape[3] = -1;
}

创建推理请求

ov::CompiledModel compiled_model = ie.compile_model(model, "CPU");
infer_request = compiled_model.create_infer_request();

如果有多个输入层的模型,想动态修改输入层与模型输入的格式,然后再创建推理请求,代码实现如下:

ov::Core ie;
std::cout<<"model file: "<<settings.getweight_file()<<std::endl;< span="">
auto model = ie.read_model(settings.getWeight_file());
std::cout<<"read model file finished!"<<std::endl;< span="">

// setting input data format and layout
ov::preprocess::PrePostProcessor ppp(model);
ov::preprocess::InputInfo& inputInfo0 = ppp.input(0);
inputInfo0.tensor().set_element_type(ov::element::u8);
inputInfo0.tensor().set_layout({ "NCHW" });
inputInfo0.model().set_layout("NCHW");

ov::preprocess::InputInfo& inputInfo1 = ppp.input(1);
inputInfo1.tensor().set_element_type(ov::element::u8);
inputInfo1.tensor().set_layout({ "NCHW" });
inputInfo1.model().set_layout("NCHW");
model = ppp.build();

ov::CompiledModel compiled_model = ie.compile_model(model, "CPU");
this->infer_request = compiled_model.create_infer_request();

导出IR格式模型

我发现OpenVINO已经支持脚本方式导出XML的IR格式文件,简单易用,推荐给大家。以下是导出YOLOv8格式IR文件脚本,亲测有效:

ov_model = ov.convert_model("D:/python/my_yolov8_train_demo/yolov8n.onnx",
                             input=[[1, 3, 640, 640]])
ov.save_model(ov_model, str("D:/bird_test/back1/yolov8_ov.xml"))

图像预处理

OpenVINO已经有自己的预处理方式,代码如下:

ov::preprocess::PrePostProcessor ppp(model);
ov::preprocess::InputInfo& input = ppp.input(tensor_name);
// we only need to know where is C dimension
input.model().set_layout("...C");
// specify scale and mean values, order of operations is important
input.preprocess().mean(116.78f).scale({ 57.21f, 57.45f, 57.73f });
// insert preprocessing operations to the 'model'
model = ppp.build();

同时你还可以使用OpenCV的blobfromImage函数来完成图像预处理:

// 预处理
cv::Mat blob_image;
resize(image, blob_image, cv::Size(input_w, input_h));
blob_image.convertTo(blob_image, CV_32F);
blob_image = blob_image / 255.0;

或者

cv::Mat blob = cv::dnn::blobFromImage(image, 1 / 255.0, cv::Size(640, 640), cv::Scalar(0, 0, 0), true, false);

预测推理

OpenVINO C++ SDK支持两种方式预测推理,分别是同步与异步模式,此外异步模式还支持Callback的方式实现后处理,这样对于实现推理流水线非常有用。代码片段如下:
同步推理,等待结果

this->infer_request.infer();

异步方式 + Callback

auto restart_once = true;
infer_request.set_callback([&, restart_once](std::exception_ptr exception_ptr) mutable {
    if (exception_ptr) {
        // procces exception or rethrow it.
        std::rethrow_exception(exception_ptr);
    } else {
        // Extract inference result
        ov::Tensor output_tensor = infer_request.get_output_tensor();
        // Restart inference if needed
        if (restart_once) {
            infer_request.start_async();
            restart_once = false;
        }
    }
});
// Start inference without blocking current thread
infer_request.start_async();
// Get inference status immediately
bool status = infer_request.wait_for(std::chrono::milliseconds{0});
// Wait for one milisecond
status = infer_request.wait_for(std::chrono::milliseconds{1});
// Wait for inference completion
infer_request.wait();

cv::Mat与ov::Tensor转换

从Mat创建Tensor对象,这个时候我就喜欢模型的输入格式是NHWC的方式,这样创建Tensor,设置输入数据只要一行代码即可,示例如下:

bgr.convertTo(bgr, CV_32FC3);
gray.convertTo(gray, CV_32F, 1.0/255);

ov::Tensor blob1(input_tensor_1.get_element_type(), input_tensor_1.get_shape(), (float *)bgr.data);
ov::Tensor blob2(input_tensor_2.get_element_type(), input_tensor_2.get_shape(), (float *)gray.data);

推理预测结果Tensor到OpenCV Mat对象,也很简单明了,如果输出数据是NHWC四维,可以直接用下面的代码:

const float* prob = (float*)output.data();
const ov::Shape outputDims = output.get_shape();
size_t numRows = outputDims[1];
size_t numCols = outputDims[2];
// 通道数为1 用这行
cv::Mat detOut(numRows, numCols, CV_32F, (float*)prob);
// 通道数为3 用这行
cv::Mat detOut(numRows, numCols, CV_32FC3, (float*)prob);

如果输出是1xHW的三维张量,直接用下面这样:

cv::Mat detOut(numRows, numCols, CV_32F, (float*)prob);

从此你就真的解锁了OpenVINO C++ 模型推理部署的各种细节了。

猛戳这里,立即解锁更多OpenVINO开发技能!!!
OpenVINO2023计算机视觉模型部署与加速教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gloomyfish

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值