ctde_v0.run_es¶
run_es
¶
MERL coexistence runner — ES evolves the selector, CTDE-gradient trains the executor.
Wires the injectable ES trainer (es.py) to the real selector + the PPO/CTDE executor.
Each outer round: (a) grad_steps of ppo.train_step train the whole agent (the dense
per-step CTDE signal — incl. the selector); (b) the gradient-current selector is taken as
the ES mean (MERL "inject the learner"); (c) es.es_step refines ONLY the selector head
against TEAM FITNESS (mean episode return via ppo.collect) on the CURRENT executor,
using common random numbers (one fixed eval key per round) for a fair population compare;
(d) the evolved selector is written back. This is the MERL / feudal-evolutionary loop
(Khadka & Tumer 2019): ES + gradient share CTDE's centralized-training signal (team return /
central critic) and touch disjoint-ish params, so they compose rather than fight.
Requires --selector on (ES evolves actor.selector_head). CPU smoke:
JAX_PLATFORMS=cpu PYTHONPATH=.:../../../FiedlerValueEstimation /Users/bijanmehr/Project.Zymera/zymera_lab/.venv/bin/python -m ctde_v0.run_es --grid 10 --n-agents 4 --outer 3 --grad-steps 3 --pop 8 --flock scripted --rollouts 4
merl_train
¶
merl_train(env, cfg, *, key, n_outer, grad_steps, es_cfg, log_fn=None, init_from=None)
Run the MERL coexistence loop on env/cfg (which must have selector on).
init_from (path to a prior model.eqx) warm-starts the (actor, critic) — the
scale-ladder entry point (16²→24²→32²), carrying the ES-evolved selector up.
Returns (final_state, history) where history is a list of per-round records.
Source code in experiments/ctde_v0/run_es.py
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | |