Onnx简要介绍
🧩 在 C# 中使用 ONNX 调用深度学习模型的完整笔记
本文系统总结了在 C# 环境中调用 ONNX 深度学习模型 的全流程,包括模型导出、模型结构分析、Metadata 信息提取、推理实现与性能优化。
一、ONNX 模型基础概念
1. 什么是 ONNX
-
ONNX(Open Neural Network Exchange) 是一种跨框架的模型中间表示格式。
-
支持 PyTorch、TensorFlow、Keras、Scikit-Learn、XGBoost 等主流框架的互通。
-
优点:
- 平台无关,跨语言部署。
- 提供推理优化(如算子融合、图剪枝)。
- 可在 C#、C++、Python、Java 等环境运行。
2. ONNX 模型文件结构
-
模型文件为
.onnx
二进制格式。 -
核心组成:
模块 说明 Graph 网络计算图 Node 每个算子(Conv、Relu、MatMul 等) Initializer 权重与偏置张量 Input/Output 模型输入输出定义 Metadata 模型元信息(版本、框架来源等)
二、ONNX 模型导出(PyTorch 示例)
1. 基本导出方式
import torch
dummy_input = torch.randn(1, 3, 224, 224)
torch.onnx.export(
model,
dummy_input,
"model.onnx",
input_names=["input"],
output_names=["output"],
opset_version=17,
dynamic_axes={
"input": {0: "batch_size"},
"output": {0: "batch_size"}
}
)
2. 导出时的注意事项
- 确保模型处于
eval()
模式。 - 动态维度能避免 batch 固定问题。
- 使用
onnx.checker.check_model()
验证模型有效性。
三、在 C# 中读取模型 Metadata 信息
在加载 ONNX 模型后,可通过
session.InputMetadata
与session.OutputMetadata
获取模型的输入输出结构信息(名称、类型、维度等)。该数据在C#中是一个字典。
1. 获取输入元数据(InputMetadata)
using Microsoft.ML.OnnxRuntime;
// 加载模型
using var session = new InferenceSession("model.onnx");
// 获取输入元数据
var inputMeta = session.InputMetadata;
Console.WriteLine("=== 模型输入信息 ===");
foreach (var item in inputMeta)
{
string name = item.Key; // 输入名称
var meta = item.Value; // Tensor 元信息
Console.WriteLine($"输入名称: {name}");
Console.WriteLine($"数据类型: {meta.ElementType}");
Console.WriteLine($"维度信息: [{string.Join(", ", meta.Dimensions)}]");
Console.WriteLine();
}
输出示例:
=== 模型输入信息 ===
输入名称: input
数据类型: Single
维度信息: [1, 3, 224, 224]
2. 获取输出元数据(OutputMetadata)
var outputMeta = session.OutputMetadata;
Console.WriteLine("=== 模型输出信息 ===");
foreach (var item in outputMeta)
{
Console.WriteLine($"输出名称: {item.Key}");
Console.WriteLine($"输出类型: {item.Value.ElementType}");
Console.WriteLine($"输出维度: [{string.Join(", ", item.Value.Dimensions)}]");
}
3. 获取模型的全局元信息(MetadataProperties)
Console.WriteLine("=== 模型全局元信息 ===");
foreach (var kvp in session.ModelMetadata.CustomMetadataMap)
{
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
Console.WriteLine($"Producer: {session.ModelMetadata.ProducerName}");
Console.WriteLine($"Graph Name: {session.ModelMetadata.GraphName}");
Console.WriteLine($"Domain: {session.ModelMetadata.Domain}");
输出示例:
=== 模型全局元信息 ===
author: torch.onnx
version: 17
Producer: pytorch
Graph Name: model_graph
Domain: ai.onnx
4. 提取输入输出名称列表
若仅需名称列表,可使用:
var inputNames = session.InputMetadata.Keys.ToList();
var outputNames = session.OutputMetadata.Keys.ToList();
Console.WriteLine("输入张量名: " + string.Join(", ", inputNames));
Console.WriteLine("输出张量名: " + string.Join(", ", outputNames));
5. 结合维度信息动态构造输入张量
// 假设模型要求输入 [1, 3, 224, 224]
var inputName = session.InputMetadata.Keys.First();
var inputShape = session.InputMetadata[inputName].Dimensions;
// 构造匹配模型输入的张量
int totalSize = inputShape.Aggregate(1, (a, b) => a * b);
var inputTensor = new DenseTensor<float>(new float[totalSize], inputShape);
✅ 这种方式可确保模型升级或导出变化时,C# 推理端仍能自动适配输入尺寸。
四、ONNX 模型查看与可视化工具
1. 使用 Netron
-
拖入
.onnx
文件即可查看:- 输入/输出名称与 shape
- 每层算子结构与连接关系
- 参数数量与数据流
2. Python 端快速查看
import onnx
model = onnx.load("model.onnx")
for i in model.graph.input:
print(i.name, [d.dim_value for d in i.type.tensor_type.shape.dim])
五、C# 模型推理与性能优化(简要)
1. 基础推理
var inputName = session.InputMetadata.Keys.First();
var tensor = new DenseTensor<float>(inputData, new[] { 1, 3, 224, 224 });
var inputs = new List<NamedOnnxValue>
{
NamedOnnxValue.CreateFromTensor(inputName, tensor)
};
using var results = session.Run(inputs);
var output = results.First().AsTensor<float>().ToArray();
2. 优化建议
优化方向 | 方法 |
---|---|
Session 重用 | 复用同一 InferenceSession 实例 |
图优化 | GraphOptimizationLevel.ORT_ENABLE_ALL |
GPU 加速 | AppendExecutionProvider_CUDA(0) |
异步推理 | 使用 RunAsync() |
六、总结
- 导出时务必设置动态轴与合适的 opset。
- 在 C# 端可通过 InputMetadata / OutputMetadata 动态解析模型输入输出信息。
- 可利用 ModelMetadata 提取模型作者、框架、域等信息,便于版本管理。
- 建议结合 Netron 与 Metadata 双重方式了解模型结构,确保推理正确性。
📚 推荐资源: