Implementación de un modelo en Azure Functions

Aprenda cómo implementar un modelo de Machine Learning de ML.NET previamente entrenado para realizar predicciones por HTTP a través de un entorno sin servidor de Azure Functions.

Prerrequisitos

Introducción a un ejemplo de Azure Functions

Este ejemplo es una aplicación de desencadenador HTTP de C# de Azure Functions que utiliza un modelo de clasificación binaria previamente entrenado para clasificar la opinión del texto como positiva o negativa. Azure Functions proporciona una manera sencilla de ejecutar pequeños fragmentos de código a escala en un entorno sin servidor administrado en la nube. El código de este ejemplo se puede encontrar en el repositorio dotnet/machinelearning-samples en GitHub.

Creación de un proyecto de Azure Functions

  1. En Visual Studio 2022, abra el cuadro de diálogo Crear un proyecto.

  2. En el cuadro de diálogo "Crear un nuevo proyecto", seleccione la plantilla de proyecto Azure Functions.

  3. En el cuadro de texto Nombre, escriba "SentimentAnalysisFunctionsApp" y seleccione el botón Siguiente.

  4. En el "cuadro de diálogo Información adicional", deje todos los valores predeterminados tal y como está y seleccione el botón Crear.

  5. Instale el paquete NuGet Microsoft.ML

    1. En el Explorador de soluciones, haga clic con el botón derecho en Administrar paquetes NuGet.
    2. Elija "nuget.org" como origen del paquete.
    3. Seleccione la pestaña "Examinar ".
    4. Busque Microsoft.ML.
    5. Seleccione el paquete en la lista y seleccione el botón Instalar.
    6. Haga clic en el botón Aceptar en el cuadro de diálogo Vista previa de los cambios.
    7. Haga clic en el botón Acepto en el cuadro de diálogo Aceptación de la licencia si está de acuerdo con los términos de licencia de los paquetes que aparecen.

    Siga los mismos pasos para instalar los paquetes NuGet Microsoft.Extensions.ML, Microsoft.Extensions.DependencyInjection y Microsoft.Azure.Functions.Extensions.

Incorporación del modelo entrenado previamente en el proyecto

  1. Cree un directorio denominado MLModels en el proyecto para guardar los modelosanteriores a la compilación: en el Explorador de soluciones, haga clic con el botón derecho en el proyecto y seleccione Agregar > Nueva carpeta. Escriba "MLModels" y presione ENTRAR.
  2. Copie el modelo precompilado en la carpeta MLModels.
  3. En el Explorador de soluciones, haga clic con el botón derecho en el archivo del modelo precompilado y seleccione Propiedades. En Avanzadas, cambie el valor de Copiar en el directorio de salida por Copiar si es posterior.

Creación de una función de Azure para analizar sentimientos

Cree una clase para predecir sentimientos. Agregue una nueva clase a su proyecto:

  1. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto y, luego, seleccione Agregar>Nueva Función de Azure.

  2. En el cuadro de diálogo Agregar nuevo elemento, seleccione Función de Azure y cambie el campo Nombre a AnalyzeSentiment.cs. A continuación, seleccione el botón Agregar.

  3. En el cuadro de diálogo Nueva función de Azure, seleccione Desencadenador Http y elija Anónimo en la lista desplegable Nivel de autorización. Luego haga clic en el botón Aceptar.

    El archivo AnalyzeSentiment.cs se abre en el editor de código. Agregue la siguiente instrucción using a la parte superior de 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;
    

    De forma predeterminada, la clase AnalyzeSentiment es static. Asegúrese de quitar la palabra clave static de la definición de clase.

    public class AnalyzeSentiment
    {
    
    }
    

Creación de modelos de datos

Debe crear algunas clases para los datos de entrada y las predicciones. Agregue una nueva clase a su proyecto:

  1. Cree un directorio denominado DataModels en el proyecto para guardar los modelos de datos. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto y seleccione Agregar > Nueva carpeta. Escriba "DataModels" y presione ENTRAR.

  2. En el Explorador de soluciones, haga clic con el botón derecho en el directorio DataModels y luego seleccione Agregar > Clase.

  3. En el cuadro de diálogo Agregar nuevo elemento, seleccione Clase y cambie el campo Nombre a SentimentData.cs. A continuación, seleccione el botón Agregar.

    Se abre el archivo SentimentData.cs en el editor de código. Agregue la instrucción using siguiente en la parte superior del archivo SentimentData.cs:

    using Microsoft.ML.Data;
    

    Quite la definición de clase existente y agregue el código siguiente al archivo SentimentData.cs:

    public class SentimentData
    {
        [LoadColumn(0)]
        public string SentimentText;
    
        [LoadColumn(1)]
        [ColumnName("Label")]
        public bool Sentiment;
    }
    
  4. En el Explorador de soluciones, haga clic con el botón derecho en el directorio DataModels y luego seleccione Agregar > Clase.

  5. En el cuadro de diálogo Agregar nuevo elemento, seleccione Clase y cambie el campo Nombre a SentimentPrediction.cs. A continuación, seleccione el botón Agregar. El archivo SentimentPrediction.cs se abre en el editor de código. Agregue la instrucción using siguiente en la parte superior del archivo SentimentPrediction.cs:

    using Microsoft.ML.Data;
    

    Quite la definición de clase existente y agregue el código siguiente al archivo SentimentPrediction.cs:

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

    SentimentPrediction hereda de SentimentData el cual proporciona acceso a los datos originales en la propiedad SentimentText, así como la salida generada por el modelo.

Registro del servicio PredictionEnginePool

Para realizar una sola predicción, tendrá que crear un objeto PredictionEngine. PredictionEngine no es seguro para subprocesos. Además, tiene que crear una instancia de ella en cualquier lugar en que se necesite dentro de la aplicación. A medida que crece la aplicación, este proceso puede volverse difícil de administrar. Para mejorar el rendimiento y la seguridad para subprocesos, use una combinación de inserción de dependencias y el servicio PredictionEnginePool, que crea un elemento ObjectPool de objetos PredictionEngine para usarlo en toda la aplicación.

En el vínculo siguiente se proporciona más información si quiere aprender más sobre la inserción de dependencias.

  1. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto y seleccione Agregar > Clase.

  2. En el cuadro de diálogo Agregar nuevo elemento, seleccione Clase y cambie el campo Nombre a Startup.cs. A continuación, seleccione el botón Agregar.

  3. Agregue las instrucciones using siguientes en la parte superior del archivo 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. Quite el código existente debajo de las instrucciones using y agregue el código siguiente:

    [assembly: FunctionsStartup(typeof(Startup))]
    namespace SentimentAnalysisFunctionsApp
    {
        public class Startup : FunctionsStartup
        {
    
        }
    }
    
  5. Defina variables para almacenar el entorno en el que se ejecuta la aplicación y la ruta de acceso del archivo donde se encuentra el modelo dentro de la clase Startup

    private readonly string _environment;
    private readonly string _modelPath;
    
  6. A continuación, cree un constructor para establecer los valores de las variables _environment y _modelPath. Cuando la aplicación se ejecuta localmente, el entorno predeterminado es Development.

    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. A continuación, agregue un nuevo método llamado Configure para registrar el servicio PredictionEnginePool debajo del constructor.

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

En un nivel alto, este código inicializa los objetos y servicios de manera automática para su uso más adelante cuando lo solicite la aplicación en lugar de tener que hacerlo manualmente.

Los modelos de Machine Learning no son estáticos. A medida que haya nuevos datos de entrenamiento disponibles, el modelo se vuelve a entrenar y a implementar. Una manera de obtener la versión más reciente del modelo en la aplicación es volver a empezar o volver a implementar la aplicación. Sin embargo, esto implica un tiempo de inactividad de la aplicación. El servicio PredictionEnginePool proporciona un mecanismo para volver a cargar un modelo actualizado sin necesidad de volver a empezar o volver a implementar la aplicación.

Establezca el parámetro watchForChanges en true y el PredictionEnginePool inicia un FileSystemWatcher que escucha las notificaciones de cambios en el sistema de archivos y genera eventos cuando se produce un cambio en el archivo. Este solicita al PredictionEnginePool que vuelva a cargar automáticamente el modelo.

El modelo se identifica mediante el parámetro modelName, por lo que se puede volver a cargar más de un modelo por aplicación tras el cambio.

Sugerencia

Como alternativa, puede usar el método FromUri al trabajar con modelos almacenados de manera remota. En lugar de ver si hay eventos modificados de archivo, FromUri sondea la ubicación remota en busca de cambios. El intervalo de sondeo predeterminado es de 5 minutos. Puede aumentar o disminuir el intervalo de sondeo en función de los requisitos de la aplicación. En el ejemplo de código siguiente, PredictionEnginePool sondea el modelo almacenado en el URI especificado cada 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));

Carga del modelo en la función

Inserte el código siguiente dentro de la clase AnalyzeSentiment:

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

Este código asigna PredictionEnginePool al pasarlo al constructor de la función que se obtiene a través de una inserción de dependencias.

Uso del modelo para realizar predicciones

Reemplace la implementación existente del método Run en la clase AnalyzeSentiment por el código siguiente:

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

Cuando se ejecuta el método Run, los datos entrantes de la solicitud HTTP se deserializan y se usan como entrada en el PredictionEnginePool. A continuación, se llama al método Predict para realizar predicciones con el SentimentAnalysisModel registrado en la clase Startup y devuelve los resultados al usuario si se realiza correctamente.

Prueba local

Ahora que está todo configurado, es momento de probar la aplicación:

  1. Ejecutar la aplicación

  2. Abra PowerShell y escriba el código en el símbolo del sistema, donde PORT es el puerto en que se ejecuta la aplicación. Por lo general, se trata del puerto 7071.

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

    Si se realiza correctamente, la salida debería ser similar al texto siguiente:

    Negative
    

¡Enhorabuena! Publicó correctamente el modelo para realizar predicciones en Internet mediante una función de Azure.

Pasos siguientes