共计 3329 个字符,预计需要花费 9 分钟才能阅读完成。
背景与痛点
在传统的 C ++ 项目中直接使用原始模型格式(如 TensorFlow 的.pb 或 PyTorch 的.pt)进行推理时,往往会遇到以下问题:

- 模型格式与框架强绑定,跨框架部署困难
- 缺乏统一的运行时优化接口,性能难以保证
- 内存管理复杂,容易造成泄漏
- 多线程支持不足,无法充分利用硬件资源
ONNX(Open Neural Network Exchange)格式的出现解决了这些问题。作为开放的标准格式,ONNX 具有以下优势:
- 框架无关性:支持 PyTorch、TensorFlow 等主流框架导出的模型
- 运行时优化:ONNX Runtime 提供统一的优化推理接口
- 跨平台支持:可在各种操作系统和设备上运行
- 性能保证:内置多种图优化和加速技术
环境配置
Linux/macOS 安装
-
下载预编译包
wget https://github.com/microsoft/onnxruntime/releases/download/v1.10.0/onnxruntime-linux-x64-1.10.0.tgz tar -xzvf onnxruntime-linux-x64-1.10.0.tgz -
设置环境变量
export ONNXRUNTIME_HOME=/path/to/onnxruntime export LD_LIBRARY_PATH=$ONNXRUNTIME_HOME/lib:$LD_LIBRARY_PATH
Windows 安装
-
使用 vcpkg 安装
vcpkg install onnxruntime -
或者下载预编译包并配置 VS 项目属性
CMake 集成
find_package(onnxruntime REQUIRED)
target_link_libraries(your_target PRIVATE onnxruntime::onnxruntime)
核心实现
模型加载与初始化
-
创建推理会话
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "test"); Ort::SessionOptions session_options; session_options.SetIntraOpNumThreads(1); session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); Ort::Session session(env, "model.onnx", session_options); -
获取输入输出信息
Ort::AllocatorWithDefaultOptions allocator; // 获取输入信息 std::vector<const char*> input_names; std::vector<int64_t> input_shape; Ort::TypeInfo input_type_info = session.GetInputTypeInfo(0); auto input_tensor_info = input_type_info.GetTensorTypeAndShapeInfo(); input_shape = input_tensor_info.GetShape(); // 获取输出信息(类似)
输入 / 输出张量管理
-
创建输入张量
std::vector<float> input_data = {...}; // 你的输入数据 std::vector<Ort::Value> input_tensors; input_tensors.push_back(Ort::Value::CreateTensor<float>(allocator.GetInfo(), input_data.data(), input_data.size(), input_shape.data(), input_shape.size())); -
执行推理
auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names.data(), input_tensors.data(), input_tensors.size(), output_names.data(), output_names.size());
同步 / 异步接口对比
-
同步接口:简单直接,适合低延迟场景
auto outputs = session.Run(...); -
异步接口:适合高吞吐场景
Ort::RunOptions run_options; run_options.SetRunTag("async_run"); session.RunAsync(run_options, ...);
性能优化
模型量化
-
使用 ONNX Runtime 提供的量化工具
python -m onnxruntime.quantization.preprocess \ --input model.onnx \ --output model_quant.onnx \ --opset 13 -
在 C ++ 中加载量化模型
Ort::SessionOptions session_options; session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
多线程配置
-
设置线程数
session_options.SetIntraOpNumThreads(4); // 算子内并行 session_options.SetInterOpNumThreads(2); // 算子间并行 -
使用线程池
OrtThreadingOptions threading_options; Ort::GetApi().CreateThreadingOptions(&threading_options); Ort::GetApi().SetGlobalThreadPoolSize(threading_options, 4); session_options.SetExecutionMode(ExecutionMode::ORT_PARALLEL);
GPU 加速
- CUDA EP 配置
Ort::SessionOptions session_options; session_options.AppendExecutionProvider_CUDA( OrtCUDAProviderOptions{ .device_id = 0, .cudnn_conv_algo_search = OrtCudnnConvAlgoSearchExhaustive, .arena_extend_strategy = 1, .do_copy_in_default_stream = 1, .has_user_compute_stream = 0, .default_memory_arena_cfg = nullptr } );
生产环境注意事项
模型版本兼容
- 使用固定版本的 ONNX opset
- 在生产环境和开发环境使用相同的 ONNX Runtime 版本
内存泄漏排查
- 使用 Ort::MemoryInfo 跟踪内存分配
- 定期检查 Ort::Allocator 的统计信息
性能监控
- 使用 Ort::RunOptions 收集计时信息
Ort::RunOptions run_options; run_options.SetRunLogVerbosityLevel(1); run_options.SetRunTag("profiling_run");
基准测试
测试方法
- 预热运行 10 次
- 正式测试 1000 次,统计平均延迟
- 使用不同批量大小测试吞吐量
测试结果示例
| 优化方法 | 平均延迟 (ms) | 吞吐量 (qps) |
|---|---|---|
| CPU 原始 | 45.2 | 22.1 |
| CPU+ 量化 | 28.7 | 34.8 |
| GPU 原始 | 12.3 | 81.3 |
| GPU+ 量化 | 8.5 | 117.6 |
进阶思考
- 如何实现动态批处理以进一步提高吞吐量?
- 在多模型部署场景下,如何优化资源共享?
- 当模型输入尺寸动态变化时,如何保证最佳性能?
通过本文的介绍,我们全面了解了在 C ++ 项目中使用 ONNX Runtime 进行高效模型推理的完整流程。从环境配置到核心实现,再到性能优化和生产环境注意事项,每个环节都需要仔细考虑才能获得最佳性能。希望这些实践经验能帮助你在实际项目中顺利部署 ONNX 模型。
正文完
