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.

Nota

In questo esempio viene eseguita una versione di anteprima del PredictionEnginePool servizio.

Prerequisiti

Panoramica di esempio di funzioni di Azure

Questo esempio è un' applicazione di funzioni di Azure trigger http di C# che usa un modello di classificazione binaria con training per categorizzare il sentimento del testo come positivo o negativo. Funzioni di Azure offre un modo semplice per eseguire piccole porzioni di codice su larga scala in un ambiente senza server gestito nel cloud. Il codice per questo esempio è disponibile nel repository DotNet/machinelearning-Samples in GitHub.

Creare un progetto di Funzioni di Azure

  1. Aprire Visual Studio 2017. Scegliere file > nuovo > progetto dalla barra dei menu. Nella finestra di dialogo Nuovo progetto selezionare il nodo Visual C# seguito dal nodo Cloud. Selezionare quindi il modello di progetto Funzioni di Azure. Nella casella di testo Nome digitare "SentimentAnalysisFunctionsApp" e quindi selezionare il pulsante OK.

  2. Nella finestra di dialogo Nuovo progetto aprire l'elenco a discesa sopra le opzioni del progetto e selezionare Azure Functions v2 (.NET Core) (Funzioni di Azure v2 - .NET Core). Selezionare quindi il progetto Trigger HTTP e infine fare clic su OK.

  3. Creare una directory denominata MLModels nel progetto per salvare il modello:

    In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e selezionare Aggiungi > Nuova cartella. Digitare "MLModels" e premere INVIO.

  4. Installare il pacchetto NuGet Microsoft.ml versione 1.3.1:

    In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e selezionare Gestisci pacchetti NuGet. Scegliere "nuget.org" come Origine pacchetto, selezionare la scheda Sfoglia, cercare Microsoft.ML, selezionare il pacchetto nell'elenco e quindi selezionare il pulsante Installa. Selezionare il pulsante OK nella finestra di dialogo Anteprima modifiche e quindi selezionare il pulsante Accetto nella finestra di dialogo Accettazione della licenza se si accettano le condizioni di licenza per i pacchetti elencati.

  5. Installare il pacchetto NuGet Microsoft.Azure.Functions.Extensions:

    In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e selezionare Gestisci pacchetti NuGet. Scegliere "nuget.org" come origine del pacchetto, selezionare la scheda Sfoglia, cercare Microsoft.Azure.Functions.Extensions, selezionare il pacchetto nell'elenco e quindi il pulsante Installa. Selezionare il pulsante OK nella finestra di dialogo Anteprima modifiche e quindi selezionare il pulsante Accetto nella finestra di dialogo Accettazione della licenza se si accettano le condizioni di licenza per i pacchetti elencati.

  6. Installare la versione del pacchetto NuGet Microsoft.Extensions.ml 0.15.1:

    In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e selezionare Gestisci pacchetti NuGet. Scegliere "nuget.org" come origine del pacchetto, selezionare la scheda Sfoglia, cercare Microsoft.Extensions.ML, selezionare il pacchetto nell'elenco e quindi il pulsante Installa. Selezionare il pulsante OK nella finestra di dialogo Anteprima modifiche e quindi selezionare il pulsante Accetto nella finestra di dialogo Accettazione della licenza se si accettano le condizioni di licenza per i pacchetti elencati.

  7. Installare la versione del pacchetto NuGet Microsoft. NET. Sdk. Functions 1.0.31:

    In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e selezionare Gestisci pacchetti NuGet. Scegliere "nuget.org" come origine del pacchetto, selezionare la scheda installato, cercare Microsoft. NET. Sdk. Functions, selezionare il pacchetto nell'elenco, selezionare 1.0.31 nell'elenco a discesa versione e selezionare il pulsante Aggiorna . Selezionare il pulsante OK nella finestra di dialogo Anteprima modifiche e quindi selezionare il pulsante Accetto nella finestra di dialogo Accettazione della licenza se si accettano le condizioni di licenza per i pacchetti elencati.

Aggiungere il modello con training preliminare al progetto

  1. Copiare il modello predefinito nella cartella MLModels.
  2. 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 quindi selezionare Aggiungi > Nuovo elemento.

  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. 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 Datamodes 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 Datamodes , quindi scegliere Aggiungi > nuovo elemento.

  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 Datamodes , quindi scegliere Aggiungi > nuovo elemento.

  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 necessario all'interno dell'applicazione. Con la crescita dell'applicazione, questo processo può diventare non gestibile. Per migliorare le prestazioni e thread safety, utilizzare una combinazione di inserimento di dipendenze e il PredictionEnginePool servizio, che consente di creare un oggetto ObjectPool di PredictionEngine oggetti da utilizzare nell'applicazione.

Il collegamento seguente fornisce ulteriori informazioni se si desidera ottenere ulteriori informazioni sull' inserimento delle dipendenze.

  1. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e quindi selezionare Aggiungi > Nuovo elemento.

  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 System;
    using System.IO;
    using Microsoft.Azure.Functions.Extensions.DependencyInjection;
    using Microsoft.Extensions.ML;
    using SentimentAnalysisFunctionsApp;
    using SentimentAnalysisFunctionsApp.DataModels;
    
  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 è in esecuzione l'app e il percorso del file in cui si trova il modello all'interno della Startup classe

    private readonly string _environment;
    private readonly string _modelPath;
    
  6. Di seguito, creare un costruttore per impostare i valori delle _environment variabili e _modelPath . Quando l'applicazione viene eseguita localmente, l'ambiente predefinito è lo 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 al di PredictionEnginePool sotto del costruttore.

    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddPredictionEnginePool<SentimentData, SentimentPrediction>()
            .FromFile(modelName: "SentimentAnalysisModel", filePath: _modelPath, watchForChanges: true);
    }
    

A un livello elevato, questo codice inizializza automaticamente gli oggetti e i servizi per un uso successivo quando richiesto dall'applicazione anziché eseguire manualmente questa operazione.

I modelli di apprendimento automatico non sono statici. Al momento della disponibilità dei 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 ridistribuire l'intera applicazione. Questa operazione introduce tuttavia i tempi di inattività dell'applicazione. Il PredictionEnginePool servizio fornisce un meccanismo per ricaricare un modello aggiornato senza interrompere l'esecuzione dell'applicazione.

Impostare il watchForChanges parametro su true e il PredictionEnginePool avvia un oggetto FileSystemWatcher che resta in ascolto del file System le notifiche di modifica e genera eventi quando viene apportata una modifica al file. PredictionEnginePoolViene richiesto di ricaricare automaticamente il modello.

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

Suggerimento

In alternativa, è possibile utilizzare il FromUri metodo quando si utilizzano i modelli archiviati in remoto. Invece di controllare gli eventi di modifica dei file, esegue FromUri il polling della posizione remota per le modifiche. Per impostazione predefinita, l'intervallo di polling è 5 minuti. È possibile aumentare o diminuire l'intervallo di polling in base ai requisiti dell'applicazione. Nell'esempio di codice riportato di seguito, il esegue il PredictionEnginePool polling del modello archiviato nell'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:

private readonly PredictionEnginePool<SentimentData, SentimentPrediction> _predictionEnginePool;

// AnalyzeSentiment class constructor
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:

[FunctionName("AnalyzeSentiment")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "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 (ActionResult)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 Predict metodo viene quindi chiamato per eseguire stime utilizzando l'oggetto SentimentAnalysisModel registrato nella Startup classe e restituisce i risultati all'utente in caso di 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
    

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

Passaggi successivi