Distribuire un modello in Funzioni di Azure

Informazioni su come distribuire un modello di Machine Learning ML.NET con training preliminare per le previsioni su HTTP tramite un ambiente serverless di Funzioni di Azure.

Prerequisiti

Panoramica dell'esempio di Funzioni di Azure

Questo esempio è un'applicazione di Funzioni di Azure trigger HTTP C# che usa un modello di classificazione binaria con training preliminare per classificare il sentiment del testo come positivo o negativo. Funzioni di Azure offre un modo semplice per eseguire piccole parti di codice su larga scala in un ambiente serverless gestito nel cloud. Il codice per questo esempio è disponibile nel repository dotnet/machinelearning-samples in GitHub.

Creare un progetto di Funzioni di Azure

  1. In Visual Studio 2022 aprire la finestra di dialogo Crea un nuovo progetto.

  2. Nella finestra di dialogo "Crea un nuovo progetto" selezionare il modello di progetto Funzioni di Azure.

  3. Nella casella di testo Nome digitare "SentimentAnalysisFunctionsApp" e selezionare il pulsante Avanti.

  4. Nella finestra di dialogo "Informazioni aggiuntive" lasciare invariate tutte le impostazioni predefinite e selezionare il pulsante Crea.

  5. Installare il pacchetto NuGet Microsoft.ML

    1. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e selezionare Gestisci pacchetti NuGet.
    2. Scegliere "nuget.org" come origine pacchetto.
    3. Selezionare la scheda “Sfoglia”.
    4. Cercare Microsoft.ML.
    5. Selezionare il pacchetto nell'elenco e selezionare il pulsante Installa.
    6. Selezionare il pulsante OK nella finestra di dialogo Anteprima modifiche
    7. Selezionare il pulsante Accetto nella finestra di dialogo Accettazione licenza se si accettano le condizioni di licenza per i pacchetti elencati.

    Seguire la stessa procedura per installare i pacchetti NuGet di Microsoft.Extensions.ML, Microsoft.Extensions.DependencyMakection e Microsoft.Azure.Functions.Extensions.

Aggiungere il modello con training preliminare al progetto

  1. Creare una directory denominata MLModels nel progetto per salvare il modello di pre-compilazione: in Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e scegliere Aggiungi > Nuova cartella. Digitare "MLModels" e premere INVIO.
  2. Copiare il modello predefinito nella cartella MLModels.
  3. In Esplora soluzioni fare clic con il pulsante destro del mouse sul file del modello predefinito e scegliere Proprietà. In Avanzate impostare il valore di Copia nella directory di output su Copia se più recente.

Creare la funzione di Azure per analizzare il sentiment

Creare una classe per prevedere il sentiment. Aggiungere una nuova classe al progetto:

  1. In Esplora soluzioni, fare clic con il pulsante destro del mouse sul progetto e scegliere Aggiungi>Nuova funzione Azure.

  2. Nella finestra di dialogo Aggiungi nuovo elemento selezionare Funzione di Azure e impostare il campo Nome su AnalyzeSentiment.cs. Selezionare quindi il pulsante Aggiungi.

  3. Nella finestra di dialogo Nuova funzione di Azure selezionare trigger HTTP e scegliere anonimo nell'elenco a discesa Livello di autorizzazione. Fare quindi clic su OK.

    Il file AnalyzeSentiment.cs verrà aperto nell'editor del codice. Aggiungere l'istruzione using seguente all'inizio di AnalyzeSentiment.cs:

    using System;
    using System.IO;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Extensions.Http;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json;
    using Microsoft.Extensions.ML;
    using SentimentAnalysisFunctionsApp.DataModels;
    

    Per impostazione predefinita, la classe AnalyzeSentiment è static. Assicurarsi di rimuovere la parola chiave static dalla definizione della classe.

    public class AnalyzeSentiment
    {
    
    }
    

Creare i modelli di dati

È necessario creare alcune classi per i dati di input e le stime. Aggiungere una nuova classe al progetto:

  1. Creare una directory denominata DataModels nel progetto per salvare i modelli di dati: in Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e scegliere Aggiungi > Nuova cartella. Digitare "DataModels" e premere INVIO.

  2. In Esplora soluzioni fare clic con il pulsante destro del mouse sulla directory DataModels e quindi scegliere Aggiungi > Classe.

  3. Nella finestra di dialogo Aggiungi nuovo elemento selezionare Classe e impostare il campo Nome su SentimentData.cs. Selezionare quindi il pulsante Aggiungi.

    Il file SentimentData.cs verrà aperto nell'editor del codice. Aggiungere l'istruzione using seguente all'inizio del file SentimentData.cs:

    using Microsoft.ML.Data;
    

    Rimuovere la definizione di classe esistente e aggiungere il codice seguente al file SentimentData.cs:

    public class SentimentData
    {
        [LoadColumn(0)]
        public string SentimentText;
    
        [LoadColumn(1)]
        [ColumnName("Label")]
        public bool Sentiment;
    }
    
  4. In Esplora soluzioni fare clic con il pulsante destro del mouse sulla directory DataModels e quindi scegliere Aggiungi > Classe.

  5. Nella finestra di dialogo Aggiungi nuovo elemento selezionare Classe e impostare il campo Nome su SentimentPrediction.cs. Selezionare quindi il pulsante Aggiungi. Il file SentimentPrediction.cs verrà aperto nell'editor del codice. Aggiungere l'istruzione using seguente all'inizio del file SentimentPrediction.cs:

    using Microsoft.ML.Data;
    

    Rimuovere la definizione di classe esistente e aggiungere il codice seguente al file SentimentPrediction.cs:

    public class SentimentPrediction : SentimentData
    {
    
        [ColumnName("PredictedLabel")]
        public bool Prediction { get; set; }
    
        public float Probability { get; set; }
    
        public float Score { get; set; }
    }
    

    SentimentPrediction eredita da SentimentData che consente l'accesso ai dati originali nella proprietà SentimentText e all'output generato dal modello.

Registrare il servizio PredictionEnginePool

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.

Il collegamento seguente fornisce ulteriori informazioni sull'inserimento delle dipendenze.

  1. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e scegliere Aggiungi>Classe.

  2. Nella finestra di dialogo Aggiungi nuovo elemento selezionare Classe e modificare il campo Nome in Startup.cs. Selezionare quindi il pulsante Aggiungi.

  3. Aggiungere le istruzioni using seguenti all'inizio di Startup.cs:

    using Microsoft.Azure.Functions.Extensions.DependencyInjection;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.ML;
    using SentimentAnalysisFunctionsApp;
    using SentimentAnalysisFunctionsApp.DataModels;
    using System.IO;
    using System;
    
  4. Rimuovere il codice esistente sotto le istruzioni using e aggiungere il codice seguente:

    [assembly: FunctionsStartup(typeof(Startup))]
    namespace SentimentAnalysisFunctionsApp
    {
        public class Startup : FunctionsStartup
        {
    
        }
    }
    
  5. Definire le variabili per archiviare l'ambiente in cui l'app è in esecuzione e il percorso del file in cui si trova il modello all'interno della classe Startup

    private readonly string _environment;
    private readonly string _modelPath;
    
  6. Di seguito, creare un costruttore per impostare i valori delle variabili _environment e _modelPath. Quando l'applicazione è in esecuzione in locale, l'ambiente predefinito è Sviluppo.

    public Startup()
    {
        _environment = Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT");
    
        if (_environment == "Development")
        {
            _modelPath = Path.Combine("MLModels", "sentiment_model.zip");
        }
        else
        {
            string deploymentPath = @"D:\home\site\wwwroot\";
            _modelPath = Path.Combine(deploymentPath, "MLModels", "sentiment_model.zip");
        }
    }
    
  7. Aggiungere quindi un nuovo metodo denominato Configure per registrare il servizio PredictionEnginePool sotto il costruttore.

    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddPredictionEnginePool<SentimentData, SentimentPrediction>()
            .FromFile(modelName: "SentimentAnalysisModel", filePath: _modelPath, 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.

builder.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));

Caricare il modello nella funzione

Inserire il codice seguente all'interno della classe AnalyzeSentiment:

public AnalyzeSentiment(PredictionEnginePool<SentimentData, SentimentPrediction> predictionEnginePool)
{
    _predictionEnginePool = predictionEnginePool;
}

Questo codice assegna PredictionEnginePool passandolo al costruttore della funzione ottenuto tramite l'inserimento delle dipendenze.

Usare il modello per effettuare previsioni

Sostituire l'implementazione esistente del metodo Run nella classe AnalyzeSentiment con il codice seguente:

public async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
    ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");

    // Parse HTTP Request Body
    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    SentimentData data = JsonConvert.DeserializeObject<SentimentData>(requestBody);

    //Make Prediction
    SentimentPrediction prediction = _predictionEnginePool.Predict(modelName: "SentimentAnalysisModel", example: data);

    //Convert prediction to string
    string sentiment = Convert.ToBoolean(prediction.Prediction) ? "Positive" : "Negative";

    //Return Prediction
    return new OkObjectResult(sentiment);
}

Quando il metodo Run viene eseguito, i dati in ingresso dalla richiesta HTTP vengono deserializzati e usati come input per PredictionEnginePool. Il metodo Predict viene quindi chiamato per eseguire stime usando l’oggetto SentimentAnalysisModel registrato nella classe Startup e restituisce i risultati all'utente, se ha esito positivo.

Test in locale

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

  1. Eseguire l'applicazione

  2. Aprire PowerShell e immettere il codice nel prompt, dove PORT è la porta su cui l'applicazione è in esecuzione. La porta è in genere la 7071.

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

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

    Negative
    

Complimenti. È stato creato il modello per eseguire previsioni tramite Internet usando una funzione di Azure.

Passaggi successivi