Quick Start Guide
Get up and running with NEAT-JavaScript in a few minutes, install, configure, and evolve your first population.
Installation
Node.js
To install via npm, run the following command:
npm install neat-javascriptBrowser
To use NEAT-JavaScript in the browser, add the following script tag to your HTML file:
<script src="https://neat-javascript.org/releases/NEAT-JavaScript-1.1.0.js"></script>Browser namespace
In browser environments, all components are available under the NEATJavaScript namespace by default. You can make everything available globally with:
// Make all NEAT-JavaScript components available in the global namespaceObject.assign(window, NEATJavaScript);This lets you use all components without the NEATJavaScript. prefix.
Configuration
Begin by creating a configuration instance and customizing any parameters as needed. The configuration system uses a flexible object-based approach. For details, see the Configuration section.
// Create a new instance of Configconst config = new Config({ // Basic network structure inputSize: 2, // Number of input nodes outputSize: 1, // Number of output nodes
// Activation function (string-based selection) activationFunction: 'Sigmoid', // 'Sigmoid', 'NEATSigmoid', 'Tanh', 'ReLU', 'LeakyReLU', 'Gaussian'
// Bias settings bias: 1.0, // Bias value connectBias: true, // Connect the bias node to all output nodes biasMode: 'WEIGHTED_NODE', // Bias implementation mode
// Fitness function fitnessFunction: 'XOR', // Default XOR fitness function
// Weight initialization weightInitialization: { type: 'Random', params: [-1, 1] // Min and max values for random weights },
// Speciation parameters c1: 1.0, // Coefficient for excess genes c2: 1.0, // Coefficient for disjoint genes c3: 0.4, // Coefficient for weight differences compatibilityThreshold: 3.0, // Species compatibility threshold interspeciesMatingRate: 0.001, // Rate of interspecies mating
// Mutation parameters mutationRate: 1.0, // Overall mutation rate weightMutationRate: 0.8, // Mutation rate for weights addConnectionMutationRate: 0.05, // Rate for adding new connections addNodeMutationRate: 0.03, // Rate for adding new nodes minWeight: -4.0, // Minimum allowed weight maxWeight: 4.0, // Maximum allowed weight reinitializeWeightRate: 0.1, // Rate to completely reinitialize weights minPerturb: -0.5, // Minimum perturbation value maxPerturb: 0.5, // Maximum perturbation value
// Evolution parameters populationSize: 150, // Size of the population generations: 100, // Number of generations targetFitness: 0.95, // Target fitness to achieve survivalRate: 0.2, // Proportion that survives each generation numOfElite: 10, // Number of elite individuals to retain dropOffAge: 15, // Maximum age before dropping off populationStagnationLimit: 20, // Generations with no improvement before reset keepDisabledOnCrossOverRate: 0.75, // Keep disabled connections during crossover mutateOnlyProb: 0.25, // Probability for mutation-only
// Recurrent network options allowRecurrentConnections: true, // Allow recurrent connections recurrentConnectionRate: 1.0 // Rate for recurrent connections});Note
When you leave out any specific parameter, its default value is used automatically — you only need to specify the parameters you want to customize.
Creating a Population
The first step in using NEAT-JavaScript is to create a population of genomes. The Population class manages all aspects of the evolutionary process, including:
- Maintaining a collection of genomes
- Organizing genomes into species
- Handling selection, reproduction, and mutation
Create a population instance by passing your configuration:
// Create a new population with your configurationlet population = new Population(config);Note
The initial population consists of minimal networks with random weights. These simple networks evolve into more complex structures through the NEAT process.
Accessing and Propagating Genomes
After creating a population, you can access individual genomes through the population.genomes array:
// Access the first genome in the populationconst genome = population.genomes[0];
// Access all genomespopulation.genomes.forEach(genome => { // Do something with each genome});To activate a neural network, propagate inputs through a genome to get its outputs. This is essential for both fitness evaluation and for using the network to produce results:
// Create an array of inputs matching your inputSizelet inputs = [0, 1];
// Get outputs by propagating inputs through the networklet outputs = genome.propagate(inputs);The propagate method passes the input values through the network and returns an array of output values. The input array length should match the inputSize in your configuration, and the output array length will match the outputSize.
Running the Evolution
To evolve your population, evaluate the fitness of each genome and then evolve to the next generation. There are two main approaches for fitness evaluation.
Option 1: Manual Fitness Assignment (Recommended)
The most direct approach is to manually assign fitness values to each genome and then call the evolve method:
population.genomes.forEach(genome => { // Manually evaluate each genome genome.fitness = /* your fitness calculation logic */;});
// Evolve to the next generationpopulation.evolve()For example:
// Create a new populationlet population = new Population(config);
// For each generationfor (let i = 0; i < config.generations; i++) { // Manually evaluate each genome population.genomes.forEach(genome => { // Your own evaluation logic here // Use genome.propagate() to test inputs and calculate fitness genome.fitness = /* your fitness calculation */; });
// Track progress const bestGenome = population.getBestGenome(); console.log(`Generation ${i}: Best fitness = ${bestGenome.fitness}`);
// Evolve to the next generation population.evolve();}Option 2: Using a Fitness Function
Alternatively, you can create a reusable fitness function class:
class XOR { calculateFitness(genome) { const inputs = [ [0, 0], [0, 1], [1, 0], [1, 1] ]; const expectedOutputs = [0, 1, 1, 0]; let error = 0;
for (let i = 0; i < inputs.length; i++) { const input = inputs[i]; const output = genome.propagate(input); error += Math.pow(output[0] - expectedOutputs[i], 2); }
return 1.0 / (1.0 + error); }}After creating your fitness function, assign it to the configuration instance:
config.fitnessFunction = new XOR();To run the algorithm with your fitness function, use:
let algorithm = new Algorithm(config);algorithm.run(); // Starts the evolution processThis runs the algorithm until the target fitness is reached, displaying the generation number and best fitness in the console.