Это простое руководство предоставит вам необходимые знания о переобучении моделей ML.NET.

ПРОБЛЕМА

Как только я начал играть с библиотекой ML.NET, я попытался использовать несколько руководств Microsoft, чтобы иметь возможность определить и использовать модель, отвечающую всем моим требованиям. К сожалению, в этих руководствах есть неясная часть, которая, вероятно, сбивает с толку новичков в библиотеке машинного обучения, которые еще не знакомы с ее функциями. Я говорю о примере переобучения модели, который опускает важные детали в своем объяснении.

РЕШЕНИЕ

Я собрал простой пример кода, иллюстрирующий процесс переобучения. Давайте рассмотрим пример шаг за шагом и объясним каждый блок кода. Вы также можете найти исходный код здесь.

Конфигурация моего проекта, отраженная в файле .csproj, выглядит следующим образом:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.ML" Version="2.0.0" />
  </ItemGroup>

</Project>

В моем файле Program.cs в классе Program я определил два дополнительных класса, которые представляют типы данных, используемые моей моделью, а также статический метод, который инициирует тренировочный процесс.

namespace Tutorial
{
    class Program
    {
        private class HouseData
        {
            public float Size { get; set; }
            public float Price { get; set; }
        }

        private class Prediction
        {
            [ColumnName("Score")]
            public float Price { get; set; }
        }

        public static void Main()
        {
            ...
        }
    }
}

Прежде чем мы углубимся в содержание метода Main, я хотел бы высказать несколько соображений.

  1. Не все алгоритмы могут быть переобучены. Список переобучаемых алгоритмов смотрите здесь.
  2. Этот учебник становится более полезным, если вы используете функцию сохранить-загрузить вашей модели. Путеводитель можно найти здесь.
  3. Свяжите свою модель в цепочку независимых трансформеров (мы опишем позже в этом руководстве). Итак, большую часть времени это не структура, а набор структур.

Наша первая остановка в коде — создание MLContext:

 MLContext mlContext = new MLContext();

Затем мы должны подготовить некоторые обучающие данные для нашей модели:

// 1. Import or create training data
HouseData[] houseData =
{
    new HouseData() { Size = 1.1F, Price = 1.2F },
    new HouseData() { Size = 1.9F, Price = 2.3F },
    new HouseData() { Size = 2.8F, Price = 3.0F },
    new HouseData() { Size = 3.4F, Price = 3.7F }
};

IDataView trainingData = mlContext.Data.LoadFromEnumerable(houseData);

// Define data preparation estimator
IEstimator<ITransformer> dataPrepEstimator = mlContext.Transforms.Concatenate(
    "Features",
    new[] { "Size" }
);

// Create data preparation transformer
ITransformer dataPrepTransformer = dataPrepEstimator.Fit(trainingData);

// Pre-process data using data prep operations
IDataView transformedData = dataPrepTransformer.Transform(trainingData);

Обратите внимание, что на этом шаге нам нужно вызвать метод Fit для оценщика, чтобы иметь возможность создать объект ITransformer. Трансформатор станет «первой ступенью» в цепочке модели.

Теперь нам нужно определить алгоритм обучения (тренажер) для модели. Этого можно легко добиться, если использовать следующий код:

// 2. Specify model trainer
// Define regression algorithm estimator
OnlineGradientDescentTrainer? regressionEstimator =
    mlContext.Regression.Trainers.OnlineGradientDescent(
        labelColumnName: "Price",
        numberOfIterations: 100
    );
// Create algorithm preparation transformer
var regressionTransformer = regressionEstimator.Fit(transformedData);

Мы снова используем метод Fit, потому что он станет «вторым этапом» в цепочке модели.

Наконец, цепочка модели выглядит так:

 // 3. Create model
 var model = dataPrepTransformer.Append(regressionTransformer);

Мы можем протестировать модель и вывести ее вывод на консоль.

// 4. Make a prediction
var size = new HouseData() { Size = 2.5F };
var price = mlContext.Model
    .CreatePredictionEngine<HouseData, Prediction>(model)
    .Predict(size);

Console.WriteLine(
    $"//4 Predicted price for size: {size.Size * 1000} sq ft= {price.Price * 100:C}k"
);

//4 Predicted price for size: 2500 sq ft= £276.98k

На этом этапе мы можем сохранить наши трансформеры, чтобы переобучить и использовать их позже.

// 5. Save model and and data transformer
string regressionTransformerlPath = "./models/TutorialRegressionTransformer.zip";
string dataTransformerPath = "./models/TutorialDataTransformer.zip";

// Save Data Prep Transformer
mlContext.Model.Save(dataPrepTransformer, trainingData.Schema, dataTransformerPath);
// Save Trained Model
mlContext.Model.Save(
    regressionTransformer,
    transformedData.Schema,
    regressionTransformerlPath
);

// 5.1 (OPTIONAL) Load model and data transformer
// Define DataViewSchema of data prep pipeline and trained model
DataViewSchema dataPrepPipelineSchema,
    modelSchema;

// Load data preparation pipeline
dataPrepTransformer = mlContext.Model.Load(
    dataTransformerPath,
    out dataPrepPipelineSchema
);

// Load trained model
regressionTransformer =
    (RegressionPredictionTransformer<LinearRegressionModelParameters>)
        mlContext.Model.Load(regressionTransformerlPath, out modelSchema);

Для переобучения модели необходимо получить две вещи:

  1. Новый набор данных
  2. Исходные параметры модели

Мы можем создать новый набор данных точно так же, как создали набор данных transformedData.

// 6. Get new data (repeat step 1)
HouseData[] newDataSet =
{
    new HouseData { Size = 4F, Price = 3F },
    new HouseData { Size = 2F, Price = 2.3F }
};

IDataView newTrainingData = mlContext.Data.LoadFromEnumerable(newDataSet);

// Preprocess Data
IDataView transformedNewData = dataPrepTransformer.Transform(newTrainingData);

Получение исходного параметра является немного более сложной задачей.

// 7. Extract trained model parameters
// model.Last() is used here to extract weights and biases from model
// as it is added to the end of the chain
var originalModelParameters =
    ((ISingleFeaturePredictionTransformer<object>)model.Last()).Model
    as LinearRegressionModelParameters;

var retrainedRegressionTransformer = regressionEstimator.Fit(
    transformedNewData,
    originalModelParameters
);

На этом этапе мы также воссоздаем преобразователь регрессии, поскольку он должен использовать обновленные данные. Обратите внимание, что мы передаем исходные параметры в метод Fit. Эта опция доступна только для переобучаемых алгоритмов.

Пришло время воссоздать модель.

// 8. Recreate model
model = dataPrepTransformer.Append(retrainedRegressionTransformer);

В качестве последнего шага мы можем протестировать обновленную модель.

 // 9 Make a prediction on re-trained model
var newPrice = mlContext.Model
    .CreatePredictionEngine<HouseData, Prediction>(model)
    .Predict(size);

Console.WriteLine(
    $"//9 Predicted price for size: {size.Size * 1000} sq ft= {newPrice.Price * 100:C}k"
);
//9 Predicted price for size: 2500 sq ft= £228.00k

ЗАКЛЮЧЕНИЕ

Следуя этим простым шагам, модель можно легко сохранить, загрузить и повторно обучить с новыми данными.