如何将动态 类 传递给通用函数?

How to pass dynamic classes to a generic function?

我想制作一个机器学习 api 用于 Web 应用程序,字段名称将连同它们的数据类型一起传递给 api。

目前我正在使用此答案中提供的代码在运行时制作 class:

当我需要调用 ML.NET PredictionFunction 时出现问题,我无法传入泛型函数的类型,因为它们是在运行时创建的。 我试过使用反射来调用它,但它似乎无法找到该函数。

注意:目前 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});
    }
  }
}

尝试在 IDataView 中读取测试数据,而不是将 IDataView 传递给 model.Transform();

这应该将 Score 和 PredictedLabel 作为单独的列插入到您的测试数据中。

看来,在尝试反映 MakePredictionFunction 时,您混淆了 TransformerChain<TLastTransformer> 类型(这是一个可实例化的通用类型)与静态 class TransformerChain .

但是即使反思TransformerChain<TLastTransformer>也不会成功,因为MakePredictionFunction不是这个类型声明的方法。相反,MakePredictionFunction 是在静态 class PredictionFunctionExtensions⁽¹⁾.

中声明的扩展方法

因此,要获取 MakePredictionFunctionMethodInfo,试试这个:

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



⁽¹⁾ 我不是 100% 确定 PredictionFunctionExtensions 位于哪个命名空间。搜索 ML.NET 0.9.0 API 文档,它似乎位于 Microsoft.ML.Runtime.Data 命名空间。但是尝试访问 MakePredictionFunction 的实际文档页面目前只会导致 404 错误,因此此信息可能不准确(我不是 ML.NET用户,所以我无法验证):-(