[TOC]

文章参考:https://github.com/onnx/onnx

概述

环境搭建

PyPi

1
pip install onnx -i https://pypi.tuna.tsinghua.edu.cn/simple

Conda packages

A binary build of ONNX is available from Conda, in conda-forge:

1
2
conda install -c conda-forge numpy protobuf==3.16.0 libprotobuf=3.16.0
conda install -c conda-forge onnx

You can also use the onnx-dev docker image for a Linux-based installation without having to worry about dependency versioning.

ONNX Runtime环境搭建

文章参考:https://onnxruntime.ai/

python版本环境搭建

1
2
3
4
pip install onnxruntime  -i  https://pypi.tuna.tsinghua.edu.cn/simple

# 可以指定版本号
(py36) frewen@freweniubuntu:~$ pip install onnxruntime==1.10.0 -i https://pypi.tuna.tsinghua.edu.cn/simple

Mac下C++的ONNX Runtime环境搭建

文章参考:https://juejin.cn/post/7120494957625868325

文章参考:https://blog.csdn.net/qq_44747572/article/details/121467657?spm=1001.2014.3001.5502

文章参考:https://blog.csdn.net/qq_44747572/article/details/120820964?spm=1001.2014.3001.5501

文章参考:https://github.com/luogantt/onnxruntime_cpp_demo

下载对应的依赖库

https://onnxruntime.ai/

https://github.com/microsoft/onnxruntime/releases

image-20230323225929717

集成到我们项目工程中

image-20230323230337035

添加dependence依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if (BUILD_ONNX_LIB)
# 添加ONNX推理库的依赖
# 参考文档: https://github.com/microsoft/onnxruntime/releases/tag/v1.14.1
set(ONNX_VERSION v1.14.1) # 设置QNN的版本号
set(ONNX_BASE_DIR ${LIB_DIR}/onnx/${ONNX_VERSION}/${TARGET_OS}-${TARGET_ARCH}-release) # 设置QNN的基础目录
set(ONNX_INCLUDE_DIR ${ONNX_BASE_DIR}/include)
set(ONNX_LINK_DIR ${ONNX_BASE_DIR}/lib) # 根据系统版本设置依赖库的目录
set(ONNX_LIB onnxruntime)
include_directories(${ONNX_INCLUDE_DIR})
link_directories(${ONNX_LINK_DIR})
message(STATUS "[Dependency] onnx ONNX_INCLUDE_DIR = ${ONNX_INCLUDE_DIR}")
message(STATUS "[Dependency] onnx ONNX_LINK_DIR = ${ONNX_LINK_DIR}")
message(STATUS "[Dependency] onnx ONNX_LIB = ${ONNX_LIB}")
else ()
message(STATUS "[Dependency] NotBuild onnx dependence ignored")
endif ()

参考集成的实例库

https://github.com/microsoft/onnxruntime-inference-examples

源码实现

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
class OnnxPredictor : public AbsPredictor {
public:
~OnnxPredictor() override = default;

int init(const ModelInfo &model) override;

int doPredict(aura_cv::TensorArray &inputs, aura_cv::TensorArray &outputs) override;

int deInit() override;

private:
/**
* 定义OnnxRuntime Session
*/
Ort::Session session;
/**
* 定义OnnxRuntime MemoryInfo
*/
Ort::MemoryInfo memoryInfo;
/**
* 输入张量的大小
*/
size_t inputTensorSize;
/**
* 输入张量的数据
*/
std::vector<float> inputTensorValues;

std::vector<const char *> input_node_names = {"input", "input_mask"};
std::vector<const char *> output_node_names = {"output", "output_mask"};
std::vector<int64_t> input_node_dims = {10, 20};

};
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
int OnnxPredictor::init(const ModelInfo &model) {
if (model.blobs.size() != 1) {
ALOGE(TAG, "Predictor model mem error, one blob needed! error model info:%s", model.version.c_str());
VA_RET(Error::MODEL_INIT_ERR);
}
auto *modelData = static_cast<const uint8_t *>(model.blobs[0].data);
auto modelSize = static_cast<const size_t>(model.blobs[0].len);

// onnxruntime setup onnxruntime的初始化
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "example-model-explorer");
// 获取配置
Ort::SessionOptions session_options;
// 使用1个线程执行op,若想提升速度,增加线程数
session_options.SetIntraOpNumThreads(1);

// CUDA加速开启(由于onnxruntime的版本太高,无cuda_provider_factory.h的头文件,加速可以使用onnxruntime V1.8的版本)
// OrtSessionOptionsAppendExecutionProvider_CUDA(session_options, 0);

// 设置图优化的级别
// ORT_DISABLE_ALL = 0,
// ORT_ENABLE_BASIC = 1, # 启用基础优化
// ORT_ENABLE_EXTENDED = 2,
// ORT_ENABLE_ALL = 99 # 启用所有可能的优化
session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL);

// 创建通过ONNX模型路径进行实例化的Session
// Ort::Session session(env, "model_path", session_options);
// 通过ONNX模型的原始数据和模型大小
session = Ort::Session(env, modelData, modelSize, session_options);

// print model input layer (node names, types, shape etc.)
Ort::AllocatorWithDefaultOptions allocator;

// print number of model input nodes
size_t num_input_nodes = session.GetInputCount();

// 初始化输入张量的大小
inputTensorSize = 10 * 20;
inputTensorValues = std::vector<float>(inputTensorSize);

for (unsigned int i = 0; i < inputTensorSize; i++) {
inputTensorValues[i] = (float) i / (inputTensorSize + 1);
}

// create MemoryInfo
memoryInfo = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);

}

int OnnxPredictor::doPredict(aura_cv::TensorArray &inputs, aura_cv::TensorArray &outputs) {


Ort::Value input_tensor = Ort::Value::CreateTensor<float>(memoryInfo, inputTensorValues.data(), inputTensorSize,
input_node_dims.data(), 2);
assert(input_tensor.IsTensor());

std::vector<int64_t> input_mask_node_dims = {1, 20, 4};
size_t input_mask_tensor_size = 1 * 20 * 4;
std::vector<float> input_mask_tensor_values(input_mask_tensor_size);
for (unsigned int i = 0; i < input_mask_tensor_size; i++)
input_mask_tensor_values[i] = (float) i / (input_mask_tensor_size + 1);
// create input tensor object from data values
auto mask_memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
Ort::Value input_mask_tensor = Ort::Value::CreateTensor<float>(mask_memory_info, input_mask_tensor_values.data(),
input_mask_tensor_size, input_mask_node_dims.data(),
3);
assert(input_mask_tensor.IsTensor());

std::vector<Ort::Value> ort_inputs;
ort_inputs.push_back(std::move(input_tensor));
ort_inputs.push_back(std::move(input_mask_tensor));
// score model & input tensor, get back output tensor
auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_node_names.data(), ort_inputs.data(),
ort_inputs.size(), output_node_names.data(), 2);

// Get pointer to output tensor float values
float *floatarr = output_tensors[0].GetTensorMutableData<float>();
float *floatarr_mask = output_tensors[1].GetTensorMutableData<float>();

printf("Done!\n");
return 0;
}

int OnnxPredictor::deInit() {
return 0;
}

}