Eseguire previsioni con un modello ONNX AutoML in .NET
Questo articolo spiega come usare un modello Open Neural Network Exchange (ONNX) di Machine Learning automatizzato (AutoML) per eseguire previsioni in un'applicazione console C# con ML.NET.
ML.NET è un framework di apprendimento automatico open source multipiattaforma per l'ecosistema .NET che consente di eseguire il training e usare modelli di apprendimento automatico personalizzati grazie a un approccio Code First in C# o F#, o tramite strumenti a basso impiego di codice come Model Builder e l'interfaccia della riga di comando di ML.NET. Il framework è estendibile e consente di sfruttare altri framework di apprendimento automatico più diffusi, ad esempio TensorFlow e ONNX.
ONNX è un formato open source per i modelli di intelligenza artificiale. ONNX supporta l'interoperabilità tra framework. Ciò significa che è possibile eseguire il training di un modello in uno dei tanti framework di apprendimento automatico più diffusi, come PyTorch, convertirlo in formato ONNX e usare il modello ONNX in un framework diverso come ML.NET. Per altre informazioni, vedere il sito Web ONNX.
Prerequisiti
- .NET 6 SDK o versioni successive
- Editor di testo o IDE (ad esempio Visual Studio o Visual Studio Code)
- Modello ONNX. Per informazioni su come eseguire il training di un modello ONNX AutoML, vedere il notebook sulla classificazione del marketing bancario seguente.
- Netron (facoltativo)
Creare un'applicazione console C#
In questo esempio si usa l'interfaccia della riga di comando di .NET per compilare l'applicazione, ma è possibile eseguire le stesse attività usando Visual Studio. Altre informazioni sull'interfaccia della riga di comando di .NET.
Aprire un terminale e creare una nuova applicazione console C# .NET. In questo esempio il nome dell'applicazione è
AutoMLONNXConsoleApp
. Viene creata una directory con lo stesso nome contenente il contenuto dell'applicazione.dotnet new console -o AutoMLONNXConsoleApp
Nel terminale passare alla directory AutoMLONNXConsoleApp.
cd AutoMLONNXConsoleApp
Aggiungere pacchetti software
Installare i pacchetti NuGet Microsoft.ML, Microsoft.ML.OnnxRuntimee Microsoft.ML.OnnxTransformer usando l'interfaccia della riga di comando di .NET.
dotnet add package Microsoft.ML dotnet add package Microsoft.ML.OnnxRuntime dotnet add package Microsoft.ML.OnnxTransformer
Questi pacchetti contengono le dipendenze necessarie per usare un modello ONNX in un'applicazione .NET. ML.NET fornisce un'API che usa il runtime ONNX per le stime.
Aprire il file program.cs e aggiungere le direttive
using
seguenti in alto.using System.Linq; using Microsoft.ML; using Microsoft.ML.Data; using Microsoft.ML.Transforms.Onnx;
Aggiungere un riferimento al modello ONNX
Un modo per consentire all'applicazione console di accedere al modello ONNX prevede l'aggiunta del modello stesso alla directory di compilazione di output. Se non si dispone già di un modello, seguire questo notebook per creare un modello di esempio.
Aggiungere un riferimento al file del modello ONNX nell'applicazione:
Copiare il modello ONNX nella directory radice AutoMLONNXConsoleApp dell'applicazione.
Aprire il file AutoMLONNXConsoleApp.csproj e aggiungere il contenuto seguente all'interno del nodo
Project
.<ItemGroup> <None Include="automl-model.onnx"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup>
In questo caso, il nome del file del modello ONNX è automl-model.onnx.
(Per altre informazioni sugli elementi comuni di MSBuild, vedere la guida di MSBuild.)
Aprire il file Program.cs e aggiungere la riga seguente all'interno della classe
Program
.static string ONNX_MODEL_PATH = "automl-model.onnx";
Inizializzare MLContext
All'interno del metodo Main
della classe Program
creare una nuova istanza di MLContext
.
MLContext mlContext = new MLContext();
La classe MLContext
è un punto di partenza per tutte le operazioni ML.NET e l'inizializzazione di mlContext
crea un nuovo ambiente ML.NET che può essere condiviso nel ciclo di vita del modello. Dal punto di vista concettuale è simile a DbContext in Entity Framework.
Definire lo schema dei dati del modello
Un modello si aspetta un formato specifico per i dati di input e output. ML.NET consente di definire il formato dei dati tramite classi. A volte il formato dei dati potrebbe essere noto. Se invece non si conosce il formato dei dati, è possibile usare strumenti come Netron per controllare il modello ONNX.
Il modello usato in questo esempio usa i dati del set di dati NYC TLC Taxi Trip. Nella tabella seguente, è riportato un esempio di dati:
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 |
Esaminare il modello ONNX (facoltativo)
Usare uno strumento come Netron per esaminare gli input e gli output del modello.
Aprire Netron.
Nella barra dei menu in alto selezionare File > Apri e usare il browser file per selezionare il modello.
Verrà aperto il modello. Ad esempio, la struttura del modello automl-model.onnx è simile alla seguente:
Selezionare l'ultimo nodo nella parte inferiore del grafico (
variable_out1
in questo caso) per visualizzare i metadati del modello. Gli input e gli output sulla barra laterale mostrano gli input, gli output e i tipi di dati previsti del modello. Usare queste informazioni per definire lo schema di input e output del modello.
Definire lo schema di input del modello
Creare una nuova classe denominata OnnxInput
con le proprietà seguenti all'interno del file 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; }
}
Ciascuna proprietà esegue il mapping a una colonna nel set di dati. Le proprietà vengono ulteriormente associate ad attributi mediante annotazioni.
L'attributo ColumnName
consente di specificare come ML.NET deve fare riferimento alla colonna quando si opera sui dati. Ad esempio, anche se la proprietà TripDistance
segue convenzioni di denominazione .NET standard, il modello conosce solo una colonna o una funzionalità nota come trip_distance
. Per risolvere questa discrepanza di denominazione, l'attributo ColumnName
esegue il mapping tra la proprietà TripDistance
e una colonna o una funzionalità in base al nome trip_distance
.
Per i valori numerici, ML.NET opera solo sui tipi valore Single
. Tuttavia, il tipo di dati originale di alcune colonne è integer. L'attributo OnnxMapType
esegue il mapping dei tipi tra ONNX e ML.NET.
Per altre informazioni sugli attributi dei dati, vedere la guida al caricamento dei dati ML.NET.
Definire lo schema di output del modello
Una volta elaborati i dati, viene generato un output di un determinato formato. Definire lo schema di output dei dati. Creare una nuova classe denominata OnnxOutput
con le proprietà seguenti all'interno del file Program.cs.
public class OnnxOutput
{
[ColumnName("variable_out1")]
public float[] PredictedFare { get; set; }
}
Analogamente a OnnxInput
, usare l'attributo ColumnName
per eseguire il mapping tra l'output variable_out1
e un nome più descrittivo PredictedFare
.
Definire una pipeline di previsione
Una pipeline in ML.NET è in genere una serie di trasformazioni concatenate che operano sui dati di input per produrre un output. Per altre informazioni sulle trasformazioni dei dati, vedere la guida alla trasformazione dei dati ML.NET.
Creare un nuovo metodo denominato
GetPredictionPipeline
all'interno della classeProgram
static ITransformer GetPredictionPipeline(MLContext mlContext) { }
Definire il nome delle colonne di input e output. Aggiungere il codice seguente all'interno del metodo
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" };
Definire la pipeline. Un oggetto
IEstimator
fornisce un progetto di operazioni e gli schemi di input e output della pipeline.var onnxPredictionPipeline = mlContext .Transforms .ApplyOnnxModel( outputColumnNames: outputColumns, inputColumnNames: inputColumns, ONNX_MODEL_PATH);
In questo caso,
ApplyOnnxModel
è l'unica trasformazione nella pipeline, che accetta i nomi delle colonne di input e output, nonché il percorso del file di modello ONNX.Un'interfaccia
IEstimator
definisce solo il set di operazioni da applicare ai dati. Ciò che opera sui dati è noto comeITransformer
. Usare il metodoFit
per crearne uno daonnxPredictionPipeline
.var emptyDv = mlContext.Data.LoadFromEnumerable(new OnnxInput[] {}); return onnxPredictionPipeline.Fit(emptyDv);
Il metodo
Fit
prevedeIDataView
come input per eseguire le operazioni.IDataView
è un modo per rappresentare i dati in ML.NET usando un formato tabulare. Poiché in questo caso la pipeline viene usata solo per le previsioni, è possibile fornire un valoreIDataView
vuoto per fornire all'interfacciaITransformer
le informazioni sullo schema di input e output necessarie. L'interfacciaITransformer
montata viene quindi restituita per un ulteriore uso nell'applicazione.Suggerimento
In questo esempio la pipeline viene definita e usata all'interno della stessa applicazione. È tuttavia consigliabile usare applicazioni separate per definire e usare la pipeline per eseguire le previsioni. In ML.NET, le pipeline possono essere serializzate e salvate per un ulteriore uso in altre applicazioni degli utenti finali .NET. ML.NET supporta diverse destinazioni di distribuzione, ad esempio applicazioni desktop, servizi Web, applicazioni WebAssembly e molte altre ancora. Per altre informazioni sul salvataggio delle pipeline, vedere la guida ML.NET relativa al salvataggio e al caricamento di modelli con training.
All'interno del metodo
Main
eseguire una chiamata al metodoGetPredictionPipeline
con i parametri obbligatori.var onnxPredictionPipeline = GetPredictionPipeline(mlContext);
Usare il modello per effettuare previsioni
A questo punto si dispone di una pipeline e sarà pertanto possibile usarla per eseguire previsioni. ML.NET fornisce un'API utile per eseguire previsioni su una singola istanza di dati denominata PredictionEngine
.
All'interno del metodo
Main
creare una classePredictionEngine
usando il metodoCreatePredictionEngine
.var onnxPredictionEngine = mlContext.Model.CreatePredictionEngine<OnnxInput, OnnxOutput>(onnxPredictionPipeline);
Creare un input di dati di test.
var testInput = new OnnxInput { VendorId = "CMT", RateCode = 1, PassengerCount = 1, TripTimeInSecs = 1271, TripDistance = 3.8f, PaymentType = "CRD" };
Usare la classe
predictionEngine
per eseguire previsioni in base ai nuovi datitestInput
usando il metodoPredict
.var prediction = onnxPredictionEngine.Predict(testInput);
Restituire il risultato della previsione nella console.
Console.WriteLine($"Predicted Fare: {prediction.PredictedFare.First()}");
Usare l'interfaccia della riga di comando di .NET per eseguire l'applicazione.
dotnet run
Il risultato dovrebbe essere simile all'output seguente:
Predicted Fare: 15.621523
Per altre informazioni sull'esecuzione di previsioni in ML.NET, vedere la Uso di un modello per eseguire previsioni.