Tutoriel : catégoriser les problèmes de prise en charge à l’aide de la classification multiclasse avec ML.NET

Ce tutoriel montre comment utiliser ML.NET pour créer un classifieur de problèmes GitHub afin d’entraîner un modèle qui classe et prédit l’étiquette Area d’un problème GitHub par le biais d’une application console .NET Core en C# dans Visual Studio.

Dans ce tutoriel, vous allez apprendre à :

  • Préparer vos données
  • Transformer les données
  • Effectuer l’apprentissage du modèle
  • Évaluer le modèle
  • Prédire avec le modèle entraîné
  • Déployer et prédire avec un modèle chargé

Vous trouverez le code source de ce tutoriel dans le référentiel dotnet/samples.

Prérequis

Création d’une application console

Création d’un projet

  1. Créez une application Console C# appelée « GitHubIssueClassification ». Sélectionnez Suivant.

  2. Choisissez .NET 7 comme infrastructure à utiliser. Sélectionnez Create (Créer).

  3. Créez un répertoire nommé Données dans votre projet pour enregistrer vos fichiers de jeu de données :

    Dans l'Explorateur de solutions, cliquez avec le bouton droit sur votre projet, puis sélectionnez Ajouter>Nouveau dossier. Tapez « Données », puis appuyez sur Entrée.

  4. Créez un répertoire nommé Models dans votre projet pour enregistrer votre modèle :

    Dans l'Explorateur de solutions, cliquez avec le bouton droit sur votre projet, puis sélectionnez Ajouter>Nouveau dossier. Tapez « Modèles », puis appuyez sur Entrée.

  5. Installez le package NuGet Microsoft.ML :

    Notes

    Cet exemple utilise la dernière version stable des packages NuGet mentionnés, sauf indication contraire.

    Dans l'Explorateur de solutions, cliquez avec le bouton droit sur votre projet, puis sélectionnez Gérer les packages NuGet. Choisissez « nuget.org » comme source du package, sélectionnez l’onglet Parcourir, recherchez Microsoft.ML, sélectionnez le package dans la liste, puis sélectionnez le bouton Installer. Cliquez sur le bouton OK dans la boîte de dialogue Aperçu des modifications, puis sur le bouton J’accepte dans la boîte de dialogue Acceptation de la licence si vous acceptez les termes du contrat de licence pour les packages répertoriés.

Préparer vos données

  1. Téléchargez les jeux de données issues_train.tsv et issues_test.tsv, puis enregistrez-les dans le dossier Données créé précédemment. Le premier jeu de données effectue l’apprentissage automatique du modèle, et le second peut servir à évaluer la précision de votre modèle.

  2. Dans l'Explorateur de solutions, cliquez avec le bouton droit sur chacun des fichiers *.tsv, puis sélectionnez Propriétés. Sous Avancé, définissez la valeur Copier dans le répertoire de sortie sur Copier si plus récent.

Créer des classes et définir des chemins

Ajoutez les instructions using supplémentaires suivantes en haut du fichier Program.cs :

using Microsoft.ML;
using GitHubIssueClassification;

Créez trois champs globaux pour accueillir les chemins des fichiers récemment téléchargés, puis des variables globales pour MLContext, DataView et PredictionEngine :

  • _trainDataPath contient le chemin d’accès au jeu de données utilisé pour l’apprentissage du modèle.
  • _testDataPath contient le chemin d’accès au jeu de données utilisé pour évaluer le modèle.
  • _modelPath contient le chemin d’accès où le modèle formé est enregistré.
  • _mlContext est le MLContext qui fournit le contexte de traitement.
  • _trainingDataView est le IDataView utilisé pour traiter le jeu de données d’entraînement.
  • _predEngine est le PredictionEngine<TSrc,TDst> utilisé pour des prédictions uniques.

Ajoutez le code suivant à la ligne située en dessous des instructions using pour spécifier ces chemins d’accès et d’autres variables :

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;

Créez des classes pour vos données d’entrée et vos prévisions. Ajoutez une nouvelle classe à votre projet :

  1. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet, puis sélectionnez Ajouter>Nouvel élément.

  2. Dans la boîte de dialogue Ajouter un nouvel élément, sélectionnez Classe, puis remplacez la valeur du champ Nom par GitHubIssueData.cs. Ensuite, sélectionnez le bouton Ajouter.

    Le fichier GitHubIssueData.cs s’ouvre dans l’éditeur de code. Ajoutez l’instruction using suivante en haut de GitHubIssueData.cs :

using Microsoft.ML.Data;

Supprimez la définition de classe existante et ajoutez le code suivant, lequel contient deux classes (GitHubIssue et IssuePrediction), au fichier 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 est la colonne à prédire. Les valeurs Features identifiées sont les entrées que vous fournissez au modèle pour prédire l’étiquette.

Utilisez LoadColumnAttribute pour spécifier les index des colonnes sources dans le jeu de données.

GitHubIssue, la classe de jeu de données d’entrée, comprend les champs String suivants :

  • La première colonne ID est l’ID du problème GitHub.
  • La deuxième colonne Area est la prédiction pour l’entraînement.
  • La troisième colonne Title (titre du problème GitHub) est la première caractéristique (feature) utilisée pour prédire l’étiquette Area
  • La quatrième colonne Description est la deuxième caractéristique (feature) utilisée pour prédire Area

IssuePrediction représente la classe utilisée pour la prédiction, une fois le modèle formé. Il comporte une valeur string unique (Area) et un attribut ColumnNamePredictedLabel. L’attribut PredictedLabel est utilisé pendant la prédiction et l’évaluation. L’évaluation utilise une entrée avec les données d’apprentissage, les valeurs prédites et le modèle.

Toutes les opérations de ML.NET démarrent dans la classe MLContext. L’initialisation de mlContext crée un environnement ML.NET qui peut être partagé par les objets du workflow de création de modèle. Sur le plan conceptuel, cette classe est similaire à DBContext dans Entity Framework.

Initialiser les variables

Initialisez la variable globale _mlContext à l’aide d’une nouvelle instance de MLContext avec une valeur de départ aléatoire (seed: 0) pour obtenir des résultats reproductibles/déterministes dans différents entraînements. Remplacez la ligne Console.WriteLine("Hello World!") par le code suivant :

_mlContext = new MLContext(seed: 0);

Chargement des données

ML.NET utilise l’interface IDataView comme un moyen flexible et efficace de décrire des données tabulaires numériques ou texte. IDataView peut charger des fichiers texte ou en temps réel (par exemple, une base de données SQL ou des fichiers journaux).

Pour initialiser et charger la variable globale _trainingDataView afin de l’utiliser pour le pipeline, ajoutez le code suivant après l’initialisation de mlContext :

_trainingDataView = _mlContext.Data.LoadFromTextFile<GitHubIssue>(_trainDataPath,hasHeader: true);

LoadFromTextFile() définit le schéma de données et lit le fichier. Elle prend les variables de chemin de données et retourne un IDataView.

Ajoutez ce qui suit après avoir appelé la méthode LoadFromTextFile() :

var pipeline = ProcessData();

La méthode ProcessData exécute les tâches suivantes :

  • Extrait et transforme les données.
  • Retourne le pipeline de traitement.

Créez la méthode ProcessData en bas du fichier Program.cs à l’aide du code suivant :

IEstimator<ITransformer> ProcessData()
{

}

Extraire des caractéristiques et transformer les données

Pour prédire l’étiquette Area GitHub pour un GitHubIssue, utilisez la méthode MapValueToKey() afin de transformer la colonne Area en une colonne Label de type clé numérique (un format accepté par les algorithmes de classification) et ajoutez-la comme nouvelle colonne au jeu de données :

var pipeline = _mlContext.Transforms.Conversion.MapValueToKey(inputColumnName: "Area", outputColumnName: "Label")

Ensuite, appelez mlContext.Transforms.Text.FeaturizeText qui transforme les colonnes de texte (Title et Description) en vecteur numérique pour chaque TitleFeaturized et DescriptionFeaturized appelé. Utilisez le code suivant pour ajouter la caractérisation des deux colonnes au pipeline :

.Append(_mlContext.Transforms.Text.FeaturizeText(inputColumnName: "Title", outputColumnName: "TitleFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(inputColumnName: "Description", outputColumnName: "DescriptionFeaturized"))

La dernière étape de préparation des données consiste à combiner toutes les colonnes de caractéristiques dans la colonne Features à l’aide de la méthode Concatenate(). Par défaut, un algorithme d’apprentissage traite uniquement les caractéristiques issues de la colonne Features. Utilisez le code suivant pour ajouter cette transformation au pipeline :

.Append(_mlContext.Transforms.Concatenate("Features", "TitleFeaturized", "DescriptionFeaturized"))

Ajoutez ensuite un AppendCacheCheckpoint pour mettre en cache le DataView. Ainsi, quand vous itérerez plusieurs fois sur les données, l’utilisation du cache vous fera peut-être gagner en performances, à l’instar du code suivant :

.AppendCacheCheckpoint(_mlContext);

Avertissement

Utilisez AppendCacheCheckpoint pour les jeux de données petits/moyens afin de réduire le temps d’apprentissage. Ne l’utilisez PAS (supprimez .AppendCacheCheckpoint()) lors du traitement de jeux de données très volumineux.

Retournez le pipeline à la fin de la méthode ProcessData.

return pipeline;

Cette étape gère le prétraitement/la caractérisation. L’utilisation des composants supplémentaires disponibles dans ML.NET peut améliorer les résultats de votre modèle.

Générer et entraîner le modèle

Ajoutez l’appel suivant à la méthode BuildAndTrainModel comme ligne suivante après l’appel à la méthode ProcessData() :

var trainingPipeline = BuildAndTrainModel(_trainingDataView, pipeline);

La méthode BuildAndTrainModel exécute les tâches suivantes :

  • Crée la classe d’algorithme d’entraînement.
  • Effectue l’apprentissage du modèle.
  • Prédit la zone en fonction des données d’entraînement.
  • Retourne le modèle.

Créez la méthode BuildAndTrainModel juste après la méthode ProcessData(), en utilisant le code suivant :

IEstimator<ITransformer> BuildAndTrainModel(IDataView trainingDataView, IEstimator<ITransformer> pipeline)
{

}

À propos de la tâche de classification

La classification est une tâche de machine learning qui utilise des données pour déterminer la catégorie, le type ou la classe d’un élément ou d’une ligne de données. Cette tâche est souvent d’un de ces types :

  • Binaire : A ou B.
  • Multiclasse : plusieurs catégories pouvant être prédites à l’aide d’un modèle unique.

Pour ce type de problème, utilisez un algorithme de machine learning de classification multiclasse, dans la mesure où votre prédiction de catégorie de problème peut appartenir à une catégorie parmi plusieurs possibles (multiclasse) plutôt qu’à une catégorie parmi deux possibles (binaire).

Ajoutez l’algorithme de machine learning aux définitions de transformation de données en ajoutant la première ligne de code suivante dans BuildAndTrainModel() :

var trainingPipeline = pipeline.Append(_mlContext.MulticlassClassification.Trainers.SdcaMaximumEntropy("Label", "Features"))
        .Append(_mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel"));

SdcaMaximumEntropy est l’algorithme de machine learning de classification multiclasse. Il est ajouté à pipeline et accepte les caractéristiques Title et Description (Features) ainsi que les paramètres d’entrée Label pour apprendre à partir des données d’historique.

Entraîner le modèle

Ajustez le modèle aux données splitTrainSet et retournez le modèle entraîné en ajoutant la ligne de code suivante dans la méthode BuildAndTrainModel() :

_trainedModel = trainingPipeline.Fit(trainingDataView);

La méthode Fit() entraîne votre modèle en transformant le jeu de données et en appliquant l’entraînement.

PredictionEngine est une API utile qui vous permet de passer et d’exécuter une prédiction sur une seule instance de données. Ajoutez ce contenu à la ligne suivante dans la méthode BuildAndTrainModel() :

_predEngine = _mlContext.Model.CreatePredictionEngine<GitHubIssue, IssuePrediction>(_trainedModel);

Prédire avec le modèle entraîné

Ajoutez un problème GitHub pour tester la prédiction du modèle entraîné dans la méthode Predict en créant une instance 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.."
};

Utilisez la fonction Predict() pour effectuer une prédiction sur une seule ligne de données :

var prediction = _predEngine.Predict(issue);

Utilisation du modèle : résultats de la prédiction

Affichez GitHubIssue et la prédiction d’étiquette Area correspondante pour partager les résultats et prendre les mesures nécessaires. Créez une vue des résultats à l’aide du code Console.WriteLine() suivant :

Console.WriteLine($"=============== Single Prediction just-trained-model - Result: {prediction.Area} ===============");

Retourner le modèle entraîné à utiliser pour l’évaluation

Retournez le modèle à la fin de la méthode BuildAndTrainModel.

return trainingPipeline;

Évaluer le modèle

Maintenant que vous avez créé et effectué l’apprentissage du modèle, vous devez l’évaluer avec un jeu de données différent à des fins d’assurance qualité et de validation. Dans la méthode Evaluate, le modèle créé dans BuildAndTrainModel est passé pour évaluation. Créez la méthode Evaluate juste après BuildAndTrainModel, comme dans le code suivant :

void Evaluate(DataViewSchema trainingDataViewSchema)
{

}

La méthode Evaluate exécute les tâches suivantes :

  • Charge le jeu de données de test.
  • Crée l’évaluateur multiclasse.
  • Évalue le modèle et crée des métriques.
  • Affiche les métriques.

Ajoutez un appel à la nouvelle méthode juste en dessous de l’appel de la méthode BuildAndTrainModel, en utilisant le code suivant :

Evaluate(_trainingDataView.Schema);

Comme vous l’avez fait précédemment avec le jeu de données d’entraînement, chargez le jeu de données de test en ajoutant le code suivant à la méthode Evaluate :

var testDataView = _mlContext.Data.LoadFromTextFile<GitHubIssue>(_testDataPath,hasHeader: true);

La méthode Evaluate() calcule les métriques de qualité pour le modèle à l’aide du jeu de données spécifié. Elle retourne un objet MulticlassClassificationMetrics contenant les métriques globales calculées par les évaluateurs de classification multiclasse. Pour afficher les métriques permettant de déterminer la qualité du modèle, vous devez d’abord les obtenir. Notez l’utilisation de la méthode Transform() de la variable globale de machine learning _trainedModel (un ITransformer) pour entrer les caractéristiques et retourner les prédictions. Ajoutez comme nouvelle ligne le code suivant à la méthode Evaluate :

var testMetrics = _mlContext.MulticlassClassification.Evaluate(_trainedModel.Transform(testDataView));

Les métriques suivantes sont évaluées pour la classification multiclasse :

  • Micro-précision : chaque paire exemple-classe contribue de manière égale à la métrique de précision. Vous voulez que la micro-précision soit aussi proche de un que possible.

  • Macro-précision : chaque classe contribue de manière égale à la métrique de précision. Les classes minoritaires sont aussi importantes que les classes plus grandes. Vous voulez que la macro-précision soit aussi proche de un que possible.

  • Perte logarithmique : consultez Perte logarithmique. Vous voulez que la perte logarithmique soit aussi proche de zéro que possible.

  • Réduction de la perte logarithmique : comprise entre [-inf, 1.00], où 1.00 correspond à des prédictions parfaites et 0 à des prédictions moyennes. Vous voulez que la réduction de la perte logarithmique soit aussi proche de un que possible.

Affichage des métriques pour la validation du modèle

Utilisez le code suivant pour afficher les métriques, partager les résultats et agir dessus :

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($"*************************************************************************************************************");

Enregistrer le modèle dans un fichier

Une fois que vous êtes satisfait de votre modèle, enregistrez-le dans un fichier pour faire des prédictions ultérieurement ou dans une autre application. Ajoutez le code suivant à la méthode Evaluate .

SaveModelAsFile(_mlContext, trainingDataViewSchema, _trainedModel);

Créez la méthode SaveModelAsFile sous votre méthode Evaluate.

void SaveModelAsFile(MLContext mlContext,DataViewSchema trainingDataViewSchema, ITransformer model)
{

}

Ajoutez le code suivant à votre méthode SaveModelAsFile. Ce code utilise la méthode Save pour sérialiser et stocker le modèle entraîné en tant que fichier zip.

mlContext.Model.Save(model, trainingDataViewSchema, _modelPath);

Déployer et prédire avec un modèle

Ajoutez un appel à la nouvelle méthode juste en dessous de l’appel de la méthode Evaluate, en utilisant le code suivant :

PredictIssue();

Créez la méthode PredictIssue, juste après la méthode Evaluate (et juste avant la méthode SaveModelAsFile), en utilisant le code suivant :

void PredictIssue()
{

}

La méthode PredictIssue exécute les tâches suivantes :

  • Charge le modèle enregistré.
  • Crée un problème unique de données de test.
  • Prédit la zone en fonction des données de test.
  • Combine les données de test et les prédictions pour générer des rapports.
  • Affiche les résultats prédits.

Chargez le modèle enregistré dans votre application en ajoutant le code suivant à la méthode PredictIssue :

ITransformer loadedModel = _mlContext.Model.Load(_modelPath, out var modelInputSchema);

Ajoutez un problème GitHub pour tester la prédiction du modèle entraîné dans la méthode Predict en créant une instance de GitHubIssue :

GitHubIssue singleIssue = new GitHubIssue() { Title = "Entity Framework crashes", Description = "When connecting to the database, EF is crashing" };

Comme vous l’avez fait précédemment, créez une instance PredictionEngine avec le code suivant :

_predEngine = _mlContext.Model.CreatePredictionEngine<GitHubIssue, IssuePrediction>(loadedModel);

Le PredictionEngine est une API pratique qui vous permet d’effectuer une prédiction sur une seule instance de données. PredictionEngine n’est pas thread-safe. Il est acceptable de l’utiliser dans des environnements monothreads ou de prototype. Pour améliorer les performances et la sécurité des threads dans les environnements de production, utilisez le service PredictionEnginePool, qui crée un ObjectPool de PredictionEngine objets à utiliser dans votre application. Consultez ce guide sur l’utilisation de PredictionEnginePool dans une API web ASP.NET Core.

Notes

L’extension de service PredictionEnginePool est disponible en préversion.

Utilisez PredictionEngine pour prédire l’étiquette Area GitHub en ajoutant le code suivant à la méthode PredictIssue servant à la prédiction :

var prediction = _predEngine.Predict(singleIssue);

Utiliser le modèle chargé à des fins de prédiction

Affichez Area pour catégoriser le problème et agir en conséquence. Créez une vue des résultats à l’aide du code Console.WriteLine() suivant :

Console.WriteLine($"=============== Single Prediction - Result: {prediction.Area} ===============");

Résultats

Vos résultats doivent être similaires à ce qui suit. Lors du traitement, le pipeline affiche des messages. Vous pouvez voir des avertissements ou des messages de traitement. Ces messages ont été supprimés des résultats suivants par souci de clarté.

=============== 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 ===============

Félicitations ! Vous venez de créer un modèle d’apprentissage automatique pour la classification et la prédiction d’une étiquette Area d’un problème GitHub. Vous trouverez le code source de ce tutoriel dans le référentiel dotnet/samples.

Étapes suivantes

Dans ce didacticiel, vous avez appris à :

  • Préparer vos données
  • Transformer les données
  • Effectuer l’apprentissage du modèle
  • Évaluer le modèle
  • Prédire avec le modèle entraîné
  • Déployer et prédire avec un modèle chargé

Passer au tutoriel suivant pour en savoir plus