导读:本期聚焦于小伙伴创作的《C#如何使用ONNX Runtime加载和运行AI模型?详细步骤与代码示例》,敬请观看详情。把训练好的PyTorch或TensorFlow模型转成ONNX格式后,怎样在C#项目里跑起来做推理?不少团队卡在环境配置和输入输出张量处理上。ONNX Runtime提供跨平台原生库,通过NuGet引入后能直接加载模型文件,利用Session执行预测。核心流程包括创建InferenceSession、构造输入Tensor、调用Run方法、读取输出结果。输入数据需按模型要求的维度与类型排布,比如图像通常要归一化并转成NCHW布局。本文以图像分类为例,给出从安装包、编写加载代码到解析输出的完整C#实现,并说明常见报错如形状不匹配的排查方式,帮助你在Windows或Linux服务中稳定集成AI能力。

在C#项目中集成人工智能推理能力,最实用的方式之一是将模型导出为ONNX格式,然后使用ONNX Runtime进行加载与执行。ONNX(Open Neural Network Exchange)作为一种开放的模型表示标准,能够让不同训练框架产出的模型在多种运行环境中复用。对于C#开发者来说,不需要依赖Python环境,就能在桌面程序、Web后端或微服务中完成高效的模型推理。

C#如何使用ONNX Runtime加载和运行AI模型?详细步骤与代码示例

一、环境准备与NuGet包安装

要在C#中使用ONNX Runtime,第一步是通过NuGet引入对应的运行时包。微软官方维护了Microsoft.ML.OnnxRuntime包,它包含了原生的执行引擎,支持CPU以及CUDA、TensorRT等加速后端。如果你的应用只需要基础CPU推理,安装CPU版本的包即可;若要在生产环境利用显卡,可以选择Microsoft.ML.OnnxRuntime.Gpu

在Visual Studio中,可以通过包管理器控制台执行以下命令完成安装:

// 使用NuGet Package Manager Console安装CPU版本
Install-Package Microsoft.ML.OnnxRuntime

// 如果需要GPU支持,可安装GPU版本
// Install-Package Microsoft.ML.OnnxRuntime.Gpu

安装完成后,项目就会引用相关的动态库。需要注意的是,ONNX Runtime的版本最好与导出模型时使用的ONNX算子集版本保持兼容。如果遇到不支持的算子,通常会抛出明确的异常信息,此时可以考虑升级运行时或转换模型时指定更低的opset版本。

二、加载ONNX模型并创建推理会话

模型加载的核心类是InferenceSession,它负责读取.onnx文件并构建内部执行图。创建会话时,可以传入模型文件路径,也可以从字节流加载,方便将模型嵌入到程序资源中。会话对象创建后,可以通过其InputMetadata和OutputMetadata属性查看模型期望的输入输出名称、数据类型和维度。

下面是一段典型的模型加载代码,展示了如何打开会话并输出元数据信息:

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

class Program
{
    static void Main()
    {
        // 模型文件路径,可以是相对或绝对路径
        string modelPath = "model/resnet50.onnx";

        // 创建推理会话
        using var session = new InferenceSession(modelPath);

        // 输出输入元数据,方便确认名称和形状
        foreach (var input in session.InputMetadata)
        {
            Console.WriteLine($"输入名称: {input.Key}");
            Console.WriteLine($"维度: {string.Join(',', input.Value.Dimensions)}");
            Console.WriteLine($"类型: {input.Value.ElementType}");
        }
    }
}

通过打印元数据,开发者能够明确模型需要的输入张量形状。例如图像分类模型常要求输入为[1, 3, 224, 224]的NCHW格式,即一张图、三个通道、高宽各224像素。如果不清楚这些信息,后续构造输入时极易出现形状不匹配的错误。

三、构造输入张量并执行推理

ONNX Runtime使用Tensor<T>类来表达多维数组。我们需要把业务数据(如图片像素)转换为对应类型的扁平数组,并按照模型要求的维度布局填充。以float类型的图像输入为例,要先将图像缩放到目标尺寸,再做归一化,最后按通道顺序写入一维数组。

以下示例演示了如何构造输入并调用Run方法获得输出:

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

class InferenceDemo
{
    static void Run()
    {
        string modelPath = "model/resnet50.onnx";
        using var session = new InferenceSession(modelPath);

        // 假设已经准备好长度为 1*3*224*224 的float数组 data
        float[] data = new float[1 * 3 * 224 * 224];
        // 这里省略图像预处理细节,实际应填入归一化后的R,G,B值

        // 构造输入张量,维度为 NCHW
        var inputTensor = new DenseTensor<float>(data, new int[] { 1, 3, 224, 224 });
        var inputs = new List<NamedOnnxValue>
        {
            NamedOnnxValue.CreateFromTensor("input", inputTensor)
        };

        // 执行推理
        using var results = session.Run(inputs);

        // 读取第一个输出
        var output = results[0].AsTensor<float>();
        var scores = output.ToArray();
        Console.WriteLine($"输出长度: {scores.Length}");
    }
}

在上面的代码中,NamedOnnxValue.CreateFromTensor的的第一个参数必须与模型输入元数据中的名称完全一致,否则会报找不到输入的错误。Run方法返回的结果也是一个NamedOnnxValue集合,通过索引或名称可以取出对应的输出张量。

如果模型有多个输入,只需在inputs列表中按顺序或名称添加多个张量即可。推理本身通常很快,但首次运行会因内部图编译产生一定延迟,这属于正常现象。在Web服务中,建议将会话对象设为单例,避免重复加载带来的开销。

四、输出结果解析与常见误区

模型推理得到的输出往往是原始分数或概率分布。对于分类模型,输出一般是一个一维float数组,每个位置代表某个类别的置信度。如果需要最高分类别,可以遍历数组取最大值索引,必要时结合Softmax将分数转为概率。

很多开发者在接入时会踩到两个坑:一是输入数据未做归一化,直接把0到255的像素值送入网络,导致输出完全错误;二是维度顺序弄反,把HWC格式当成NCHW输入。可以通过在Python侧打印同一张图的输入数组前后几个值,与C#侧构造的数组对比来验证。

// 简单取最大分数对应的类别索引
int maxIndex = 0;
float maxScore = scores[0];
for (int i = 1; i < scores.Length; i++)
{
    if (scores[i] > maxScore)
    {
        maxScore = scores[i];
        maxIndex = i;
    }
}
Console.WriteLine($"预测类别索引: {maxIndex}, 分数: {maxScore}");

此外,当模型包含动态维度(标记为-1)时,需要在运行时根据实际批次大小构造对应形状的张量。如果部署在Linux服务器,还要注意原生库依赖如libonnxruntime.so的权限和路径,确保程序启动时能够加载到正确版本。

五、在生产中集成的最佳实践

将ONNX推理嵌入C#生产系统,推荐将会话创建、输入预处理、输出后处理封装为独立服务类,对外只暴露业务友好的方法,例如PredictImageAsync(byte[] imageBytes)。这样上层调用方不需要了解ONNX细节,也方便后续替换模型文件而不改动业务代码。

对于高并发场景,ONNX Runtime的Session本身是线程安全的,可以被多个线程共享调用,但每个Run调用最好传入独立的输入容器。如果显存或内存紧张,可以限制并发数或采用模型量化版本减小资源占用。配合异步编程模型,还能在ASP.NET Core中提供稳定的AI接口。

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

    public int Predict(float[] inputData)
    {
        var tensor = new DenseTensor<float>(inputData, new int[] { 1, 3, 224, 224 });
        var inputs = new List<NamedOnnxValue>
        {
            NamedOnnxValue.CreateFromTensor("input", tensor)
        };
        using var result = _session.Run(inputs);
        var scores = result[0].AsTensor<float>().ToArray();
        // 返回最大索引逻辑省略
        return 0;
    }
}

通过上述方式,C#工程能够以较低门槛融合AI能力,既保留了原有系统的开发效率,又获得了跨平台推理的灵活性。随着模型优化手段的丰富,后续还可以引入OpenVINO或TensorRT执行提供者进一步提升吞吐。

C#ONNX_Runtime模型推理修改时间:2026-08-02 00:00:36

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。