C# 与 ONNX:在 .NET 中部署机器学习模型

2026-01-31 23:50:00 · 2 minute read

ONNX(Open Neural Network Exchange)是一种开放的神经网络交换格式,让机器学习模型可以在不同框架之间无缝迁移。对于 .NET 开发者来说,C# 与 ONNX 的结合提供了一个高效、低延迟的模型部署方案。

什么是 ONNX

ONNX 是微软和 Facebook 联合推出的开源项目,旨在解决机器学习模型的互操作性问题。它提供了一个标准的格式,使得在一个框架(如 PyTorch、TensorFlow)中训练的模型可以在另一个框架中推理运行。

关键特性:

为什么选择 C# + ONNX

在 .NET 生态中使用 ONNX 有显著优势:

安装 ONNX Runtime

在 C# 项目中使用 ONNX,首先需要安装 ONNX Runtime NuGet 包:

dotnet add package Microsoft.ML.OnnxRuntime
dotnet add package Microsoft.ML.OnnxRuntime.Managed

两个包的区别:

加载和运行模型

以下是一个完整的示例,展示如何加载 ONNX 模型并进行推理:

using Microsoft.ML.OnnxRuntime;
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static async Task Main(string[] args)
    {
        // 1. 加载 ONNX 模型
        string modelPath = "model.onnx";
        using InferenceSession session = new InferenceSession(modelPath);

        // 2. 准备输入数据
        var inputName = session.InputNames[0];
        var inputShape = new long[] { 1, 3, 224, 224 };
        var inputData = new float[inputShape[0] * inputShape[1] * inputShape[2] * inputShape[3]];

        // 填充输入数据(此处用随机数据作为示例)
        var random = new Random();
        for (int i = 0; i < inputData.Length; i++)
        {
            inputData[i] = (float)random.NextDouble();
        }

        // 3. 创建输入 Tensor
        using var inputTensor = new DenseTensor<float>(inputData, inputShape);

        // 4. 运行推理
        IDisposableReadOnlyCollection<DisposableNamedOnnxValue> inputs =
            new List<DisposableNamedOnnxValue>
            {
                DisposableNamedOnnxValue.CreateFromTensor(inputTensor)
            };

        IDisposableReadOnlyCollection<DisposableNamedOnnxValue> outputs =
            InferenceSession.Run(inputs, session.OutputNames);

        // 5. 获取输出结果
        var outputTensor = outputs[0].AsTensor<float>();
        float[] result = outputTensor.ToArray();

        // 输出结果
        Console.WriteLine($"预测结果: {result.Length} 个元素");
        Console.WriteLine($"最大值: {result.Max()}");
    }
}

代码解析

  1. 加载模型:使用 InferenceSession 类加载 .onnx 文件
  2. 准备输入:创建符合模型输入形状的 Tensor
  3. 运行推理:调用 Run 方法执行前向传播
  4. 获取输出:从输出 Tensor 中提取预测结果

性能优化技巧

1. 使用正确的后端

ONNX Runtime 支持多种执行提供者(Execution Provider),根据硬件自动选择最优方案:

var sessionOptions = new SessionOptions();
sessionOptions.AppendExecutionProvider("CUDAExecutionProvider");
sessionOptions.AppendExecutionProvider("TensorrtExecutionProvider");
var session = new InferenceSession(modelPath, sessionOptions);

2. 内存管理

避免频繁创建和销毁 Session,尽量复用:

public class ModelService : IDisposable
{
    private readonly InferenceSession _session;

    public ModelService(string modelPath)
    {
        _session = new InferenceSession(modelPath);
    }

    public float[] Predict(float[] input)
    {
        // 复用 Session,避免重复加载
        using var inputTensor = new DenseTensor<float>(input);
        var outputs = _session.Run(new[] {
            DisposableNamedOnnxValue.CreateFromTensor(inputTensor)
        }, _session.OutputNames);

        return outputs[0].AsTensor<float>().ToArray();
    }

    public void Dispose()
    {
        _session?.Dispose();
    }
}

3. 批处理推理

如果可能,将多个样本打包成一个批次进行推理,减少调用次数:

var batchSize = 32;
var inputShape = new long[] { batchSize, 3, 224, 224 };
var inputData = new float[batchSize * 3 * 224 * 224];

// 单次推理返回 32 个结果,而不是 32 次调用
var outputs = session.Run(inputs, session.OutputNames);

常见问题与解决方案

1. 模型输入输出名称不匹配

ONNX 模型有明确的输入输出名称,必须与模型定义一致。可以使用 Netron 等工具查看模型结构:

Console.WriteLine($"输入: {string.Join(", ", session.InputNames)}");
Console.WriteLine($"输出: {string.Join(", ", session.OutputNames)}");

2. 内存不足

大模型推理可能占用大量内存,解决方案:

学习资源

小结

C# 与 ONNX 的结合为 .NET 开发者提供了一个强大且高效的机器学习模型部署方案。通过 ONNX Runtime,可以在不牺牲性能的情况下,将 PyTorch 或 TensorFlow 训练的模型轻松集成到 C# 应用中。

关键要点:

随着 ONNX 生态的不断完善,.NET 开发者在机器学习领域的部署能力将得到进一步提升。

已复制