跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++AI算法

ONNX Runtime C++ 推理入门与实战

ONNX Runtime C++ 库为 C++ 项目提供了高效的模型推理能力。涵盖库的获取方式(预编译或源码)、核心 API 结构解析、基础推理流程及完整代码示例。内容包括环境配置、会话创建、张量构建、推理执行与结果处理,并附带 Python 测试模型生成脚本及 Linux/Windows 编译运行指南。重点强调异常处理机制、GPU 支持配置及内存管理细节,帮助开发者快速上手集成。

心动瞬间发布于 2026/3/16更新于 2026/10/792 浏览

ONNX Runtime C++ 推理入门与实战

ONNX Runtime 为 C++ 提供了完整的推理 API,集成它可以在现有项目中高效运行 ONNX 模型。本文将带你从环境搭建到代码实现,完整梳理 C++ 端的推理流程。

获取库文件

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

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

API 结构概览

ONNX Runtime 的 C++ API 是对底层 C API 的现代封装,设计符合 C++ 习惯。核心接口主要包含在两个头文件中:

  • 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++ 中使用 ONNX Runtime 进行模型推理,一般遵循以下几个典型步骤:

  1. 包含头文件:在你的代码中包含 ONNX Runtime 的头文件。
  2. 创建环境和会话选项:首先,创建一个 Ort::Env 对象来管理推理环境的日志和全局状态。然后,创建 Ort::SessionOptions 对象来配置会话,例如设置优化级别、线程数等。
  3. 加载模型并创建会话:使用上一步创建的环境和选项,加载模型文件(.onnx)并创建 Ort::Session 对象。会话是执行推理的核心对象。
  4. 准备输入数据:通过 session.GetInputCount()、session.GetInputName() 等方法,动态获取模型期望的输入名称、维度(shape)和数据类型。将你的数据填充到 std::vector 中,然后使用 Ort::Value::CreateTensor() 创建一个 ONNX Runtime 张量。
  5. 运行推理:调用 session.Run() 方法,传入输入张量的名称和值,以及你想要获取的输出张量名称。函数会返回一个 std::vector<Ort::Value>,包含了推理结果。
  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,编译命令如下:

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

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

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

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

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

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

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 版本。

目录

  1. ONNX Runtime C++ 推理入门与实战
  2. 获取库文件
  3. API 结构概览
  4. 基础推理流程
  5. 完整示例
  6. 生成测试模型(Python)
  7. 创建随机权重和偏置
  8. 定义输入输出
  9. 创建初始值
  10. 创建节点(Gemm 实现线性变换 y = x * W^T + b)
  11. 构建图
  12. 构建模型
  13. 保存模型
  14. 编译与运行
  15. Linux / macOS
  16. Windows
  17. 注意事项

更多推荐文章

查看全部
  • 程序员转行大模型:核心高薪岗位解析与技能要求
  • Flutter 三方库 arcane_helper_utils 鸿蒙化适配指南
  • JNI 本质解析:Android Framework 下的 Java-Native 衔接机制
  • Cursor 辅助开发:Web 背单词应用实战指南
  • 树莓派智能家居毕设:AI 辅助开发与边缘推理实战
  • C++ 关联式容器详解:set、map 及其变体
  • 前端函数防抖详解
  • RAG 知识库调优方案深度解析:学术界检索前优化实践
  • BPMN 边界事件详解及代码实现
  • Llama3-8B 实测对比:逻辑推理与编码能力评估
  • VS Code 配置 C/C++ 开发环境指南(支持万能头文件)
  • Higress 网关实战:REST API 转 MCP Server 工具配置指南
  • 666 条数据训练 AI 写万字长文,模型数据集开源
  • Webhook 核心原理及 Langflow 自动化工作流实践
  • 鸿蒙金融理财全栈项目:安全合规与用户体验优化
  • LangChain 调用国产大模型实战:以智谱 AI 为例
  • Windows 10/11 部署 OpenClaw 指南:环境搭建与机器人互联
  • 前端 pnpm workspace 架构详解
  • Git 版本控制基础操作指南
  • 企业级 Web 大学生一体化服务平台管理系统:SpringBoot+Vue+MyBatis 架构

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online