Tutorial: Categorizar problemas de suporte com a classificação multiclasse com ML.NET
Este tutorial de exemplo ilustra a utilização de ML.NET para criar um classificador de problemas do GitHub para preparar um modelo que classifica e prevê a etiqueta Área para um problema do GitHub através de uma aplicação de consola .NET Core com C# no Visual Studio.
Neste tutorial, ficará a saber como:
- Preparar os dados
- Transformar os dados
- Preparar o modelo
- Avaliar o modelo
- Prever com o modelo preparado
- Implementar e Prever com um modelo carregado
Pode encontrar o código fonte deste tutorial no repositório dotnet/samples .
Pré-requisitos
- Visual Studio 2022 com a carga de trabalho ".NET Desktop Development" instalada.
- O ficheiro separador problemas do GitHub (issues_train.tsv).
- O GitHub emite um ficheiro separado por separador de teste (issues_test.tsv).
Criar uma aplicação de consola
Criar um projeto
Crie uma Aplicação de Consola C# denominada "GitHubIssueClassification". Selecione Seguinte.
Selecione .NET 7 como a arquitetura a utilizar. Selecione Criar.
Crie um diretório com o nome Dados no projeto para guardar os ficheiros do conjunto de dados:
No Explorador de Soluções, clique com o botão direito do rato no projeto e selecione Adicionar>Nova Pasta. Escreva "Dados" e prima Enter.
Crie um diretório com o nome Modelos no seu projeto para guardar o modelo:
No Explorador de Soluções, clique com o botão direito do rato no projeto e selecione Adicionar>Nova Pasta. Escreva "Modelos" e prima Enter.
Instale o Pacote NuGet Microsoft.ML:
Nota
Este exemplo utiliza a versão estável mais recente dos pacotes NuGet mencionados, salvo indicação em contrário.
No Explorador de Soluções, clique com o botão direito do rato no projeto e selecione Gerir Pacotes NuGet. Selecione "nuget.org" como origem do pacote, selecione o separador Procurar, procure Microsoft.ML e selecione o botão Instalar . Selecione o botão OK na caixa de diálogo Pré-visualizar Alterações e, em seguida, selecione o botão Aceito na caixa de diálogo Aceitação da Licença se concordar com os termos de licenciamento dos pacotes listados.
Preparar os dados
Transfira os conjuntos de dados issues_train.tsv e issues_test.tsv e guarde-os na pasta Dados que criou anteriormente. O primeiro conjunto de dados prepara o modelo de machine learning e o segundo pode ser utilizado para avaliar a precisão do modelo.
No Explorador de Soluções, clique com o botão direito do rato em cada um dos ficheiros *.tsv e selecione Propriedades. Em Avançadas, altere o valor de Copiar para Diretório de Saída para Copiar se for mais recente.
Criar classes e definir caminhos
Adicione as seguintes instruções adicionais using
à parte superior do ficheiro Program.cs :
using Microsoft.ML;
using GitHubIssueClassification;
Crie três campos globais para manter os caminhos para os ficheiros transferidos recentemente e as variáveis globais para , MLContext
DataView
e PredictionEngine
:
_trainDataPath
tem o caminho para o conjunto de dados utilizado para preparar o modelo._testDataPath
tem o caminho para o conjunto de dados utilizado para avaliar o modelo._modelPath
tem o caminho onde o modelo preparado é guardado._mlContext
é o MLContext que fornece contexto de processamento._trainingDataView
é o IDataView utilizado para processar o conjunto de dados de preparação._predEngine
é utilizado PredictionEngine<TSrc,TDst> para predições individuais.
Adicione o seguinte código à linha diretamente abaixo das instruções using para especificar esses caminhos e as 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 seus dados de entrada e predições. Adicione uma nova classe ao seu projeto:
Em Explorador de Soluções, clique com o botão direito do rato no projeto e, em seguida, 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 ficheiro GitHubIssueData.cs é aberto no editor de código. Adicione a seguinte
using
instrução à parte superior 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 ficheiro 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;
}
É label
a coluna que pretende prever. Os identificados Features
são as entradas que dá ao modelo para prever a Etiqueta.
Utilize 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 String campos:
- a primeira coluna
ID
(ID de Problema do GitHub) - a segunda coluna
Area
(a predição para preparação) - a terceira coluna
Title
(título do problema do GitHub) é a primeirafeature
utilizada para prever oArea
- a quarta coluna
Description
é a segundafeature
utilizada para prever oArea
IssuePrediction
é a classe utilizada para predição depois de o modelo ter sido preparado. Tem um único string
(Area
) e um PredictedLabel
ColumnName
atributo. O PredictedLabel
é utilizado durante a predição e avaliação. Para avaliação, é utilizada uma entrada com dados de preparação, os valores previstos e o modelo.
Todas as operações ML.NET começam na classe MLContext . A inicialização mlContext
cria um novo ambiente de ML.NET que pode ser partilhado entre os objetos de fluxo de trabalho de criação de modelos. É semelhante, conceptualmente, a DBContext
em Entity Framework
.
Inicializar variáveis
Inicialize a _mlContext
variável global com uma nova instância de MLContext
com uma semente aleatória (seed: 0
) para resultados repetíveis/deterministas em várias preparações. Substitua a Console.WriteLine("Hello World!")
linha pelo seguinte código:
_mlContext = new MLContext(seed: 0);
Carregar os dados
ML.NET utiliza a interface IDataView como uma forma flexível e eficiente de descrever dados tabulares numéricos ou de texto. IDataView
pode carregar ficheiros de texto ou em tempo real (por exemplo, base de dados SQL ou ficheiros de registo).
Para inicializar e carregar a _trainingDataView
variável global para utilizá-la para o pipeline, adicione o seguinte código após a mlContext
inicialização:
_trainingDataView = _mlContext.Data.LoadFromTextFile<GitHubIssue>(_trainDataPath,hasHeader: true);
LoadFromTextFile() define o esquema de dados e lê no ficheiro. Utiliza as variáveis de caminho de dados e devolve um IDataView
.
Adicione o seguinte depois de chamar o LoadFromTextFile()
método:
var pipeline = ProcessData();
O ProcessData
método executa as seguintes tarefas:
- Extrai e transforma os dados.
- Devolve o pipeline de processamento.
Crie o ProcessData
método na parte inferior do ficheiro Program.cs com o seguinte código:
IEstimator<ITransformer> ProcessData()
{
}
Extrair funcionalidades e transformar os dados
Como pretende prever a etiqueta Área do GitHub para um GitHubIssue
, utilize o método MapValueToKey() para transformar a Area
coluna numa coluna de tipo Label
de chave numérica (um formato aceite por algoritmos de classificação) e adicione-a 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 de texto (Title
e Description
) num vetor numérico para cada chamada TitleFeaturized
e DescriptionFeaturized
. Acrescente a caracterização de ambas as colunas ao pipeline com o seguinte código:
.Append(_mlContext.Transforms.Text.FeaturizeText(inputColumnName: "Title", outputColumnName: "TitleFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(inputColumnName: "Description", outputColumnName: "DescriptionFeaturized"))
O último passo na preparação de dados combina todas as colunas de funcionalidades na coluna Funcionalidades com o método Concatenar( ). Por predefinição, um algoritmo de aprendizagem processa apenas funcionalidades da coluna Funcionalidades . Acrescente esta transformação ao pipeline com o seguinte código:
.Append(_mlContext.Transforms.Concatenate("Features", "TitleFeaturized", "DescriptionFeaturized"))
Em seguida, acrescente um AppendCacheCheckpoint para colocar em cache o DataView para que, quando iterar os dados várias vezes através da cache, possa obter um melhor desempenho, tal como acontece com o seguinte código:
.AppendCacheCheckpoint(_mlContext);
Aviso
Utilize AppendCacheCheckpoint para conjuntos de dados pequenos/médios para reduzir o tempo de preparação. NÃO o utilize (remova . AppendCacheCheckpoint()) ao processar conjuntos de dados muito grandes.
Devolva o pipeline no final do ProcessData
método .
return pipeline;
Este passo processa a pré-processamento/caracterização. A utilização de componentes adicionais disponíveis no ML.NET pode permitir melhores resultados com o seu modelo.
Criar e preparar o modelo
Adicione a seguinte chamada ao BuildAndTrainModel
método como a linha seguinte após a chamada para o ProcessData()
método:
var trainingPipeline = BuildAndTrainModel(_trainingDataView, pipeline);
O BuildAndTrainModel
método executa as seguintes tarefas:
- Cria a classe de algoritmo de preparação.
- Prepara o modelo.
- Prevê a área com base nos dados de preparação.
- Devolve o modelo.
Crie o BuildAndTrainModel
método logo após a declaração do ProcessData()
método, com o seguinte código:
IEstimator<ITransformer> BuildAndTrainModel(IDataView trainingDataView, IEstimator<ITransformer> pipeline)
{
}
Acerca da tarefa de classificação
A classificação é uma tarefa de machine learning que utiliza dados para determinar a categoria, tipo ou classe de um item ou linha de dados e é frequentemente um dos seguintes tipos:
- Binário: A ou B.
- Multiclasse: várias categorias que podem ser previstas através de um único modelo.
Para este tipo de problema, utilize um algoritmo de aprendizagem de classificação multiclasse, uma vez que a predição da categoria de problema pode ser uma de várias categorias (multiclasse) em vez de apenas duas (binárias).
Acrescente o algoritmo de machine learning às definições de transformação de dados ao adicionar o seguinte como 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 é o algoritmo de preparação de classificação de várias classes. Isto é acrescentado ao pipeline
e aceita os parâmetros em destaque Title
e Description
(Features
) e os Label
parâmetros de entrada para aprender com os dados históricos.
Preparar o modelo
Ajuste o modelo aos splitTrainSet
dados e devolva o modelo preparado ao adicionar o seguinte como a próxima linha de código no BuildAndTrainModel()
método:
_trainedModel = trainingPipeline.Fit(trainingDataView);
O Fit()
método prepara o seu modelo ao transformar o conjunto de dados e aplicar a preparação.
PredictionEngine é uma API de conveniência, que lhe permite transmitir e, em seguida, efetuar uma predição numa única instância de dados. Adicione-o como a linha seguinte no BuildAndTrainModel()
método:
_predEngine = _mlContext.Model.CreatePredictionEngine<GitHubIssue, IssuePrediction>(_trainedModel);
Prever com o modelo preparado
Adicione um problema do GitHub para testar a predição do modelo preparado no Predict
método 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.."
};
Utilize a função Predict() efetuar uma predição numa única linha de dados:
var prediction = _predEngine.Predict(issue);
Utilizar o modelo: resultados de predição
Apresentar GitHubIssue
e a predição de etiqueta correspondente Area
para partilhar os resultados e agir em conformidade. Crie um ecrã para os resultados com o seguinte Console.WriteLine() código:
Console.WriteLine($"=============== Single Prediction just-trained-model - Result: {prediction.Area} ===============");
Devolver o modelo preparado para ser utilizado para avaliação
Devolva o modelo no final do BuildAndTrainModel
método.
return trainingPipeline;
Avaliar o modelo
Agora que criou e preparou o modelo, tem de o avaliar com um conjunto de dados diferente para garantia de qualidade e validação. Evaluate
No método, o modelo criado no BuildAndTrainModel
é transmitido para ser avaliado. Crie o Evaluate
método logo após BuildAndTrainModel
, como no seguinte código:
void Evaluate(DataViewSchema trainingDataViewSchema)
{
}
O Evaluate
método executa as seguintes tarefas:
- Carrega o conjunto de dados de teste.
- Cria o avaliador de várias classes.
- Avalia o modelo e cria métricas.
- Apresenta as métricas.
Adicione uma chamada ao novo método, diretamente sob a chamada do BuildAndTrainModel
método, com o seguinte código:
Evaluate(_trainingDataView.Schema);
Tal como fez anteriormente com o conjunto de dados de preparação, carregue o conjunto de dados de teste ao adicionar o seguinte código ao Evaluate
método:
var testDataView = _mlContext.Data.LoadFromTextFile<GitHubIssue>(_testDataPath,hasHeader: true);
O método Evaluate() calcula as métricas de qualidade do modelo com o conjunto de dados especificado. Devolve um MulticlassClassificationMetrics objeto que contém as métricas gerais calculadas pelos avaliadores de classificação de várias classes.
Para apresentar as métricas para determinar a qualidade do modelo, tem de as obter primeiro.
Repare na utilização do método Transform() da variável global de machine learning _trainedModel
(um ITransformer) para introduzir as funcionalidades e devolver predições. Adicione o seguinte código ao Evaluate
método como a linha seguinte:
var testMetrics = _mlContext.MulticlassClassification.Evaluate(_trainedModel.Transform(testDataView));
As seguintes métricas são avaliadas para classificação de várias classes:
Micro Precisão – cada par de classe de exemplo contribui igualmente para a métrica de precisão. Quer que a Micro Precisão esteja o mais próxima possível de uma.
Precisão da Macro – todas as classes contribuem igualmente para a métrica de precisão. As classes minoritárias têm o mesmo peso que as classes maiores. Pretende que a Precisão da Macro esteja o mais próxima possível de uma.
Perda de registo – veja Perda de Registo. Pretende que a perda de registo esteja o mais próxima possível de zero.
Redução da perda de registos – varia entre [-inf, 1,00], em que 1,00 é predições perfeitas e 0 indica predições médias. Pretende que a redução da perda de registos esteja o mais próxima possível de uma.
Apresentar as métricas para validação de modelos
Utilize o seguinte código para apresentar as métricas, partilhar os resultados e, em seguida, agir sobre as mesmas:
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($"*************************************************************************************************************");
Guardar o modelo num ficheiro
Depois de satisfeito com o modelo, guarde-o num ficheiro para efetuar predições posteriormente ou noutra aplicação. Adicione o seguinte código ao método Evaluate
.
SaveModelAsFile(_mlContext, trainingDataViewSchema, _trainedModel);
Crie o SaveModelAsFile
método abaixo do seu Evaluate
método.
void SaveModelAsFile(MLContext mlContext,DataViewSchema trainingDataViewSchema, ITransformer model)
{
}
Adicione o seguinte código ao seu SaveModelAsFile
método. Este código utiliza o Save
método para serializar e armazenar o modelo preparado como um ficheiro zip.
mlContext.Model.Save(model, trainingDataViewSchema, _modelPath);
Implementar e Prever com um modelo
Adicione uma chamada ao novo método, diretamente sob a chamada do Evaluate
método, com o seguinte código:
PredictIssue();
Crie o PredictIssue
método logo após o Evaluate
método (e imediatamente antes do SaveModelAsFile
método), com o seguinte código:
void PredictIssue()
{
}
O PredictIssue
método executa as seguintes tarefas:
- Carrega o modelo guardado
- Cria um único problema de dados de teste.
- Prevê a área com base nos dados de teste.
- Combina dados de teste e predições para relatórios.
- Apresenta os resultados previstos.
Carregue o modelo guardado para a sua aplicação ao adicionar o seguinte código ao PredictIssue
método:
ITransformer loadedModel = _mlContext.Model.Load(_modelPath, out var modelInputSchema);
Adicione um problema do GitHub para testar a predição do modelo preparado no Predict
método ao criar uma instância de GitHubIssue
:
GitHubIssue singleIssue = new GitHubIssue() { Title = "Entity Framework crashes", Description = "When connecting to the database, EF is crashing" };
Tal como fez anteriormente, crie uma PredictionEngine
instância com o seguinte código:
_predEngine = _mlContext.Model.CreatePredictionEngine<GitHubIssue, IssuePrediction>(loadedModel);
PredictionEngine é uma API de conveniência, que lhe permite efetuar uma predição numa única instância de dados. PredictionEngine
não é seguro para threads. É aceitável utilizar em ambientes de thread único ou protótipo. Para melhorar o desempenho e a segurança dos threads em ambientes de produção, utilize o PredictionEnginePool
serviço, que cria um ObjectPool
objeto PredictionEngine
para utilização em toda a sua aplicação. Veja este guia sobre como utilizar PredictionEnginePool
numa API Web ASP.NET Core.
Nota
PredictionEnginePool
A extensão de serviço está atualmente em pré-visualização.
Utilize o PredictionEngine
para prever a etiqueta do GitHub da Área ao adicionar o seguinte código ao PredictIssue
método para a predição:
var prediction = _predEngine.Predict(singleIssue);
Utilizar o modelo carregado para predição
Apresentar Area
para categorizar o problema e agir em conformidade. Crie um ecrã para os resultados com o seguinte Console.WriteLine() código:
Console.WriteLine($"=============== Single Prediction - Result: {prediction.Area} ===============");
Resultados
Os seus resultados devem ser semelhantes aos seguintes. À medida que o pipeline é processado, apresenta mensagens. Poderá ver avisos ou mensagens de processamento. Estas mensagens foram removidas dos seguintes resultados para maior clareza.
=============== 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! Criou com êxito um modelo de machine learning para classificar e prever uma Etiqueta de área para um problema do GitHub. Pode encontrar o código fonte deste tutorial no repositório dotnet/samples .
Passos seguintes
Neste tutorial, ficou a saber como:
- Preparar os dados
- Transformar os dados
- Preparar o modelo
- Avaliar o modelo
- Prever com o modelo preparado
- Implementar e Prever com um modelo carregado
Avance para o tutorial seguinte para saber mais