使用 C# 和 ONNX Runtime 加载和运行 ONNX 模型

文章目录

  • 前言
  • 一、准备工作
  • 二、实现 ONNX 模型封装
  • 三、运行模型推理
  • 四、使用 OnnxModelWrapper 类
  • 总结
  • 参考资源


前言

今天突然有人和我说想要实现windows环境下c#调用tensorflow模型,我想着ONNX不是可以搞嘛,然后我翻了一下以前做的,没翻到,就查询了下资料,鼓捣出来了

下面将介绍如何使用 C# 和 ONNX Runtime 库加载并运行 ONNX 模型。ONNX是啥我就不说了,留个链接。


废话不说,show me code!

一、准备工作

首先,确保您已经安装了 .NET Core SDK。然后,创建一个新的控制台应用程序项目:

dotnet new console -n OnnxInferenceExample  
cd OnnxInferenceExample 

接下来,添加以下 NuGet 包到您的项目中:

  • Microsoft.ML.OnnxRuntime
  • Microsoft.ML.OnnxRuntime.Managed
  • System.Drawing.Common (用于图像处理)

可以通过以下命令安装这些包:

dotnet add package Microsoft.ML.OnnxRuntime  
dotnet add package Microsoft.ML.OnnxRuntime.Managed  
dotnet add package System.Drawing.Common  

二、实现 ONNX 模型封装

为了方便地加载和运行 ONNX 模型,我们将创建一个 OnnxModelWrapper 类。这个类将负责加载模型、准备输入数据和运行推理。以下是 OnnxModelWrapper 类的完整实现,包括构造函数和 RunInference 方法。

using Microsoft.ML.OnnxRuntime;  
using Microsoft.ML.OnnxRuntime.Tensors;  
using System.Collections.Generic;  
using System.Linq;  
  
namespace OnnxModelLibrary  
{  
    public class OnnxModelWrapper  
    {  
        private string _modelPath;  
        private InferenceSession _session;  
        private readonly string _inputName;  
  
        public OnnxModelWrapper(string modelPath)  
        {  
            _modelPath = modelPath;  
            _session = new InferenceSession(_modelPath);  
            // 获取模型的输入节点名称  
            _inputName = _session.InputMetadata.Keys.First();  
        }  
  
        public float[] RunInference(float[] inputData, int inputSize)  
        {  
            // 将输入数据调整为 (1, 28, 28) 形状的张量  
            var reshapedInputData = new DenseTensor<float>(new[] { 1, 28, 28 });  
            for (int i = 0; i < 28; i++)  
            {  
                for (int j = 0; j < 28; j++)  
                {  
                    reshapedInputData[0, i, j] = inputData[i * 28 + j];  
                }  
            }  
  
            // 创建输入 NamedOnnxValue  
            var inputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor(_inputName, reshapedInputData) };  
  
            // 运行模型推理  
            using var results = _session.Run(inputs);  
  
            // 获取输出数据  
            float[] outputData = results.ToArray()[0].AsEnumerable<float>().ToArray();  
  
            return outputData;  
        }  
    }  
}  

这个类包含一个构造函数,用于加载 ONNX 模型并获取输入节点的名称。此外,它还包含一个 RunInference 方法,该方法接受一维浮点数组作为输入(例如,图像的像素值)并返回模型的输出数据。

三、运行模型推理

为了运行模型推理,我们需要实现一个 RunInference 方法。这个方法接受一个一维浮点数组(例如,来自图像的像素值)和输入数据的大小。它返回一个浮点数组,包含模型的输出数据。

首先,我们需要将输入数据调整为适当的形状。在本例中,我们将把一维数组调整为一个形状为 (1, 28, 28) 的张量。

然后,我们需要创建一个 NamedOnnxValue 对象,用于存储输入数据。NamedOnnxValue 类表示 ONNX Runtime 中的输入或输出值,它包含一个名字(在本例中是输入节点的名字)和一个张量。

接下来,我们运行模型推理并获取输出数据。可以通过调用 InferenceSession.Run 方法并传递输入 NamedOnnxValue 列表来实现。这个方法返回一个包含输出数据的 IDisposableReadOnlyCollection 对象。我们可以将其转换为一个浮点数组,以便进一步处理。

public float[] RunInference(float[] inputData, int inputSize)  
{  
    // 将输入数据调整为 (1, 28, 28) 形状的张量  
    var reshapedInputData = new DenseTensor<float>(new[] { 1, 28, 28 });  
    for (int i = 0; i < 28; i++)  
    {  
        for (int j = 0; j < 28; j++)  
        {  
            reshapedInputData[0, i, j] = inputData[i * 28 + j];  
        }  
    }  
  
    // 创建输入 NamedOnnxValue  
    var inputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor(_inputName, reshapedInputData) };  
  
    // 运行模型推理  
    using var results = _session.Run(inputs);  
  
    // 获取输出数据  
    float[] outputData = results.ToArray()[0].AsEnumerable<float>().ToArray();  
  
    return outputData;  
}  

四、使用 OnnxModelWrapper 类

现在我们已经实现了 OnnxModelWrapper 类,我们可以在控制台应用程序中使用它。首先,我们需要加载一张图像并将其转换为一个二维浮点数组。我们可以使用 System.Drawing.Common 库来实现这一点。

using SixLabors.ImageSharp;  
using SixLabors.ImageSharp.PixelFormats;  
using SixLabors.ImageSharp.Processing;  
  
public static float[,] LoadImageTo2DArray(string imagePath)
{
    // 加载图像    
    using var image = Image.Load<Rgb24>(imagePath);

    // 转换为灰度图像  
    using var grayscaleImage = image.Clone(ctx => ctx.Grayscale());

    // 调整图像大小(如果需要)    
    if (grayscaleImage.Width != 28 || grayscaleImage.Height != 28)
    {
        grayscaleImage.Mutate(x => x.Resize(new ResizeOptions
        {
            Size = new Size(28, 28),
            Sampler = new NearestNeighborResampler()
        }));
    }

    // 将图像转换为二维数组    
    float[,] imageData = new float[28, 28];
    for (int y = 0; y < grayscaleImage.Height; y++)
    {
        for (int x = 0; x < grayscaleImage.Width; x++)
        {
            // 将像素值转换为浮点数并归一化到 [0, 1] 范围    
            imageData[y, x] = (float)grayscaleImage[x, y].R / 255;
        }
    }

    return imageData;
}

接下来,在 Main 方法中,我们可以使用以下步骤来加载 ONNX 模型、加载图像、运行推理并输出预测结果:

  1. 创建一个 OnnxModelWrapper 对象,传入 ONNX 模型的文件路径。
  2. 调用 LoadImageTo2DArray 方法,将图像文件路径作为参数传入,以获取二维浮点数组。
  3. 将二维浮点数组转换为一维浮点数组,以便传递给 RunInference 方法。
  4. 调用 RunInference 方法,并传入一维浮点数组和输入数据的大小。
  5. 处理输出数据(例如,找到具有最高概率的类别)。
  6. 输出预测结果。
static void Main(string[] args)  
{  
    var onnxModelPath = "my_mnist_model.onnx";  
    var modelWrapper = new OnnxModelWrapper(onnxModelPath);  
    string imagePath = "59992.png";  
    float[,] image = LoadImageTo2DArray(imagePath);  
  
    float[] inputData = new float[28 * 28]; // 你的输入数据  
    for (int i = 0; i < 28; i++)  
    {  
        for (int j = 0; j < 28; j++)  
        {  
            inputData[i * 28 + j] = image[i, j];  
        }  
    }  
    int inputSize = 28 * 28; // 输入数据的大小  
    float[] outputData = modelWrapper.RunInference(inputData, inputSize);  
  
    // 处理输出数据(例如,找到具有最高概率的类别)  
    int predictedClass = -1;  
    float maxProbability = float.MinValue;  
    for (int i = 0; i < outputData.Length; i++)  
    {  
        if (outputData[i] > maxProbability)  
        {  
            maxProbability = outputData[i];  
            predictedClass = i;  
        }  
    }  
  
    // 输出预测结果  
    Console.WriteLine($"Predicted class: {predictedClass}, probability: {maxProbability}");  
  
    Console.ReadKey();  
}  

至此,我们已经创建了一个可以加载 ONNX 模型并使用 C# 运行推理的控制台应用程序。这个应用程序可以轻松地适应不同的模型和数据输入格式,因此可以作为一个通用的 ONNX 模型推理示例。


总结

在本篇博客中,我们展示了如何使用 C# 和 ONNX Runtime 库加载和运行 ONNX 模型。我们创建了一个 OnnxModelWrapper 类来封装 ONNX Runtime 的功能,并在控制台应用程序中使用它来加载图像、运行推理并输出预测结果。

这个示例可以轻松地扩展到其他类型的模型和输入数据。通过使用 ONNX Runtime 和 C#,您可以在 Windows 环境下轻松地集成机器学习模型,从而为您的应用程序带来强大的 AI 功能。

参考资源

ONNX Runtime 官方文档
ONNX 官方 GitHub 仓库
.NET Core SDK
SixLabors.ImageSharp 库

你可能感兴趣的:(笔记,c#,开发语言,机器学习,tensorflow)