教學課程:使用多類別分類搭配 ML.NET 來分類支持問題
演示如何使用 ML.NET 來建立 GitHub 問題分類器,以便在 Visual Studio 中使用 C# 開發的 .NET 主控台應用程式,訓練模型來分類和預測 GitHub 問題的區域標籤。
在本教學課程中,您將瞭解如何:
- 準備您的資料
- 轉換數據
- 訓練模型
- 評估模型
- 使用定型模型預測
- 使用已載入的模型進行部署和預測
您可以在 dotnet/samples 存放庫找到本教學課程的原始程式碼。
先決條件
- 已安裝 「.NET Desktop Development」 工作負載的 Visual Studio 2022。
- 以標籤分隔的 GitHub 問題訓練檔案(issues_train.tsv)。
- GitHub 會發出測試索引標籤分隔檔案 (issues_test.tsv)。
建立主控台應用程式
建立專案
建立名為 「GitHubIssueClassification」 的 C# 主控台應用程式。 請選取下一步。
選擇 [.NET 7] 作為要使用的架構。 選取 [建立]。
在專案中建立名為 Data 的目錄,以儲存資料集檔案:
在 [方案總管]中,以滑鼠右鍵按兩下您的項目,然後選取 [新增>新增資料夾]。 輸入「Data」,然後按 Enter。
在您的專案中建立名為 Models 的目錄,以儲存您的模型:
在 [方案總管]中,以滑鼠右鍵點擊您的專案,然後選取 [新增>新資料夾]。 輸入 “Models”,然後按 Enter。
安裝 Microsoft.ML NuGet 套件:
注意
除非另有說明,否則此範例會使用所提及 NuGet 套件的最新穩定版本。
在 [方案總管] 中,以滑鼠右鍵按下您的項目,然後選取 [管理 NuGet 套件]
。 選擇 [nuget.org] 作為套件來源,選取 [瀏覽] 索引標籤,搜尋 Microsoft.ML,然後選取 [安裝]。 選取 [確定] 按鈕,然後在 [預覽變更] 對話方塊上選取 [我接受] 按鈕,在 [授權接受] 對話方塊上如果你同意列出的套件的授權條款。
準備您的資料
下載 issues_train.tsv 和 issues_test.tsv 數據集,並將其儲存至您先前建立的 Data 資料夾。 第一個數據集會定型機器學習模型,而第二個數據集可用來評估模型的精確度。
在 [方案總管] 中,以滑鼠右鍵按一下每個 *.tsv 檔案,然後選取 [屬性]。 在 [進階] 中,將 [複製到輸出目錄] 的值變更為 [如果更新則複製]。
建立類別並定義路徑
將下列其他 using
指示詞新增至 Program.cs 檔案頂端:
using Microsoft.ML;
using GitHubIssueClassification;
建立三個全域欄位來保存最近下載之檔案的路徑,以及 MLContext
、DataView
和 PredictionEngine
的全域變數:
-
_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;
為您的輸入數據和預測建立一些類別。 將新類別新增至您的專案:
在 [方案總管]中,以滑鼠右鍵按兩下專案,然後選取 [[新增>新專案]。
在 [[新增專案] 對話框中,選取 [類別],然後將 [名稱] 字段變更為 [GitHubIssueData.cs]。 然後,選取 新增。
GitHubIssueData.cs 檔案會在程式碼編輯器中開啟。 將下列
using
指示詞新增至 GitHubIssueData.cs頂端:using Microsoft.ML.Data;
拿掉現有的類別定義,並將下列程式代碼新增至 GitHubIssueData.cs 檔案。 此程式代碼有兩個類別,
GitHubIssue
和IssuePrediction
。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 Issue ID)。 - 第二個欄位
Area
(訓練的預測)。 - 第三欄
Title
(GitHub 問題標題)是第一個用於預測Area
的feature
。 - 第四欄
Description
是用於預測Area
的第二個數據feature
。
IssuePrediction
是模型定型之後用於預測的類別。 它有單一string
(Area
) 和PredictedLabel
ColumnName
屬性。PredictedLabel
會在預測和評估期間使用。 針對評估,會使用包含訓練數據的輸入、預測值和模型。所有 ML.NET 作業都會從 MLContext 類別開始。 初始化
mlContext
會建立可跨模型建立工作流程對象共用的新 ML.NET 環境。 在概念上,在Entity Framework
中DBContext
類似。- 第一欄
初始化變數
使用含隨機種子(seed: 0
)的新 MLContext
實例初始化 _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")
接下來,呼叫 mlContext.Transforms.Text.FeaturizeText
,它會將每個呼叫 TitleFeaturized
和 DescriptionFeaturized
的文字 (Title
和 Description
) 數據行轉換成數值向量。 使用以下程式碼,將這兩個欄位的特徵提取附加到管道中:
.Append(_mlContext.Transforms.Text.FeaturizeText(inputColumnName: "Title", outputColumnName: "TitleFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(inputColumnName: "Description", outputColumnName: "DescriptionFeaturized"))
數據準備的最後一個步驟會使用 Concatenate() 方法,將所有特徵數據行合併到 功能 數據行。 根據預設,學習演算法只會處理 特徵 欄的資料。 使用下列程式代碼將此轉換附加至管線:
.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
方法會執行下列工作:
- 建立訓練算法類別。
- 訓練模型。
- 根據訓練數據預測區域。
- 傳回模型。
使用下列程序代碼,在宣告 ProcessData()
方法之後,建立 BuildAndTrainModel
方法:
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
,並接受特徵化 Title
和 Description
(Features
)和 Label
輸入參數,以從歷史數據中學習。
訓練模型
將模型擬合到 splitTrainSet
數據,然後在 BuildAndTrainModel()
方法中新增下列程式碼作為下一行,以傳回訓練好的模型:
_trainedModel = trainingPipeline.Fit(trainingDataView);
Fit()
方法會藉由轉換數據集並進行訓練來訓練模型。
PredictionEngine 是一個方便的 API,它允許您輸入單筆資料並進行預測。 將此新增為 BuildAndTrainModel()
方法中的下一行:
_predEngine = _mlContext.Model.CreatePredictionEngine<GitHubIssue, IssuePrediction>(_trainedModel);
使用定型模型預測
藉由建立 GitHubIssue
的實例,新增 GitHub 問題,以在 Predict
方法中測試定型模型的預測:
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
全域變數的 Transform() 方法(ITransformer),來輸入特徵並傳回預測。 請將下列程式碼新增至 Evaluate
方法中,作為下一行程式碼:
var testMetrics = _mlContext.MulticlassClassification.Evaluate(_trainedModel.Transform(testDataView));
下列計量會針對多類別分類進行評估:
- 微精確度 - 每個樣本類別組都同樣有助於精確度計量。 您希望 Micro Accuracy 盡可能接近 1。
- 宏觀準確性 - 每個類別都對準確性指標貢獻相等。 少數類別與較大的類別被賦予相等的權重。 您希望整體準確率盡可能接近 1。
- 記錄遺失 - 請參閱 記錄遺失。 您希望對數損失(Log-loss)盡可能接近零。
- 記錄損失縮減 - 範圍從 [-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
方法之後建立 PredictIssue
方法(在 SaveModelAsFile
方法之前:
void PredictIssue()
{
}
PredictIssue
方法會執行下列工作:
- 載入儲存的模型。
- 建立一個測試數據項。
- 根據測試數據預測區域。
- 將測試數據和預測進行結合以便報告。
- 顯示預測的結果。
將下列程式代碼新增至 PredictIssue
方法,將儲存的模型載入您的應用程式:
ITransformer loadedModel = _mlContext.Model.Load(_modelPath, out var modelInputSchema);
藉由建立 GitHubIssue
的實例,新增 GitHub 問題,以在 Predict
方法中測試定型模型的預測:
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
服務擴展目前處於預覽階段。
使用 PredictionEngine
預測區域 GitHub 標籤,方法是將下列程式代碼新增至 PredictIssue
方法以進行預測:
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 存放庫找到本教學課程的原始程式碼。
後續步驟
在本教學課程中,您已瞭解如何:
- 準備您的數據
- 轉換數據
- 訓練模型
- 評估模型
- 使用定型模型預測
- 使用載入的模型部署和預測
繼續下一個教學課程以更深入了解。