🦔 i05 echidna: back to PPO, one ingredient at a time¶
🏁 concluded 2026-09-25, v2.17.0 · negative on the gate environment · its toy test bed (toy_envs.py) is still in use
Question. Which of dragonfly's ingredients helps on its own? Each is tested on small, cheap environments first, and only a winner goes onto the gate environment.
Answer. Each ingredient helps on one kind of task and hurts on another. Self-imitation won clearly on the gate-like toy but held training back on the gate environment itself. None beats plain PPO there.
Design (agents/ppo_plus.py, toy_envs.py, toybench.py)¶
PPO plus three switches, for any environment with the toy interface:
- OU exploration noise (
ou_rho): \(a_t = \mu(s_t) + \sigma \epsilon_t\), \(\epsilon_t = \rho\,\epsilon_{t-1} + \sqrt{1-\rho^2}\,\eta_t\), restarted every episode. The policy is conditioned on the previous noise, \(\pi(a \mid s, \epsilon_{t-1}) = \mathcal N(\mu + \sigma\rho\,\epsilon_{t-1},\ \sigma^2(1-\rho^2))\), with \(\epsilon_{t-1}\) stored in the rollout, so the PPO ratio stays an exact likelihood ratio. (Tested: the conditionals multiply to the exact joint density of the correlated noise.) - Pessimistic veto (
veto): a 4-head Q ensemble regresses the λ-return; of 8 candidates from π the first is taken unless its lower bound (mean − std) is more than half a return-spread below the best's. - Golden-cache self-imitation (
sil_coef): a canonical archive of the best transitions by return and by reward; the policy imitates cached actions whose return beats the critic's value (Oh et al. 2018).
The toys: Pendulum (dense reward, a sanity check), MountainCar (sparse reward behind a hill, the classic exploration trap) and Tracker (a miniature gate problem: delta actions on an amplitude bounded to ±1, overshooting ends the episode with a penalty, \(-\log_{10}\) tracking-error reward).
Toy grid (5 seeds each)¶
| Variant | MountainCar | Tracker: final · AUC | Pendulum |
|---|---|---|---|
| PPO | 75 ± 38 (4/5 solved) | 338 ± 76 · 304 ± 10 | −165 ± 40 |
| OU noise | 94 ± 0.1 (5/5) | 252 ± 42 · 225 ± 9 | −167 ± 39 |
| veto | 94 ± 0.3 (5/5) | 365 ± 38 · 301 ± 19 | −164 ± 41 |
| self-imitation | 37 ± 46 (2/5) | 480 ± 15 · 389 ± 3 | −243 ± 63 |
| all three | 94 ± 0.2 (5/5) | 361 ± 44 · 238 ± 49 | −181 ± 44 |
AUC is the mean evaluation return over training. The veto costs about 2× wall time and is neutral.
Caveat found later
These Tracker runs used a reward that turns negative once the tracking error exceeds 1 %, which can make ending an episode early optimal (found in fox). Self-imitation may have looked good partly by steering away from that trap. The conclusion below rests on the gate-env runs, not on this.
Self-imitation on the gate environment (20M steps, the baseline's settings)¶
| Seed | Plain PPO (same code): best · median last 30 · to \(J_T<0.1\) | Self-imitation: best · median · to \(J_T<0.1\) |
|---|---|---|
| 1 | 7.5e-4 · 1.8e-3 · 0.13M steps | 1.3e-2 · 3.5e-2 · 3.6M |
| 2 | 2.8e-4 · 5.7e-4 · 1.05M | 0.14 · 0.17 · never |
| 3 | 5.5e-4 · 1.7e-3 · 1.1M | 7.2e-4 · 2.3e-3 · 3.0M |
The plain control matches the existing baseline seeds, so the new code path is sound.
Outcome¶
- Self-imitation locks in early. While the critic still undervalues everything, every cached entry counts as "better than expected", so the policy imitates the early best transitions of a still-bad policy. The start is 3× slower and one seed never recovers. By the end, no cached entry beats the critic any more and self-imitation has switched itself off. It is the same lock-in as on MountainCar.
- Exploration ingredients do not transfer to an environment that is not exploration-limited; correlated noise hurts precise tracking.
Records: results/i05_echidna/ (toy-grid summary and curves, gate-run numbers).
Rerun: python -m rlquantopt.jx.toybench --env tracker --variant sil;
python -m rlquantopt.jx.train --idea echidna --algo ppo_plus --activation relu --sil-coef 0.1 --seed 1.