在 .NET 中使用 AutoML ONNX 模型进行预测

本文介绍如何使用 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 模型。

先决条件

创建 C# 控制台应用程序

此示例使用 .NET CLI 生成应用程序。 还可以使用 Visual Studio 或其他 IDE。

  1. 打开一个新的终端,并创建新的名为 AutoMLONNXConsoleAppC# .NET 控制台应用程序。 为应用程序创建具有该名称的目录。

    dotnet new console -o AutoMLONNXConsoleApp
    
  2. 更改为 AutoMLONNXConsoleApp 目录。

    cd AutoMLONNXConsoleApp
    

添加软件包

ML.NET 提供一个使用 ONNX 运行时进行预测的 API。 Microsoft.MLMicrosoft.ML.OnnxRuntimeMicrosoft.ML.OnnxTransformer NuGet 包包含 .NET 应用程序中使用 ONNX 模型所需的依赖项。

  1. 安装这些包。

    dotnet add package Microsoft.ML
    dotnet add package Microsoft.ML.OnnxRuntime
    dotnet add package Microsoft.ML.OnnxTransformer
    
  2. 编辑 Program.cs 文件,在顶部添加以下 using 指令。

    using System.Linq;
    using Microsoft.ML;
    using Microsoft.ML.Data;
    using Microsoft.ML.Transforms.Onnx;
    

添加对 ONNX 模型的引用

将 ONNX 模型文件的引用添加到您的应用程序。 应用程序访问 ONNX 模型的一种方法是通过生成输出目录。 有关 MSBuild 常用项的详细信息,请参阅 MSBuild 指南

  1. 复制 ONNX 模型并将其粘贴到应用程序的 AutoMLONNXConsoleApp 根目录。

  2. 编辑 AutoMLONNXConsoleApp.csproj 文件,在节点中添加 Project 以下代码。 在本例中,ONNX 模型文件的名称为 automl-model.onnx。

    <ItemGroup>
        <None Include="automl-model.onnx">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
    </ItemGroup>
    
  3. 编辑 Program.cs 文件,在类中添加 Program 以下行。

    static string ONNX_MODEL_PATH = "automl-model.onnx";
    
  4. 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 检查模型的输入和输出:

  1. 打开 Netron

  2. 在顶部菜单栏中,选择“打开>”并使用文件浏览器选择模型。

  3. 你的模型打开。 例如,模型的结构 automl-model.onnx 如以下屏幕截图所示:

    显示“Netron”AutoML ONNX 模型的屏幕截图。

  4. 在此示例中, 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 的列或特性。 为了解决此命名差异问题,属性 ColumnNameTripDistance 属性映射到名为 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 数据转换指南

  1. GetPredictionPipeline类中创建一个名为Program的新方法。

    static ITransformer GetPredictionPipeline(MLContext mlContext)
    {
    
    }
    
  2. 若要定义输入和输出列名称,请在方法中添加 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" };
    
  3. 添加定义管道的代码。 IEstimator 提供管道的操作以及输入和输出架构的蓝图。

    var onnxPredictionPipeline =
        mlContext
            .Transforms
            .ApplyOnnxModel(
                outputColumnNames: outputColumns,
                inputColumnNames: inputColumns,
                ONNX_MODEL_PATH);
    

    在这种情况下,ApplyOnnxModel 是管道中的唯一转换器,它接收输入和输出列的名称以及ONNX模型文件的路径。

  4. 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 保存和加载训练的模型指南

  5. Main 方法中,用所需的参数调用 GetPredictionPipeline 方法。

    var onnxPredictionPipeline = GetPredictionPipeline(mlContext);
    

使用模型进行预测

有了管道后,即可使用它进行预测。 ML.NET 提供了一个方便的 API,用于在名为 PredictionEngine 的单个数据实例上进行预测。

  1. Main 方法中,使用 PredictionEngine 方法创建 CreatePredictionEngine

    var onnxPredictionEngine = mlContext.Model.CreatePredictionEngine<OnnxInput, OnnxOutput>(onnxPredictionPipeline);
    
  2. 创建测试数据输入。

    var testInput = new OnnxInput
    {
        VendorId = "CMT",
        RateCode = 1,
        PassengerCount = 1,
        TripTimeInSecs = 1271,
        TripDistance = 3.8f,
        PaymentType = "CRD"
    };
    
  3. 使用 Predict 方法,基于新的 testInput 数据,通过 onnxPredictionEngine 进行预测。

    var prediction = onnxPredictionEngine.Predict(testInput);
    
  4. 将预测结果写入控制台。

    Console.WriteLine($"Predicted Fare: {prediction.PredictedFare.First()}");
    
  5. 使用 .NET CLI 运行你的应用程序。

    dotnet run
    

    结果应类似于以下输出:

    Predicted Fare: 15.621523
    

有关在 ML.NET 中进行预测的详细信息,请参阅 使用模型进行预测