Crossover
Two parents, one child, and the reason the child takes exactly the fitter parent's shape
Historical markings exist so that this post is short. Once both parents' genes carry stable IDs, combining them is bookkeeping.
Discussing all things around software engineering.
Two parents, one child, and the reason the child takes exactly the fitter parent's shape
Historical markings exist so that this post is short. Once both parents' genes carry stable IDs, combining them is bookkeeping.
Adding and removing nodes and connections, and why a new node has to start out doing almost nothing
This is the half of mutation that NEAT is named after: the part that grows the topology. Four mutations, all of them rare.
func (b *Breeder) mutateStructure(genome Genome) Genome {
genome = b.mutateAddNode(genome)
genome = b.mutateDeleteNode(genome)
genome = b.mutateAddConnection(genome)
genome = b.mutateDeleteConnection(genome)
return genome
}
The four mutations that only change numbers, and the one that would have frozen every weight's sign for the whole run
Mutation comes in two halves, and they are kept apart deliberately.
func (b *Breeder) mutateGenome(genome Genome) Genome {
return b.mutateStructure(b.mutateParameters(genome))
}
This post is the first half: the mutations that change existing genes without adding or removing any.
The idea the whole algorithm rests on: the same innovation gets the same ID, whoever finds it
If you take one idea away from NEAT, take this one. It is a page of code and it is what makes everything else possible.
The thing evolution edits, why it starts as small as it possibly can, and why every genome in the first generation is the same one
A genome is a description of a network that has not been built yet. It is what mutation edits, what crossover combines, and what gets written to disk when a run finds something worth keeping.
Turning a bag of nodes and connections into a flat loop over slices
Before there is anything to evolve there has to be something to run. The network package takes a list of nodes and a list of connections and turns them into something that activates fast, and it knows nothing at all about evolution.
Eight small functions, two of which decide whether a run can ever be repeated
Before any of the algorithm, a handful of helpers for drawing random numbers and poking at slices. They are eight short functions and it would be fair to skip them - except that two of them encode decisions that everything else in the series depends on.
An implementation of NeuroEvolution of Augmenting Topologies, a piece at a time
Most neural network training holds the shape of the network fixed and moves the weights. NEAT moves both. A run starts from the smallest network that could possibly answer the question - every input wired straight to every output, nothing in between - and grows hidden nodes and connections one at a time, keeping whatever happens to help.
I have wanted to build one properly for years. This series is that: neatgo, a piece at a time.