mdabros / SharpLearning

Machine learning for C# .Net
MIT License
384 stars 85 forks source link

Can this project be called under xamarin forms and run on android? I tried, loading the model failed. #108

Closed sharpwood closed 5 years ago

mdabros commented 5 years ago

Hi @sharpwood,

I have not tried running a model under Xamarin forms on android myself, so to be honest I am not sure if it will work. Can you provide a little more information on the error you are getting?

Best regards Mads

sharpwood commented 5 years ago

Unhandled Exception:

System.Runtime.Serialization.SerializationException: Invalid XML encountered. The same Id value '5' is defined more than once. Multiple objects cannot be deserialized using the same Id.

sharpwood commented 5 years ago

I tried, the same code, will report an error under xamarin forms, and it works fine under windows. Can you help me check the problem?

mdabros commented 5 years ago

@sharpwood It seems to be a problem with either the XML format or the deserializer. Since the same code works under Windows it might also be some localization related XML issue. Sadly I don't have much experience with Android and Xamarin. However, I would like to help you solve the problem if I can.

Which model type are you trying to load?

To rule out problems with training a model on Windows and then deploying on Android, could you try running the following code on your android/xamarin device:


/// Create random training data.
var random = new Random(23);
var observations = new F64Matrix(100, 10);
observations.Map(() => random.NextDouble());
var targets = Enumerable.Range(0, 100)
    .Select(v => (double)random.Next(3))
    .ToArray();

// Learn model.
var learner = new ClassificationDecisionTreeLearner();
var saveModel = learner.Learn(observations, targets);

// Save model to string writer.
var writer = new StringWriter();
saveModel.Save(() => writer);

// Load model from string reader.
var reader = new StringReader(writer.ToString());
var loadModel = ClassificationDecisionTreeModel.Load(() => reader);

This will save and load a very simple model, in memory, and serve as a sanity check if load/save works on android/xamarin at all.

mdabros commented 5 years ago

@sharpwood From .NET Standard 2.0 Support in Xamarin.Forms it seems that .Net Standard 2.0 and Xamarin.Forms 2.4 (and greater) should be compatible. Since SharpLearning is .Net Standard 2.0 they should work together. The only exception being SharpLearning.Neural which is currently not .Net Standard 2.0.

sharpwood commented 5 years ago

The same exception occurred when running the above code.

mdabros commented 5 years ago

@sharpwood That seems to indicate that there is an issue with the XML serializer/deserializer on android/xamarin. The XML serializer/deserializer used as default in SharpLearning can be found here: GenericXmlDataContractSerializer. I will need an android/xamarin environment to debug this further.

As a workaround you can try using the GenericBinarySerializer instead, and see if this works with android/xamarin. Try running the following code:

var random = new Random(23);

/// Create random training data.
var observations = new F64Matrix(100, 10);
observations.Map(() => random.NextDouble());
var targets = Enumerable.Range(0, 100)
    .Select(v => (double)random.Next(3))
    .ToArray();

/// Learn model.
var learner = new ClassificationDecisionTreeLearner();
var saveModel = learner.Learn(observations, targets);

/// Save model using the GenericBinarySerializer.            
var writer = new StringWriter();
var serializer = new GenericBinarySerializer();
serializer.Serialize(saveModel, () => writer);

/// Load model using the GenericBinarySerializer.    
var reader = new StringReader(writer.ToString());
var loadModel = serializer.Deserialize<ClassificationDecisionTreeModel>(() => reader);

var prediction = loadModel.Predict(new double[10]);
sharpwood commented 5 years ago

Great! It works. Thank you

mdabros commented 5 years ago

@sharpwood Sounds good. Then at least you can continue with your work. One thing to note about the GenericBinarySerializer is that large models can take longer time to deserialize compared to the xml alternative. So this would be the disadvantage of this solution. The advantage is that the model will take op less disc space because of the more compact format.

mdabros commented 5 years ago

@sharpwood I am closing this issue with the answer: Yes, this project will work under android/xamarin.forms with the limitation that the GenericBinarySerializer has to be used to serialize/deserialize models.

Feel free to open a separate issue for getting the GenericXmlDataContractSerializer to work on andriod/xamarin if you need it at some point.