Fr4ctlize / OxiNEAT

An implementation of NeuroEvolution of Augmenting Topologies, and its later iteration HyperNEAT.
1 stars 0 forks source link

Insertion of genomes into a population #2

Closed Byter09 closed 3 years ago

Byter09 commented 3 years ago

Hello again,

I currently use this library with great success. Am learning a ton as well. I have noticed though, that if I ever get a champion out at the end, there is no way for me to start a second run in which I can insert a previous champion.

Of course there would be some assertions, for example that the input and output nodes are the same as the GeneticConfig of the new population, but one could just panic in that case, or make the method return a Result.

Maybe this is already planned, or somehow impossible? I'd love to know what you think.

Thanks again for this lovely crate. :)

Fr4ctlize commented 3 years ago

Hello! I'm glad it's useful.

Yes, that is a deficiency I was aware of but forgot, as I haven't actually been able to apply the library much while working on it. I think it should be pretty easy to implement, probably with something along the lines of

impl<C, H, G> Population<C, H, G>
where
    G: Genome<InnovationHistory = H, Config = C> + Clone,
{
    ...
    fn from_seed(seed: &[G], population_config: PopulationConfig, genetic_config: C) -> Option<Population<C, H, G>> {
        for g in seed {
            if !g.compatible_with_config(&C) {
                return None;
            }
        }
        ... // create a new population with (population_config.size.get() / seed.len()) clones of each genome
        Some(population)
    }
    ...
}

adding Genome::compatible_with_config(&Self::Config) to Genome.

I pushed the updated documentation and examples I mentioned in the multithreading issue, so you can play around with that if you wish. I don't have much time right now to work on this, but I'd be happy to review any contributions you'd like to make (I neither have concrete guidelines on this nor know if you can even do that as the repo is currently configured...), if you wanted to try your hand at adding this.

Thank you for bringing it up!

Byter09 commented 3 years ago

I barely understand the basics. I typically don't work in this kind of programming/mathematics. Should I ever feel comfortable, I'll fork and create a PR though. But so far everything I need is there and its working flawlessly. Even gave it a pretty hard task.

Should I find more things I'll open more issues and maybe you or I can work on that stuff, but again, just a beginner in neuroevolution. Hah :D

Fr4ctlize commented 3 years ago

I've been able to look into it for a few minutes here and I'd like your opinion on something, as a user.

The way I'm approaching it, following the sketch above, is that the new population is partitioned according to the number of seed genomes, and each partition is filled with clones of the corresponding genome. However, I'm not sure if they should all be assigned to the same species, or if each partition should get it's own.

If we go with the former, then the population would have to wait one generation before partitioning into different species, if necessary. This could be problematic if some of the seed genomes perform worse than others, as they could be completely eliminated from the mating pool... I suppose I've answered my own question then, because presumably you'd want all the seed genomes to have time to proliferate.

Fr4ctlize commented 3 years ago

I've pushed a tentative implementation. If you use it, let me know what you think.

Byter09 commented 3 years ago

I don't even know how to answer your question in depth haha. I just imagined that you'd have like "one individual" or something injected into the gene pool, and given that it (probably) started out as the winner from another population, it will proliferate/reproduce/clone/whatever because it is supposedly better than all the other randomly generated population members. I really don't know anything about this haha.

And the only reason I'd love to have this feature is because I may have a process with a huge population size (to get more chances of positive genetic mutations) but now and then I have to kill the process (or I'd like to "quick-save") so I can continue later. How that exactly is implemented? I don't know the best method.

So far I'm still testing out the basics, playing with numbers, adjusting where necessary and modify a bit of the code to get multi-threading.

Whatever the implementation is you think of, maybe a good (unit-)test would be to just assert that a test started from an already good genome should find an answer quicker than a purely random population. Though, given this is based on random chance, its not really a stable test :D

Fr4ctlize commented 3 years ago

I've reworked the seeded population generation slightly, should be more flexible now. Also, I've enabled serde for populations, so you should be able to use that to save populations and reload them (as long as the particular format you're using can represent the population correctly. JSON, for example, can represent NNGenomes but not full populations, because of how the innovation history is implemented).

Byter09 commented 3 years ago

Oh nice. I typically use YAML as it can represent basically everything. Thanks so much. Hope I can use that soon. I think you can close this issue if you think it's solved. For me just having some way to do is good enough. So thank you!