Table of Contents

Class NEAT<T>

Namespace
AiDotNet.NeuralNetworks
Assembly
AiDotNet.dll

Represents a NeuroEvolution of Augmenting Topologies (NEAT) algorithm implementation, which evolves neural networks through genetic algorithms.

public class NEAT<T> : NeuralNetworkBase<T>, INeuralNetworkModel<T>, INeuralNetwork<T>, IFullModel<T, Tensor<T>, Tensor<T>>, IModel<Tensor<T>, Tensor<T>, ModelMetadata<T>>, IModelSerializer, ICheckpointableModel, IParameterizable<T, Tensor<T>, Tensor<T>>, IFeatureAware, IFeatureImportance<T>, ICloneable<IFullModel<T, Tensor<T>, Tensor<T>>>, IGradientComputable<T, Tensor<T>, Tensor<T>>, IJitCompilable<T>, IInterpretableModel<T>, IInputGradientComputable<T>, IDisposable

Type Parameters

T

The numeric type used for calculations, typically float or double.

Inheritance
NEAT<T>
Implements
IFullModel<T, Tensor<T>, Tensor<T>>
IModel<Tensor<T>, Tensor<T>, ModelMetadata<T>>
IParameterizable<T, Tensor<T>, Tensor<T>>
ICloneable<IFullModel<T, Tensor<T>, Tensor<T>>>
IGradientComputable<T, Tensor<T>, Tensor<T>>
Inherited Members
Extension Methods

Remarks

NEAT is an evolutionary algorithm that creates and evolves neural network topologies along with connection weights. Unlike traditional neural networks with fixed structures, NEAT starts with simple networks and gradually adds complexity through evolution. It uses genetic operators like mutation and crossover, along with speciation to protect innovation, to evolve networks that solve specific problems without requiring manual design of the network architecture.

For Beginners: NEAT is a way to grow neural networks through evolution rather than training them with fixed structures.

Think of NEAT like breeding plants to get better features:

  • Instead of designing a neural network by hand, you start with simple networks
  • These networks "reproduce" and "mutate" over generations
  • Networks that perform better on your task are more likely to pass on their "genes"
  • Over time, the networks evolve complex structures that solve your problem well

The key differences from traditional neural networks:

  • The structure (connections between neurons) evolves along with the weights
  • Networks can grow more complex over time by adding new neurons and connections
  • You work with a population of many networks, not just one
  • Instead of training with gradient descent, you use evolution to improve performance

NEAT is particularly good for:

  • Problems where you don't know the ideal network structure
  • Reinforcement learning tasks (like game playing)
  • Finding novel solutions that a human designer might not think of

Constructors

NEAT(NeuralNetworkArchitecture<T>, int, double, double, ILossFunction<T>?)

Initializes a new instance of the NEAT<T> class with the specified architecture and evolution parameters.

public NEAT(NeuralNetworkArchitecture<T> architecture, int populationSize, double mutationRate = 0.1, double crossoverRate = 0.75, ILossFunction<T>? lossFunction = null)

Parameters

architecture NeuralNetworkArchitecture<T>

The neural network architecture defining input and output sizes.

populationSize int

The number of individual genomes in the population.

mutationRate double

The probability of mutation occurring during reproduction. Default is 0.1.

crossoverRate double

The probability of crossover occurring during reproduction. Default is 0.75.

lossFunction ILossFunction<T>

Remarks

This constructor initializes a NEAT algorithm with the specified parameters. Unlike traditional neural networks, NEAT doesn't use a fixed architecture with predefined layers. Instead, it uses the architecture primarily to determine input and output sizes. The constructor initializes a population of minimal network structures (genomes) that will evolve over time through the evolutionary process.

For Beginners: This creates a new NEAT system with your chosen settings.

When creating a NEAT system, you specify:

  1. Architecture: Mainly used to define how many inputs and outputs your networks need

    • For example, if solving a game, inputs might be game state variables
    • Outputs might be action choices the AI can make
  2. Population Size: How many different neural networks to evolve at once

    • Larger populations explore more possibilities but need more computing power
  3. Mutation Rate: How often random changes occur (default 0.1 or 10%)

    • Controls the amount of exploration vs. stability
  4. Crossover Rate: How often networks combine vs. just being copied (default 0.75 or 75%)

    • Controls how much genetic material is mixed between solutions

After creation, NEAT initializes a starting population of very simple networks that will grow more complex through evolution.

Properties

ParameterCount

Gets the total number of trainable parameters (connections) in the best genome.

public override int ParameterCount { get; }

Property Value

int

Remarks

In NEAT, parameters are the connection weights in a genome. This property returns the number of connections in the best-performing genome in the population.

Methods

CreateNewInstance()

Creates a new instance of the NEAT model with the same architecture and evolutionary parameters.

protected override IFullModel<T, Tensor<T>, Tensor<T>> CreateNewInstance()

Returns

IFullModel<T, Tensor<T>, Tensor<T>>

A new instance of the NEAT model.

Remarks

This method creates a new NEAT model with the same architecture, population size, mutation rate, and crossover rate as the current instance. The new instance starts with a fresh population, making it useful for restarting evolution with the same parameters or for creating parallel evolutionary runs.

For Beginners: This creates a brand new NEAT system with the same settings.

This is useful when you want to:

  • Start over with a fresh population but keep the same settings
  • Run multiple separate evolutions with identical parameters
  • Create a "clean slate" version of a successful setup

The new NEAT system will have:

  • The same number of inputs and outputs
  • The same population size and mutation/crossover rates
  • A brand new initial population (not copying any evolved networks)

This effectively creates a "twin" of your NEAT system, but at the starting point rather than with any of the evolved progress.

DeserializeNetworkSpecificData(BinaryReader)

Deserializes NEAT-specific data from a binary reader.

protected override void DeserializeNetworkSpecificData(BinaryReader reader)

Parameters

reader BinaryReader

The binary reader to read from.

Remarks

This method loads the state of a previously saved NEAT model from a binary stream. It restores the evolutionary parameters, innovation number, and all genomes in the population, allowing evolution to continue from exactly where it left off.

For Beginners: This loads a complete NEAT system from a saved file.

When loading the NEAT model:

  • Population size, mutation rate, and crossover rate are restored
  • The innovation number is restored
  • Every genome in the population is recreated with all its connections

This lets you:

  • Continue evolution from where you left off
  • Use previously evolved populations
  • Compare or combine results from different runs

EvolvePopulation(Func<Genome<T>, T>, int)

Evolves the population over a specified number of generations using the provided fitness function.

public void EvolvePopulation(Func<Genome<T>, T> fitnessFunction, int generations)

Parameters

fitnessFunction Func<Genome<T>, T>

A function that evaluates the fitness of each genome.

generations int

The number of generations to evolve.

Remarks

This method drives the evolutionary process over multiple generations. For each generation, it evaluates the fitness of each genome using the provided fitness function, sorts the population by fitness, and creates a new population through selection, crossover, and mutation. Through this process, the networks evolve to better solve the specified problem.

For Beginners: This method runs the evolutionary process for a specified number of generations.

The evolution process works like this:

  1. Evaluate each network:

    • The provided fitness function tests how well each network performs
    • Higher fitness scores mean better performance
  2. Sort networks by fitness:

    • The best-performing networks are prioritized for reproduction
  3. Create a new population:

    • Keep the very best network unchanged (called "elitism")
    • Create new networks through either: a) Crossover: Combining two parent networks b) Mutation: Copying and modifying a single parent
  4. Repeat for the specified number of generations

Each generation should produce slightly better networks as successful traits are selected for and new beneficial mutations occur.

The fitness function you provide is crucial - it's what defines "good performance" and guides the entire evolutionary process.

GetModelMetadata()

Gets metadata about the NEAT model.

public override ModelMetadata<T> GetModelMetadata()

Returns

ModelMetadata<T>

A ModelMetaData object containing information about the NEAT model.

Remarks

This method returns comprehensive metadata about the NEAT model, including its architecture, evolutionary parameters, and population statistics. This information is useful for model management, tracking experiments, and reporting results.

For Beginners: This provides detailed information about your NEAT system.

The metadata includes:

  • What this model is and what it does
  • Population size and evolutionary parameters
  • Statistics about the current population
  • Information about the best-performing network

This information is useful for:

  • Tracking your experiments
  • Comparing different NEAT runs
  • Documenting your work
  • Understanding the evolved solution

InitializeLayers()

Initializes the layers of the neural network.

protected override void InitializeLayers()

Remarks

This method is intentionally left empty because NEAT does not use fixed layers like traditional neural networks. Instead, NEAT evolves the network structure dynamically through the evolutionary process, adding nodes and connections as needed.

For Beginners: This method is intentionally empty because NEAT works differently from traditional neural networks.

In traditional neural networks:

  • You define specific layers (input, hidden, output)
  • Each layer has a fixed number of neurons
  • The connections between layers are predetermined

In NEAT:

  • Networks don't have fixed layers
  • The structure evolves dynamically
  • Neurons and connections are added gradually through evolution

This fundamental difference is why this method doesn't need to do anything in NEAT. The network structure is defined by the genome, not by predefined layers.

IsReadyToPredict()

Checks if the NEAT model is ready to make predictions.

public bool IsReadyToPredict()

Returns

bool

True if the model is ready; otherwise, false.

Remarks

This method checks if the NEAT model has a population with at least one genome that can be used for making predictions. It's useful for determining if the model has been properly initialized and evolved.

For Beginners: This checks if your NEAT system is ready to use.

It verifies that:

  • The population exists
  • There is at least one genome in the population
  • At least one genome has connections that can process inputs

This is helpful for error checking before trying to use the model for predictions or continuing evolution.

Predict(Tensor<T>)

Predicts output values for input data using the best genome in the population.

public override Tensor<T> Predict(Tensor<T> input)

Parameters

input Tensor<T>

The input tensor to process.

Returns

Tensor<T>

The output tensor after processing.

Remarks

This method uses the highest-fitness genome in the population to make predictions. It activates the genome's neural network with the provided input data and returns the resulting output activations. For batch inputs, it processes each sample independently.

For Beginners: This method uses the best evolved network to make predictions.

When making a prediction:

  • NEAT uses the highest-performing network from the population
  • The input data is fed into this network
  • The network processes the data through its evolved structure
  • The resulting output values are returned

Unlike traditional neural networks with fixed structures, the network used here has evolved its structure through the evolutionary process, potentially developing complex and unique connection patterns that solve the problem effectively.

SerializeNetworkSpecificData(BinaryWriter)

Serializes NEAT-specific data to a binary writer.

protected override void SerializeNetworkSpecificData(BinaryWriter writer)

Parameters

writer BinaryWriter

The binary writer to write to.

Remarks

This method saves the state of the NEAT model to a binary stream. It serializes the evolutionary parameters, innovation number, and all genomes in the population, allowing the complete state to be restored later.

For Beginners: This saves the complete state of your NEAT system to a file.

When saving the NEAT model:

  • Population size, mutation rate, and crossover rate are saved
  • The current innovation number is saved
  • Every genome in the population is saved with all its connections

This allows you to:

  • Save your progress and continue evolution later
  • Share evolved populations with others
  • Keep records of particularly successful runs
  • Deploy evolved networks in applications

Train(Tensor<T>, Tensor<T>)

Trains the NEAT system using supervised learning data.

public override void Train(Tensor<T> input, Tensor<T> expectedOutput)

Parameters

input Tensor<T>

The input training data tensor.

expectedOutput Tensor<T>

The expected output tensor.

Remarks

This method adapts NEAT to work with traditional supervised learning data. It creates a fitness function based on the mean squared error between network predictions and expected outputs, then evolves the population to minimize this error. This allows NEAT to be used in scenarios where traditional supervised learning would be applied.

For Beginners: This teaches the NEAT system using example input-output pairs.

Unlike traditional neural networks that use gradient descent, NEAT learns through evolution:

  1. It creates a fitness function based on prediction error

    • Networks that make more accurate predictions get higher fitness scores
    • Networks with lower error perform better
  2. It evolves the population for several generations

    • Better networks reproduce more often
    • Genetic operators (crossover and mutation) create diversity
    • The population gradually improves at the task

This allows NEAT to work with supervised learning data while using its evolutionary approach to discover effective network structures.

UpdateParameters(Vector<T>)

Updates the connection weights of the best genome using the provided parameter vector.

public override void UpdateParameters(Vector<T> parameters)

Parameters

parameters Vector<T>

A vector containing parameters to update.

Remarks

This method allows direct parameter updates to the best genome's connection weights, enabling integration with external optimization or parameter management systems. Note that this bypasses NEAT's evolutionary mechanisms and should be used carefully.

For Beginners: This method allows direct weight updates when needed.

In traditional NEAT:

  • Parameters evolve through natural selection
  • Better-performing networks reproduce more often
  • Parameters change through crossover and mutation

However, this method allows you to:

  • Directly set connection weights on the best genome
  • Integrate with external optimization algorithms
  • Transfer parameters from other sources

Important: Changes may be lost if the modified genome doesn't survive selection in subsequent evolution cycles. For typical NEAT training, use the EvolvePopulation method instead.

Exceptions

InvalidOperationException

Thrown when the best genome has no connections.

ArgumentException

Thrown when parameter vector length doesn't match connection count.