0%

常见编程技巧

摘要

  • OpenVINO 常见编程技巧

使用cv::Mat 初始化一个 ov::Tensor

在 OpenVINO 中,可以通过 cv::Mat 初始化一个 ov::Tensor,以便直接使用 OpenCV 加载或处理的图像作为推理输入。这种方法简化了数据传递流程,尤其适合处理图像数据的应用场景。


使用 cv::Mat 初始化 ov::Tensor 的步骤

  1. 准备 cv::Mat 数据
    使用 OpenCV 加载图像并处理为适合模型的输入格式。

  2. 创建 ov::Tensor
    绑定 cv::Mat 的数据到 ov::Tensor

  3. 设置张量到推理请求
    将创建的 ov::Tensor 作为输入张量传递到推理请求。


完整代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <openvino/openvino.hpp>
#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
// Step 1: 使用 OpenCV 加载图像
cv::Mat image = cv::imread("image.jpg");
if (image.empty()) {
std::cerr << "Failed to load image!" << std::endl;
return -1;
}

// Step 2: 调整图像大小和通道格式
cv::resize(image, image, cv::Size(224, 224)); // 假设模型输入为 224x224
cv::cvtColor(image, image, cv::COLOR_BGR2RGB); // 转换为 RGB 格式

// Step 3: 转换数据为浮点类型并归一化 (0-1)
image.convertTo(image, CV_32F, 1.0 / 255.0);

// Step 4: 创建 ov::Tensor 并绑定 cv::Mat 数据
ov::Tensor input_tensor(ov::element::f32, {1, 3, 224, 224}, image.data);

// Step 5: 初始化 OpenVINO 核心和模型
ov::Core core;
auto model = core.read_model("model.xml");
auto compiled_model = core.compile_model(model, "CPU");

// Step 6: 创建推理请求并设置输入张量
ov::InferRequest infer_request = compiled_model.create_infer_request();
infer_request.set_input_tensor(input_tensor);

// Step 7: 执行推理
infer_request.infer();

// Step 8: 获取输出张量并处理结果
ov::Tensor output_tensor = infer_request.get_output_tensor();
float* output_data = output_tensor.data<float>();
for (size_t i = 0; i < output_tensor.get_size(); ++i) {
std::cout << "Output[" << i << "] = " << output_data[i] << std::endl;
}

return 0;
}

关键说明

  1. 图像预处理

    • 模型通常要求特定大小和通道顺序的输入数据。
    • 使用 cv::resizecv::cvtColor 进行调整。
  2. 数据类型与归一化

    • 通常模型输入为浮点数(float32)。
    • 使用 convertTo 将像素值从 [0, 255] 归一化为 [0, 1]
  3. 绑定 cv::Mat 的数据

    • cv::Matdata 成员指向底层数据缓冲区,可以直接传递给 ov::Tensor
    • 注意cv::Mat 的内存管理由 OpenCV 负责,确保在推理期间 cv::Mat 的数据未被释放或修改。
  4. 张量形状

    • ov::Tensor 的形状为 {1, 3, 224, 224},即 batch_size = 1channels = 3height = 224width = 224
    • 需根据模型具体要求调整。
  5. 高效内存共享

    • 通过直接绑定 cv::Mat 数据避免了数据拷贝,提升性能。

性能优化

  • 批量推理
    如果需要一次推理多张图像,可以将多张图像组合到一个批量张量中:

    1
    ov::Tensor batch_tensor(ov::element::f32, {batch_size, 3, 224, 224}, batch_data);
  • 减少数据预处理开销
    如果预处理操作固定,尽量在图像加载阶段完成(如归一化和通道转换)。


总结

通过绑定 cv::Mat 数据到 ov::Tensor,可以高效地将 OpenCV 处理的图像输入到 OpenVINO 模型中。这种方式既简化了数据传递流程,又避免了不必要的内存拷贝,是实现图像推理应用的推荐实践。

cv::Core 编译onnx模型到CPU

在 OpenVINO 中,通过 ov::Core 将 ONNX 模型编译到 CPU 的过程包括以下几个步骤:

  1. 创建 ov::Core 对象:初始化 OpenVINO 核心对象。
  2. 加载 ONNX 模型:使用 ov::Core::read_model() 方法加载 ONNX 模型文件。
  3. 编译模型到 CPU:调用 ov::Core::compile_model() 方法,将模型优化并绑定到 CPU 设备。
  4. 推理或查询模型信息:通过编译好的模型执行推理任务或获取模型结构。

以下是完整的代码和步骤说明:


1. 示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <openvino/openvino.hpp>
#include <iostream>

int main() {
try {
// 1. 创建 Core 对象
ov::Core core;

// 2. 加载 ONNX 模型
std::string onnx_model_path = "model.onnx";
auto model = core.read_model(onnx_model_path);

// 3. 编译模型到 CPU
ov::AnyMap config = {
{ov::hint::performance_mode.name(), ov::hint::PerformanceMode::THROUGHPUT} // 设置性能模式为吞吐量优化
};
auto compiled_model = core.compile_model(model, "CPU", config);

// 4. 查询模型输入输出信息
std::cout << "Model Inputs:" << std::endl;
for (const auto& input : compiled_model.inputs()) {
std::cout << " - Name: " << input.get_any_name() << std::endl;
std::cout << " Shape: " << input.get_shape() << std::endl;
}

std::cout << "Model Outputs:" << std::endl;
for (const auto& output : compiled_model.outputs()) {
std::cout << " - Name: " << output.get_any_name() << std::endl;
std::cout << " Shape: " << output.get_shape() << std::endl;
}

} catch (const std::exception& ex) {
std::cerr << "Error: " << ex.what() << std::endl;
}

return 0;
}

2. 主要步骤

步骤 1: 创建 ov::Core 对象

  • ov::Core 是 OpenVINO 的核心对象,用于管理设备、加载模型和配置参数。
1
ov::Core core;

步骤 2: 加载 ONNX 模型

  • 使用 read_model 方法加载 ONNX 格式的模型文件。
  • 传入模型路径(model.onnx)。
  • 返回值为 std::shared_ptr<ov::Model>,代表模型的中间表示(IR)。
1
auto model = core.read_model("model.onnx");

步骤 3: 编译模型到 CPU

  • 使用 compile_model 将模型编译到 CPU。
  • 可选地传入配置参数,如性能模式 (PerformanceMode)、线程数等。
1
2
3
4
ov::AnyMap config = {
{ov::hint::performance_mode.name(), ov::hint::PerformanceMode::THROUGHPUT}
};
auto compiled_model = core.compile_model(model, "CPU", config);

步骤 4: 查询模型输入输出信息

  • 使用 inputs()outputs() 方法获取模型的输入输出信息,包括名称和形状。
1
2
3
4
5
6
7
8
for (const auto& input : compiled_model.inputs()) {
std::cout << "Input name: " << input.get_any_name() << std::endl;
std::cout << "Input shape: " << input.get_shape() << std::endl;
}
for (const auto& output : compiled_model.outputs()) {
std::cout << "Output name: " << output.get_any_name() << std::endl;
std::cout << "Output shape: " << output.get_shape() << std::endl;
}

3. 添加推理步骤

编译模型后,可以使用 create_infer_request 创建推理请求,并执行推理任务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 创建推理请求
auto infer_request = compiled_model.create_infer_request();

// 设置输入数据
auto input_tensor = infer_request.get_input_tensor();
std::vector<float> input_data = { /* 填充输入数据 */ };
std::copy(input_data.begin(), input_data.end(), input_tensor.data<float>());

// 执行推理
infer_request.infer();

// 获取输出数据
auto output_tensor = infer_request.get_output_tensor();
auto output_data = output_tensor.data<float>();

// 处理输出结果
for (size_t i = 0; i < output_tensor.get_size(); ++i) {
std::cout << "Output[" << i << "] = " << output_data[i] << std::endl;
}

4. 常见配置参数

以下是一些常见的 config 配置:

配置参数 值类型 描述
ov::hint::performance_mode ov::hint::PerformanceMode 性能优化模式(如 LATENCY, THROUGHPUT)。
ov::inference_num_threads int 推理线程数。
ov::num_streams std::string 推理流数量(如 "AUTO""1")。
ov::enable_profiling bool 是否启用性能分析(默认为 false)。

5. 动态输入形状支持

如果 ONNX 模型支持动态输入形状,可以在编译前指定具体形状:

1
2
model->reshape({{"input", ov::PartialShape{-1, 3, 224, 224}}}); // 动态批量大小
auto compiled_model = core.compile_model(model, "CPU");

6. 注意事项

  1. 环境配置:
    • 确保 OpenVINO 环境已正确安装并设置环境变量。
  2. 模型兼容性:
    • 确认 ONNX 模型的格式是否受支持。
    • 如果模型包含不支持的算子,可能需要重新导出或转换。
  3. 设备支持:
    • 确保目标设备(如 CPU)的插件已正确安装。

通过上述步骤,可以轻松使用 OpenVINO 的 ov::Core 将 ONNX 模型编译并运行在 CPU 上。如果需要进一步优化或处理特定场景,欢迎继续讨论!

感谢老板支持!敬礼(^^ゞ