17370845950

如何使用c++和ONNX Runtime部署深度学习模型? (AI推理)
C++可直接调用ONNX Runtime实现高性能轻量部署,需严格匹配模型输入输出名称、shape与dtype,正确管理内存并配置执行提供者与优化选项。

可以直接用 C++ 调用 ONNX Runtime 进行模型推理,无需 Python 中转,性能高、部署轻量。关键在于正确加载模型、匹配输入输出张量形状与数据类型,并避免内存生命周期错误。

ONNX Runtime C++ API 初始化和会话创建

必须显式设置 Ort::EnvOrt::SessionOptions,否则默认行为可能触发调试日志或禁用优化。Windows 下若链接失败,大概率是没正确导入 onnxruntime.lib(不是 DLL)或 ABI 不匹配(如 /MD 与 /MT 混用)。

  • Ort::Env 建议用 ORT_LOGGING_LEVEL_WARNING 避免刷屏
  • 启用图优化:调用 session_options.SetGraphOptimizationLevel(ORT_ENABLE_ALL)
  • CUDA 执行提供者需手动注册:OrtSessionOptionsAppendExecutionProvider_CUDA(options, 0),且必须在 Ort::Session 构造前完成
  • Linux *意 LD_LIBRARY_PATH 包含 libonnxruntime.so 路径

输入张量构造与内存管理

ONNX Runtime 不接管用户分配的内存,Ort::Value::CreateTensor 的第 4 个参数(data pointer)必须保证在整个 Run() 调用期间有效。常见崩溃源于栈内存传入或提前 free()

  • 推荐用 std::vector 分配输入数据,再用 .data() 传指针
  • 输入 shape 必须与模型期望完全一致,包括 batch 维度 —— 即使只推一个样本也要是 {1, 3, 224, 224},不能是 {3, 224, 224}
  • 数据排布默认是 NCHW;若模型导出为 NHWC,需在预处理时重排,或用 Ort::Value::CreateTensor 指定 Ort::MemoryInfo::CreateCpu(..., OrtArenaAllocator) 并自行处理 layout
  • 图像归一化必须与训练时一致:例如 (pixel - [123.675, 116.28, 103.53]) / [58.395, 57.12, 57.375],顺序错会导致输出全零

运行推理并读取输出结果

session.Run() 返回的是 std::vector<:value>,每个元素对应一个输出节点。直接调用 .GetTensorData() 得到指针,但必须先确认输出 shape 和数据类型,否则越界读写。

  • output_values[0].GetTensorTypeAndShapeInfo().GetShape() 检查维度,比如分类模型常为 {1, 1000}
  • output_values[0].GetTensorTypeAndShapeInfo().GetElementType() 确认是否为 ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT
  • 不要假设输出名是 "output" —— 查看模型用 netrononnx.shape_inference.infer_shapes() 确认实际 output name
  • 若输出是 int64(如 token ids),需用 .GetTensorData(),混用类型会读出垃圾值
Ort::Session session(env, L"model.onnx", session_options);
std::vector input_names = {"input"};
std::vector output_names = {"output"};

std::vector input_shape = {1, 3, 224, 224}; std::vector input_tensor_values(1 3 224 * 224, 0.0f); // ... 填充 input_tensor_values

auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAlloc

ator, OrtMemTypeDefault); auto input_tensor = Ort::Value::CreateTensor( memory_info, input_tensor_values.data(), input_tensor_values.size(), input_shape.data(), input_shape.size());

auto output_tensors = session.Run( Ort::RunOptions{nullptr}, input_names.data(), &input_tensor, 1, output_names.data(), 1 );

float* output_data = output_tensors[0].GetTensorData(); std::vector output_shape = output_tensors[0].GetTensorTypeAndShapeInfo().GetShape();

最易被忽略的是:模型输入/输出名称、shape、dtype 三者必须与 ONNX 文件定义严格一致,任何一项不匹配都会导致静默错误(如输出全零)或段错误。建议首次部署时用 Python 的 onnxruntime.InferenceSession 同样输入跑一遍,比对输出数值和 shape,再迁移到 C++。