netcl wiki
api

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.


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