Differentiable ES-HyperNEAT: experiments
Code behind the post Differentiable ES-HyperNEAT.
Pure Python and NumPy, no GPU, no autodiff library: the CPPN’s backward pass
is written out by hand in eshn.py.
| File | What it is |
|---|---|
eshn.py |
CPPN (forward and input-gradient), the 2^n-tree substrate search with both split tests, network assembly, the evolution strategy |
tasks.py |
The 3D pursuit task and the four substrate layouts |
run_pursuit.py |
Train one arm for one seed |
scaling.py |
Search cost against substrate dimension, and how often the two split tests disagree |
run_all.py |
The whole protocol, resumable, any OS |
summarise.py |
Turns results/ into assets/es-hyperneat/results.json for the post |
export_swimmers.py |
Exports a few evolved CPPNs (checked against their recorded scores) for the swimming-cell figures |
The sampling and gradient arms differ only in complexity() in eshn.py.
Protocol
Fixed before any sampling-vs-gradient comparison was looked at:
- pursuit: 120 generations of 32 genomes (16 antithetic pairs), held-out score on 16 fixed chases every 5 generations
- 3D and 2D (map projection) substrates, sampling and gradient tests: seeds 0-7
- 2D “drop z” and 2D ring substrates, sampling only: seeds 0-3
- scaling: 10 random CPPNs for each substrate dimension n = 2..7, tree depth 2 (plus depth 3-4 for n = 2, 3)
Running it on Windows
Needs Python 3.10 or newer and git. In PowerShell:
git fetch origin
git checkout es-hyperneat-experiments
cd experiments\es-hyperneat
py -m venv .venv
.\.venv\Scripts\Activate.ps1 # if blocked: Set-ExecutionPolicy -Scope Process Bypass
python -m pip install -r requirements.txt
python run_all.py --smoke # ~1 minute: checks everything runs, writes to results_smoke\
python run_all.py # the real thing
run_all.py uses every core but one and prints a line as each run finishes.
Keep the laptop on mains power and stop it sleeping while it runs
(powercfg /change standby-timeout-ac 0). If anything interrupts it, run the
same command again: finished runs are kept and skipped.
When it finishes it writes assets\es-hyperneat\results.json. Commit the
results and push:
cd ..\..
git add experiments/es-hyperneat/results assets/es-hyperneat/results.json
git commit -m "ES-HyperNEAT experiment results"
git push -u origin es-hyperneat-experiments
Simplifications relative to ES-HyperNEAT as published
All of these apply identically to every arm:
- The CPPN has a fixed shape (two hidden layers of sin, Gaussian and tanh units, plus a linear skip path) and is trained with an OpenAI-style evolution strategy, not evolved with NEAT.
- One tree per network, with complexity averaged over every input and output neuron, rather than one tree per input neuron.
- One hidden layer; band pruning is replaced by keeping leaves whose own complexity exceeds a lower threshold.
- Two changes were needed before anything learned at all (see the post): 1/sqrt(fan-in) scaling in the substrate network, and shifting the CPPN’s output bias so its average weight starts at zero.