Creating Custom Genomes
This documentation explains how to create custom genomes in NEAT (NeuroEvolution of Augmenting Topologies). A genome in NEAT represents the genetic encoding of a neural network, containing nodes (neurons) and connections between them, along with their associated weights and properties.
There are two primary methods for creating genomes in NEAT. You can either use the GenomeBuilder utility class to generate genomes based on configuration parameters, or you can manually construct genomes by creating and connecting individual nodes.
Understanding Population ID
The populationID
parameter is a feature specific to this NEAT implementation that ensures proper tracking of nodes and innovations within a population of genomes. While not part of the original NEAT algorithm, in our implementation it's important for the following reasons:
- Node ID Tracking: Each node must have a unique identifier. The
populationID
helps our NodeTracker maintain separate node ID counters for different populations. - Innovation Tracking: Innovation numbers are historical markings that identify when and where structural changes (like new connections) first occurred in a population's evolutionary history.
- Consistent Crossover: When genomes mate, they need to identify which genes correspond to one another across different genomes. This requires a shared innovation numbering system.
- Separation for Multiple Experiments: Using different population IDs allows you to run multiple separate NEAT experiments in the same application without their innovation and node systems interfering with each other.
Important
All genomes within the same population must share the same populationID
. This ensures that when structural mutations occur, innovation numbers are assigned consistently across the entire population.
Method 1: Using GenomeBuilder
The GenomeBuilder class provides a convenient way to create genomes with a standard topology determined by your configuration settings. This approach is recommended for initializing populations with consistent starting topologies.
buildGenome
Creates a new genome with input and output nodes connected according to the configuration parameters.
Parameter | Type | Description |
---|---|---|
config | Config | Configuration object containing parameters for genome creation |
populationID | String/Number | ID of the population this genome belongs to |
Returns | Type | Description |
---|---|---|
genome | Genome | A new genome with the specified topology |
Note
When using GenomeBuilder, the InnovationTracker (obtained through StaticManager) automatically handles the tracking of innovation numbers and node IDs for you using the provided populationID
. This ensures that when mutations occur later, the historical markings are properly maintained within that population.
The system maintains separate innovation trackers for each unique population ID, which is why it's essential to use the same populationID
for all genomes that will be evolved together.
Method 2: Manual Genome Creation
For more control over the genome structure, you can manually create nodes and connections. This approach is useful when you want to design specific neural network architectures.
To manually create a genome, you need to follow these steps in the correct order:
- Create input nodes first
- Create output nodes second (the order is important for proper ID assignment)
- Create bias nodes and hidden nodes
- Create connections between nodes
- Construct a genome from these components
Note on Node Order
It is essential to initialize nodes in the correct order: inputs first, then outputs, followed by bias and hidden nodes. This sequence is required due to how node IDs are managed internally.
Important
When manually creating genomes, it's crucial to properly track innovation numbers using the InnovationTracker (obtained via StaticManager) with the correct populationID
. This ensures that when multiple genomes are evolved together in a population, their historical markings are consistent, which is essential for crossover operations and speciation.
If you create multiple custom genomes for the same population, always use the same populationID
when calling StaticManager.getNodeTracker(populationID)
and StaticManager.getInnovationTracker(populationID)
. This allows the system to properly track which innovations and node IDs have already been created within that population.
Creating Recurrent Connections
If you want to create recurrent connections (connections that point backwards in the network), set the "recurrent" parameter to true when creating the ConnectionGene:
Comparison of Methods
GenomeBuilder | Manual Creation |
---|---|
Simple and quick to use | More complex but offers greater control |
Good for initializing populations | Good for specific network architectures |
Creates fully-connected input-to-output networks | Can create any connection pattern |
Handles innovation tracking automatically | Requires manual innovation tracking |
Limited to config-based topologies | Can implement custom topologies |