
VS c++ onnxruntime 环境配置、onnx教程、部署推理模型、sklearn pkl模型转onnx、问题汇总
目录
3. 3.“GetInputName“: 不是 “Ort::Session“ 的成员
GitHub - microsoft/onnxruntime
一、初步认识ONNX
Onnx模型介绍_HelloWorldQAQ。的博客-CSDN博客
ONNX(Open Neural Network Exchange)是一个开放的深度学习模型交换格式,它的目标是提供一个标准化的桥梁,使得不同深度学习框架之间能够更轻松地共享和部署模型。
ONNX 的主要特点和目标包括:
- 开放性: ONNX 是一个开放标准,由微软、Facebook和其他合作伙伴共同推动。它的目标是促进深度学习生态系统的互操作性。
- 跨平台: ONNX 支持在不同的深度学习框架之间交换模型。目前,它支持诸如PyTorch、TensorFlow、MXNet等流行的深度学习框架。
- 灵活性: ONNX 支持多种深度学习模型的表示,包括卷积神经网络(CNN)、循环神经网络(RNN)和其他常见的神经网络架构。
- 部署: ONNX 不仅仅是一个模型表示格式,还提供了一些工具和库,使得用户能够在不同的硬件和软件环境中有效地部署模型。
一些学习资料:[推理部署]🔥🔥🔥 全网最详细 ONNXRuntime C++/Java/Python 资料!
二、pkl转ONNX+可视化模型
python onnx版本:1.15.0
import joblib
import onnxmltools
from onnxmltools.convert.common.data_types import FloatTensorType
import netron
from sklearn.model_selection import train_test_split # 如果使用 scikit-learn 0.23 以上版本,请改用 sklearn.model_selection 而不是 sklearn.externals
# 加载.pkl模型
model = joblib.load('LinearRegressor.pkl')
# 定义输入特征的类型和形状
num_features = 1 # 你的特征数量
initial_type = [('float_input', FloatTensorType([None, num_features]))]
# 导出ONNX模型
onnx_model = onnxmltools.convert.convert_sklearn(model, initial_types=initial_type)
# 保存ONNX模型为文件
onnxmltools.utils.save_model(onnx_model, 'do_LinearRegressor.onnx')
# 指定你的 ONNX 模型路径
onnx_model_path = 'do_LinearRegressor.onnx'
# 启动 Netron 服务并在浏览器中打开可视化界面
netron.start(onnx_model_path)
三、ONNX Runtime运行时
3.1 相关介绍(了解此运行时):
想深入了解可以看一下,如果想快速实践可以简单看一下或者跳过
Everything You Want to Know About ONNX
MicroSoft onnx and onnx runtim
3.2 VS、c++部署onnxruntime
c++ onnxruntime版本:1.15.1
网址:Releases · microsoft/onnxruntime · GitHub
下载onnxruntime-win-x64-1.15.1.zip
将压缩包解压得到include与lib文件夹,添加到环境变量中,然后将lib中的dll放入release与debug中
#include <iostream>
#include <assert.h>
#include <onnxruntime_cxx_api.h>
#include <onnxruntime_c_api.h>
int main() {
const wchar_t* model_path = L"do_LinearRegressor.onnx";
try {
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "ONNX_C_API");
std::wcout << L"Attempting to load model from: " << model_path << std::endl;
Ort::SessionOptions session_options;
Ort::Session session(env, model_path, session_options);
std::wcout << L"Model loaded successfully." << std::endl;
Ort::AllocatorWithDefaultOptions allocator;
// 获取输入节点信息
size_t num_input_nodes = session.GetInputCount();
size_t num_output_nodes = session.GetOutputCount();
// 定义输入和输出节点的名称向量
std::vector<const char*> input_node_names;
std::vector<const char*> output_node_names;
// 获取输入节点信息并填充到向量中
for (size_t i = 0; i < num_input_nodes; i++) {
Ort::AllocatedStringPtr in_name = session.GetInputNameAllocated(i, allocator);
const char* in_name_cstr = in_name.get(); // 获取字符串指针
std::cout << "Input Name: " << in_name_cstr << std::endl;
input_node_names.push_back(in_name_cstr);
}
// 获取输出节点信息并填充到向量中
for (size_t i = 0; i < num_output_nodes; i++) {
Ort::AllocatedStringPtr out_name = session.GetOutputNameAllocated(i, allocator);
const char* out_name_cstr = out_name.get(); // 获取字符串指针
std::cout << "Output Name: " << out_name_cstr << std::endl;
output_node_names.push_back(out_name_cstr);
}
// 设置输入数据的维度,这里以单条数据为例
std::vector<int64_t> input_node_dims = { 1, 1 };
size_t input_tensor_size = 1 * 1;
// 构造输入数据
std::vector<float> input_tensor_values(input_tensor_size);
for (unsigned int i = 0; i < input_tensor_size; i++)
{
input_tensor_values[i] = 30000;
std::cout << input_tensor_values[i] << std::endl;
}
// create input tensor object from data values
auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
Ort::Value input_tensor = Ort::Value::CreateTensor<float>(
memory_info,
input_tensor_values.data(),
input_tensor_size,
input_node_dims.data(),
input_node_dims.size()
);
assert(input_tensor.IsTensor());
std::vector<Ort::Value> ort_inputs;
ort_inputs.push_back(std::move(input_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(),
1
);
// Get pointer to output tensor float values
float* floatarr = output_tensors[0].GetTensorMutableData<float>();
std::cout << "推理结果:" << *floatarr << std::endl;
}
catch (const Ort::Exception& e) {
// 处理 Ort::Exception 异常
std::cerr << "Caught Ort::Exception: " << std::string(e.what()) << std::endl;
// 在异常描述信息中查找错误代码
size_t pos = std::string(e.what()).find("ErrorCode: ");
if (pos != std::string::npos) {
std::string error_code_str = std::string(e.what()).substr(pos + 12); // 12 是 "ErrorCode: " 的长度
int error_code = std::stoi(error_code_str);
std::cerr << "Error Code: " << error_code << std::endl;
}
// 可选:进行其他异常处理或返回错误码
return -1;
}
return 0;
}
可以参照这个:VS2019 快速配置Onnxruntime环境_onnxruntime_cxx_api.h_小wu学cv的博客-CSDN博客
c++通过onnxruntime调用sklearn_c++调用sklearn模型_欧拉欧拉木大的博客-CSDN博客
3.3 头文件引用的一些问题
网上有很多头文件就不是
#include <onnxruntime_c_api.h>
这样的而是这样的
#include <onnxruntime/core/providers/providers.h>
所以他下的是一个完整的资源,什么设备环境都有的包括各种docs文档,不是一个针对性的库,比如说x64,win,gpu的版本的库。我们用的时候主要还是要用到3.2中下载的include文件夹中的.h文件,providers.h是一个集合库,包含了很多.h文件的整合文件,并不是核心库。
那他们这些文件都在这里:
Releases · microsoft/onnxruntime · GitHub
然后我们可以根据官网的说明编译出自己想要的库,自定义性质比较强。一个简单的例子:
onnxruntime (C++/CUDA) 编译安装及部署_initcxxruntime_白色小靴的博客-CSDN博客
四、问题汇总:
1. 类没有成员
换个写法,1.15.1版本好像不这么写了,除非你换回旧版本
2. 版本兼容问题
c++onnxruntime加载onnx模型的时候发现加载的模型是未知版本,说明这个c++onnxruntime不认识,那么就需要知道生成oonx模型的库版本和推理部署的onnxruntime版本是否兼容
比如我的onnx文件是py生成的onnx版本是1.15.0,那么我的c++中的onnxruntime就需要下载部署1.15.0,如果你的c++中的onnxruntime是1.8.0,运行时onnxruntime不认识太新的onnx文件
3. 3.“GetInputName“: 不是 “Ort::Session“ 的成员
不要用GetInputName,因为已弃用,指针不安全,改成GetInputNameAllocated
不要用GetOutputName,因为已弃用,指针不安全,改成GetOutputNameAllocated
更多推荐
所有评论(0)