本文介绍如何使用 Azure 机器学习 AutoML Open Neural Network Exchange (ONNX) 模型通过 ML.NET 在 C# 控制台应用程序中进行预测。 ML.NET 是 .NET 生态系统的开源跨平台机器学习框架,可用于训练和使用自定义机器学习模型。 ML.NET 支持代码优先方法,如 C# 或 F# 或低代码工具,如 模型生成器 和 ML.NET CLI。
ML.NET 框架是可扩展的,因此可以使用其他常用的机器学习框架,如 TensorFlow 和 ONNX。 ONNX 是 AI 模型的开放源代码格式,支持框架之间的互作性。 可以在常用的机器学习框架(如 PyTorch)中训练模型,将其转换为 ONNX 格式,并在其他框架(如 ML.NET)中使用 ONNX 模型。
先决条件
- .NET 6 SDK 或更高版本。
- 命令 shell 和文本编辑器或 IDE,如 Visual Studio 或 Visual Studio Code。
- ONNX 模型。 可以按照 NYC 出租车数据回归笔记本 创建示例模型。
- 可以选择使用
Netron来检查 ONNX 模型的工具。
创建 C# 控制台应用程序
此示例使用 .NET CLI 生成应用程序。 还可以使用 Visual Studio 或其他 IDE。
打开一个新的终端,并创建新的名为
AutoMLONNXConsoleAppC# .NET 控制台应用程序。 为应用程序创建具有该名称的目录。dotnet new console -o AutoMLONNXConsoleApp更改为 AutoMLONNXConsoleApp 目录。
cd AutoMLONNXConsoleApp
添加软件包
ML.NET 提供一个使用 ONNX 运行时进行预测的 API。 Microsoft.ML、Microsoft.ML.OnnxRuntime 和 Microsoft.ML.OnnxTransformer NuGet 包包含 .NET 应用程序中使用 ONNX 模型所需的依赖项。
安装这些包。
dotnet add package Microsoft.ML dotnet add package Microsoft.ML.OnnxRuntime dotnet add package Microsoft.ML.OnnxTransformer编辑 Program.cs 文件,在顶部添加以下
using指令。using System.Linq; using Microsoft.ML; using Microsoft.ML.Data; using Microsoft.ML.Transforms.Onnx;
添加对 ONNX 模型的引用
将 ONNX 模型文件的引用添加到您的应用程序。 应用程序访问 ONNX 模型的一种方法是通过生成输出目录。 有关 MSBuild 常用项的详细信息,请参阅 MSBuild 指南。
复制 ONNX 模型并将其粘贴到应用程序的 AutoMLONNXConsoleApp 根目录。
编辑 AutoMLONNXConsoleApp.csproj 文件,在节点中添加
Project以下代码。 在本例中,ONNX 模型文件的名称为 automl-model.onnx。<ItemGroup> <None Include="automl-model.onnx"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup>编辑 Program.cs 文件,在类中添加
Program以下行。static string ONNX_MODEL_PATH = "automl-model.onnx";在
MLContext类的Main方法中创建Program的新实例。MLContext mlContext = new MLContext();
这个 MLContext 类是所有 ML.NET 操作的起点。 初始化 mlContext 可创建可在模型生命周期内共享的新 ML.NET 环境。 类在概念上类似于 Entity Framework 中的 DbContext 。
定义模型数据架构
模型需要特定格式的输入和输出数据。 ML.NET 允许通过类定义数据的格式。 下表显示了使用 NYC 出租车行程数据集数据模型的一个示例。
| 供应商ID | 费率代码 | 乘客数量 | trip_time_in_secs(行程时间(秒)) | 行程距离 | 支付类型 | 车费金额 |
|---|---|---|---|---|---|---|
VTS |
1 | 1 | 1140 | 3.75 | CRD |
15.5 |
VTS |
1 | 1 | 480 | 2.72 | CRD |
10.0 |
VTS |
1 | 1 | 1680 | 7.8 | CSH |
26.5 |
检查 ONNX 模型
如果您还不知道您的数据格式是什么样子,可以使用诸如 Netron 这样的工具来检查 ONNX 模型。 使用 Netron 检查模型的输入和输出:
打开
Netron。在顶部菜单栏中,选择“打开>”并使用文件浏览器选择模型。
你的模型打开。 例如,模型的结构
automl-model.onnx如以下屏幕截图所示:在此示例中,
variable_out1选择图形底部的最后一个节点以显示模型的元数据。 侧栏中的输入和输出显示模型的预期输入、输出和数据类型。 使用此信息可定义模型的输入和输出架构。
定义模型输入架构
在 Program.cs 文件中,使用以下属性创建一 OnnxInput 个名为的新类:
public class OnnxInput
{
[ColumnName("vendor_id")]
public string VendorId { get; set; }
[ColumnName("rate_code"),OnnxMapType(typeof(Int64),typeof(Single))]
public Int64 RateCode { get; set; }
[ColumnName("passenger_count"), OnnxMapType(typeof(Int64), typeof(Single))]
public Int64 PassengerCount { get; set; }
[ColumnName("trip_time_in_secs"), OnnxMapType(typeof(Int64), typeof(Single))]
public Int64 TripTimeInSecs { get; set; }
[ColumnName("trip_distance")]
public float TripDistance { get; set; }
[ColumnName("payment_type")]
public string PaymentType { get; set; }
}
使用数据属性
每个属性映射到数据集中的列。 属性将用特性进一步批注。
使用
ColumnName属性时,可以指定 ML.NET 在对数据操作时如何引用列。 例如,尽管该TripDistance属性遵循标准 .NET 命名约定,但模型中只包含一个命名为trip_distance的列或特性。 为了解决此命名差异问题,属性ColumnName将TripDistance属性映射到名为trip_distance的列或特征。对于数值,ML.NET 仅对
Single值类型执行作,但某些列的原始数据类型为整数。OnnxMapType特性在 ONNX 和 ML.NET 之间映射类型。
有关数据属性的详细信息,请参阅 ML.NET 加载数据指南。
定义模型输出架构
数据被处理后,它将生成特定格式的输出。 若要定义数据输出架构,请使用以下属性在 OnnxOutput 文件中创建新的类:
public class OnnxOutput
{
[ColumnName("variable_out1")]
public float[] PredictedFare { get; set; }
}
与 OnnxInput 类似,使用 ColumnName 特性可将 variable_out1 输出映射到更具描述性的名称 PredictedFare。
定义预测管道
ML.NET 中的管道通常是一系列链式转换,它们对输入数据进行操作以生成输出。 有关数据转换的详细信息,请参阅 ML.NET 数据转换指南。
在
GetPredictionPipeline类中创建一个名为Program的新方法。static ITransformer GetPredictionPipeline(MLContext mlContext) { }若要定义输入和输出列名称,请在方法中添加
GetPredictionPipeline以下代码。var inputColumns = new string [] { "vendor_id", "rate_code", "passenger_count", "trip_time_in_secs", "trip_distance", "payment_type" }; var outputColumns = new string [] { "variable_out1" };添加定义管道的代码。
IEstimator提供管道的操作以及输入和输出架构的蓝图。var onnxPredictionPipeline = mlContext .Transforms .ApplyOnnxModel( outputColumnNames: outputColumns, inputColumnNames: inputColumns, ONNX_MODEL_PATH);在这种情况下,
ApplyOnnxModel是管道中的唯一转换器,它接收输入和输出列的名称以及ONNX模型文件的路径。IEstimator仅定义要应用于数据的操作集。 使用Fit方法从你的ITransformer创建一个onnxPredictionPipeline以操作你的数据。var emptyDv = mlContext.Data.LoadFromEnumerable(new OnnxInput[] {}); return onnxPredictionPipeline.Fit(emptyDv);Fit方法需要IDataView作为输入以对其执行操作。IDataView是一种使用表格格式在 ML.NET 中表示数据的方法。 在本例中,管道仅用于预测,因此你可提供一个空的IDataView来为ITransformer提供必要的输入和输出架构信息。 然后,系统会返回拟合的ITransformer,以供在应用程序中使用。提示
此示例定义和使用同一应用程序中的管道。 但是,最好使用单独的应用程序来定义和使用管道进行预测。 在 ML.NET 中,可将管道序列化并进行保存,以供今后在其他 .NET 最终用户应用程序中使用。
ML.NET 支持各种部署目标,例如桌面应用程序、Web 服务和 WebAssembly 应用程序。 有关保存管道的详细信息,请参阅 ML.NET 保存和加载训练的模型指南。
在
Main方法中,用所需的参数调用GetPredictionPipeline方法。var onnxPredictionPipeline = GetPredictionPipeline(mlContext);
使用模型进行预测
有了管道后,即可使用它进行预测。 ML.NET 提供了一个方便的 API,用于在名为 PredictionEngine 的单个数据实例上进行预测。
在
Main方法中,使用PredictionEngine方法创建CreatePredictionEngine。var onnxPredictionEngine = mlContext.Model.CreatePredictionEngine<OnnxInput, OnnxOutput>(onnxPredictionPipeline);创建测试数据输入。
var testInput = new OnnxInput { VendorId = "CMT", RateCode = 1, PassengerCount = 1, TripTimeInSecs = 1271, TripDistance = 3.8f, PaymentType = "CRD" };使用
Predict方法,基于新的testInput数据,通过onnxPredictionEngine进行预测。var prediction = onnxPredictionEngine.Predict(testInput);将预测结果写入控制台。
Console.WriteLine($"Predicted Fare: {prediction.PredictedFare.First()}");使用 .NET CLI 运行你的应用程序。
dotnet run结果应类似于以下输出:
Predicted Fare: 15.621523
有关在 ML.NET 中进行预测的详细信息,请参阅 使用模型进行预测。