チュートリアル: ML.NET での多クラス分類を使用したサポートの問題の分類

このサンプル チュートリアルでは ML.NET を使用して GitHub の問題の分類子を作成し、Visual Studio で C# を使用する .NET Core コンソール アプリケーションから GitHub の問題に対する区分ラベルを分類して予測するモデルをトレーニングする方法を示します。

このチュートリアルでは、次の作業を行う方法について説明します。

  • データを準備する
  • データを変換する
  • モデルをトレーニングする
  • モデルを評価する
  • トレーニング済みモデルを使用して予測する
  • 読み込み済みのモデルを使用して配置および予測する

このチュートリアルのソース コードは dotnet/samples リポジトリで確認できます。

必須コンポーネント

コンソール アプリケーションを作成する

プロジェクトを作成する

  1. "GitHubIssueClassification" という名前の C# コンソール アプリケーションを作成します。 [次へ] を選択します。

  2. 使用するフレームワークとして .NET 7 を選択します。 作成 を選択します。

  3. プロジェクトに Data という名前のディレクトリを作成して、データ セット ファイルを保存します。

    ソリューション エクスプローラーで、プロジェクトを右クリックし、 [追加]>[新しいフォルダー] を選択します。 「Data」と入力し、Enter キーを押します。

  4. プロジェクトに Models という名前のディレクトリを作成して、モデルを保存します。

    ソリューション エクスプローラーで、プロジェクトを右クリックし、 [追加]>[新しいフォルダー] を選択します。 「Models」と入力し、Enter キーを押します。

  5. Microsoft.ML NuGet パッケージをインストールします。

    注意

    このサンプルでは、特に明記されていない限り、記載されている最新の安定バージョンの NuGet パッケージを使用します。

    ソリューション エクスプローラーで、プロジェクトを右クリックし、 [NuGet パッケージの管理] を選択します。 [パッケージ ソース] として [nuget.org] を選択します。[参照] タブを選択し、「Microsoft.ML」を検索し、 [インストール] ボタンを選択します。 [変更のプレビュー] ダイアログの [OK] を選択します。表示されているパッケージのライセンス条項に同意する場合は、 [ライセンスの同意] ダイアログの [同意する] を選択します。

データを準備する

  1. issues_train.tsv および issues_test.tsv データ セットをダウンロードして、それらを作成済みの Data フォルダーに保存します。 1 番目のデータ セットでは機械学習モデルをトレーニングし、2 番目のデータ セットはモデルの精度を評価するために使用します。

  2. ソリューション エクスプローラーで、各 *.tsv ファイルを右クリックし、[プロパティ] を選択します。 [詳細設定] で、 [出力ディレクトリにコピー] の値を [新しい場合はコピーする] に変更します。

クラスを作成してパスを定義する

次に示す追加の using ステートメントを Program.cs ファイルの先頭に追加します。

using Microsoft.ML;
using GitHubIssueClassification;

最近ダウンロードしたファイルのパスを保持する 3 つのグローバル フィールドと、MLContextDataView、および PredictionEngine のためのグローバル変数を作成します。

  • _trainDataPath には、モデルのトレーニングに使用するデータ セットのパスが含まれます。
  • _testDataPath には、モデルの評価に使用するデータ セットのパスが含まれます。
  • _modelPath には、トレーニング済みのモデルを保存するパスが含まれます。
  • _mlContext は処理コンテキストを提供する MLContext です。
  • _trainingDataView は、トレーニング データセットを処理するために使用される IDataView です。
  • _predEngine は、1 つの予測に使用される PredictionEngine<TSrc,TDst> です。

using ステートメントのすぐ下にある行に次のコードを追加して、それらのパスとその他の変数を指定します。

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;

入力データと予測のために、いくつかのクラスを作成します。 プロジェクトに新しいクラスを追加します。

  1. ソリューション エクスプローラーで、プロジェクトを右クリックし、 [追加]>[新しい項目] を選択します。

  2. [新しい項目の追加] ダイアログ ボックスで、 [クラス] を選択し、 [名前] フィールドを「GitHubIssueData.cs」に変更します。 次に [追加] を選択します。

    コード エディターで GitHubIssueData.cs ファイルが開きます。 GitHubIssueData.cs の先頭に次の using ステートメントを追加します。

using Microsoft.ML.Data;

既存のクラス定義を削除し、GitHubIssueIssuePrediction の 2 つのクラスを含む次のコードを 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 は予測する列です。 識別された Features は、ラベルを予測するためにモデルを指定する入力です。

データ セット内のソース列のインデックスを指定するには、LoadColumnAttribute を使用します。

GitHubIssue は、入力データセット クラスで、次の String フィールドがあります。

  • 最初の列 ID (GitHub 問題 ID)
  • 2 番目の列 Area (トレーニングの予測)
  • 3 番目の列 Title (GitHub の問題のタイトル) は、Area の予測に使用される最初の feature です
  • 第 4 列 Description は、Area の予測に使用される 2 番目の feature です

IssuePrediction は、モデルがトレーニングされた後に、予測に使用されるクラスです。 これには、1 つの string (Area) と、PredictedLabelColumnName 属性があります。 PredictedLabel は予測と評価の際に使用されます。 評価では、トレーニング データを含む入力、予測された値、およびモデルが使用されます。

すべての ML.NET 操作は、MLContext クラスで始まります。 mlContext を初期化することで、モデル作成ワークフローのオブジェクト間で共有できる新しい ML.NET 環境が作成されます。 Entity Framework における DBContext と、概念的にはほぼ同じです。

変数の初期化

複数のトレーニング間で反復可能な決定論的結果を得るために、_mlContext グローバル変数をランダム シード (seed: 0) を使用して MLContext の新しいインスタンスで初期化します。 Console.WriteLine("Hello World!") の行を次のコードに置き換えます。

_mlContext = new MLContext(seed: 0);

データを読み込む

ML.NET では、数値またはテキストの表形式データを記述する柔軟で効率的な方法として、IDataView インターフェイスを使います。 IDataView は、テキスト ファイルを読み込むか、またはリアルタイムで読み込むことができます (たとえば、SQL データベースまたはログ ファイル)。

パイプラインで利用するために _trainingDataView グローバル変数を初期化して読み込むには、mlContext 初期化の後に次のコードを追加します。

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

LoadFromTextFile() は、データ スキーマを定義し、ファイルを読み取ります。 データ パス変数を取得して、IDataView を返します。

LoadFromTextFile() メソッドの呼び出し後に次を追加します。

var pipeline = ProcessData();

ProcessData メソッドは次のタスクを実行します。

  • データを抽出して変換します。
  • 処理パイプラインを返します。

次のコードを使用して、Program.cs ファイルの末尾に ProcessData メソッドを作成します。

IEstimator<ITransformer> ProcessData()
{

}

特徴を抽出してデータを変換する

GitHubIssue に対する GitHub の区分ラベルを予測する場合、MapValueToKey() メソッドを使用して Area 列を数値キー型の Label 列 (分類アルゴリズムによって許可される形式) に変換し、それを新しいデータセット列として追加します。

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

次に、テキスト (Title および Description) 列をそれぞれ TitleFeaturized および DescriptionFeaturized と呼ばれる数値ベクターに変換する mlContext.Transforms.Text.FeaturizeText を呼び出します。 次のコードを使用して、両列の特徴付けをパイプラインに追加します。

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

データ準備の最後の手順では、Concatenate() メソッドを使用して、すべての特徴列を Features 列に結合します。 既定では、学習アルゴリズムは Features 列の特徴のみを処理します。 次のコードを使用してパイプラインに、この変換を追加します。

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

次に、DataView をキャッシュするために AppendCacheCheckpoint を追加します。つまり、次のコードでキャッシュを使用してデータが複数回反復されると、パフォーマンスが向上する場合があります。

.AppendCacheCheckpoint(_mlContext);

警告

小/中規模のデータセットの場合は、AppendCacheCheckpoint を使用して、トレーニング時間を短くします。 非常に大きいデータセットを処理するときは、使用しないでください (.AppendCacheCheckpoint() を削除します)。

ProcessData メソッドの最後で、パイプラインが返されます。

return pipeline;

この手順で前処理と特徴付けが処理されます。 ML.NET に用意されているその他のコンポーネントを使用すると、モデルでより良い結果が得られます。

モデルを構築してトレーニングする

ProcessData() メソッドへの呼び出しの次の行に、BuildAndTrainModel メソッドへの次の呼び出しを追加します。

var trainingPipeline = BuildAndTrainModel(_trainingDataView, pipeline);

BuildAndTrainModel メソッドは次のタスクを実行します。

  • トレーニング アルゴリズムのクラスを作成します。
  • モデルをトレーニングする。
  • トレーニング データに基づいて区分を予測します。
  • モデルを返します。

ProcessData() メソッドの宣言の直後に、次のコードを使用して BuildAndTrainModel メソッドを作成します。

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

}

分類タスクについて

分類とは、データを使用して項目またはデータ行のカテゴリ、型、クラスを判断する機械学習タスクであり、多くの場合、次のいずれかの種類になります。

  • バイナリ: A か B のいずれかである。
  • 多クラス: 1 つのモデルを使用して予測できるカテゴリが多数ある。

この種の問題では、問題カテゴリの予測が 2 つだけ (バイナリ) ではなく複数のカテゴリの 1 つ (多クラス) なので、多クラス分類学習アルゴリズムを使用します。

BuildAndTrainModel() 内に最初のコード行として以下を付加することで、データ変換定義に機械学習アルゴリズムを追加します。

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

SdcaMaximumEntropy は、マルチクラス分類のトレーニング アルゴリズムです。 これは pipeline に付加され、特徴付けされた TitleDescription (Features) および Label 入力パラメータ―を受け入れて、履歴データから学習します。

モデルをトレーニングする

BuildAndTrainModel() メソッドの次のコード行として以下を追加して、モデルを splitTrainSet データに適合させ、トレーニング済みモデルを返します。

_trainedModel = trainingPipeline.Fit(trainingDataView);

Fit() メソッドでは、データセットを変換してトレーニングを適用することで、モデルをトレーニングします。

PredictionEngine は、データの 1 つのインスタンスを渡してから、その予測を実行できる便利な API です。 BuildAndTrainModel() メソッドに次の行として以下を追加します。

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

トレーニング済みモデルを使用して予測する

GitHub の問題を追加して、Predict メソッドでトレーニングされたモデルの予測をテストします。これには 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.."
};

Predict() 関数を使用して、データの 1 つの行に対して予測を行います。

var prediction = _predEngine.Predict(issue);

モデルを使用する: 予測結果

結果を共有し、それに応じたアクションを実行するために、GitHubIssue および対応する Area ラベル予測を表示します。 次の Console.WriteLine() コードを使用して、結果の表示を作成します。

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

評価に使用する、トレーニング済みのモデルを返す

BuildAndTrainModel メソッドの最後で、モデルを返します。

return trainingPipeline;

モデルを評価する

これでモデルの作成とトレーニングが完了したので、品質保証と検証のために、別のデータ セットを使用してモデルを評価します。 Evaluate メソッドでは、BuildAndTrainModel で作成されたモデルが渡されて評価されます。 BuildAndTrainModel の直後に、次のコードに示すように Evaluate メソッドを作成します。

void Evaluate(DataViewSchema trainingDataViewSchema)
{

}

Evaluate メソッドは次のタスクを実行します。

  • テスト データ セットを読み込む。
  • 多クラス評価器を作成する。
  • モデルを評価し、メトリックを作成する。
  • メトリックを表示する。

次のコードを使用して、BuildAndTrainModel メソッド呼び出しのすぐ下に新しいメソッドへの呼び出しを追加します。

Evaluate(_trainingDataView.Schema);

トレーニング データセットで以前にも行ったように、次のコードを Evaluate メソッドに追加することで、テスト データセットを読み込みます。

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

Evaluate() メソッドは、指定されたデータセットを使用して、モデルに対する品質メトリックを計算します。 これによって返される MulticlassClassificationMetrics オブジェクトには、多クラス分類評価器によって計算されるメトリック全体が含まれます。 メトリックを表示してモデルの品質を判定するには、最初にメトリックを取得する必要があります。 特徴を入力して予測を返すために、機械学習の _trainedModel グローバル変数 (ITransformer) の Transform() メソッドを使用していることに注目してください。 Evaluate メソッドに次のコード行を追加します。

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

多クラス分類では、次のメトリックが評価されます。

  • マイクロ精度: すべてのサンプルとクラスのペアが、精度メトリックに均等に作用します。 マイクロ精度は可能な限り 1 に近づけます。

  • マクロ精度: すべてのクラスが、精度メトリックに均等に作用します。 少数派のクラスは、大規模なクラスと同じ重みが与えられています。 マクロ精度は可能な限り 1 に近づけます。

  • 対数損失: 対数損失に関するページを参照してください。 対数損失は可能な限り 1 に近づけます。

  • 対数損失還元: 範囲は [-inf, 1.00] です。ここで、1.00 は完璧な予測で、0 は平均の予測です。 対数損失還元は可能な限り 1 に近づけます。

モデルの検証のためにメトリックを表示する

次のコードを使用してメトリックを表示し、結果を共有し、それに対してアクションを実行します。

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

モデルをファイルに保存する

モデルに問題がなければ、後で、または別のアプリケーションで予測を行うために、そのモデルをファイルに保存します。 Evaluate メソッドに次のコードを追加します。

SaveModelAsFile(_mlContext, trainingDataViewSchema, _trainedModel);

Evaluate メソッドの下に SaveModelAsFile メソッドを作成します。

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

}

次のコードを SaveModelAsFile メソッドに追加します。 このコードでは Save メソッドを使用して、トレーニング済みのモデルを zip ファイルとしてシリアル化し、格納します。

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

モデルによるデプロイと予測

次のコードを使用して、Evaluate メソッド呼び出しのすぐ下に新しいメソッドへの呼び出しを追加します。

PredictIssue();

Evaluate メソッドの直後 (および SaveModelAsFile メソッドの直前) に、次のコードを使用して PredictIssue メソッドを作成します。

void PredictIssue()
{

}

PredictIssue メソッドは次のタスクを実行します。

  • 保存されたモデルを読み込む
  • テスト データの問題を 1 つ作成します。
  • テスト データに基づいて区分を予測します。
  • テスト データと予測をレポート用に結合する。
  • 予測された結果を表示する。

PredictIssue メソッドに次のコードを追加して、保存されたモデルをアプリケーションに読み込みます。

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

GitHub の問題を追加して、Predict メソッドでトレーニングされたモデルの予測をテストします。これには GitHubIssue のインスタンスを作成します。

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

以前に行ったように、次のコードを使って PredictionEngine インスタンスを作成します。

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

PredictionEngine は、データの 1 つのインスタンスに対して予測を実行できる便利な API です。 PredictionEngine はスレッド セーフではありません。 シングル スレッド環境またはプロトタイプ環境で使用できます。 運用環境でパフォーマンスとスレッド セーフを向上させるには、PredictionEnginePool サービスを使用します。これにより、アプリケーション全体で使用するできる PredictionEngine オブジェクトの ObjectPool が作成されます。 ASP.NET Core Web API で PredictionEnginePool を使用する方法については、こちらのガイドを参照してください。

注意

PredictionEnginePool サービスの拡張機能は、現在プレビュー段階です。

PredictionEngine を使用して、予測のための PredictIssue メソッドに次のコードを追加して、GitHub の区分ラベルを予測します。

var prediction = _predEngine.Predict(singleIssue);

読み込み済みのモデルを予測のために使用する

問題を分類し、それに応じて処理するために Area を表示します。 次の Console.WriteLine() コードを使用して、結果の表示を作成します。

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

結果

結果は以下のようになるはずです。 パイプラインが処理されると、メッセージが表示されます。 警告または処理メッセージが表示されることがありますが、 わかりやすくするために、これらのメッセージは次の結果から削除してあります。

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

おめでとうございます! これで、GitHub の問題用の区分ラベルを分類および予測するための機械学習モデルをビルドできました。 このチュートリアルのソース コードは dotnet/samples リポジトリで確認できます。

次の手順

このチュートリアルでは、次の作業を行う方法を学びました。

  • データを準備する
  • データを変換する
  • モデルをトレーニングする
  • モデルを評価する
  • トレーニング済みモデルを使用して予測する
  • 読み込み済みのモデルを使用して配置および予測する

さらに詳しく学習するには、次のチュートリアルに進んでください。