【问题标题】:dynamic training/test classes with ML.NET使用 ML.NET 进行动态训练/测试类
【发布时间】:2018-10-15 18:24:15
【问题描述】:

这是对这里问题的跟进 Dynamic classes/objects ML.net's PredictionMoadel<TInput, TOutput> Train()

我的系统在编译时无法使用预定义的类,因此我尝试将动态类提供给 ML.NET,如下所示

    // field data type
    public class Field
    {
        public string FieldName { get; set; }
        public Type FieldType { get; set; }
    }

    // dynamic class helper
    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);
    }

并得到错误:“在类型 'System.Object' 中找不到名称为 'Name' 的字段或属性”。我尝试使用反射生成类,但遇到了同样的问题。

有解决方法吗?谢谢

【问题讨论】:

标签: c# machine-learning ml.net


【解决方案1】:

对于那些尝试这样做的人,我有一个可行的解决方案,它可以创建架构并可用于动态训练数据。

首先,从我的另一个答案here 中获取 DynamicTypeProperty 和 DynamicType 的代码。

以下代码将动态创建架构:

var properties = new List<DynamicTypeProperty>()
{
    new DynamicTypeProperty("SepalLength", typeof(float)),
    new DynamicTypeProperty("SepalWidth", typeof(float)),
    new DynamicTypeProperty("PetalLength", typeof(float)),
    new DynamicTypeProperty("PetalWidth", typeof(float)),
};

// create the new type
var dynamicType = DynamicType.CreateDynamicType(properties);
var schema = SchemaDefinition.Create(dynamicType);

然后您需要创建包含所需数据的列表。这样做如下:

var dynamicList = DynamicType.CreateDynamicList(dynamicType);

// get an action that will add to the list
var addAction = DynamicType.GetAddAction(dynamicList);

// call the action, with an object[] containing parameters in exact order added
addAction.Invoke(new object[] {1.1, 2.2, 3.3, 4.4});
// call add action again for each row.

然后您需要使用数据创建一个 IDataView,这需要使用反射,否则培训师将无法推断出正确的类型。

            var mlContext = new MLContext();
            var dataType = mlContext.Data.GetType();
            var loadMethodGeneric = dataType.GetMethods().First(method => method.Name =="LoadFromEnumerable" && method.IsGenericMethod);
            var loadMethod = loadMethodGeneric.MakeGenericMethod(dynamicType);
            var trainData = (IDataView) loadMethod.Invoke(mlContext.Data, new[] {dynamicList, schema});

然后,您应该能够通过您的管道运行trainData

祝你好运。

【讨论】:

  • 谢谢加里!我能够从您的示例中创建一个动态 IDataView 。但是,我有一个后续问题。训练模型后,您必须创建一个预测引擎,该引擎要求声明源类类型。但是,我不确定如何声明这个类,因为我使用的是动态类型的静态实例。我是否误解了如何使用这些类?或者您能否提供一个简短示例,说明如何使用此示例中创建的 IDataView 来实例化预测引擎?
  • @andyopayne,看看我对另一个类似问题的回答。我发布了一些示例代码来做到这一点。 stackoverflow.com/questions/66893993/…
【解决方案2】:

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

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

您可以将类创建为具有所有动态属性的字符串,并使用 Microsoft 编译器服务(又名 Roslyn)对其进行编译。见here。这将使用您的动态类型生成一个程序集(在内存中作为内存流或在文件系统上)。

现在你只完成了一半。要从动态程序集中获取动态类型,您需要将其加载到应用程序域中。请参阅this 帖子。 加载程序集后,您可以使用“Activator.CreateInstance()”,如果它是同一个域,或者如果它是您的自定义域,那么您将需要yourDomain.CreateInstanceAndUnwrap() 从动态生成的类中创建对象并获取使用Assembly.GetType() 的类型。

这里的样本很少,有点过时,但如果你愿意的话,会让你站起来。请参阅 CompilerEngineCompilerService 以编译和加载程序集。

其他选项Refelection.Emit(),但它需要大量的 IL 级编码。看到这个post

【讨论】:

  • 我确实尝试了反射解决方案,但没有帮助,然后会检查其他人
【解决方案3】:

现在我正在使用像这样的虚拟占位符作为解决方法

    public class TrainingSample
    {
        public string TextField1;
        public string TextField2;
        public string TextField3;
        public string TextField4;
        public string TextField5;

        public float FloatField1;
        public float FloatField2;
        public float FloatField3;
        public float FloatField4;
        public float FloatField5;
        public float FloatField6;
        public float FloatField7;
        public float FloatField8;
        public float FloatField9;
        public float FloatField10;
        public float FloatField11;
        public float FloatField12;
        public float FloatField13;
        public float FloatField14;
        public float FloatField15;
    }

【讨论】:

  • 您可以改为使用 FloatFeatures 向量和 TextFeatures 向量,然后只使用接受向量参数的编码估计器步骤。大多数数字接受输入列的向量,对于文本特征,有一些(例如 ApplyWordEmbedding)参考:docs.microsoft.com/en-us/dotnet/api/…
猜你喜欢
  • 1970-01-01
  • 2017-10-12
  • 2019-08-20
  • 2020-04-02
  • 1970-01-01
  • 2011-12-16
  • 1970-01-01
  • 2011-01-25
  • 2015-10-06
相关资源
最近更新 更多