使用ML.NET进行动态训练/测试类

这是对ML.net的PredictionMoadel<TInput, TOutput> Train()方法中动态类/对象问题的后续内容

我的系统无法在编译时使用预定义的类,因此我尝试像下面这样将动态类输入到ML.NET中

// 字段数据类型
public class Field
{
    public string FieldName { get; set; }
    public Type FieldType { get; set; }
}

// 动态类助手
public class DynamicClass : DynamicObject
{
    private readonly Dictionary<string, KeyValuePair<Type, object>> _fields;
    public DynamicClass(List<Field> fields)
    {
        _fields = new Dictionary<string, KeyValuePair<Type, object>>();
        fields.ForEach(x => _fields.Add(x.FieldName,
            new KeyValuePair<Type, object>(x.FieldType, null)));
    }
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (_fields.ContainsKey(binder.Name))
        {
            var type = _fields[binder.Name].Key;
            if (value.GetType() == type)
            {
                _fields[binder.Name] = new KeyValuePair<Type, object>(type, value);
                return true;
            }
            else throw new Exception("Value " + value + " is not of type " + type.Name);
        }
        return false;
    }
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = _fields[binder.Name].Value;
        return true;
    }
}

private static void Main(string[] args)
{
    var fields = new List<Field>
    {
        new Field {FieldName = "Name", FieldType = typeof(string)},
        new Field {FieldName = "Income", FieldType = typeof(float)}
    };
    dynamic obj1 = new DynamicClass(fields);
    obj1.Name = "John";
    obj1.Income = 100f;
    dynamic obj2 = new DynamicClass(fields);
    obj2.Name = "Alice";
    obj2.Income = 200f;
    var trainingData = new List<dynamic> {obj1, obj2};
    var env = new LocalEnvironment();
    var schemaDef = SchemaDefinition.Create(typeof(DynamicClass));
    schemaDef.Add(new SchemaDefinition.Column(null, "Name", TextType.Instance));
    schemaDef.Add(new SchemaDefinition.Column(null, "Income", NumberType.R4));
    var trainDataView = env.CreateStreamingDataView(trainingData, schemaDef);
    var pipeline = new CategoricalEstimator(env, "Name")
        .Append(new ConcatEstimator(env, "Features", "Name"))
        .Append(new FastTreeRegressionTrainer(env, "Income", "Features"));
    var model = pipeline.Fit(trainDataView);
}

结果得到了以下错误:

No field or property with name 'Name' found in type 'System.Object

我尝试使用反射生成类,但遇到了同样的问题。

有没有解决方法?


回答:

动态类实际上并不创建类定义,而是为您提供动态对象。

我查看了SchemaDefinition.Create()的代码,它需要一个实际的类定义来构建架构。所以您的选项是动态创建和加载类定义。

您可以将类作为包含所有动态属性的字符串创建,并使用Microsoft编译器服务(即Roslyn)进行编译。请参见这里。这将生成一个包含您的动态类型的程序集(以内存流形式存在于内存中或存在于文件系统中)。

现在您已经完成了一半。要从动态程序集中获取您的动态类型,您需要在应用程序域中加载它。请参见帖子。一旦程序集加载完毕,如果是在同一个域中,您可以使用’Activator.CreateInstance()‘,如果是您自定义的域,则需要使用yourDomain.CreateInstanceAndUnwrap()来从动态生成的类中创建对象,并使用Assembly.GetType()获取类型。

这里有一些示例,虽然有点过时,但如果您准备好这样做,它们会帮助您入门。请参见CompilerEngineCompilerService来编译和加载程序集。

其他选项Refelection.Emit(),但它需要大量的IL级编码。请参见此帖子

Related Posts

为什么我们在K-means聚类方法中使用kmeans.fit函数?

我在一个视频中使用K-means聚类技术,但我不明白为…

如何获取Keras中ImageDataGenerator的.flow_from_directory函数扫描的类名?

我想制作一个用户友好的GUI图像分类器,用户只需指向数…

如何查看每个词的tf-idf得分

我试图了解文档中每个词的tf-idf得分。然而,它只返…

如何修复 ‘ValueError: Found input variables with inconsistent numbers of samples: [32979, 21602]’?

我在制作一个用于情感分析的逻辑回归模型时遇到了这个问题…

如何向神经网络输入两个不同大小的输入?

我想向神经网络输入两个数据集。第一个数据集(元素)具有…

逻辑回归与机器学习有何关联

我们正在开会讨论聘请一位我们信任的顾问来做机器学习。一…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注