VS c++ onnxruntime 环境配置、onnx教程、部署推理模型、sklearn pkl模型转onnx、问题汇总

目录

一、初步认识ONNX

二、pkl转ONNX+可视化模型

三、ONNX Runtime运行时

3.1 相关介绍(了解此运行时):

3.2 VS、c++部署onnxruntime

3.3 头文件引用的一些问题

四、问题汇总:

1. 类没有成员

2. 版本兼容问题

3. 3.“GetInputName“: 不是 “Ort::Session“ 的成员


官网:ONNX Runtime | Home

GitHub - microsoft/onnxruntime

一、初步认识ONNX

一图看懂ONNX模型格式

ONNX学习笔记

Onnx模型介绍_HelloWorldQAQ。的博客-CSDN博客

ONNX(Open Neural Network Exchange)是一个开放的深度学习模型交换格式,它的目标是提供一个标准化的桥梁,使得不同深度学习框架之间能够更轻松地共享和部署模型。

ONNX 的主要特点和目标包括:

  1. 开放性: ONNX 是一个开放标准,由微软、Facebook和其他合作伙伴共同推动。它的目标是促进深度学习生态系统的互操作性。
  2. 跨平台: ONNX 支持在不同的深度学习框架之间交换模型。目前,它支持诸如PyTorch、TensorFlow、MXNet等流行的深度学习框架。
  3. 灵活性: ONNX 支持多种深度学习模型的表示,包括卷积神经网络(CNN)、循环神经网络(RNN)和其他常见的神经网络架构。
  4. 部署: 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 相关介绍(了解此运行时):

想深入了解可以看一下,如果想快速实践可以简单看一下或者跳过

模型部署之 ONNX ONNXRuntime

推理模型部署(一):ONNX runtime 实践

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

“GetInputName“: 不是 “Ort::Session“ 的成员-CSDN博客

  • 20
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
C++中调用Pythonsklearn训练好的pkl模型,可以使用PythonC++接口来实现。PythonC++接口提供了一组函数和类,使得C++能够直接调用Python的函数和对象,并且能够传递Python对象到C++中。 下面是一个简单的例子,展示如何在C++中调用Pythonsklearn训练好的pkl模型: 1. 首先需要安装PythonC++接口库pybind11,可以使用pip安装: ``` pip install pybind11 ``` 2. 在C++代码中引入pybind11库头文件,并且定义需要调用的Python函数和模型路径: ```c++ #include <pybind11/embed.h> #include <pybind11/stl.h> namespace py = pybind11; // 定义Python函数和模型路径 std::string predict_func = "predict"; std::string model_path = "model.pkl"; ``` 3. 在需要调用Python函数的地方,初始化Python解释器并加载模型: ```c++ // 初始化Python解释器 py::scoped_interpreter guard{}; // 加载模型 py::object model = py::module::import("sklearn.externals.joblib").attr("load")(model_path); ``` 4. 调用Python函数并传递数据: ```c++ // 调用Python函数 py::object predict_func_obj = model.attr(predict_func.c_str()); py::list input = py::cast(data); py::object result = predict_func_obj(input); // 将Python返回值换为C++类型 std::vector<int> output = py::cast<std::vector<int>>(result); ``` 完整的代码示例: ```c++ #include <pybind11/embed.h> #include <pybind11/stl.h> namespace py = pybind11; std::string predict_func = "predict"; std::string model_path = "model.pkl"; int main() { // 初始化Python解释器 py::scoped_interpreter guard{}; // 加载模型 py::object model = py::module::import("sklearn.externals.joblib").attr("load")(model_path); // 准备输入数据 std::vector<std::vector<double>> data = {{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}}; // 调用Python函数 py::object predict_func_obj = model.attr(predict_func.c_str()); py::list input = py::cast(data); py::object result = predict_func_obj(input); // 将Python返回值换为C++类型 std::vector<int> output = py::cast<std::vector<int>>(result); // 输出结果 for (auto i : output) { std::cout << i << " "; } std::cout << std::endl; return 0; } ``` 注意,需要在C++代码中引入需要使用的Python库,例如sklearn.externals.joblib等。另外需要注意的是,如果使用了虚拟环境,需要在初始化Python解释器之前设置环境变量PYTHONHOME和PYTHONPATH,以便正确地加载Python库。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AIScholar_lrm

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

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

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

打赏作者

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

抵扣说明:

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

余额充值