Quick Start Guide
Welcome to the Quick Start Guide for NEAT-JavaScript! This guide will help you get up and running quickly with basic installation and configuration.
Installation
Node.js Installation
To install via npm, run the following command:
npm install neat-javascript
Browser Usage
To use NEAT-JavaScript in the browser, add the following script tag to your HTML file:
<script src="path/to/neat-javascript.js"></script>
Important Note
In browser environments, all components are available under the NEATJavaScript
namespace by default. You can make all components available globally by adding:
// Make all NEAT-JavaScript components available in the global namespace
Object.assign(window, NEATJavaScript);
This allows you to use all components without the NEATJavaScript.
prefix.
Configuration
Begin by creating a configuration instance and customizing any parameters as needed. The new configuration system uses a more flexible object-based approach. For more details, refer to the Configuration section.
// Create a new instance of Config
const 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', // Options: 'Sigmoid', 'NEATSigmoid', 'Tanh', 'ReLU', 'LeakyReLU', 'Gaussian'
// Fitness function
fitnessFunction: 'XOR', // Default XOR fitness function
// Weight initialization
weightInitialization: {
type: 'Random',
params: [-1, 1] // Min and max values for random weights
},
// Network topology 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
perturbRange: 0.5, // Range for weight perturbation
minWeight: -4.0, // Minimum allowed weight
maxWeight: 4.0, // Maximum allowed weight
// Evolution parameters
populationSize: 150, // Size of the population
generations: 100, // Number of generations
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, // Chance to keep disabled genes in 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 in the configuration, its default value will be used automatically. This means 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 is responsible for managing 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 configuration
let population = new Population(config);
Note
The initial population consists of minimal networks with random weights. These simple networks will 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 population
const genome = population.genomes[0];
// Access all genomes
population.genomes.forEach(genome => {
// Do something with each genome
});
To activate a neural network, you can propagate inputs through a genome to get its outputs. This is essential for both fitness evaluation and using the network to produce results:
// Create an array of inputs matching your inputSize
let inputs = [0, 1];
// Get outputs by propagating inputs through the network
let outputs = genome.propagate(inputs);
The propagate
method passes the input values through the neural network and returns an array of output values. The length of the input array should match the inputSize
in your configuration, and the length of the output array will match the outputSize
.
Running the Evolution
To evolve your population, you need to 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 generation
population.evolve()
For example:
// Create a new population
let population = new Population(config);
// For each generation
for (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 like this:
config.fitnessFunction = new XOR();
To run the algorithm with your fitness function, use the following:
let algorithm = new Algorithm(config);
algorithm.run(); // Starts the evolution process
This will run the algorithm until the target fitness is reached, displaying the generation number and best fitness in the console.