Как передать динамические классы в универсальную функцию? - PullRequest
0 голосов
/ 10 января 2019

Я хочу сделать API машинного обучения для использования с веб-приложением, имена полей будут переданы API с их типами данных.

В настоящее время я делаю урок во время выполнения с кодом, представленным в этом ответе: https://stackoverflow.com/a/3862241

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

ПРИМЕЧАНИЕ. В настоящее время документы для ML.NET обновляются до версии 0.9.0, поэтому они недоступны.

То, что я пробовал, это (минимально):

Type[] typeArgs = { generatedType, typeof(ClusterPrediction) };
object[] parametersArray = { mlContext }; // value

MethodInfo method = typeof(TransformerChain).GetMethod("MakePredictionFunction");
if (method == null) { // Using PredictionFunctionExtensions helps here
  Console.WriteLine("Method not found!");
}
MethodInfo generic = method.MakeGenericMethod(typeArgs);
var temp = generic.Invoke(model, parametersArray);

Полный (пересмотренный и урезанный) источник (для большего контекста): Program.cs

namespace Generic {
  class Program {
    public class GenericData {
      public float SepalLength;
      public float SepalWidth;
      public float PetalLength;
      public float PetalWidth;
    }
    public class ClusterPrediction {
      public uint PredictedLabel;
      public float[] Score;
    }

    static void Main(string[] args) {
      List<Field> fields = new List<Field>() {
                new Field(){ name="SepalLength", type=typeof(float)},
                new Field(){ name="SepalWidth", type=typeof(float)},
                new Field(){ name="PetalLength", type=typeof(float)},
                new Field(){ name="PetalWidth", type=typeof(float)},
            };
      var generatedType = GenTypeBuilder.CompileResultType(fields);

      var mlContext = new MLContext(seed: 0);
      TextLoader textLoader = mlContext.Data.TextReader(new TextLoader.Arguments() {
        Separator = ",",
        Column = new[]
        {
          new TextLoader.Column("SepalLength", DataKind.R4, 0),
          new TextLoader.Column("SepalWidth", DataKind.R4, 1),
          new TextLoader.Column("PetalLength", DataKind.R4, 2),
          new TextLoader.Column("PetalWidth", DataKind.R4, 3)
        }
      });
      IDataView dataView = textLoader.Read(Path.Combine(Environment.CurrentDirectory, "Data", "flowers.txt"););

      var pipeline = mlContext.Transforms
        .Concatenate("Features", "SepalLength", "SepalWidth", "PetalLength", "PetalWidth")
        .Append(mlContext.Clustering.Trainers.KMeans("Features", clustersCount: 3));
      var model = pipeline.Fit(dataView);

      Type[] typeArgs = { generatedType, typeof(ClusterPrediction) };
      object[] parametersArray = { mlContext }; // value

      MethodInfo method = typeof(TransformerChain).GetMethod("MakePredictionFunction");
      if (method == null) { // Using PredictionFunctionExtensions helps here
        Console.WriteLine("Method not found!");
      }
      MethodInfo generic = method.MakeGenericMethod(typeArgs);
      var temp = generic.Invoke(model, parametersArray);

      var prediction = temp.Predict(new GenericData {SepalLength = 5.6f, SepalWidth = 2.5f,
                                                     PetalLength = 3.9f, PetalWidth = 1.1f});
    }
  }
}

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Кажется, пытаясь отразить для MakePredictionFunction, вы перепутали тип TransformerChain<TLastTransformer> (который является экземпляром универсального типа) со статическим классом TransformerChain.

Но даже размышление о TransformerChain<TLastTransformer> не будет успешным, потому что MakePredictionFunction не является методом, объявленным этим типом. Скорее, MakePredictionFunction - это метод расширения, объявленный в статическом классе PredictionFunctionExtensions ⁽¹⁾.

Таким образом, чтобы получить MethodInfo для MakePredictionFunction, попробуйте это:

MethodInfo method = typeof(PredictionFunctionExtensions).GetMethod("MakePredictionFunction");



⁽¹⁾ Я не уверен на 100%, в каком пространстве имен PredictionFunctionExtensions находится. При поиске документации по API ML.NET 0.9.0 кажется, что оно находится в Microsoft.ML.Runtime.Data пространстве имен. Но попытка посетить действительную страницу документации для MakePredictionFunction в настоящее время приводит только к ошибке 404, поэтому есть вероятность, что эта информация может быть неточной (я не пользователь ML.NET, поэтому могу проверить): - (

0 голосов
/ 10 января 2019

Попробуйте прочитать ваши тестовые данные в IDataView, а затем передать этот IDataView в model.Transform ();

Это должно вставить Score и PredictedLabel как отдельные столбцы в ваши тестовые данные.

...