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

Criar uma aplicação de consola

Criar um projeto

  1. Crie uma Aplicação de Consola C# denominada "GitHubIssueClassification". Selecione Seguinte.

  2. Selecione .NET 7 como a arquitetura a utilizar. Selecione Criar.

  3. 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.

  4. 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.

  5. 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

  1. 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.

  2. 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 , MLContextDataViewe 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:

  1. Em Explorador de Soluções, clique com o botão direito do rato no projeto e, em seguida, selecione Adicionar>Novo Item.

  2. 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 primeira feature utilizada para prever o Area
  • a quarta coluna Description é a segunda feature utilizada para prever o Area

IssuePrediction é a classe utilizada para predição depois de o modelo ter sido preparado. Tem um único string (Area) e um PredictedLabelColumnName 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 BuildAndTrainModelmé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