C#開源跨平台機器學習框架ML.NET----結合SqlSugar進行多類分類
- 2019 年 10 月 4 日
- 筆記

前一篇文章《C#開源跨平台機器學習框架ML.NET----二元分類情緒分析》我們做了ML.NET中二元分類任務的一個小Demo,今天我們來試一下多類分類的Demo。

說明
由於前面我們剛剛學習了SqlSugar的框架,檢驗學習效果的其中一個方法就是輸出,所以這次我們的多類分類裡面就把訓練數據改為資料庫中的數據。

影片演示
實現目標
我們資料庫中存在商品資訊(tbSpXinXi)和品類資訊(tbSpPLXinXi)兩個表,商品資訊中有一個品類編碼(stype)的欄位,通過對商品資訊的對應的品類碼進行訓練,實現我們輸一個商品名稱後系統自動預測出輸入的商品屬於什麼品類的效果。

數據源
品類資訊表

上面紅框中我們只用到三位數級別的,商品資訊中因為是5位的最小級別,我們這裡只取到三位對應
商品資訊表

商品資訊表中欄位較多,我們只查詢出編碼incode,品名fname和品類stype三個欄位使用

創建項目
我們用VS2017創建了一個名稱為MLSqlSugar的項目,在Nuget安裝包中安裝上Microsoft.ML和SqlSugar。
SqlSugar

在sqlsugar文件夾下,我們建了一個DBConnect的類,另一個是SqlSugar我們說過的二級快取的類,詳細可以看我以前的文章
窗體布局

- 窗體布局中我們加入一個ToolStrip裡面寫了多級分類,主要是以後的分類也在這個Demo中加入,所以用的這個
- 主介面上加入一個輸入文本框,一個按鈕和下部的顯示文本框

定義類
Goods類

定義的Goods類,對應的就是我們的商品資訊類裡面就是incode,fname,stype三項,分別是編碼,品名和品類碼
ResGoods類

ResGoods類為我們預測後的返回類,其中stype就是預測後的結果,Probability為概率,Score為得到的分數。
多類分類實現
流程
進行多類分析的實現順序
- 從資料庫獲取訓練數據
- 訓練數據並將訓練模型存入本地
- 輸入要預測的數據
- 載入訓練模型進行數據預測
01
創建訓練模型
點擊初始化數據按鈕

上面是點擊初始化數據按鈕,實現在提取數據及訓練數據並保存到本地
訓練
採集資料庫數據
獲取數據

從資料庫中獲取商品資訊並存入List<Good>集合中,我們把品類stype只取到前三位,通過Order by newid()全部打亂順序再輸出,後面有個分頁為取了1200條,這裡最後我們說原因
訓練
訓練並保存數據模型
1

2

3

4

5

02
預測數據
按鈕事件

載入模型並預測數據


MLMultiApi程式碼
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.ML; namespace MLSqlSugar.Multiclass { /// <summary> /// 多類分類訓練API /// </summary> public class MLMultiApi { //訓練數據存檔位置 private string _modelpath = Path.Combine( Environment.CurrentDirectory, "stypemodel.zip"); //定義ML的基本參數 private MLContext _ml; private DataOperationsCatalog.TrainTestData _dataView; private IDataView _tranDataView; private ITransformer _trainedModel, _testModel; private PredictionEngine<Goods, ResGoods> _predEngine; /// <summary> /// 初始化數據 /// </summary> /// <param name="list"></param> public void InitData(IEnumerable<Goods> list) { //載入數據 LoadData(list); //訓練數據 var pipe = TrainData(); BuildAndTrainModel(_tranDataView, pipe); //測試並保存訓練數據 EvaluateAndSaveModel(); } /// <summary> /// 載入數據 /// </summary> /// <param name="list"></param> private void LoadData(IEnumerable<Goods> list) { _ml = new MLContext(0); //載入數據 _tranDataView = _ml.Data.LoadFromEnumerable(list); //拆分數據集進行模擬訓練和測試 _dataView = _ml.Data.TrainTestSplit(_tranDataView, 0.2); } /// <summary> /// 訓練數據 /// </summary> /// <returns></returns> private IEstimator<ITransformer> TrainData() { //將stype轉換為數字鍵類型Label(分類演算法所接受的格式) //並將其添加為新的數據集列 var pipeline = _ml.Transforms.Conversion .MapValueToKey(inputColumnName: "stype" , outputColumnName: "Label") //將fname轉換為名為fnameFeaturized的值的數字向量, //並將特徵化附加到管道 .Append(_ml.Transforms.Text .FeaturizeText(inputColumnName: "fname" , outputColumnName: "fnameFeaturized")) // .Append(_ml.Transforms.Text // .FeaturizeText(inputColumnName: "incode" // , outputColumnName: "incodeFeaturized")) //Concatenate() 方法將所有特徵合併到「特徵」列 。 //默認情況下,學習演算法僅處理「特徵」列的特徵 .Append(_ml.Transforms.Concatenate( "Features", "fnameFeaturized")); return pipeline; } /// <summary> /// 訓練數據 /// </summary> /// <param name="data"></param> /// <param name="pipeline"></param> /// <returns></returns> private IEstimator<ITransformer> BuildAndTrainModel( IDataView data, IEstimator<ITransformer> pipeline) { //SdcaMaximumEntropy 即多類分類訓練演算法 var trainingPipeline = pipeline.Append(_ml.MulticlassClassification .Trainers.SdcaMaximumEntropy("Label", "Features")) .Append(_ml.Transforms.Conversion.MapKeyToValue("PredictedLabel")); //定型模型 _trainedModel = trainingPipeline.Fit(data); //定義訓練的模型進行預測 _predEngine = _ml.Model.CreatePredictionEngine <Goods, ResGoods>(_trainedModel); Goods good=new Goods(); good.incode = "00090"; good.fname = "神行鞋墊"; var prediction = _predEngine.Predict(good); Console.WriteLine("stype:" + prediction.stype + " percent:"+ prediction.Percent + " score:"+ prediction.Score[0] + "," + prediction.Score[1]); return trainingPipeline; } /// <summary> /// 評估模型 /// </summary> public void EvaluateAndSaveModel() { //用測試數據進行預測 var testMetrics = _ml.MulticlassClassification .Evaluate(_trainedModel.Transform(_dataView.TestSet)); Console.WriteLine($"Metrics for Multi-class Classification model - Test Data "); Console.WriteLine($"MicroAccuracy: {testMetrics.MicroAccuracy:0.###}"); Console.WriteLine($"MacroAccuracy: {testMetrics.MacroAccuracy:0.###}"); Console.WriteLine($"LogLoss: {testMetrics.LogLoss:#.###}"); Console.WriteLine($"LogLossReduction: {testMetrics.LogLossReduction:#.###}"); //保存模型 _ml.Model.Save(_trainedModel, _dataView.TrainSet.Schema, _modelpath); } /// <summary> /// 初始化並載入保存的模型 /// </summary> public void InitFinalModel() { _ml = new MLContext(0); _testModel = _ml.Model.Load(_modelpath, out var modelInputSchema); } /// <summary> /// 進行預測 /// </summary> /// <param name="good"></param> /// <returns></returns> public ResGoods Predict(Goods good) { _predEngine = _ml.Model.CreatePredictionEngine <Goods, ResGoods>(_testModel); return _predEngine.Predict(good); } } } 運行效果


劃重點
多類分類做的時候遇到的幾個問題
上圖中我們獲取數據訓練時分頁數據用的是1200條,我這裡試過,只要寫到1300或再大的,就直接沒有訓練成功,懷疑過是有個臨界點超過後需要訓練時間非常長?所以花了9個半小時晚上訓練20000條還是沒有結果,這裡有知道什麼原因的小夥伴可以留言告訴我,我也非常困惑。

GitHub程式碼地址
https://github.com/Vaccae/MLSqlSugar.git
-END-