динамическое обучение / тестовые занятия с ML.NET - PullRequest
0 голосов
/ 15 октября 2018

Это продолжение вопроса здесь Динамические классы / объекты PredictionMoadel ML.netTrain ()

Моя система не может использовать предопределенный класс во время компиляции, поэтому я попытался передать динамический класс в 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);
    }

, и получил ошибку: "'Поле или свойство с именем' Name 'не найдено в типе' System.Object '".Я попытался создать класс с помощью Reflection только для того, чтобы столкнуться с той же проблемой.

Есть ли обходной путь?Спасибо

Ответы [ 3 ]

0 голосов
/ 16 октября 2018

Динамический класс на самом деле не создает определение класса, а скорее предоставляет вам динамический объект.

Я посмотрел код для SchemaDefinition.Create(), ему нужно фактическое определение класса для построения схемы.Таким образом, вы можете создать и загрузить определение класса динамически.

Вы можете создать свой класс как строку со всеми динамическими свойствами и скомпилировать его, используя службы компиляции Microsoft, также известные как Roslyn.Смотрите здесь .Это создаст сборку (в памяти как поток памяти или в файловой системе) с вашим динамическим типом.

Теперь вы только на полпути.Чтобы получить динамический тип из динамической сборки, вам нужно загрузить его в домен приложения.Смотрите этот пост.После загрузки сборки вы можете использовать ' Activator.CreateInstance () ', если это тот же домен или если это ваш пользовательский домен, тогда вам потребуется yourDomain.CreateInstanceAndUnwrap(), чтобы создать объект из динамически генерируемого класса и получитьтип использования Assembly.GetType().

Немного образца здесь, Немного устаревшего, но вы встанете на ноги, если вы готовы к этому.См. CompilerEngine и CompilerService для компиляции и загрузки сборки.

Другие опции : Refelection.Emit(), но это требует большого количества кодирования уровня IL.Смотрите сообщение .

0 голосов
/ 18 апреля 2019

Для тех, кто пытается это сделать, у меня есть рабочее решение, которое создает схему и может использоваться для динамического обучения данных.

Сначала возьмите код для 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 через свой конвейер.

Удачи.

0 голосов
/ 15 октября 2018

Прямо сейчас я использую пустышку как это в качестве обходного пути

    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;
    }
...