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
- Visual Studio 2022 com as cargas de trabalho de desenvolvimento para área de trabalho do .NET e desenvolvimento do Azure instaladas. O SDK do .NET 6 é instalado automaticamente quando você seleciona essa carga de trabalho.
- Ferramentas do Azure Functions
- PowerShell
- Modelo previamente treinado. Baixe este modelo de machine learning de análise de sentimento pré-treinado ou use o tutorial de Análise de Sentimento do ML.NET para criar seu modelo.
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
No Visual Studio 2022, abra a caixa de diálogo Criar um projeto.
Na caixa de diálogo "Criar um projeto", selecione o modelo de projeto Azure Functions.
Na caixa de texto Nome, digite "SentimentAnalysisFunctionsApp" e, em seguida, selecione o botão Avançar.
Na caixa de diálogo "Informações adicionais", deixe todos os padrões como estão e selecione o botão Criar.
Instale o pacote NuGet Microsoft.ML
- No Gerenciador de Soluções, clique com o botão direito do mouse no seu projeto e selecione Gerenciar Pacotes NuGet.
- Escolha "nuget.org" como a fonte do pacote.
- Selecione a guia "Procurar".
- Pesquise Microsoft.ML.
- Selecione o pacote na lista e clique no botão Instalar.
- Clique no botão OK na caixa de diálogo Pré-visualização de alterações
- 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
- 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.
- Copie o modelo previamente criado para o diretório MLModels.
- 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:
No Gerenciador de Soluções, clique com o botão direito do mouse no projeto e selecione Adicionar>Nova Função do Azure.
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.
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 diretiva
using
à parte superior do 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-chavestatic
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:
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.
No Gerenciador de Soluções, clique com o botão direito do mouse no diretório DataModels e selecione Adicionar > Classe.
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 diretiva
using
à 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; }
No Gerenciador de Soluções, clique com o botão direito do mouse no diretório DataModels e selecione Adicionar > Classe.
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 diretiva
using
à 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 deSentimentData
, que dá acesso aos dados originais na propriedadeSentimentText
, 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.
No Gerenciador de Soluções, clique com o botão direito do mouse no projeto e selecione Adicionar>Classe.
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.
Adicione as seguintes diretivas
using
à 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;
Remova o código existente abaixo das diretivas
using
e adicione o seguinte código:[assembly: FunctionsStartup(typeof(Startup))] namespace SentimentAnalysisFunctionsApp { public class Startup : FunctionsStartup { } }
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;
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"); } }
Em seguida, adicione um novo método chamado
Configure
para registrar o serviçoPredictionEnginePool
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:
Executar o aplicativo
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.