A real-time simulation where autonomous cars learn to navigate complex circuits using an Evolutionary Strategy and a Neural Network implemented from scratch in NumPy.
Unlike traditional machine learning that uses gradient descent, this project uses a Genetic Algorithm to optimize the weights of the neural networks. The learning process mimics biological evolution through successive generations.
Each generation consists of a population (default 30 cars). The population is divided into three distinct groups to maintain a balance between stability and exploration:
- Elites: The top performing cars from the previous generation are cloned exactly. This ensures that the "best solution found so far" is never lost (zero regression).
- Random Scouts: A percentage of the population is initialized with completely random weights. This introduces high variability and prevents the simulation from getting stuck in local optima.
- Offspring: The majority of the population is created through reproduction of the top performers.
The simulation uses Truncation Selection. At the end of each generation, cars are ranked by their progress (distance traveled) or lap time. Only the Top 50% are allowed to pass their "genetic material" to the next generation. The bottom half is discarded, ensuring that only successful behaviors propagate.
To create new generations, the simulation employs two main operators:
- Uniform Crossover: When two parents are selected from the top 50%, their "brains" (weight matrices) are combined. For every single weight, a "coin flip" (50/50 chance) determines whether it is inherited from Parent A or Parent B. This allows the offspring to combine successful traits from different individuals.
- Gaussian Mutation: After inheritance, weights are subjected to mutation. We add random noise to the weights following a Gaussian distribution. The intensity of this change is controlled by the Mutation STD:
- Low STD: Fine-tunes the existing behavior (exploitation).
- High STD: Dramatically changes the behavior, potentially discovering new strategies (exploration).
Each car is powered by a Feedforward Neural Network:
- Input Layer (7): Distance sensors measuring proximity to track boundaries at specific angles.
- Hidden Layer (Dynamic): A fully connected layer with ReLU activation. The number of neurons can be adjusted in the settings.
- Output Layer (2): Tanh activation controlling Steering and Acceleration/Braking.
The entire network logic is implemented in Pure NumPy, allowing for vectorized batch processing where all cars are updated in a single matrix operation, maximizing performance.
The simulation features a real-time settings menu where you can tune the evolutionary parameters:
- Population Size: Total individuals per generation.
- Elite Count: Number of top performers to keep unchanged.
- Random Scouts: Frequency of brand-new random solutions.
- Mutation STD: The magnitude of random changes in offspring.
- Hidden Neurons: Complexity of the car's "brain".
-
Install Dependencies:
pip install -r requirements.txt
-
Run the Simulation:
python src/main.py
V: Toggle sensor visualization.S: Save the best car's weights tomodels/.D: (In circuit editor) Set current circuit as Default.Space: Boost mode (fast-forward physics).Escape: Pause / Settings menu.F11: Tog gle Fullscreen.Q: Quit.
