Share via


Implantar um modelo no Azure Functions

Saiba como implantar um modelo de machine learning do ML.NET pré-treinado para previsões por HTTP por meio de um ambiente sem servidor do Azure Functions.

Pré-requisitos

Visão geral do exemplo Azure Functions

Este exemplo é um aplicativo C# HTTP Trigger Azure Functions que usa um modelo de classificação binária pré-treinado para categorizar o sentimento do texto como positivo ou negativo. O Azure Functions fornece uma maneira fácil de executar pequenas partes de código em escala em um ambiente gerenciado sem servidor na nuvem. O código para este exemplo pode ser encontrado no repositório dotnet/machinelearning-samples no GitHub.

Criar um projeto do Azure Functions

  1. No Visual Studio 2022, abra a caixa de diálogo Criar um projeto.

  2. Na caixa de diálogo "Criar um projeto", selecione o modelo de projeto Azure Functions.

  3. Na caixa de texto Nome, digite "SentimentAnalysisFunctionsApp" e, em seguida, selecione o botão Avançar.

  4. Na caixa de diálogo "Informações adicionais", deixe todos os padrões como estão e selecione o botão Criar.

  5. Instale o pacote NuGet Microsoft.ML

    1. No Gerenciador de Soluções, clique com o botão direito do mouse no seu projeto e selecione Gerenciar Pacotes NuGet.
    2. Escolha "nuget.org" como a fonte do pacote.
    3. Selecione a guia "Procurar".
    4. Pesquise Microsoft.ML.
    5. Selecione o pacote na lista e clique no botão Instalar.
    6. Clique no botão OK na caixa de diálogo Pré-visualização de alterações
    7. Clique no botão Aceito na caixa de diálogo Aceitação de licença se você concordar com os termos de licença dos pacotes listados.

    Siga as mesmas etapas para instalar os pacotes NuGet Microsoft.Extensions.ML, Microsoft.Extensions.DependencyInjection e Microsoft.Azure.Functions.Extensions.

Adicionar modelo pré-treinado ao projeto

  1. Crie um diretório chamado MLModels no projeto para salvar seu modelo pré-criado: no Gerenciador de Soluções, clique com o botão direito do mouse em seu projeto e selecione Adicionar > Nova Pasta. Digite "MLModels" e pressione ENTER.
  2. Copie o modelo previamente criado para o diretório MLModels.
  3. No Gerenciador de Soluções, clique com o botão direito do mouse no arquivo do modelo criado previamente e selecione Propriedades. Em Avançado, altere o valor de Copiar para Diretório de Saída para Copiar se for mais novo.

Criar Função do Azure para analisar o sentimento

Crie uma classe para prever o sentimento. Adicione uma nova classe ao seu projeto:

  1. No Gerenciador de Soluções, clique com o botão direito do mouse no projeto e selecione Adicionar>Nova Função do Azure.

  2. Na caixa de diálogo Adicionar novo item, selecione Função do Azure e altere o campo Nome para AnalyzeSentiment.cs. Em seguida, selecione o botão Adicionar.

  3. Na caixa de diálogo Nova Função do Azure, selecione Gatilho Http e escolha Anônimo na lista suspensa Nível de autorização. Depois, selecione o botão OK.

    O arquivo AnalyzeSentiment.cs é aberto no editor de códigos. Adicione a seguinte instrução using acima 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;
    

    Por padrão, a classe AnalyzeSentiment é static. Remova a palavra-chave static da definição da classe.

    public class AnalyzeSentiment
    {
    
    }
    

Criar modelo de dados

Você precisa criar algumas classes para os dados e previsões de entrada. Adicione uma nova classe ao seu projeto:

  1. Crie um diretório chamado DataModels em seu projeto para salvar seus modelos de dados: no Gerenciador de Soluções, clique com o botão direito do mouse em seu projeto e selecione Adicionar > Nova Pasta. Digite "DataModels" e pressione ENTER.

  2. No Gerenciador de Soluções, clique com o botão direito do mouse no diretório DataModels e selecione Adicionar > Classe.

  3. Na caixa de diálogo Adicionar Novo Item, selecione Classe e altere o campo Nome para SentimentData.cs. Em seguida, selecione o botão Adicionar.

    O arquivo SentimentData.cs é aberto no editor de códigos. Adicione a seguinte instrução using na parte superior do SentimentData.cs:

    using Microsoft.ML.Data;
    

    Remova a definição de classe existente e adicione o seguinte código ao arquivo SentimentData.cs:

    public class SentimentData
    {
        [LoadColumn(0)]
        public string SentimentText;
    
        [LoadColumn(1)]
        [ColumnName("Label")]
        public bool Sentiment;
    }
    
  4. No Gerenciador de Soluções, clique com o botão direito do mouse no diretório DataModels e selecione Adicionar > Classe.

  5. Na caixa de diálogo Adicionar Novo Item, selecione Classe e altere o campo Nome para SentimentPrediction.cs. Em seguida, selecione o botão Adicionar. O arquivo SentimentPrediction.cs é aberto no editor de códigos. Adicione a seguinte instrução "using" na parte superior do SentimentPrediction.cs:

    using Microsoft.ML.Data;
    

    Remova a definição de classe existente e adicione o seguinte código ao arquivo SentimentPrediction.cs:

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

    SentimentPrediction herda de SentimentData, que dá acesso aos dados originais na propriedade SentimentText, bem como a saída gerada pelo modelo.

Registrar serviço PredictionEnginePool

Para fazer uma única previsão, é necessário criar um PredictionEngine. PredictionEngine não é thread-safe. Além disso, você precisa criar uma instância dele em qualquer lugar em que seja necessário dentro de seu aplicativo. À medida que seu aplicativo cresce, esse processo pode se tornar não gerenciável. Para melhorar o desempenho e o acesso thread-safe, use uma combinação de injeção de dependência e o serviço PredictionEnginePool, que cria um ObjectPool dos objetos PredictionEngine para uso em todo o aplicativo.

O link a seguir fornece mais informações sobre a injeção de dependência.

  1. No Gerenciador de Soluções, clique com o botão direito do mouse no projeto e selecione Adicionar>Classe.

  2. Na caixa de diálogo Adicionar Novo Item, selecione Classe e altere o campo Nome para Startup.cs. Em seguida, selecione o botão Adicionar.

  3. Adicione as seguintes instruções using na parte superior do 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. Remova o código existente abaixo do usando instruções e adicione o seguinte código:

    [assembly: FunctionsStartup(typeof(Startup))]
    namespace SentimentAnalysisFunctionsApp
    {
        public class Startup : FunctionsStartup
        {
    
        }
    }
    
  5. Definir variáveis para armazenar o ambiente em que o aplicativo está em execução e o caminho do arquivo no qual o modelo está localizado dentro da classe Startup

    private readonly string _environment;
    private readonly string _modelPath;
    
  6. Abaixo disso, crie um construtor para definir os valores das variáveis _environment e _modelPath. Quando o aplicativo está sendo executado localmente, o ambiente padrão é Desenvolvimento.

    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. Em seguida, adicione um novo método chamado Configure para registrar o serviço PredictionEnginePool abaixo do construtor.

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

Em um alto nível, esse código inicializa os objetos e serviços automaticamente para uso posterior quando solicitado pelo aplicativo em vez de precisar fazê-lo manualmente.

Os modelos de machine learning não são estáticos. À medida que novos dados de treinamento se tornam disponíveis, o modelo é retreinado e reimplantado. Uma maneira de obter a versão mais recente do modelo em seu aplicativo é reiniciar ou reimplantar seu aplicativo. No entanto, isso introduz tempo de inatividade do aplicativo. O serviço PredictionEnginePool fornece um mecanismo para recarregar um modelo atualizado sem reiniciar ou reimplantar seu aplicativo.

Defina o parâmetro watchForChanges como true, e o PredictionEnginePool inicia um FileSystemWatcher que escuta as notificações de alteração do sistema de arquivos e gera eventos quando há uma alteração no arquivo. Isso solicita que o PredictionEnginePool recarregue automaticamente o modelo.

O modelo é identificado pelo parâmetro modelName para que mais de um modelo por aplicativo possa ser recarregado após a alteração.

Dica

Como alternativa, você pode usar o método FromUri ao trabalhar com modelos armazenados remotamente. Em vez de observar eventos de alteração de arquivo, o FromUri sonda o local remoto em busca de alterações. O intervalo de sondagem padrão é de 5 minutos. Você pode aumentar ou diminuir o intervalo de sondagem com base nos requisitos do aplicativo. No exemplo de código abaixo, o PredictionEnginePool sonda o modelo armazenado no URI especificado a 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));

Carregar o modelo na função

Insira o seguinte código dentro da classe AnalyzeSentiment:

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

Esse código atribui o PredictionEnginePool passando-o para o construtor da função que você obtém por meio da injeção de dependência.

Usar o modelo para fazer previsões

Substitua a implementação existente do método Run na classe AnalyzeSentiment pelo código a seguir:

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 o método Run é executado, os dados de entrada da solicitação HTTP são desserializados e usados como entrada para o PredictionEnginePool. O método Predict é, então, chamado para fazer previsões usando o SentimentAnalysisModel registrado na classe Startup e retornará os resultados para o usuário se for bem-sucedido.

Testar localmente

Agora que está tudo definido, é hora de testar o aplicativo:

  1. Executar o aplicativo

  2. Abra o PowerShell e digite o seguinte código no prompt, em que PORT é a porta em que seu aplicativo está sendo executado. Normalmente, a porta é a 7071.

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

    Se houver êxito, a saída deverá ser semelhante ao texto abaixo:

    Negative
    

Parabéns! Você usou com êxito o modelo para fazer previsões pela internet usando uma função do Azure.

Próximas etapas