Compartir a través de


Realización de predicciones con un modelo AutoML de ONNX en .NET

En este artículo, aprenderá a usar un modelo de Intercambio de red neuronal abierto (ONNX) de ML automatizado (AutoML) para realizar predicciones en una aplicación de consola de C# con ML.NET.

ML.NET es un marco de aprendizaje automático multiplataforma y de código abierto para el ecosistema de .NET que permite entrenar y consumir modelos de aprendizaje automático personalizados mediante un enfoque de código primero en C# o F#, o mediante herramientas de código bajo como Model Builder y la CLI de ML.NET. El marco es extensible y le permite aprovechar otros marcos de aprendizaje automático populares, como TensorFlow y ONNX.

ONNX es un formato de código abierto para modelos de IA. ONNX admite la interoperabilidad entre marcos. Esto significa que puede entrenar un modelo en uno de los muchos marcos de aprendizaje automático que son más conocidos, como PyTorch, convertirlo a un formato ONNX y consumir el modelo de ONNX en un marco de trabajo diferente, como ML.NET. Para más información, visite el sitio web de ONNX.

Requisitos previos

Creación de una aplicación de consola en C#

En este ejemplo, va a utilizar la CLI de .NET Core para compilar la aplicación, pero puede realizar las mismas tareas con Visual Studio. Obtenga más información sobre el CLI de .NET.

  1. Abra un terminal y cree una aplicación de consola .NET de C#. En este ejemplo, el nombre de la aplicación es AutoMLONNXConsoleApp. Se creará un directorio que tendrá el mismo nombre con el contenido de la aplicación.

    dotnet new console -o AutoMLONNXConsoleApp
    
  2. En el terminal, vaya al directorio AutoMLONNXConsoleApp.

    cd AutoMLONNXConsoleApp
    

Incorporación de los paquetes de software

  1. Instale el Microsoft.ML, Microsoft.ML.OnnxRuntime, y Microsoft.ML.OnnxTransformer paquetes NuGet mediante la CLI de .NET.

    dotnet add package Microsoft.ML
    dotnet add package Microsoft.ML.OnnxRuntime
    dotnet add package Microsoft.ML.OnnxTransformer
    

    Estos paquetes contienen las dependencias necesarias para usar un modelo de ONNX en una aplicación .NET. ML.NET cuenta con una API que usa el entorno de ejecución de ONNX para realizar las predicciones.

  2. Abra el archivo Program.cs y agregue las siguientes using directivas en la parte superior.

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

Incorporación de una referencia al modelo de ONNX

Una forma de conseguir que la aplicación de consola acceda al modelo de ONNX es agregarla al directorio de salida de la compilación. Si aún no tiene un modelo, siga este cuaderno para crear un modelo de ejemplo.

Agregue una referencia al archivo de modelo ONNX en la aplicación:

  1. Copie el modelo ONNX en el directorio raíz AutoMLONNXConsoleApp de la aplicación.

  2. Abra el archivo AutoMLONNXConsoleApp. csproj y agregue el siguiente contenido dentro del nodo Project.

    <ItemGroup>
        <None Include="automl-model.onnx">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
    </ItemGroup>
    

    En este caso, el nombre del archivo de modelo de ONNX es automl-model.onnx.

    (Para más información sobre los elementos comunes de MSBuild, consulte la Guía de MSBuild.)

  3. Abra el archivo Program.cs y agregue la línea siguiente dentro de la clase Program.

    static string ONNX_MODEL_PATH = "automl-model.onnx";
    

Inicialización de MLContext

Dentro del método Main de la clase Program, cree una nueva instancia de MLContext.

MLContext mlContext = new MLContext();

La clase MLContext es el punto de partida de todas las operaciones de ML.NET, mientras que la inicialización de mlContext crea un nuevo entorno de ML.NET que puede compartirse durante el ciclo de vida del modelo. Como concepto, se parece a DbContext en Entity Framework.

Definición del esquema de datos del modelo

Un modelo espera los datos de entrada y salida en un formato específico. ML.NET permite definir el formato de los datos mediante clases. A veces, es posible que ya sepa el aspecto de ese formato. En los casos en los que no conoce el formato de datos, puede usar herramientas como Netron para inspeccionar el modelo ONNX.

El modelo de este ejemplo utiliza la información del conjunto de datos NYC TLC Taxi Trip. En la tabla siguiente se muestra un ejemplo de los datos:

vendor_id rate_code passenger_count trip_time_in_secs trip_distance payment_type fare_amount
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

Inspección del modelo de ONNX (opcional)

Utilice una herramienta como Netron para inspeccionar las entradas y salidas del modelo.

  1. Abra Netron.

  2. En la barra de menús superior, seleccione Archivo> Abrir y use el explorador de archivos para seleccionar el modelo.

  3. Se abre el modelo. Por ejemplo, la estructura del modelo automl-model.onnx se parece a la siguiente:

    Modelo AutoML de ONNX en Netron

  4. Seleccione el último nodo de la parte inferior del grafo (variable_out1 en este caso) para ver los metadatos del modelo. Las entradas y salidas de la barra lateral representan las entradas, salidas y tipos de datos esperados del modelo. Utilice esta información para definir el esquema de entrada y salida del modelo.

Definición del esquema de entrada del modelo

Cree una nueva clase llamada OnnxInput con las siguientes propiedades en el archivo Program.cs.

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; }
}

Cada una de las propiedades se asigna a una columna del conjunto de datos. Además, se incluirán atributos en las notas de las propiedades.

El atributo ColumnName permite especificar cómo ML.NET debe hacer referencia a la columna al trabajar con los datos. Por ejemplo, aunque la propiedad TripDistance sigue las convenciones de nomenclatura estándar de .NET, el modelo solo tiene información de una columna o característica llamada trip_distance. Para solucionar esta discrepancia de nomenclatura, el atributo ColumnName asigna la propiedad TripDistance a una columna o característica con el nombre trip_distance.

En el caso de los valores numéricos, ML.NET solo trabaja con tipos de valor Single. Sin embargo, el tipo de datos original de algunas de las columnas es un entero. El atributo OnnxMapType asigna tipos entre ONNX y ML.NET.

Para más información sobre los atributos de datos, consulte la guía de datos de carga de ML.NET.

Definición del esquema de salida del modelo

Una vez procesados los datos, se genera una salida con un formato determinado. Defina el esquema de salida de los datos. Cree una nueva clase llamada OnnxOutput con las siguientes propiedades en el archivo Program.cs.

public class OnnxOutput
{
    [ColumnName("variable_out1")]
    public float[] PredictedFare { get; set; }
}

Al igual que con OnnxInput, utilice el atributo ColumnName para asignar a la salida variable_out1 un nombre más descriptivo: PredictedFare.

Definición de una canalización de predicciones

Normalmente, las canalizaciones de ML.NET son una serie de transformaciones en cadena que se realizan en los datos de entrada para generar una salida. Para más información sobre las transformaciones de datos, consulte la guía de transformación de datos de ML.NET.

  1. Cree un nuevo método llamado GetPredictionPipeline dentro de la clase Program.

    static ITransformer GetPredictionPipeline(MLContext mlContext)
    {
    
    }
    
  2. Defina el nombre de las columnas de entrada y de salida. Agregue el código siguiente dentro del método 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. Defina la canalización. Un IEstimator proporciona un plano técnico de las operaciones y los esquemas de entrada y salida de la canalización.

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

    En este caso, ApplyOnnxModel es la única transformación de la canalización, que toma los nombres de las columnas de entrada y salida, y la ruta de acceso al archivo del modelo de ONNX.

  4. Los objetos IEstimator solo definen el conjunto de operaciones que se van a aplicar a los datos. Lo que realmente trabaja con los datos se conoce como ITransformer. Utilice el método Fit para crear uno a partir de onnxPredictionPipeline.

    var emptyDv = mlContext.Data.LoadFromEnumerable(new OnnxInput[] {});
    
    return onnxPredictionPipeline.Fit(emptyDv);
    

    El método Fit espera un objeto IDataView como entrada para realizar las operaciones. Los objetos IDataView permiten representar los datos en ML.NET con un formato tabular. Dado que en este caso la canalización solo se usa para realizar predicciones, puede proporcionar un objeto IDataView para que ITransformer tenga la información necesaria del esquema de entrada y de salida. A continuación, se devolverá el objeto ITransformer al que se le ha aplicado el método Fit para que siga utilizándose en la aplicación.

    Sugerencia

    En este ejemplo, la canalización se define y se utiliza dentro de la misma aplicación. Sin embargo, cuando se creen predicciones, se recomienda usar diferentes aplicaciones para definir y usar la canalización. En ML.NET, las canalizaciones se pueden serializar y guardar para utilizarse en otras aplicaciones NET dirigidas a usuarios finales. ML.NET admite varios destinos de implementación, como aplicaciones de escritorio, servicios web, aplicaciones de WebAssembly y muchos otros. Para más información acerca de cómo guardar las canalizaciones, consulte la guía para guardar y cargar modelos entrenados de ML.NET.

  5. En el método Main, llame al método GetPredictionPipeline con los parámetros necesarios.

    var onnxPredictionPipeline = GetPredictionPipeline(mlContext);
    

Uso del modelo para realizar predicciones

Ahora que tiene una canalización, es el momento de utilizarla para realizar predicciones. ML.NET dispone de una práctica API que permite llevar a cabo predicciones en una única instancia de datos denominada PredictionEngine.

  1. En el método Main, cree un objeto PredictionEngine utilizando el método CreatePredictionEngine.

    var onnxPredictionEngine = mlContext.Model.CreatePredictionEngine<OnnxInput, OnnxOutput>(onnxPredictionPipeline);
    
  2. Cree una entrada de datos de prueba.

    var testInput = new OnnxInput
    {
        VendorId = "CMT",
        RateCode = 1,
        PassengerCount = 1,
        TripTimeInSecs = 1271,
        TripDistance = 3.8f,
        PaymentType = "CRD"
    };
    
  3. Utilice el objeto predictionEngine para hacer predicciones basadas en los nuevos datos de testInput con el método Predict.

    var prediction = onnxPredictionEngine.Predict(testInput);
    
  4. Envíe la salida de la predicción a la consola.

    Console.WriteLine($"Predicted Fare: {prediction.PredictedFare.First()}");
    
  5. Use la CLI de .NET para ejecutar la aplicación.

    dotnet run
    

    La resultado tiene que ser similar a la siguiente salida:

    Predicted Fare: 15.621523
    

Para obtener más información sobre cómo realizar predicciones en ML.NET, consulte Uso de un modelo para realizar predicciones.

Pasos siguientes