教學課程:使用具有 ML.NET 的多類別分類來分類支援問題

此範例教學課程會示範使用 ML.NET,透過使用 Visual Studio 中 C# 的 .NET Core 主控台應用程式,建立 GitHub 問題分類器,來定型分類及預測 GitHub 問題 Area 標籤的模型。

在本教學課程中,您會了解如何:

  • 準備您的資料
  • 轉換資料
  • 將模型定型
  • 評估模型
  • 使用訓練過的模型預測
  • 使用已載入的模型部署和預測

您可以在 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、並選取 [安裝] 按鈕。 在 [預覽變更] 對話方塊上,選取 [確定] 按鈕,然後在 [授權接受] 對話方塊上,如果您同意所列套件的授權條款,請選取 [我接受]

準備您的資料

  1. 下載 issues_train.tsvissues_test.tsv 資料集,並將其儲存至您先前建立的 Data 資料夾。 第一個資料集會將機器學習模型定型,第二個資料集則可用來評估您模型的準確率。

  2. 在 方案總管中,以滑鼠右鍵按一下每個 *.tsv 檔案,然後選取 [屬性]。 在 [進階] 底下,將 [複製到輸出目錄] 的值變更為 [有更新時才複製]。

建立類別及定義路徑

Program.cs 檔案頂端新增下列額外的 using 陳述式:

using Microsoft.ML;
using GitHubIssueClassification;

建立三個全域欄位來保留近期下載檔案的路徑,以及 MLContextDataViewPredictionEngine 的全域變數:

  • _trainDataPath 包含用來將模型定型的資料集路徑。
  • _testDataPath 包含用來評估模型的資料集路徑。
  • _modelPath 包含用來儲存定型模型的路徑。
  • _mlContext 是提供處理內容的 MLContext
  • _trainingDataView 是用來處理定型資料集的 IDataView
  • _predEngine 是用於單一預測的 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 檔案隨即在程式碼編輯器中開啟。 將下列 using 陳述式新增至 GitHubIssueData.cs 最上方:

using Microsoft.ML.Data;

移除現有的類別定義,然後將下列程式碼 (具有 GitHubIssueIssuePrediction 這兩個類別) 新增至 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 是您提供模型,以預測標籤 (Label) 的輸入。

請使用 LoadColumnAttribute 來指定資料集中來源資料行的索引。

GitHubIssue 是輸入資料集類別,並具有下列 String 欄位:

  • 第一個資料行 ID(GitHub 問題識別碼)
  • 第二個資料行 Area(用於定型的預測)
  • 第三個資料行 Title (GitHub 問題標題) 是第一個用來預測 Areafeature
  • 第四個數據行是用來預測 的第二 feature 個數據行 DescriptionArea

IssuePrediction 是在模型定型後,用來進行預測的類別。 它包含單一布林值 string (Area) 和 PredictedLabelColumnName 屬性。 PredictedLabel 的使用時機是在進行預測和評估的期間。 就評估而言,會使用含有定型資料、預設值及模型的輸入。

所有 ML.NET 作業都會在 MLCoNtext 類別中啟動。 將 mlContext 初始化會建立新的 ML.NET 環境,可在模型建立工作流程物件間共用。 就概念而言,它與 Entity Framework 中的 DBContext 相似。

將變數初始化

_mlContext使用隨機種子的新實例 MLContext 初始化全域變數, (seed: 0) ,以便跨多個定型進行可重複/具決定性的結果。 使用下列程式碼取代 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 預測 Area GitHub 標籤時,請使用 MapValueToKey() 方法,將 Area 資料行轉換成數字索引鍵類型 Label 資料行 (分類演算法接受的格式),並將它新增為新的資料集資料行:

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

接下來,呼叫 mlContext.Transforms.Text.FeaturizeText ,將文字 (TitleDescription) 資料行轉換成每個呼叫 TitleFeaturizedDescriptionFeaturized 的數值向量。 將這兩個資料行的特徵轉換附加至管線,使用的程式碼如下:

.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"))

接著,附加 AppendCacheCheckpoint 來快取 DataView,以便在您多次逐一查看資料時,使用快取可獲得更高的效能,如下列程式碼所示:

.AppendCacheCheckpoint(_mlContext);

警告

針對小型/中型資料集使用 AppendCacheCheckpoint 以減少訓練時間。 請不要在處理非常大的資料集時使用它 (移除 .AppendCacheCheckpoint())。

ProcessData 方法的結尾傳回管線。

return pipeline;

這個步驟會處理前置處理/特徵轉換。 使用 ML.NET 中可用的額外元件可讓您的模型產生更佳的結果。

建置和定型模型

將下列呼叫新增至 BuildAndTrainModel 方法,作為方法呼叫 ProcessData() 之後的下一行:

var trainingPipeline = BuildAndTrainModel(_trainingDataView, pipeline);

BuildAndTrainModel 方法會執行下列工作:

  • 建立定型演算法類別。
  • 將模型定型。
  • 根據定型資料預測區域。
  • 傳回模型。

BuildAndTrainModel使用下列程式碼,在 方法宣告 ProcessData() 之後建立 方法:

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

}

關於分類工作

分類是一項機器學習服務工作,會使用資料來判斷項目或資料列的分類、類型或類別,且經常是下列其中一種類型:

  • 二元:不是 A 就是 B。
  • 多元分類:可使用單一模型來預測的多重分類。

針對此類型的問題,請使用多類別分類學習演算法,因為您的問題類別預測可能是多個類別 (多類別) 的其中之一,而不只是兩個類別 (二元)。

透過將下列內容新增為 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 是一種便利的 API,可讓您傳遞並在單一資料執行個體上接著執行預測。 將此新增為 BuildAndTrainModel() 方法中的下一行:

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

使用訓練過的模型預測

透過建立 GitHubIssue 的執行個體,在 Predict 方法中新增 GitHub 問題,以測試所定型模型的預測:

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() 函式來針對單一資料列進行預測:

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));

針對多類別分類評估的計量如下:

  • 微精確度 - 每個範例類別組同樣都會對精確度計量提出貢獻。 您希望 Micro Accuracy 盡可能接近一個。

  • 大精確度 - 每個類別同樣都會對精確度計量提出貢獻。 少數類別會加上與較大類別相同的權重。 您希望宏精確度盡可能接近一個。

  • 記錄檔遺失 - 請參閱記錄檔遺失。 建議讓記錄檔遺失盡量接近零。

  • 對數損失減少 - 從 [-inf, 1.00] 的範圍,其中 1.00 是完美的預測,0 表示平均預測。 您想要盡可能減少記錄遺失。

顯示模型驗證的計量

使用下列程式碼來顯示計量、共用結果,然後依結果採取動作:

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 方法會執行下列工作:

  • 載入已儲存的模型
  • 建立測試資料的單一問題。
  • 根據測試資料預測區域。
  • 合併測試資料和預測來進行報告。
  • 顯示預測的結果。

將下列程式碼新增至 PredictIssue 方法,以將已儲存模型載入至您的應用程式:

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

透過建立 GitHubIssue 的執行個體,在 Predict 方法中新增 GitHub 問題,以測試所定型模型的預測:

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 是一種便利的 API,可讓您在單一資料執行個體上接著執行預測。 PredictionEngine 不是安全執行緒。 可接受在單一執行緒或原型環境中使用。 為了提升效能和執行緒安全性,請使用 PredictionEnginePool 服務,以建立 PredictionEngine 物件的 ObjectPool 供整個應用程式使用。 請參閱本指南,以瞭解如何在ASP.NET Core Web API 中使用 PredictionEnginePool

注意

PredictionEnginePool 服務延伸模組目前處於預覽狀態。

使用 PredictionEngine 來透過將下列程式碼新增到預測的 PredictIssue 方法,來預測 Area 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 問題分類和預測 Area 標籤的機器學習模型。 您可以在 dotnet/samples 存放庫中找到本教學課程的原始程式碼。

後續步驟

在本教學課程中,您已了解如何:

  • 準備您的資料
  • 轉換資料
  • 將模型定型
  • 評估模型
  • 使用訓練過的模型預測
  • 使用已載入的模型部署和預測

前進到下一個教學課程來深入了解