ML.NET — как обратить вспять mlContext.Преобразования.Преобразование.MapValueToKey с использованием хранимой модели

#c# #ml.net

#c# #ml.net

Вопрос:

Я использую ML.Net модель, использующая преобразование MapValueToKey в pipleline. После обучения модели я сохраняю ее.

Во время выполнения я загружаю сохраненную модель и делаю прогноз. Это работает нормально, но я получаю только значение (целое число). Как я могу извлечь ключи (строковые значения), которые соответствуют прогнозируемым значениям, используя модель, загруженную из сохраненного файла (я знаю, что сопоставление включено в сохраненную модель, потому что я вижу это, если печатаю матрицу путаницы).

Ниже приведен пример кода, показывающий основные элементы моей проблемы:

 //Note: this.AllData is preloaded:  IDataView AllData

        //Create the PipeLine - Mapping Treatment Name to a Label as needed by the Multiclass Classification model
        var pipeline = mlContext.Transforms.Conversion.MapValueToKey(outputColumnName: "Label", nameof(TreatmentObservation.NextTreatmentName))
                        .Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "roadclass", inputColumnName: nameof(TreatmentObservation.RoadClass)))
                        .Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "surf_mat", inputColumnName: nameof(TreatmentObservation.SurfMaterial)))                                                       
                        .Append(mlContext.Transforms.Concatenate("Features", "roadclass", nameof(TreatmentObservation.Rut85th), nameof(TreatmentObservation.Naasra85th)));

        //Create a LightGBM Trainer
        IEstimator<ITransformer> trainer = mlContext.MulticlassClassification.Trainers.LightGbm();
        var trainingPipeline = pipeline.Append(trainer);
        var trainedModelWithPreproc = trainingPipeline.Fit(this.AllData); //Fit the pipleline on all the preloaded data

        //Save the model            
        string modelSaveFilePath = "modelPipeline.zip";            
        mlContext.Model.Save(trainedModelWithPreproc, dataSplit.TrainSet.Schema, modelSaveFilePath);

        //Now Load back the model and test it
        // Define trained model schemas
        DataViewSchema modelSchema;
        ITransformer allInOneModel = mlContext.Model.Load(modelSaveFilePath, out modelSchema);

        List<TreatmentObservation> testingData = null;
        //Load testing data here...(code not included)

        var observations = mlContext.Data.LoadFromEnumerable(testingData);
                               
        var engine = this.mlContext.Model.CreatePredictionEngine<TreatmentObservation, Prediction_MultiLabel>(allInOneModel);  //Create the prediction engine

        foreach (TreatmentObservation observation in testingData)
        {
            var predicted = engine.Predict(observation);
            uint label_value = predicted.PredictedLabel;

            string label_key;
            //How to get back the Key from the predicted value?

        }
 

И вот класс, используемый для прогнозирования в приведенном выше примере:

 // Class used to capture predictions.
public class Prediction_MultiLabel
{
    // Original label.
    public uint Label { get; set; }

    // Predicted label from the trainer.
    public uint PredictedLabel { get; set; }

}
 

Итак, мой вопрос: как я могу изменить отображение при составлении прогнозов с использованием сохраненной и загруженной модели?

Я рассмотрел примеры, подобные этому: ML.NET пример но в этих примерах не используется хранимая модель. Они создают, а затем напрямую используют конвейер. Мне нужно знать, как отменить сопоставление из хранимой модели. Я не эксперт в ML.NET , поэтому, пожалуйста, извините, если в моем вопросе есть какое-то невежество!

Ответ №1:

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

 //First create an explicit map for mapping keys to values. The values will be the index of the items in the array. 
        var lookupData = new[] {
            new LookupMap { Key = "Banana" },
            new LookupMap { Key = "Apple" },
            new LookupMap { Key = "Orange"  },
            new LookupMap { Key = "Melon" },
        };

        //Convert to IDataView
        var lookupIdvMap = mlContext.Data.LoadFromEnumerable(lookupData);
        
        //Now create the pipeline, with an explicit keyData Map using the above mapping
        var pipeline = mlContext.Transforms.Conversion.MapValueToKey(outputColumnName: "Label", nameof(Fruit.Name), keyData: lookupIdvMap)                                                        
                        .Append(mlContext.Transforms.Concatenate("Features", nameof(Fruit.Color), nameof(Fruit.Diameter), nameof(Fruit.Weight)));
 

Теперь обучите модель с использованием этого конвейера, затем сохраните ее (пример кода приведен в приведенном выше вопросе).

Затем загрузите сохраненную модель обратно для тестирования и создайте механизм прогнозирования. Опять же, пример кода приведен в приведенном выше вопросе. После того, как вы это сделаете, вы можете сделать прогноз и получить имя вместо значения следующим образом:

 //Here is an example of how you make a prediction:
        //In this case 'observation' is an instance of the type 'Fruit'
        var predicted = engine.Predict(observation);
        
        //Compare the observed and predicted name of the fruit
        string obs_Name = observation.Name;  //this is the observed value
        string pred_Name = lookupData[predicted.PredictedLabel - 1].Key;  //this is the predicted value. 
 

Тип LookupMap — это простой класс, определенный следующим образом:

 // Type for the IDataView that will be serving as the map
public class LookupMap
{
    public string Key { get; set; }
}