Tutorial: Categorizar problemas de suporte usando a classificação multiclasse com ML.NET
Este tutorial de exemplo ilustra o uso do ML.NET para criar uma classificação de problema do GitHub para treinar um modelo que classifica e prevê o rótulo de área de um problema do GitHub por meio de um aplicativo de console do .NET Core usando C# no Visual Studio.
Neste tutorial, você aprenderá a:
- Preparar seus dados
- Transformar os dados
- Treinar o modelo
- Avaliar o modelo
- Prever com o modelo treinado
- Implantar e prever com um modelo carregado
Você pode encontrar o código-fonte para este tutorial no repositório dotnet/samples.
Pré-requisitos
- Visual Studio 2022 com a carga de trabalho "Desenvolvimento de área de trabalho do .NET" instalada.
- O arquivo de problemas do GitHub separados por tabulação (issues_train.tsv).
- O arquivo de testes de problemas do GitHub separados por tabulação (issues_test.tsv).
Criar um aplicativo de console
Criar um projeto
Crie um aplicativo de console C# chamado "GitHubIssueClassification". Selecione Avançar.
Escolha o .NET 7 como a estrutura a ser usada. Selecione Criar.
Crie um diretório chamado Data no seu projeto para salvar seus arquivos do conjunto de dados:
No Gerenciador de Soluções, clique com o botão direito do mouse no seu projeto e selecione Adicionar>Nova Pasta. Digite "Dados" e pressione Enter.
Crie um diretório chamado Modelos em seu projeto para salvar seu modelo:
No Gerenciador de Soluções, clique com o botão direito do mouse no seu projeto e selecione Adicionar>Nova Pasta. Digite "Modelos" e pressione Enter.
Instalar o Pacote NuGet Microsoft.ML:
Observação
Este exemplo usa a versão estável mais recente dos pacotes NuGet mencionados, salvo indicação em contrário.
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 origem do Pacote, selecione a guia Procurar, pesquise Microsoft.ML e selecione o botão Instalar. Selecione o botão OK na caixa de diálogo Visualizar Alterações e selecione o botão Aceito na caixa de diálogo Aceitação da Licença, se concordar com o termos de licença para os pacotes listados.
Preparar seus dados
Baixe os conjuntos de dados issues_train.tsv e issues_test.tsv e salve-os na pasta Dados que foi criada. O primeiro conjunto de dados treina o modelo de aprendizado de máquina e o segundo pode ser usado para avaliar a precisão do seu modelo.
No Gerenciador de Soluções, clique com o botão direito do mouse em cada um dos arquivos*.tsv e selecione Propriedades. Em Avançado, altere o valor de Copiar para Diretório de Saída para Copiar se for mais novo.
Criar classes e definir demarcadores
Adicione as seguintes instruções using
adicionais ao início do arquivo Program.cs:
using Microsoft.ML;
using GitHubIssueClassification;
Crie três campos globais para manter os caminhos para os arquivos baixados recentemente e variáveis globais para MLContext
, DataView
e PredictionEngine
:
_trainDataPath
tem o demarcador para o conjunto de dados usado para treinar o modelo._testDataPath
tem o demarcador para o conjunto de dados usado para avaliar o modelo._modelPath
tem o demarcador em que o modelo treinado é salvo._mlContext
é o MLContext que fornece o contexto de processamento._trainingDataView
é o IDataView usado para processar o conjunto de dados de treinamento._predEngine
é o PredictionEngine<TSrc,TDst> usado para previsões individuais.
Adicione o seguinte código à linha diretamente abaixo das instruções de uso para especificar estes caminhos e outras variáveis:
string _appPath = Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) ?? ".";
string _trainDataPath = Path.Combine(_appPath, "..", "..", "..", "Data", "issues_train.tsv");
string _testDataPath = Path.Combine(_appPath, "..", "..", "..", "Data", "issues_test.tsv");
string _modelPath = Path.Combine(_appPath, "..", "..", "..", "Models", "model.zip");
MLContext _mlContext;
PredictionEngine<GitHubIssue, IssuePrediction> _predEngine;
ITransformer _trainedModel;
IDataView _trainingDataView;
Crie algumas classes para os dados de entrada e as previsões. 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>Novo Item.
Na caixa de diálogo Adicionar Novo Item, selecione Classe e altere o campo Nome para GitHubIssueData.cs. Em seguida, selecione o botão Adicionar.
O arquivo GitHubIssueData.cs é aberto no editor de códigos. Adicione a seguinte instrução
using
acima de GitHubIssueData.cs:
using Microsoft.ML.Data;
Remova a definição de classe existente e adicione o seguinte código, que tem duas classes, GitHubIssue
e IssuePrediction
, ao arquivo GitHubIssueData.cs:
public class GitHubIssue
{
[LoadColumn(0)]
public string? ID { get; set; }
[LoadColumn(1)]
public string? Area { get; set; }
[LoadColumn(2)]
public required string Title { get; set; }
[LoadColumn(3)]
public required string Description { get; set; }
}
public class IssuePrediction
{
[ColumnName("PredictedLabel")]
public string? Area;
}
O label
é a coluna que você deseja prever. O Features
identificado são as entradas que você atribui ao modelo para prever o rótulo.
Use o atributo LoadColumnAttribute para especificar os índices das colunas de origem no conjunto de dados.
GitHubIssue
é a classe de conjunto de dados de entrada e tem os seguintes campos String:
- a primeira coluna
ID
(ID de problema do GitHub) - a segunda coluna
Area
(a previsão do treinamento) - a terceira coluna
Title
(título do problema de GitHub) é o primeirofeature
usado para prever oArea
- a quarta coluna
Description
é o segundofeature
usado para prever oArea
IssuePrediction
é a classe usada para previsão depois que o modelo foi treinado. Tem um único string
(Area
) e um atributo PredictedLabel
ColumnName
. O PredictedLabel
é usado durante a previsão e avaliação. Para avaliação, uma entrada com dados de treinamento, os valores previstos e o modelo são usados.
Todas as operações do ML.NET iniciam na classe MLContext. Inicializar mlContext
cria um novo ambiente do ML.NET que pode ser compartilhado entre os objetos do fluxo de trabalho de criação de modelo. É similar, conceitualmente, a DBContext
em Entity Framework
.
Inicializar variáveis
Inicialize a variável global _mlContext
com uma nova instância de MLContext
com uma semente aleatória (seed: 0
) para obter resultados repetíveis/determinísticos entre vários treinamentos. Substitua a linha Console.WriteLine("Hello World!")
pelo código a seguir:
_mlContext = new MLContext(seed: 0);
Carregar os dados
O ML.NET usa a interface IDataView como uma maneira flexível e eficiente de descrever dados numéricos ou tabulares de texto. O IDataView
pode carregar arquivos de texto ou em tempo real (por exemplo, banco de dados SQL ou arquivos de log).
Para inicializar e carregar a variável global _trainingDataView
para utilizá-la para o pipeline, adicione o seguinte código após a inicialização de mlContext
:
_trainingDataView = _mlContext.Data.LoadFromTextFile<GitHubIssue>(_trainDataPath,hasHeader: true);
O LoadFromTextFile() define o esquema de dados e lê o arquivo. Ele usa as variáveis de caminho de dados e retorna uma IDataView
.
Adicione o seguinte depois de chamar o LoadFromTextFile()
método:
var pipeline = ProcessData();
O método ProcessData
executa as seguintes tarefas:
- Extrai e transforma os dados.
- Retorna o pipeline de processamento.
Crie o método ProcessData
na parte inferior do arquivo Program.cs usando o seguinte código:
IEstimator<ITransformer> ProcessData()
{
}
Extrair recursos e transformar os dados
Uma vez que você deseja prever o rótulo do GitHub de Área de um GitHubIssue
, use o método MapValueToKey() para transformar a coluna Area
em um tipo de chave numérica Label
(um formato aceito pelos algoritmos de classificação da coluna) e adicione-o como uma nova coluna de conjunto de dados:
var pipeline = _mlContext.Transforms.Conversion.MapValueToKey(inputColumnName: "Area", outputColumnName: "Label")
Em seguida, chame mlContext.Transforms.Text.FeaturizeText
que transforma as colunas do texto (Title
e Description
) em um vetor numérico para cada TitleFeaturized
e DescriptionFeaturized
chamado. Acrescente a personalização para ambas as colunas ao pipeline com o código a seguir:
.Append(_mlContext.Transforms.Text.FeaturizeText(inputColumnName: "Title", outputColumnName: "TitleFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(inputColumnName: "Description", outputColumnName: "DescriptionFeaturized"))
A última etapa na preparação de dados combina todas as colunas de recursos na coluna Recursos usando o método Concatenate(). Por padrão, um algoritmo de aprendizado processa apenas os recursos da coluna Features. Acrescente esta transformação ao pipeline com o código a seguir:
.Append(_mlContext.Transforms.Concatenate("Features", "TitleFeaturized", "DescriptionFeaturized"))
Em seguida, acrescente um AppendCacheCheckpoint para armazenar a DataView em cache, para melhorar o desempenho ao iterar nos dados várias vezes usando o cache, como no código a seguir:
.AppendCacheCheckpoint(_mlContext);
Aviso
Use AppendCacheCheckpoint para conjuntos de dados pequenos/médios a fim de reduzir o tempo de treinamento. NÃO o utilize (remova .AppendCacheCheckpoint()) ao lidar com conjuntos de dados grandes.
Retorne o pipeline no final do método ProcessData
.
return pipeline;
Esta etapa manipula o pré-processamento/personalização. Usar componentes adicionais disponíveis no ML.NET pode permitir melhores resultados com o seu modelo.
Criar e treinar o modelo
Adicione a seguinte chamada ao método BuildAndTrainModel
como a próxima linha após a chamada ao método ProcessData()
:
var trainingPipeline = BuildAndTrainModel(_trainingDataView, pipeline);
O método BuildAndTrainModel
executa as seguintes tarefas:
- Cria a classe de algoritmo de treinamento.
- Treina o modelo.
- Prevê a área com base em dados de treinamento.
- Retorna o modelo.
Crie o método BuildAndTrainModel
, logo após a declaração do método ProcessData()
, usando o seguinte código:
IEstimator<ITransformer> BuildAndTrainModel(IDataView trainingDataView, IEstimator<ITransformer> pipeline)
{
}
Sobre a tarefa de classificação
A classificação é uma tarefa de aprendizado de máquina que usa dados para determinar a categoria, o tipo ou a classe de um item ou linha de dados e costuma ser de um dos seguintes tipos:
- Binário: A ou B.
- Multiclasse: várias categorias que podem ser previstas usando um único modelo.
Para esse tipo de problema, use um algoritmo de aprendizado de classificação Multiclasse, pois a previsão de categoria do problema pode ser uma das várias categorias (multiclasse), em vez de apenas duas (binária).
Acrescente o algoritmo de aprendizado de máquina às definições de transformação de dados adicionando o seguinte como a primeira linha de código em BuildAndTrainModel()
:
var trainingPipeline = pipeline.Append(_mlContext.MulticlassClassification.Trainers.SdcaMaximumEntropy("Label", "Features"))
.Append(_mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel"));
O SdcaMaximumEntropy é seu algoritmo de treinamento de classificação multiclasse. Isso é anexado ao pipeline
e aceita os Title
e Description
(Features
) personalizados e os parâmetro de entrada Label
para aprender com os dados históricos.
Treinar o modelo
Ajuste o modelo aos dados splitTrainSet
e retorne o modelo treinado adicionando o seguinte como a próxima linha de código no método BuildAndTrainModel()
:
_trainedModel = trainingPipeline.Fit(trainingDataView);
O método Fit()
treina o modelo transformando o conjunto de dados e aplicando o treinamento.
O PredictionEngine é uma API de conveniência, que permite passar uma única instância de dados e, em seguida, executar uma previsão nessa única instância de dados. Adicione isso como a próxima linha no método BuildAndTrainModel()
:
_predEngine = _mlContext.Model.CreatePredictionEngine<GitHubIssue, IssuePrediction>(_trainedModel);
Prever com o modelo treinado
Adicione um problema do GitHub para testar a previsão do modelo treinado no método Predict
ao criar uma instância de GitHubIssue
:
GitHubIssue issue = new GitHubIssue() {
Title = "WebSockets communication is slow in my machine",
Description = "The WebSockets communication used under the covers by SignalR looks like is going slow in my development machine.."
};
Use a função Predict() faz uma previsão em uma única coluna de dados:
var prediction = _predEngine.Predict(issue);
Usar o modelo: resultados de previsão
Exiba GitHubIssue
e a previsão de rótulo Area
correspondente para compartilhar os resultados e agir de acordo com eles. Crie uma exibição para os resultados usando o seguinte código Console.WriteLine():
Console.WriteLine($"=============== Single Prediction just-trained-model - Result: {prediction.Area} ===============");
Retornar o modelo treinado a ser usado para avaliação
Retorne o modelo no final do método BuildAndTrainModel
.
return trainingPipeline;
Avaliar o modelo
Agora que você criou e treinou o modelo, precisa avaliá-lo com um conjunto de dados diferente para garantia de qualidade e validação. No método Evaluate
, o modelo criado em BuildAndTrainModel
é passado para ser avaliado. Crie o método Evaluate
, logo após BuildAndTrainModel
, como no código a seguir:
void Evaluate(DataViewSchema trainingDataViewSchema)
{
}
O método Evaluate
executa as seguintes tarefas:
- Carrega o conjunto de dados de teste.
- Cria o avaliador multiclasse.
- Avalia o modelo e cria métricas.
- Exibe as métricas.
Adicione uma chamada ao novo método logo abaixo da chamada do método BuildAndTrainModel
usando o seguinte código:
Evaluate(_trainingDataView.Schema);
Como você fez anteriormente com o conjunto de dados de treinamento, carregue o conjunto de dados de teste adicionando o seguinte código ao método Evaluate
:
var testDataView = _mlContext.Data.LoadFromTextFile<GitHubIssue>(_testDataPath,hasHeader: true);
O método Evaluate() calcula as métricas de qualidade para o modelo usando o conjunto de dados especificado. Ele retorna um objeto MulticlassClassificationMetrics que contém as métricas gerais calculadas pelos avaliadores de classificação multiclasse.
Para exibir as métricas para determinar a qualidade do modelo, você precisará obtê-las primeiro.
Observe o uso do método Transform() da variável global _trainedModel
de aprendizado de máquina (um Transformador) para inserir os recursos e retornar previsões. Adicione o seguinte código ao método Evaluate
como a linha seguinte:
var testMetrics = _mlContext.MulticlassClassification.Evaluate(_trainedModel.Transform(testDataView));
As métricas a seguir são avaliadas para classificação multiclasse:
Microprecisão – todo par de classe/exemplo contribui igualmente para a métrica de precisão. Convém que a Microprecisão seja tão próxima de 1 quanto possível.
Macroprecisão – toda classe contribui igualmente para a métrica de precisão. Classes minoritárias recebem o mesmo peso que as classes maiores. Convém que a Macroprecisão seja tão próxima de 1 quanto possível.
Perda de log – consulte Perda de log. Convém que a Perda de log seja tão próxima de zero quanto possível.
Redução de perda de log – varia de [-inf, 1.00], em que 1.00 é composto pelas previsões perfeitas e 0 indica previsões de média. Convém que a redução de perda de log seja tão próxima de 1 quanto possível.
Exibir as métricas para validação de modelo
Use o código a seguir para exibir as métricas, compartilhar os resultados e, em seguida, agir com relação a eles:
Console.WriteLine($"*************************************************************************************************************");
Console.WriteLine($"* Metrics for Multi-class Classification model - Test Data ");
Console.WriteLine($"*------------------------------------------------------------------------------------------------------------");
Console.WriteLine($"* MicroAccuracy: {testMetrics.MicroAccuracy:0.###}");
Console.WriteLine($"* MacroAccuracy: {testMetrics.MacroAccuracy:0.###}");
Console.WriteLine($"* LogLoss: {testMetrics.LogLoss:#.###}");
Console.WriteLine($"* LogLossReduction: {testMetrics.LogLossReduction:#.###}");
Console.WriteLine($"*************************************************************************************************************");
Salvar o modelo em um arquivo
Quando estiver satisfeito com seu modelo, salve-o em um arquivo para fazer previsões posteriormente ou em outro aplicativo. Adicione o seguinte código ao Evaluate
método.
SaveModelAsFile(_mlContext, trainingDataViewSchema, _trainedModel);
Crie o método SaveModelAsFile
abaixo de seu método Evaluate
.
void SaveModelAsFile(MLContext mlContext,DataViewSchema trainingDataViewSchema, ITransformer model)
{
}
Adicione o código a seguir ao método SaveModelAsFile
. Esse código usa o método Save
para serializar e armazenar o modelo treinado como um arquivo zip.
mlContext.Model.Save(model, trainingDataViewSchema, _modelPath);
Implantar e prever com um modelo
Adicione uma chamada ao novo método logo abaixo da chamada do método Evaluate
usando o seguinte código:
PredictIssue();
Crie o método PredictIssue
logo após o método Evaluate
(e antes do método SaveModelAsFile
) usando o seguinte código:
void PredictIssue()
{
}
O método PredictIssue
executa as seguintes tarefas:
- Carrega o modelo salvo
- Cria um único problema dos dados de teste.
- Prevê a área com base em dados de teste.
- Combina dados de teste e previsões para relatórios.
- Exibe os resultados previstos.
Carregue o modelo salvo em seu aplicativo adicionando o seguinte código ao método PredictIssue
:
ITransformer loadedModel = _mlContext.Model.Load(_modelPath, out var modelInputSchema);
Adicione um problema do GitHub para testar a previsão do modelo treinado no método Predict
ao criar uma instância de GitHubIssue
:
GitHubIssue singleIssue = new GitHubIssue() { Title = "Entity Framework crashes", Description = "When connecting to the database, EF is crashing" };
Como você fez anteriormente, crie uma instância de PredictionEngine
com o código a seguir:
_predEngine = _mlContext.Model.CreatePredictionEngine<GitHubIssue, IssuePrediction>(loadedModel);
O PredictionEngine é uma API de conveniência, que permite executar uma previsão em uma instância individual de dados. PredictionEngine
não é thread-safe. É aceitável usá-lo em ambientes de thread único ou de protótipo. Para aprimorar o desempenho e o acesso thread-safe em ambientes de produção, use o serviço PredictionEnginePool
, que cria um ObjectPool
de objetos PredictionEngine
para uso em todo o aplicativo. Confira este guia sobre como usar o PredictionEnginePool
em uma API Web ASP.NET Core.
Observação
A extensão de serviço PredictionEnginePool
está atualmente em versão prévia.
Use o PredictionEngine
para prever o rótulo do GitHub de Área adicionando o seguinte código ao método PredictIssue
para a previsão:
var prediction = _predEngine.Predict(singleIssue);
Usar o modelo carregado para previsão
Exiba Area
para categorizar o problema e agir adequadamente para solucioná-lo. Crie uma exibição para os resultados usando o seguinte código Console.WriteLine():
Console.WriteLine($"=============== Single Prediction - Result: {prediction.Area} ===============");
Resultados
Seus resultados devem ser semelhantes aos seguintes. Conforme o pipeline processa, exibe mensagens. Você pode ver avisos ou mensagens de processamento. Essas mensagens foram removidas dos resultados a seguir para ficar mais claro.
=============== Single Prediction just-trained-model - Result: area-System.Net ===============
*************************************************************************************************************
* Metrics for Multi-class Classification model - Test Data
*------------------------------------------------------------------------------------------------------------
* MicroAccuracy: 0.738
* MacroAccuracy: 0.668
* LogLoss: .919
* LogLossReduction: .643
*************************************************************************************************************
=============== Single Prediction - Result: area-System.Data ===============
Parabéns! Agora você criou com sucesso um modelo de machine learning para classificar e prever um rótulo de Área para um problema do GitHub. Você pode encontrar o código-fonte para este tutorial no repositório dotnet/samples.
Próximas etapas
Neste tutorial, você aprendeu a:
- Preparar seus dados
- Transformar os dados
- Treinar o modelo
- Avaliar o modelo
- Prever com o modelo treinado
- Implantar e prever com um modelo carregado
Avançar para o próximo tutorial para saber mais