前言
今天突然有人和我说想要实现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 模型、加载图像、运行推理并输出预测结果:
- 创建一个 OnnxModelWrapper 对象,传入 ONNX 模型的文件路径。
- 调用 LoadImageTo2DArray 方法,将图像文件路径作为参数传入,以获取二维浮点数组。
- 将二维浮点数组转换为一维浮点数组,以便传递给 RunInference 方法。
- 调用 RunInference 方法,并传入一维浮点数组和输入数据的大小。
- 处理输出数据(例如,找到具有最高概率的类别)。
- 输出预测结果。
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 功能。文章来源:https://www.toymoban.com/news/detail-643643.html
参考资源
ONNX Runtime 官方文档
ONNX 官方 GitHub 仓库
.NET Core SDK
SixLabors.ImageSharp 库文章来源地址https://www.toymoban.com/news/detail-643643.html
到了这里,关于使用 C# 和 ONNX Runtime 加载和运行 ONNX 模型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!