colgreen / sharpneat

SharpNEAT - Evolution of Neural Networks. A C# .NET Framework.
https://sharpneat.sourceforge.io/
Other
380 stars 97 forks source link

Why is CreateGenomeDecoder method private #57

Closed LightCZ closed 2 years ago

LightCZ commented 2 years ago

When you try to use this framework in creating algorithm and use it later, you need some way to serialize IBlackBox, or get it from serialized data. According to previous version the way to do it is to serialize NeatGenome structure and decode it later, but to use it you need to get istance of IGenomeDecoder. There is no CreateGenomeDecoder on IExperiment but there is one in the NeatUtils, but for some reason its private.

Is there some other way to use "train->store->reuse trained algorithm" pipeline?

colgreen commented 2 years ago

Please see these classes in the SharpNeat.Neat.Genome.IO namespace:

  NeatGenomeSaver
  NeatGenomeLoader
  NeatGenomeLoaderFactory

You need to get an instance of NeatGenomeLoader, and the easiest way to do that is by calling static helper method NeatGenomeLoaderFactory.CreateLoaderDouble(); that in turn requires a MetaNeatGenome object to be supplied, with these properties set accordingly:

        /// <summary>
        /// Input node count.
        /// </summary>
        public int InputNodeCount { get; }

        /// <summary>
        /// Output node count.
        /// </summary>
        public int OutputNodeCount { get; }

        /// <summary>
        /// Indicates if the genomes that are evolved are acyclic, i.e. they should have no recurrent/cyclic connection paths.
        /// </summary>
        public bool IsAcyclic { get; }

        /// <summary>
        /// The neuron activation function to use in evolved networks. NEAT uses the same activation
        /// function at each node.
        /// </summary>
        public IActivationFunction<T> ActivationFn { get; }

Some of that info is redundant because it is saved in the genome data file. This is so that we can compare a loaded genome with the expected parameters for a given experiment we are loading it for (e.g. number of inputs and outputs).

This could all be a lot clearer I think, especially for the use case of loading an evolved network for direct use where you don't care that it came from a NeatGenome, but hopefully the above info allows you to do what you want today. The genome data format is very simple actually, so it should be relatively straightforward to write some code to load a genom data file directly into one of the NeuralNet types.

LightCZ commented 2 years ago

These classes looks very nice to save progress of the evolution - thank you for that. My point was exactly pointing out this:

The genome data format is very simple actually, so it should be relatively straightforward to write some code to load a genom data file directly into one of the NeuralNet types.

I think that this code is already written - CreateGenomeDecoder from experiemnt. You easily can create experiment - since you already need it for evolution phase - why not use is again in the loading phase. Use GenomeDecoder either created from INeatExperiment (simmilar properties as MetaNeatGenome) - Is acyclic etc.

  public class MetaNeatGenome<T> where T : struct
    {
        #region Auto Properties

        /// <summary>
        /// Input node count.
        /// </summary>
        public int InputNodeCount { get; }

        /// <summary>
        /// Output node count.
        /// </summary>
        public int OutputNodeCount { get; }

        /// <summary>
        /// Indicates if the genomes that are evolved are acyclic, i.e. they should have no recurrent/cyclic connection paths.
        /// </summary>
        public bool IsAcyclic { get; }

        /// <summary>
        /// The neuron activation function to use in evolved networks. NEAT uses the same activation
        /// function at each node.
        /// </summary>
        public IActivationFunction<T> ActivationFn { get; }

From INeatExperiment


    bool IsAcyclic { get; set; }
    int CyclesPerActivation { get; set; }
    string ActivationFnName { get; set; }

you even can create MetaNeatGenome from INeatExperiment with: NeatUtils.CreateMetaNeatGenome(neatExperiment)

I think that either make CreateGenomeDecoder or maybe extend your IO namespace with directly loading into NeuralNet type would be much more clear.

By the way thank you very much for creating this framework.

colgreen commented 2 years ago

Resolved.

Please see https://github.com/colgreen/sharpneat/issues/55