【问题标题】:How to pass dynamic classes to a generic function?如何将动态类传递给泛型函数?
【发布时间】:2019-06-04 17:58:03
【问题描述】:

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

目前我正在使用此答案中提供的代码在运行时创建一个类:https://stackoverflow.com/a/3862241

当我需要调用 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);

完整(修订和修剪)来源(更多上下文): 程序.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});
    }
  }
}

【问题讨论】:

  • 我不确定问题到底是什么。是method == null的问题,即在TransformerChain上找不到方法?
  • 请提供minimal reproducible example - 显然TransformerChain(无论它是什么)没有您正在寻找的方法......但是没有真实样本就无法知道为什么。跨度>
  • @Paprika 您现在已经展示了大量的无关代码。您应该展示一个 minimal 可重现的示例。显示重现问题所需的内容,仅此而已。
  • 但是,正如 Kevin Grosse 所指出的,MakePredictionFunction 是一种可以应用于ITransformer 实例的扩展方法,而TransformerChain&lt;T&gt; 正在实现ITransformer。请注意,此扩展方法不是 TransformerChain&lt;T&gt; 类型定义的一部分,因此您在查询 TransformerChain&lt;T&gt; 类型时也会得到 null。如果需要扩展方法的MethodInfo,需要查询声明扩展方法的类型。如果是MakePredictionFunction,您需要查询PredictionFunctionExtensions 类型...
  • @elgonzo 您可能应该将您的评论转换为答案......或者我们应该将其关闭为“通过反射的呼叫扩展”(如stackoverflow.com/questions/1452261/…

标签: c# class generics dynamic ml.net


【解决方案1】:

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

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

【讨论】:

  • 这似乎是一个很好的答案,它让我完全不需要生成类并直接从 IDataView 获取数据。谢谢!
【解决方案2】:

看来,在尝试反映 MakePredictionFunction 时,您将 TransformerChain&lt;TLastTransformer&gt; 类型(它是一种可实例化的泛型类型)与静态类 TransformerChain 混淆了。

但是即使考虑TransformerChain&lt;TLastTransformer&gt; 也不会成功,因为MakePredictionFunction 不是该类型声明的方法。相反,MakePredictionFunction 是在静态类PredictionFunctionExtensions⁽¹⁾中声明的扩展方法。

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

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



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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-19
    • 2011-02-20
    • 1970-01-01
    • 1970-01-01
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多