Distribuire un modello in un'API Web ASP.NET Core

Informazioni su come rendere disponibile un modello di Machine Learning ML.NET con training preliminare sul Web usando un'API Web ASP.NET Core. La disponibilità di un modello su un'API Web consente previsioni tramite metodi HTTP standard.

Prerequisiti

Creare un progetto API Web ASP.NET Core

  1. Avviare Visual Studio 2022 e selezionare Crea un nuovo progetto.

  2. Nella finestra di dialogo Crea un nuovo progetto:

    • Immettere Web API nella casella di ricerca.
    • Selezionare il modello API Web ASP.NET Core e selezionare Avanti.
  3. Nella finestra di dialogo Configura il progetto:

    • Denominare il progetto SentimentAnalysisWebAPI.
    • Selezionare Avanti.
  4. Nella finestra di dialogo Informazioni aggiuntive:

    • Deselezionare Non usare istruzioni di primo livello.
    • Seleziona Crea.
  5. Installare i pacchetti NuGet seguenti:

    Per altre informazioni sull'installazione di pacchetti NuGet in Visual Studio, vedere la guida Installare e usare un pacchetto NuGet in Visual Studio.

Aggiungere il modello al progetto API Web ASP.NET Core

  1. Copiare il modello predefinito nella directory del progetto SentimentAnalysisWebAPI.

  2. Configurare il progetto per copiare il file del modello nella directory di output. In Esplora soluzioni:

    • Fare clic con il pulsante destro del mouse sul file ZIP del modello e scegliere Proprietà.
    • In Avanzate, impostare il valore di Copia nella directory di output su Copia se più recente.

Creare i modelli di dati

È necessario creare alcune classi per definire lo schema dell'input e dell'output del modello.

Nota

Le proprietà delle classi dello schema di input e output dipendono dalle colonne del set di dati usate per eseguire il training del modello e dall'attività di Machine Learning (regressione, classificazione e così via).

Nel file Program.cs:

  1. Aggiungere le istruzioni using seguenti:

    using Microsoft.ML.Data;
    using Microsoft.Extensions.ML;
    
  2. Nella parte inferiore del file aggiungere le classi seguenti:

    Input del modello

    Per questo modello, l'input contiene una singola proprietà SentimentText che è una stringa che rappresenta un commento utente.

    public class ModelInput
    {
        public string SentimentText;
    }
    

    Output del modello

    Dopo aver valutato l'input, il modello restituisce una stima con tre proprietà: Sentiment, Probability e Score. In questo caso, Sentiment è il sentiment stimato del commento dell'utente, e Probability e Score sono misure di attendibilità per la stima.

    public class ModelOutput
    {
        [ColumnName("PredictedLabel")]
        public bool Sentiment { get; set; }
    
        public float Probability { get; set; }
    
        public float Score { get; set; }
    }
    

Registrare PredictionEnginePool per l'uso nell'applicazione

Per eseguire una singola stima, è necessario creare un oggetto PredictionEngine. PredictionEngine non è thread-safe. Inoltre, è necessario crearne un'istanza ovunque sia necessaria all'interno dell'applicazione. Man mano che l'applicazione cresce, la gestione di questo processo può rivelarsi difficile. Per migliorare le prestazioni e la sicurezza dei thread, usare una combinazione di inserimento delle dipendenze e del servizio PredictionEnginePool, che crea un ObjectPool di oggetti PredictionEngine da usare in tutta l'applicazione.

Per ulteriori informazioni su questo argomento, vedere Inserimento delle dipendenze in ASP.NET Core.

Aggiungere il codice seguente al file Program.cs:

builder.Services.AddPredictionEnginePool<ModelInput, ModelOutput>()
    .FromFile(modelName: "SentimentAnalysisModel", filePath: "sentiment_model.zip", watchForChanges: true);

A livello generale, questo codice inizializza automaticamente gli oggetti e i servizi per usarli in un secondo momento quando richiesto dall'applicazione anziché dover eseguire manualmente questa operazione.

I modelli di Machine Learning non sono statici. Man mano che diventano disponibili nuovi dati di training, il modello viene nuovamente sottoposto a training e ridistribuito. Un modo per ottenere la versione più recente del modello nell'applicazione consiste nel riavviare o ridistribuire l'applicazione. Tuttavia, ciò comporta tempi di inattività dell'applicazione. Il servizio PredictionEnginePool fornisce un meccanismo per ricaricare un modello aggiornato senza riavviare o ridistribuire l'applicazione.

Impostare il parametro watchForChanges su true, e PredictionEnginePool avvia FileSystemWatcher in ascolto delle notifiche di modifica del file system e genera eventi quando viene apportata una modifica al file. In questo modo viene richiesto a PredictionEnginePool di ricaricare automaticamente il modello.

Il modello viene identificato dal parametro modelName in modo che sia possibile ricaricare più di un modello per applicazione al momento della modifica.

Suggerimento

In alternativa, è possibile usare il metodo FromUri quando si usano i modelli archiviati in modalità remota. Invece di cercare gli eventi modificati dei file, FromUri esegue il polling della posizione remota per individuare le modifiche. Per impostazione predefinita, l'intervallo di polling è 5 minuti. È possibile aumentare o ridurre l'intervallo di polling in base ai requisiti dell'applicazione. Nell'esempio di codice seguente, PredictionEnginePool esegue il polling del modello archiviato all'URI specificato ogni minuto.

services.AddPredictionEnginePool<SentimentData, SentimentPrediction>()
  .FromUri(
      modelName: "SentimentAnalysisModel",
      uri:"https://github.com/dotnet/samples/raw/main/machine-learning/models/sentimentanalysis/sentiment_model.zip",
      period: TimeSpan.FromMinutes(1));

Eseguire il mapping dell'endpoint di stima

Per elaborare le richieste HTTP in ingresso, creare un endpoint.

Sostituire l'endpoint / con il codice seguente:

var predictionHandler =
    async (PredictionEnginePool<ModelInput, ModelOutput> predictionEnginePool, ModelInput input) =>
        await Task.FromResult(predictionEnginePool.Predict(modelName: "SentimentAnalysisModel", input));

app.MapPost("/predict", predictionHandler);

L'endpoint /predict accetta le richieste HTTP POST e usa il pool del motore di stima per restituire una stima usando l'input fornito.

Al termine, il Program.cs dovrebbe essere simile al seguente:

using Microsoft.ML.Data;
using Microsoft.Extensions.ML;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddPredictionEnginePool<ModelInput, ModelOutput>()
    .FromFile(modelName: "SentimentAnalysisModel", filePath: "sentiment_model.zip", watchForChanges: true);

var app = builder.Build();

var predictionHandler =
    async (PredictionEnginePool<ModelInput, ModelOutput> predictionEnginePool, ModelInput input) =>
        await Task.FromResult(predictionEnginePool.Predict(modelName: "SentimentAnalysisModel", input));

app.MapPost("/predict", predictionHandler);

app.Run();

public class ModelInput
{
    public string SentimentText;
}

public class ModelOutput
{
    [ColumnName("PredictedLabel")]
    public bool Sentiment { get; set; }

    public float Probability { get; set; }

    public float Score { get; set; }
}

Testare l'API Web in locale

Dopo aver completato la configurazione, è possibile testare l'applicazione.

  1. Eseguire l'applicazione.

  2. Aprire PowerShell e immettere il codice seguente, dove PORT è la porta su cui l'applicazione è in ascolto.

    Invoke-RestMethod "https://localhost:<PORT>/predict" -Method Post -Body (@{SentimentText="This was a very bad steak"} | ConvertTo-Json) -ContentType "application/json"
    

    In caso di esito positivo, l'output sarà simile al testo seguente:

    sentiment probability score
    --------- ----------- -----
    False         0.5     0
    

Complimenti. Il modello per effettuare previsioni in Internet usando un'API Web ASP.NET Core è stato reso disponibile.

Passaggi successivi