ONNX(Open Neural Network Exchange)是一个开放的格式,用于表示深度学习模型,由微软、Facebook和AWS共同开发。它旨在使不同的机器学习框架能够将模型导出到ONNX格式,并在各种硬件配置上运行这些模型。ONNX运行时是一个可以运行转换为ONNX格式的机器学习模型的引擎,无论是传统的机器学习模型还是深度学习模型(神经网络)都可以导出到ONNX格式。ONNX运行时支持Linux、Windows和Mac操作系统,并且可以在多种芯片架构上运行,包括利用硬件加速器如GPU和TPU。但是,并非所有的操作系统、芯片架构和加速器组合都有现成的安装包,因此,如果使用的不是常见的组合,可能需要从源代码构建运行时。本文将展示如何在x64架构上安装ONNX运行时,包括默认CPU和带GPU的版本,并展示如何在C#中使用ONNX运行时。
在开始使用ONNX运行时之前,需要安装名为Microsoft.ML.OnnxRuntime的NuGet包。如果还没有安装.NET CLI,也需要安装它。以下是在默认CPU的x64架构上安装运行时的命令:
dotnet add package microsoft.ml.onnxruntime
如果要在带GPU的x64架构上安装运行时,使用以下命令:
dotnet add package microsoft.ml.onnxruntime.gpu
安装完成后,可以通过以下语句将运行时导入到C#代码文件中:
using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
导入Tensor工具的语句将帮助为ONNX模型创建输入,并解释ONNX模型的输出(预测)。
下面的代码片段展示了如何在C#中将ONNX模型加载到ONNX运行时。这段代码创建了一个会话对象,用于进行预测。这里使用的模型是从PyTorch导出的ONNX模型。值得注意的是,首先需要查询会话以获取其输入。这是通过会话的InputMetadata属性完成的。MNIST模型只有一个输入参数:一个表示MNIST数据集中一张图像的784个浮点数数组。如果模型有多个输入参数,InputMetadata将为每个参数有一个条目。
string modelPath = Directory.GetCurrentDirectory() + "/pytorch_mnist.onnx";
using (var session = new InferenceSession(modelPath))
{
float[] inputData = Utilities.ImageData[imageIndex];
string label = Utilities.ImageLabels[imageIndex];
Console.WriteLine("Selected image is the number: " + label);
var inputMeta = session.InputMetadata;
var container = new List<NamedOnnxValue>();
foreach (var name in inputMeta.Keys)
{
var tensor = new DenseTensor<float>(inputData, inputMeta[name].Dimensions);
container.Add(NamedOnnxValue.CreateFromTensor<float>(name, tensor));
}
// 运行代码省略,以简洁起见。
}
上述代码中未显示的实用工具读取原始MNIST图像,并将每张图像转换为784个浮点数的数组。每个图像的标签也从MNIST数据集中读取,以便确定预测的准确性。这段代码是标准的.NET代码,但仍然鼓励查看并使用它。如果需要读取类似于MNIST数据集的图像,它将为节省时间。
下面的函数展示了如何使用加载ONNX模型时创建的ONNX会话:
{
// 加载代码省略,以简洁起见。
// 运行推理
using (var results = session.Run(container))
{
// 获取结果
foreach (var r in results)
{
Console.WriteLine("Output Name: {0}", r.Name);
int prediction = MaxProbability(r.AsTensor<float>());
Console.WriteLine("Prediction: " + prediction.ToString());
}
}
}
大多数神经网络不会直接返回预测。它们返回每个输出类别的概率列表。在MNIST模型中,每张图像的返回值将是10个概率的列表。具有最高概率的条目是预测。一个有趣的测试是将ONNX模型返回的概率与在创建模型的框架内运行原始模型时返回的概率进行比较。理想情况下,模型格式和运行时的更改不应更改产生的任何概率。这将是一个良好的单元测试,每次模型发生变化时都会运行。