netcl.evo: Evolutionary Algorithms & NAS
netcl.evo: Evolutionary Algorithms & NAS
The netcl.evo module provides hardware-accelerated evolutionary optimization algorithms and automated Neural Architecture Search (NAS).
The entire population is maintained inside a single contiguous OpenCL device buffer. Selection, crossover, and mutation execute as parallel OpenCL kernels directly on the GPU.
[!TIP] Theory & Curriculum Link: For the first-principles derivation of Natural Evolution Strategies (NES), CMA-ES covariance scaling, and GPU population buffers, see Curriculum: Evolutionary & Black-Box Optimization.
1. Quick Example: Neuroevolution & Architecture Search
from netcl import evo
from netcl.core.device import manager
q = manager.default("auto").queue
# 1. Optimize model weights without backpropagation gradients
result = evo.neuroevolve(
model,
score_fn=lambda m: evaluate_accuracy(m),
algorithm="nes",
pop_size=32,
generations=20,
)
# 2. Automated Neural Architecture Search (NAS)
space = evo.ArchSpace(in_channels=3, input_hw=(32, 32), num_classes=10)
pop = evo.ArchPopulation.random(space, q, size=16, seed=0)
search = evo.ArchitectureSearch(pop, evo.ArchFitness(space, score_fn, q))
best_model = search.run(generations=10).build(q)
2. High-Level Functions
evo.neuroevolve
Optimizes model parameters directly using an arbitrary scoring function score_fn(model) -> float:
evo.neuroevolve(
model,
score_fn: Callable[[Module], float],
algorithm: str = "nes", # "nes", "ga", "es", "de", "cmaes"
pop_size: int = 64,
generations: int = 50,
sigma: float = 0.02, # Perturbation magnitude
seed: int = 0,
maximize: bool = True,
verbose: bool = False,
load_best: bool = True, # Writes best candidate weights directly into model
) -> EvolutionResult
Initializes from current model weights, making it ideal for gradient-free fine-tuning or reinforcement learning tasks.
evo.evolve
General-purpose vector optimization over continuous genes:
result = evo.evolve(
fitness_fn,
n_genes=64,
algorithm="cmaes",
generations=100,
maximize=False,
)
print(f"Optimal Fitness: {result.best_fitness:.4f}")
print(f"Optimal Genome: {result.best_genome}")
3. Strategy Selection Guide
| Strategy | Alias | Optimal Application |
|---|---|---|
OpenAIES |
"nes", "openai" |
Deep Neural Networks: Perturbations generated from seeds directly in GPU kernels with $O(1)$ memory. |
GeneticAlgorithm |
"ga" |
Architecture Search (NAS): Mixed discrete/continuous graph mutations. |
SepCMAES |
"cmaes", "sepcmaes" |
Continuous Landscapes: Adaptive coordinate-wise step sizes with linear $O(D)$ memory. |
DifferentialEvolution |
"de" |
Rugged Non-Convex Surfaces: High robustness against deceptive local minima. |
EvolutionStrategy |
"es" |
Classical $(\mu / \mu_w, \lambda)$-ES with self-adaptive step sizes. |
Instantiate via the factory helper:
strategy = evo.make_strategy("nes", n_genes=1000, pop_size=64, sigma=0.03, lr=0.01)
4. Neural Architecture Search (NAS)
Defining the Search Space (ArchSpace)
space = evo.ArchSpace(
in_channels=3,
input_hw=(32, 32),
num_classes=10,
max_layers=8,
layer_types=("conv", "pool", "dropout"),
channels=(16, 32, 64, 128),
kernels=(3, 5),
activations=("ReLU", "LeakyReLU"),
)
Every genome is represented as a codon matrix. The decoder is total: every combination of codons is automatically sanitized into a valid, executable architecture graph.
Executing Search (ArchitectureSearch)
search = evo.ArchitectureSearch(
arch_population,
fitness,
generations=15,
elitism=2,
mutation_rate=0.08,
)
result = search.run()
best_model = result.build(q)
result.save("best_arch.json")
Via evo.inherit_weights(parent, child), candidate models inherit overlapping trained weights from their parents, significantly accelerating evaluation convergence.
5. Fitness Wrappers (netcl.evo.fitness)
| Wrapper / Function | Description |
|---|---|
ModelFitness(model, score_fn) |
Automatically loads genomes into model weights and invokes score_fn(model) |
ArchFitness(space, score_fn, q) |
Builds candidate architectures from genomes and evaluates fitness |
CachedFitness(fitness, ...) |
Skips evaluating unmutated genomes to avoid duplicate computation |
accuracy_score(model, batches) |
Helper computing classification accuracy over mini-batches |
negative_loss(model, batches, fn) |
Inverts loss values so minimization tasks align with maximization strategies |
Related Documentation
- Concepts: Neuroevolution: Details on GPU population buffers and Philox PRNG kernels.
- Curriculum: Evolutionary Optimization: First-principles mathematical derivations of NES and CMA-ES.