ONNX Runtime C++ 库

ONNX Runtime 为 C++ 提供了完整的推理 API,你可以通过集成它来在 C++ 项目中高效地运行 ONNX 模型。

一、如何获取 ONNX Runtime C++ 库

在你的 C++ 项目中使用 ONNX Runtime,主要有两种方式:

  • 使用预编译库(推荐):这是最简单的入门方式。你可以从 ONNX Runtime 官方网站的 Releases 页面下载适用于你平台(如 Windows、Linux、macOS)的 C/C++ 预编译库。这些库通常包含了核心的推理功能。
  • 从源码编译:如果你有特殊需求,比如需要支持特定的硬件(如 GPU、OpenVINO、NNAPI),或希望定制库的大小(例如为移动端进行精简),则需要从源码编译。官方 GitHub 仓库提供了详细的构建指南。例如,在 Linux 下启用 CUDA 支持的基本步骤是:bashgit clone --recursive https://github.com/microsoft/onnxruntime.git cd onnxruntime ./build.sh --config RelWithDebInfo --build_shared_lib --use_cuda

二、C++ API 的结构

ONNX Runtime 的 C++ API 是 C API 的一个“头文件-only”的封装,设计得比较现代,符合 C++ 的使用习惯。核心的 API 都包含在两个主要的头文件中:

  • onnxruntime_cxx_api.h:这是 C++ 开发主要使用的头文件。它定义了 Ort:: 命名空间下的所有 C++ 类,如 Env(环境)、Session(推理会话)、MemoryInfo(内存信息)、Value(张量)等。这些类利用 RAII(资源获取即初始化)机制自动管理内存,并通过抛出异常来处理错误,让代码更简洁安全。
  • onnxruntime_c_api.h:这是底层的 C API,提供了 OrtApi 结构体,包含所有以 Ort 开头的函数(如 OrtCreateSession)。C++ API 是基于此实现的。虽然可以直接使用 C API,但通常更推荐使用更方便的 C++ 封装。

三、C++ 基础推理流程

在 C++ 中使用 ONNX Runtime 进行模型推理,一般遵循以下几个典型步骤:

  1. 包含头文件:在你的代码中包含 ONNX Runtime 的头文件。cpp#include <onnxruntime_cxx_api.h> #include <vector> // ... 其他标准头文件
  2. 创建环境和会话选项:首先,创建一个 Ort::Env 对象来管理推理环境的日志和全局状态。然后,创建 Ort::SessionOptions 对象来配置会话,例如设置优化级别、线程数等。cppOrt::Env env(ORT_LOGGING_LEVEL_WARNING, "test"); Ort::SessionOptions session_options; session_options.SetIntraOpNumThreads(1); // 如果需要,可以在这里添加其他执行提供程序,如 CPU、CUDA 等
  3. 加载模型并创建会话:使用上一步创建的环境和选项,加载模型文件(.onnx)并创建 Ort::Session 对象。会话是执行推理的核心对象。cppconst char* model_path = "path/to/your/model.onnx"; Ort::Session session(env, model_path, session_options);
  4. 准备输入数据
    • 获取输入输出信息:通过 session.GetInputCount()session.GetInputName()session.GetInputTypeInfo() 等方法,动态获取模型期望的输入名称、维度(shape)和数据类型。
    • 构建输入张量:将你的数据(例如预处理后的图像数据)填充到 std::vector 中。然后,使用 Ort::Value::CreateTensor() 创建一个 ONNX Runtime 张量,你需要提供数据指针、数据大小、维度信息以及数据的内存信息。
  5. 运行推理:调用 session.Run() 方法,传入输入张量的名称和值,以及你想要获取的输出张量名称。函数会返回一个 std::vector<Ort::Value>,包含了推理结果。cppconst char* input_names[] = {"input"}; const char* output_names[] = {"output"}; std::vector<Ort::Value> input_tensors; // ... 创建并填充 input_tensors ... auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names, input_tensors.data(), 1, output_names, 1);
  6. 处理输出:从返回的 Ort::Value 对象中提取数据,并进行后续处理,例如解析分类结果或显示检测框。

四、完整示例

#include <onnxruntime_cxx_api.h> #include <vector> #include <iostream> #include <exception> int main() { try { // 1. 创建推理环境(指定日志级别和名称) Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "example"); // 2. 配置会话选项 Ort::SessionOptions session_options; session_options.SetIntraOpNumThreads(1); // 线程数 // 若要使用 GPU,可在此添加 CUDA 执行提供程序(需编译时启用 CUDA) // OrtSessionOptionsAppendExecutionProvider_CUDA(session_options, 0); // 3. 加载 ONNX 模型(请替换为你的模型路径) const std::string model_path = "linear_model.onnx"; Ort::Session session(env, model_path.c_str(), session_options); // 4. 获取模型输入/输出信息 Ort::AllocatorWithDefaultOptions allocator; // 输入信息 size_t num_inputs = session.GetInputCount(); std::vector<const char*> input_names; std::vector<Ort::AllocatedStringPtr> input_names_ptr; std::vector<std::vector<int64_t>> input_shapes; std::cout << "Number of inputs: " << num_inputs << std::endl; for (size_t i = 0; i < num_inputs; ++i) { auto name = session.GetInputNameAllocated(i, allocator); std::cout << "Input [" << i << "] name: " << name.get() << std::endl; input_names_ptr.push_back(std::move(name)); auto type_info = session.GetInputTypeInfo(i); auto tensor_info = type_info.GetTensorTypeAndShapeInfo(); auto shape = tensor_info.GetShape(); input_shapes.push_back(shape); std::cout << " shape: [ "; for (auto dim : shape) std::cout << dim << " "; std::cout << "]" << std::endl; } // 输出信息 size_t num_outputs = session.GetOutputCount(); std::vector<const char*> output_names; std::vector<Ort::AllocatedStringPtr> output_names_ptr; std::cout << "Number of outputs: " << num_outputs << std::endl; for (size_t i = 0; i < num_outputs; ++i) { auto name = session.GetOutputNameAllocated(i, allocator); std::cout << "Output [" << i << "] name: " << name.get() << std::endl; output_names_ptr.push_back(std::move(name)); } // 构建名称指针数组(用于 Run 接口) for (const auto& ptr : input_names_ptr) input_names.push_back(ptr.get()); for (const auto& ptr : output_names_ptr) output_names.push_back(ptr.get()); // 5. 准备输入数据(以第一个输入的 shape 为准) // 假设第一个输入形状为 [1, 10] 的 float 张量 const std::vector<int64_t>& first_input_shape = input_shapes[0]; size_t input_size = 1; for (auto dim : first_input_shape) input_size *= dim; std::vector<float> input_data(input_size); for (size_t i = 0; i < input_size; ++i) { input_data[i] = static_cast<float>(i); // 填充一些测试数据 } // 创建 CPU 内存信息 Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); // 创建输入张量 Ort::Value input_tensor = Ort::Value::CreateTensor<float>( memory_info, input_data.data(), input_data.size(), first_input_shape.data(), first_input_shape.size() ); // 6. 运行推理 std::vector<Ort::Value> input_tensors; input_tensors.push_back(std::move(input_tensor)); std::vector<Ort::Value> output_tensors = session.Run( Ort::RunOptions{nullptr}, input_names.data(), input_tensors.data(), input_tensors.size(), output_names.data(), output_names.size() ); // 7. 处理输出(假设输出为 float 张量) float* output_data = output_tensors[0].GetTensorMutableData<float>(); auto output_info = output_tensors[0].GetTensorTypeAndShapeInfo(); auto output_shape = output_info.GetShape(); size_t output_count = output_info.GetElementCount(); std::cout << "Output shape: [ "; for (auto dim : output_shape) std::cout << dim << " "; std::cout << "]" << std::endl; std::cout << "Output data: "; for (size_t i = 0; i < output_count; ++i) { std::cout << output_data[i] << " "; } std::cout << std::endl; } catch (const Ort::Exception& e) { std::cerr << "ONNX Runtime error: " << e.what() << std::endl; return -1; } catch (const std::exception& e) { std::cerr << "Standard error: " << e.what() << std::endl; return -1; } return 0; }
如何生成测试模型(Python)

上述示例需要一个 ONNX 模型。以下 Python 脚本可生成一个简单的线性模型 linear_model.onnx(输入 x 形状为 [1,10],输出 y 形状为 [1,10]):

import onnx from onnx import helper, TensorProto, numpy_helper import numpy as np # 创建随机权重和偏置 W = np.random.randn(10, 10).astype(np.float32) b = np.random.randn(10).astype(np.float32) # 定义输入输出 x = helper.make_tensor_value_info('x', TensorProto.FLOAT, [1, 10]) y = helper.make_tensor_value_info('y', TensorProto.FLOAT, [1, 10]) # 创建初始值 W_initializer = numpy_helper.from_array(W, name='W') b_initializer = numpy_helper.from_array(b, name='b') # 创建节点(Gemm 实现线性变换 y = x * W^T + b) node = helper.make_node('Gemm', inputs=['x', 'W', 'b'], outputs=['y']) # 构建图 graph = helper.make_graph([node], 'linear_graph', [x], [y], initializer=[W_initializer, b_initializer]) # 构建模型 model = helper.make_model(graph, producer_name='example') # 保存模型 onnx.save(model, 'linear_model.onnx') print("模型已保存为 linear_model.onnx")

运行该脚本生成模型文件,然后将 model_path 指向该文件。

编译与运行
Linux / macOS

假设 ONNX Runtime 安装在 /path/to/onnxruntime,编译命令如下:

bash

g++ -std=c++11 -I/path/to/onnxruntime/include \ -L/path/to/onnxruntime/lib -lonnxruntime \ example.cpp -o example

如果 ONNX Runtime 安装到了系统路径(如 /usr/local),可以简化:

bash

g++ -std=c++11 example.cpp -lonnxruntime -o example

运行前确保动态库路径可找到(Linux 上可设置 LD_LIBRARY_PATH):

bash

export LD_LIBRARY_PATH=/path/to/onnxruntime/lib:$LD_LIBRARY_PATH ./example

Windows

使用 Visual Studio 开发人员命令提示符:

bash

cl /EHsc /I C:\path\to\onnxruntime\include example.cpp ^ /link /LIBPATH:C:\path\to\onnxruntime\lib onnxruntime.lib

运行前将 onnxruntime.dll 放在可执行文件目录或系统路径中。

说明
  • 代码自动获取输入张量的实际形状并分配数据,但假设数据类型为 float。如果你的模型输入是其他类型(如 int64),需要相应调整 CreateTensor 的模板参数和数据填充。
  • 如果模型有多个输入,需要为每个输入创建一个 Ort::Value 并放入 input_tensors 向量,同时确保输入名称顺序与模型一致。
  • 错误处理统一使用 try-catch,ONNX Runtime 的 C++ API 在出错时会抛出 Ort::Exception
  • 如需 GPU 支持,可在 session_options 中添加相应的执行提供程序(如 OrtSessionOptionsAppendExecutionProvider_CUDA),并确保 ONNX Runtime 库为 GPU 版本。

Read more

【数据结构与算法】环与相遇:链表带环问题的底层逻辑与工程实现

【数据结构与算法】环与相遇:链表带环问题的底层逻辑与工程实现

🔥小龙报:个人主页 🎬作者简介:C++研发,嵌入式,机器人等方向学习者 ❄️个人专栏:《C语言》《【初阶】数据结构与算法》 ✨ 永远相信美好的事情即将发生 文章目录 * 前言 * 一、带环链表 * 1.1题目 * 1.2 算法原理 * 1.3 代码 * 1.4 数学证明 * 1.4.1 为什么带环slow与fast必定能相遇? * 1.4.2 fast一定只能走2步吗?可以是2步甚至更多吗? * 1.4.2.1 以3步为例 * 1.4.3结论 * 二、环形链表(寻找相遇点) * 2.1 题目

By Ne0inhk
安装Anaconda+Python(2025超详细)

安装Anaconda+Python(2025超详细)

目录 第一步:下载Anaconda 第二步:安装Anaconda 第三步:配置环境变量 第四步:检查是否成功 第五步:添加快捷方式并打开   第一步:下载Anaconda 方法一: 登录Anaconda官网。(比较慢,略过,用方法二) 方法二:镜像网站下载:点击这里到清华镜像站下载 第二步:安装Anaconda 1.双击安装 2.点击 Next 3.点击 I Agree 4.选择 All Users,Next 5.选安装路径(最好不要C盘) 6.只选择第二个:默认带python环境 7.等待安装,注意:安装前关掉杀毒软件(例如火绒),否则进度条可能卡住 8.

By Ne0inhk
毕业设计源码:基于Python的 青听音乐在线平台 Django MySQL HTML-CSS-JS 人工智能 大数据 (建议收藏)✅

毕业设计源码:基于Python的 青听音乐在线平台 Django MySQL HTML-CSS-JS 人工智能 大数据 (建议收藏)✅

博主介绍:✌全网粉丝50W+,前互联网大厂软件研发、集结硕博英豪成立软件开发工作室,专注于计算机相关专业项目实战6年之久,累计开发项目作品上万套。凭借丰富的经验与专业实力,已帮助成千上万的学生顺利毕业,选择我们,就是选择放心、选择安心毕业✌ > 🍅想要获取完整文章或者源码,或者代做,拉到文章底部即可与我联系了。🍅 点击查看作者主页,了解更多项目! 🍅感兴趣的可以先收藏起来,点赞、关注不迷路,大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,希望帮助同学们顺利毕业 。🍅 1、毕业设计:2026年计算机专业毕业设计选题汇总(建议收藏)✅ 2、最全计算机大数据专业毕业设计选题大全(建议收藏)✅ 1、项目介绍 技术栈 本系统采用Python语言进行开发,基于Django框架搭建web应用,使用MySQL数据库存储音乐信息和用户数据。前端界面通过CSS、JavaScript和HTML进行设计,实现用户交互与页面展示。 功能模块 · 系统首页 · 音乐播放功能 · 歌曲排行榜 · 个人信息页面 · 音乐评论 · 数据管理页面 项目介绍 音乐在线播放系统是一个基

By Ne0inhk
Python数学可视化——显函数、隐函数及复杂曲线的交互式绘图技术

Python数学可视化——显函数、隐函数及复杂曲线的交互式绘图技术

Python数学可视化——显函数、隐函数及复杂曲线的交互式绘图技术 一、引言 在科学计算和数据分析中,函数与方程的可视化是理解数学关系和物理现象的重要工具。本文基于Python的Tkinter和Matplotlib库,实现一个功能完善的函数与方程可视化工具,支持显函数、隐函数、特殊曲线(如心形线)及物理场分布(如电势)的交互式绘图,并提供安全的表达式解析、图像保存等功能。 二、核心技术架构 2.1 系统架构与技术选型 * 界面层:使用Tkinter构建GUI,包含类型选择、表达式输入、预设函数下拉菜单等控件 * 计算层: * 显函数:通过np.linspace生成采样点,安全计算函数值 * 隐函数:基于等高线算法contour绘制等值线 * 安全机制:通过正则表达式过滤非法字符,限制白名单函数防止代码注入 * 可视化层:Matplotlib实现图表渲染,支持动态更新和交互式工具条 2.2 安全表达式解析 defis_valid_expression(expr):""

By Ne0inhk