训练和评估模型

了解如何使用 ML.NET 生成机器学习模型、收集指标和度量性能。 虽然此示例训练回归模型,但概念在整个其他大多数算法中都适用。

拆分用于训练和测试的数据

机器学习模型的目标是识别训练数据中的模式。 这些模式用于使用新数据进行预测。

数据可由类(如 HousingData)建模。

public class HousingData
{
    [LoadColumn(0)]
    public float Size { get; set; }

    [LoadColumn(1, 3)]
    [VectorType(3)]
    public float[] HistoricalPrices { get; set; }

    [LoadColumn(4)]
    [ColumnName("Label")]
    public float CurrentPrice { get; set; }
}

提供加载到 IDataView 中的以下数据。

HousingData[] housingData = new HousingData[]
{
    new HousingData
    {
        Size = 600f,
        HistoricalPrices = new float[] { 100000f ,125000f ,122000f },
        CurrentPrice = 170000f
    },
    new HousingData
    {
        Size = 1000f,
        HistoricalPrices = new float[] { 200000f, 250000f, 230000f },
        CurrentPrice = 225000f
    },
    new HousingData
    {
        Size = 1000f,
        HistoricalPrices = new float[] { 126000f, 130000f, 200000f },
        CurrentPrice = 195000f
    },
    new HousingData
    {
        Size = 850f,
        HistoricalPrices = new float[] { 150000f,175000f,210000f },
        CurrentPrice = 205000f
    },
    new HousingData
    {
        Size = 900f,
        HistoricalPrices = new float[] { 155000f, 190000f, 220000f },
        CurrentPrice = 210000f
    },
    new HousingData
    {
        Size = 550f,
        HistoricalPrices = new float[] { 99000f, 98000f, 130000f },
        CurrentPrice = 180000f
    }
};

使用 TrainTestSplit 方法将数据拆分为训练集和测试集。 结果是一个 TrainTestData 对象,其中包含两个 IDataView 成员,一个用于训练集,另一个用于测试集。 数据拆分百分比由 testFraction 参数确定。 以下代码片段保留测试集的 20% 的原始数据。

DataOperationsCatalog.TrainTestData dataSplit = mlContext.Data.TrainTestSplit(data, testFraction: 0.2);
IDataView trainData = dataSplit.TrainSet;
IDataView testData = dataSplit.TestSet;

准备数据

在训练机器学习模型之前,需要预处理数据。 有关数据准备的详细信息,请参阅 数据准备操作方法文章transforms page

ML.NET 算法对输入列类型具有约束。 此外,如果未指定任何值,则默认值用于输入和输出列名称。

使用预期的列类型

ML.NET 中的机器学习算法需要一个已知大小的浮点向量作为输入。 当所有数据都已采用数字格式且旨在同时处理(即图像像素)时,请将 VectorType 属性应用于数据模型。

如果数据不是所有数值,并且你想要单独对每个列应用不同的数据转换,则在处理完所有列后,请使用 Concatenate 方法将所有单独的列合并到输出到新列的单个特征向量中。

以下代码片段将 Size 列和 HistoricalPrices 列合并为单个特征向量,该向量输出到名为 Features的新列。 由于缩放比例的不同,因此将 NormalizeMinMax 应用于 Features 列,以实现数据的标准化。

// Define Data Prep Estimator
// 1. Concatenate Size and Historical into a single feature vector output to a new column called Features
// 2. Normalize Features vector
IEstimator<ITransformer> dataPrepEstimator =
    mlContext.Transforms.Concatenate("Features", "Size", "HistoricalPrices")
        .Append(mlContext.Transforms.NormalizeMinMax("Features"));

// Create data prep transformer
ITransformer dataPrepTransformer = dataPrepEstimator.Fit(trainData);

// Apply transforms to training data
IDataView transformedTrainingData = dataPrepTransformer.Transform(trainData);

使用默认列名

ML.NET 算法在未指定列名时使用默认列名。 所有训练程序都有一个用于算法输入的参数,称为 featureColumnName;如果适用,它们也有一个用于预期值的参数,称为 labelColumnName。 默认情况下,这些值分别 FeaturesLabel

通过在预处理过程中使用 Concatenate 方法创建名为 Features的新列,无需在算法的参数中指定特征列名称,因为它已存在于预处理 IDataView中。 标签列 CurrentPrice,但由于数据模型中使用了 ColumnName 属性,ML.NET 将 CurrentPrice 列重命名为 Label,这样就不需要向机器学习算法估算器提供 labelColumnName 参数。

如果不想使用默认列名,可以在定义机器学习估算器时,将特征和标签列的名称作为参数传入,如后续代码片段所示:

var UserDefinedColumnSdcaEstimator = mlContext.Regression.Trainers.Sdca(labelColumnName: "MyLabelColumnName", featureColumnName: "MyFeatureColumnName");

缓存数据

默认情况下,处理数据时,数据会延迟加载或流式传输,这意味着训练器可能会从磁盘加载数据,并在训练期间多次循环访问数据。 因此,对于适合内存的数据集,建议缓存以减少从磁盘加载数据的次数。 缓存使用 AppendCacheCheckpoint 作为 EstimatorChain 的一部分来完成。

建议在任何训练程序处于管道中之前,使用 AppendCacheCheckpoint

使用以下 EstimatorChain,在 训练程序之前添加 StochasticDualCoordinateAscentAppendCacheCheckpoint 可缓存以前估算器的结果以供训练程序以后使用。

// 1. Concatenate Size and Historical into a single feature vector output to a new column called Features
// 2. Normalize Features vector
// 3. Cache prepared data
// 4. Use Sdca trainer to train the model
IEstimator<ITransformer> dataPrepEstimator =
    mlContext.Transforms.Concatenate("Features", "Size", "HistoricalPrices")
        .Append(mlContext.Transforms.NormalizeMinMax("Features"))
        .AppendCacheCheckpoint(mlContext);
        .Append(mlContext.Regression.Trainers.Sdca());

训练机器学习模型

预处理数据后,使用 Fit 方法通过 StochasticDualCoordinateAscent 回归算法训练机器学习模型。

// Define StochasticDualCoordinateAscent regression algorithm estimator
var sdcaEstimator = mlContext.Regression.Trainers.Sdca();

// Build machine learning model
var trainedModel = sdcaEstimator.Fit(transformedTrainingData);

提取模型参数

训练模型后,提取已学习的 ModelParameters 用于检查或重新训练。 LinearRegressionModelParameters 提供经过训练的模型的偏差和已学习的系数或权重。

var trainedModelParameters = trainedModel.Model as LinearRegressionModelParameters;

注意

其他模型具有特定于其任务的参数。 例如,K-Means 算法 基于质心将数据放入聚类中,KMeansModelParameters 是一个包含存储这些学习到的质心属性的对象。 若要了解详细信息,请访问 Microsoft.ML.Trainers API 文档 并查找名称中包含 ModelParameters 的类。

评估模型质量

为了帮助选择性能最佳的模型,必须评估其测试数据的性能。 使用 Evaluate 方法测量训练模型的各种指标。

注意

Evaluate 方法根据执行了哪些机器学习任务生成不同的指标。 有关更多详细信息,请访问 Microsoft.ML.Data API 文档,并查找名称中包含 Metrics 的类。

// Measure trained model performance
// Apply data prep transformer to test data
IDataView transformedTestData = dataPrepTransformer.Transform(testData);

// Use trained model to make inferences on test data
IDataView testDataPredictions = trainedModel.Transform(transformedTestData);

// Extract model metrics and get RSquared
RegressionMetrics trainedModelMetrics = mlContext.Regression.Evaluate(testDataPredictions);
double rSquared = trainedModelMetrics.RSquared;

在前面的代码示例中:

  1. 在使用以前定义的数据准备转换,对测试数据集进行预处理。
  2. 训练的机器学习模型用于对测试数据进行预测。
  3. Evaluate 方法中,测试数据集 CurrentPrice 列中的值与新输出预测 Score 列进行比较,以计算回归模型的指标,其中一个值 R-Squared 存储在 rSquared 变量中。

注意

在此小型示例中,R-Squared 不是 0-1 范围内的数字,因为数据的大小有限。 在实际方案中,应会看到介于 0 和 1 之间的值。