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为得到的分数。

多类分类实现

流程

进行多类分析的实现顺序

  1. 从数据库获取训练数据
  2. 训练数据并将训练模型存入本地
  3. 输入要预测的数据
  4. 加载训练模型进行数据预测

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-