Evolutionary Algorithms
Evolutionary algorithms evolve a population of candidate solutions through selection, crossover, and mutation. Covers main types, code, and real uses.
Evolutionary algorithms (EAs) are a family of optimization algorithms that imitate natural selection. They keep a population of candidate solutions, score each one with a fitness function, let the best candidates produce offspring through recombination and random mutation, and repeat for many generations so that the population drifts toward better solutions. An EA only needs to evaluate a candidate, never to compute a gradient, so it works on problems that gradient descent cannot handle: discrete choices, non-differentiable or noisy objectives, and rugged landscapes full of local optima. That makes EAs a standard tool for hyperparameter tuning, neural architecture search, engineering design, and scheduling.
How Evolutionary Algorithms Work#
Every EA is built from the same parts:
- Representation: Each candidate is encoded as a genome, such as a string of bits, a vector of real numbers, or a program tree.
- Initialization: The first generation is usually random, sometimes seeded with known good solutions.
- Fitness evaluation: A fitness function scores each candidate on the objective being optimized.
- Selection: Fitter candidates are more likely to become parents. Tournament selection, for example, picks the better of a few random candidates, and elitism copies the very best unchanged into the next generation.
- Variation: Crossover combines parts of two parents, and mutation makes small random changes so the population keeps exploring.
In machine learning (ML), the fitness function is often a validation metric such as accuracy or mean average precision (mAP), so evaluating a candidate means training and testing a model, by far the most expensive step. The loop repeats until the budget runs out or the fitness stops improving:
Selection pressure and mutation strength set the balance between exploitation and exploration. Strong selection with small mutations converges quickly but can get stuck on a local optimum, while weak selection with large mutations explores widely but wastes evaluations.
Main Types of Evolutionary Algorithms#
- Genetic algorithms (GAs): Encode candidates as strings, often bits, and rely heavily on crossover. John Holland formalized them in his 1975 book Adaptation in Natural and Artificial Systems.
- Evolution strategies (ES): Optimize vectors of real numbers with Gaussian mutations whose step sizes adapt during the run. CMA-ES, which learns the full covariance of its mutation distribution, is one of the strongest general-purpose methods for continuous black-box problems.
- Genetic programming: Evolves programs or mathematical expressions represented as trees, used for symbolic regression and automatic program design.
- Neuroevolution: Evolves the weights, and sometimes the structure, of neural networks. OpenAI showed in 2017 that evolution strategies running on more than a thousand parallel workers could train a 3D humanoid to walk in 10 minutes, a scalable alternative to reinforcement learning.
A Genetic Algorithm in Code#
The knapsack problem asks which items to pack to maximize total value without exceeding a weight limit, a discrete problem with no gradient. This NumPy genetic algorithm evolves 50 bit-string genomes, one bit per item, using tournament selection, uniform crossover, bit-flip mutation, and elitism, then checks the answer against all 1,048,576 possible selections:
import itertools
import numpy as np
rng = np.random.default_rng(0)
# Knapsack problem: pick from 20 items to maximize total value within a weight limit of 200
values, weights, limit = rng.integers(10, 100, 20), rng.integers(5, 50, 20), 200
def fitness(pop):
"""Return each selection's total value, or 0 if it exceeds the weight limit."""
return np.where(pop @ weights <= limit, pop @ values, 0)
population = rng.random((50, 20)) < 0.2 # 50 random genomes, one bit per item
for generation in range(100):
scores = fitness(population)
# Tournament selection: each parent is the better of two random genomes
pairs = rng.integers(50, size=(50, 2))
parents = population[np.where(scores[pairs[:, 0]] > scores[pairs[:, 1]], pairs[:, 0], pairs[:, 1])]
# Uniform crossover with the next parent, then flip each bit with probability 0.05
children = np.where(rng.random((50, 20)) < 0.5, parents, np.roll(parents, 1, axis=0))
children ^= rng.random((50, 20)) < 0.05
children[0] = population[scores.argmax()] # elitism: keep the best genome
population = children
all_selections = np.array(list(itertools.product([0, 1], repeat=20)))
print(f"GA best: {fitness(population).max()}, true optimum: {fitness(all_selections).max()}")It prints GA best: 811, true optimum: 811. The algorithm found the best possible packing after 5,000 fitness evaluations, about 0.5% of the million selections that brute force had to check.
Evolving Hyperparameters#
Training settings such as learning rate, loss weights, and augmentation strengths interact in ways no formula predicts, and each candidate costs a full training run, which suits evolutionary search. The tune() method in Ultralytics YOLO uses this approach for YOLO26 models: each iteration picks a parent from the nine best configurations so far, weighted by fitness, mutates about half of the 26 hyperparameters in its default search space with Gaussian steps scaled to their search ranges, trains a model, and records its fitness, which is mAP50-95 for object detection. After 30 results, some mutations also follow the covariance of the best 20% of configurations, a borrowing from CMA-ES. The hyperparameter tuning guide lists the full search space:
from ultralytics import YOLO
# Load a pretrained YOLO26 nano model
model = YOLO("yolo26n.pt")
# Evolve hyperparameters: 30 iterations, each training one mutated configuration for 10 epochs
model.tune(data="coco8.yaml", epochs=10, iterations=30, plots=False)The tuner writes every configuration and its fitness to tune_results.ndjson and saves the winner to best_hyperparameters.yaml, ready to pass to a full training run.
Other Applications#
- Neural architecture search: Google's AmoebaNet came from regularized evolution, a tournament-selection EA that retires the oldest models instead of the worst, and reached 83.9% top-1 accuracy on ImageNet in 2018.
- Engineering design: NASA's Space Technology 5 mission flew a computer-evolved X-band antenna in 2006 whose irregular bent-wire shape matched the performance of a conventionally designed antenna.
- Algorithm discovery: AlphaEvolve, announced by Google DeepMind in May 2025, pairs Gemini models that propose code changes with automated evaluators and an evolutionary database of programs. One scheduling heuristic it evolved for Google's data centers recovers on average 0.7% of the company's worldwide compute resources.
Evolutionary Algorithms vs. Related Methods#
- Gradient descent: Follows the gradient of a differentiable loss and is far more efficient for training network weights with millions of parameters. EAs suit problems with few parameters, expensive evaluations, or no gradient.
- Swarm intelligence: Methods such as particle swarm optimization move a persistent set of agents through the search space, each adjusting its position from its own best result and its neighbors', with no generational replacement, crossover, or mutation.
- Bayesian optimization: Fits a probabilistic model of the objective and picks each next trial where that model expects the most improvement, which uses fewer evaluations than an EA on small, smooth search spaces but scales less well to many parameters and parallel workers.










