The built-in NEAT class allows you create evolutionary algorithms with just a few lines of code. If you want to evolve neural networks to conform a given dataset, check out this page. The following code is from the Agario-AI built with Neataptic.
/** Construct the genetic algorithm */
function initNeat(){
neat = new Neat(
1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2,
2,
null,
{
mutation: methods.mutation.ALL
popsize: PLAYER_AMOUNT,
mutationRate: MUTATION_RATE,
elitism: Math.round(ELITISM_PERCENT * PLAYER_AMOUNT),
network: new architect.Random(
1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2,
START_HIDDEN_SIZE,
2
)
}
);
if(USE_TRAINED_POP) neat.population = population;
}
/** Start the evaluation of the current generation */
function startEvaluation(){
players = [];
highestScore = 0;
for(var genome in neat.population){
genome = neat.population[genome];
new Player(genome);
}
}
/** End the evaluation of the current generation */
function endEvaluation(){
console.log('Generation:', neat.generation, '- average score:', neat.getAverage());
neat.sort();
var newPopulation = [];
// Elitism
for(var i = 0; i < neat.elitism; i++){
newPopulation.push(neat.population[i]);
}
// Breed the next individuals
for(var i = 0; i < neat.popsize - neat.elitism; i++){
newPopulation.push(neat.getOffspring());
}
// Replace the old population with the new population
neat.population = newPopulation;
neat.mutate();
neat.generation++;
startEvaluation();
}
You might also want to check out the target-seeking project built with Neataptic.
The constructor comes with various options. The constructor works as follows:
new Neat(input, output, fitnessFunction, options); // options should be an object
Every generation, each genome will be tested on the fitnessFunction
. The
fitness function should return a score (a number). Through evolution, the
genomes will try to maximize the output of the fitness function.
Negative scores are allowed.
You can provide the following options in an object for the options
argument:
popsize
Sets the population size of each generation. Default is 50.
elitism
Sets the elitism of every evolution loop. Default is 0.
provenance
Sets the provenance of the genetic algorithm. Provenance means that during every evolution, the given amount of genomes will be inserted which all have the original
network template (which is Network(input,output)
when no network
option is given). Default is 0.
mutation
Sets the allowed mutation methods used in the evolutionary process. Must be an array (e.g. [methods.mutation.ADD_NODE, methods.mutation.SUB_NODE]
). Default mutation methods are all non-recurrent mutation methods. A random mutation method will be chosen from the array when mutation occrus.
selection
Sets the allowed selection method used in the evolutionary process. Must be a single method (e.g. Selection.FITNESS_PROPORTIONATE
). Default is FITNESS_PROPORTIONATE
.
crossover
Sets the allowed crossover methods used in the evolutionary process. Must be an array. disabled as of now
fitnessPopulation
If set to true
, you will have to specify a fitness function that
takes an array of genomes as input and sets their .score
property.
mutationRate
Sets the mutation rate. If set to 0.3
, 30% of the new population will be mutated. Default is 0.3
.
mutationAmount
If mutation occurs (randomNumber < mutationRate
), sets the amount of times a mutation method will be applied to the network. Default is 1
.
network
If you want to start the algorithm from a specific network, specify your network here.
equal
If set to true, all networks will be viewed equal during crossover. This stimulates more diverse network architectures. Default is false
.
clear
Clears the context of the network before activating the fitness function. Should be applied to get consistent outputs from recurrent networks. Default is false
.
There are only a few properties
input
The amount of input neurons each genome has
output
The amount of output neurons each genome has
fitness
The fitness function that is used to evaluate genomes
generation
Generation counter
population
An array containing all the genomes of the current generation
There are a few built-in functions. For the client, only getFittest()
and evolve()
is important. In the future, there will be a combination of backpropagation and evolution. Stay tuned
createPool()
Initialises the first set of genomes. Should not be called manually.
async evolve()
Loops the generation through a evaluation, selection, crossover and mutation process.
async evaluate()
Evaluates the entire population by passing on the genome to the fitness function and taking the score.
sort()
Sorts the entire population by score. Should be called after evaluate()
getFittest()
Returns the fittest genome (highest score) of the current generation
mutate()
Mutates genomes in the population, each genome has mutationRate
chance of being mutated.
getOffspring()
This function selects two genomes from the population with getParent()
, and returns the offspring from those parents.
getAverage()
Returns the average fitness of the current population
getParent()
Returns a parent selected using one of the selection methods provided. Should be called after evaluation. Should not be called manually.
export()
Exports the current population of the set up algorithm to a list containing json objects of the networks. Can be used later with import(json)
to reload the population
import(json)
Imports population from a json. Must be an array of networks that have converted to json (with myNetwork.toJSON()
)