amer224 commited on
Commit
b3e47fd
·
verified ·
1 Parent(s): 9d60233

Add brains/sovereign-v3/train_notes.md

Browse files
Files changed (1) hide show
  1. brains/sovereign-v3/train_notes.md +98 -89
brains/sovereign-v3/train_notes.md CHANGED
@@ -1,29 +1,27 @@
1
- # SOVEREIGN v3 — Training Doctrine (~272M dense)
2
 
3
  Exact recipe for **2× T4 (16 GB)**, shared shard format
4
- `rl/shards_v2/*.npz`. Memory ≈9.4 GB/GPU at bs 16 + fp16 (see
5
- ARCHITECTURE.md §3). Everything is implemented by `model.py` +
6
- `data_adapters.py`.
7
 
8
  ---
9
 
10
- ## Stage A — Return-conditioned filtered BC + dynamics (offline, ~2–3 epochs)
11
 
12
  ### A.1 Sample preparation (`ShardPrepper`)
13
 
14
- 1. **Returns / RTG**: per-episode `R_t = r_t + γR_{t+1}`, γ=0.995;
15
- +2 survive / +5 win terminal bonuses; z-scored per shard. **rtg = R̄** is
16
- the conditioning input; `rtg_next` shifts within the episode (last
17
- frame repeats).
18
  2. **Weights** `w = clip(exp(R̄/τ), 0.2, 8)` τ=1; ×4 survivor episodes;
19
- ×2 ±2-frame kill windows; mean-normalized. (AWR soft filtering.)
20
- 3. **Free-label targets**: `lab64`, `lab64_next` (majority-vote 64×64),
21
- `threat`/`expand` intent mirrors, `gate_mask`/`gate_valid`,
22
- `win_lab` (survived=1), `nums_next`.
23
  4. **Arena filtering**: drop >85%-water episodes.
24
- 5. Frame stacks / sequence windows: opt-in (`stack=`, `build_sequences`).
25
 
26
- ### A.2 Loss (exact)
27
 
28
  ```
29
  L = w · [ λk CE(kind; ls=0.05)
@@ -33,81 +31,89 @@ L = w · [ λk CE(kind; ls=0.05)
33
  + λw CE(win_logits, win_lab; ls=0.05)
34
  + λg BCE(gate, gate_mask)·1[valid]
35
  + λs CE(seg64, lab64)
36
- + λd CE(next_seg, lab64_next) # dynamics
37
- + λt BCE(threat, threat) + λx BCE(expand, expand) # intent mirrors
38
  + λe smoothL1(econ, cat(nums_next, rtg_next))
39
  − λent (H(kind)+H(cell)+H(pct)) ]
40
  λ = (0.5, 1.0, 0.25, 0.1, 0.1, 0.5, 0.5, 0.4, 0.2, 0.2, 0.05, 0.003)
41
  ```
42
 
43
- **Value option (IQL-expectile)**: for the value head only, replace Huber
44
- with the τ=0.9 expectile loss `|τ−1[δ<0]|·δ²` — more robust to the weak
45
- farmer buffer. Both are supported; ablation #6 decides.
46
 
47
- ### A.3 Optimizer & schedule
48
 
49
- - AdamW lr **3e-4 → 3e-5** cosine, **300-step warmup** (cortex), wd 1e-4
50
- (Linear only), grad clip 5.0, **AMP fp16**, bs **16/GPU × accum 2**.
51
- - 2–3 epochs. Smoke test first: `python model.py` (prints the 272M
52
- breakdown), `python data_adapters.py` (adapter shapes).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
  ---
55
 
56
- ## Stage B — RPO: return-conditioned PPO (online, in sim)
57
 
58
  ### B.1 Rollouts
59
 
60
  - `model.act(..., rtg=rtg_actual)` per tick; store `logprob`, `value`,
61
- `win_prob`. **8 envs/GPU × 256 ticks** on CPU workers (2×T4 ⇒ ~2048
62
- samples/round).
63
- - Memory mode (optional): carry `state` through each episode
64
- (truncated-BPTT); the env wrapper sketch:
65
-
66
- ```python
67
- # env wrapper sketch (mem mode)
68
- s = None
69
- for step in range(ep_len):
70
- rgb_t, nums_t = env.obs()
71
- a = model.act(rgb_t, nums_t, rtg=rtg_est, state=s)
72
- s = a["state"] # (1, B, 768)
73
- obs, r, done = env.step(a["kind"], a["cell"], a["pct"])
74
- ```
75
 
76
- ### B.2 RPO specifics
77
 
78
- - **RTG-consistent advantages**: `A_t = R_t − V(s_t, R_t)` (value is
79
- rtg-conditioned — that is the whole point; the critic never has to
80
- guess the aspiration).
81
- - GAE(γ=0.995, λ=0.95) over `A_t`; z-normalize; clip ε=0.2 on the full
82
- action logprob.
83
- - Value loss: 0.5×clipped Huber (double clip ±0.2 in return space) +
84
- **win head CE on episode outcomes** + optional cell-value auxiliary
85
- (Huber vs per-cell utility bootstrap — PPO-friendly spatial critic).
86
- - 4 epochs/round, minibatch 64/GPU, AdamW lr 3e-4 + cosine tail, grad
87
- clip 5.0, **AMP fp16 + fp32 master**.
88
- - **KL-to-pretrain guard β=0.1** (frozen Stage-A prior); roll-back if mean
89
- KL > 0.15 for 3 rounds (β→0.02). ICLR 2025 evidence: pretrain-init +
90
- guard, no offline replay retention — do NOT mix shards into the PPO
91
- batches.
92
 
93
- ### B.3 Aspiration at play time
 
 
 
 
 
94
 
95
- Eval/deploy with `rtg = +1.5` z-units (above-survival ambition; tune over
96
- {0.5, 1.0, 1.5, 2.0} — ablation #1). The BC stage never saw rtg>2σ, so
97
- stay inside the trained range.
98
 
99
- ### B.4 Reward shaping (flag the sim edit)
100
 
101
- `+0.004/tick alive, +0.4/kill, +2 survive timeout, +8 win`. Keep
102
- intermediates small; the win is the judged objective.
 
 
103
 
104
- ### B.5 League-lite (fictitious self-play, cheap)
105
 
106
- Keep the top-3 checkpoints by win-rate. Every 10 rounds, evaluate the
107
- current policy against the pool; promote if it wins >55%. Once promoted,
108
- the sim runs our policy vs 7 bots + 2 frozen past selves — the only
109
- "league" a 2×T4 budget can afford, and it directly targets the weakness
110
- of the last-survivor objective (myopic bot-exploit policies).
111
 
112
  ---
113
 
@@ -115,11 +121,12 @@ of the last-survivor objective (myopic bot-exploit policies).
115
 
116
  - 100+ episodes vs **9 mixed bots**, fixed seeds; metric **win-rate +
117
  mean rank**; save best on rank; report binomial CI.
118
- - **Wake-sleep distill**: after PPO plateaus, distill the 272M policy into
119
- a ~30M dense student (same heads, distilled heat/kind/pct/value with KL;
120
- `return_all=True` provides all teacher targets). Use the student for
121
- 2× faster rollouts and richer league self-play data; the big teacher
122
- trains from it. Repeat (cap 3 cycles).
 
123
 
124
  ## Curriculum
125
 
@@ -131,31 +138,33 @@ Epoch 1 of Stage A on early-game frames (tick_frac < 0.35) → full data →
131
  | # | Question | Change | Resolves |
132
  |---|---|---|---|
133
  | 1 | Aspiration rtg at play time | {0.5, 1.0, 1.5, 2.0} | the RPO knob |
134
- | 2 | Return conditioning itself | rtg≡0 (frozen) vs conditioned | Bet 1's real value |
135
  | 3 | Intent mirrors | λt=λx=0 vs default | opponent modeling |
136
  | 4 | Dynamics head | λd=0 vs default | world-model value |
137
- | 5 | Memory | GRU off vs on (seq BPTT) | temporal credit |
138
- | 6 | Value objective | Huber vs τ=0.9 expectile | robustness |
139
- | 7 | Win head | on/off in Stage B loss | endgame behavior |
140
  | 8 | League-lite | pool vs no pool | self-play payoff |
141
  | 9 | Wake-sleep | 0 vs 3 distill cycles | scaling loop |
 
142
 
143
  ## Expected compute (2× T4, fp16)
144
 
145
- - Stage A: ~8–14 h for the current GB-scale shard set (272M, bs 16/accum 2).
146
- - Stage B: ~2–3 updates/min at minibatch 128 → one full experiment per
147
- ~1–2 days. That is the honest cost of the mandate; the sanctioned trims
148
- (in order): `head_hidden` 3072→2048, `cortex_layers` 6→4, `enc_ch` top
149
- 832→640. Each keeps the total >200M.
150
 
151
  ## Risk register
152
 
153
  | Risk | Mitigation |
154
  |---|---|
155
- | fp16 NaN in attention | fp32 master, grad clip 5, warmup; fall back fp32 for Stage A |
156
- | Unlearning the BC prior | KL guard + roll-back (B.2); no offline replay retention |
157
- | Aspiration OOD (rtg>2σ) | clamp rtg to ±2.5; ablation #1 |
158
- | Threat/expand labels are imbalanced | BCE weights 8:1 positive:negative |
159
- | GRU rollout complexity | default off; env sketch included |
160
- | Activation memory at bs 16 | `grad_ckpt=True` halves the heavy stages |
161
- | Color-identity prior (red=me) | sim-specific; documented |
 
 
1
+ # SOVEREIGN v3 — Training Doctrine (≈290M dense + MCTS planning)
2
 
3
  Exact recipe for **2× T4 (16 GB)**, shared shard format
4
+ `rl/shards_v2/*.npz`. Memory ≈9.5 GB/GPU at bs 16 + fp16 (ARCHITECTURE.md
5
+ §3). Everything below is implemented: `model.py`, `data_adapters.py`,
6
+ `search.py`, `league.py`, `distill.py`.
7
 
8
  ---
9
 
10
+ ## Stage A — Return-conditioned filtered BC + world model (offline, ~2–3 epochs)
11
 
12
  ### A.1 Sample preparation (`ShardPrepper`)
13
 
14
+ 1. **Returns / RTG**: per-episode `R_t = r_t + γR_{t+1}`, γ=0.995; +2
15
+ survive / +5 win terminal bonuses; z-scored per shard. `rtg` conditions
16
+ every head; `rtg_next` shifts within episodes.
 
17
  2. **Weights** `w = clip(exp(R̄/τ), 0.2, 8)` τ=1; ×4 survivor episodes;
18
+ ×2 ±2-frame kill windows; mean-normalized (AWR soft filtering).
19
+ 3. **Free-label targets**: `lab64`, `lab64_next`, `threat`/`expand`
20
+ intent mirrors, `gate_mask`/`gate_valid`, `win_lab`, `nums_next`,
21
+ `rgb_next` (consecutive frames), `reward`.
22
  4. **Arena filtering**: drop >85%-water episodes.
 
23
 
24
+ ### A.2 Policy loss (exact)
25
 
26
  ```
27
  L = w · [ λk CE(kind; ls=0.05)
 
31
  + λw CE(win_logits, win_lab; ls=0.05)
32
  + λg BCE(gate, gate_mask)·1[valid]
33
  + λs CE(seg64, lab64)
34
+ + λd CE(next_seg, lab64_next)
35
+ + λt BCE(threat) + λx BCE(expand)
36
  + λe smoothL1(econ, cat(nums_next, rtg_next))
37
  − λent (H(kind)+H(cell)+H(pct)) ]
38
  λ = (0.5, 1.0, 0.25, 0.1, 0.1, 0.5, 0.5, 0.4, 0.2, 0.2, 0.05, 0.003)
39
  ```
40
 
41
+ Value option: τ=0.9 expectile instead of Huber (IQL-style robustness on
42
+ the weak buffer).
 
43
 
44
+ ### A.3 World-model loss (the new thing — trains the search block)
45
 
46
+ ```
47
+ z_t = model.encode(rgb_t, nums_t, rtg_t) # stopgrad target
48
+ ẑ_{t+1} = model.dynamics(z_t, kind_t, cell_t, pct_t)
49
+ prior̂, v̂, win̂ = model.prediction(z_t)
50
+ z_{t+1} = model.encode(rgb_next_t, ...).detach()
51
+
52
+ L_wm = λz MSE(ẑ_{t+1}, z_{t+1}) # latent transition
53
+ + λr Huber(r̂, reward_t) # reward model
54
+ + λp KL(softmax(prior̂), softmax(cell_logits_t).detach()) # prior consistency
55
+ + λv̂ Huber(v̂, R̄_t) + λŵ CE(win̂, win_lab_t)
56
+ λ_wm = (0.5, 0.1, 0.3, 0.1, 0.1)
57
+ ```
58
+
59
+ This is MuZero-lite: representation + dynamics + prediction trained
60
+ entirely on labels the shards already contain (consecutive frames +
61
+ reward). Implement with `encode()/prediction()/dynamics()` + a small loop
62
+ over the loader (10 lines; both loss blocks share the same batch).
63
+
64
+ ### A.4 Optimizer & schedule
65
+
66
+ - AdamW lr **3e-4 → 3e-5** cosine, **300-step warmup** (cortex), wd 1e-4,
67
+ grad clip 5.0, **AMP fp16**, bs **16/GPU × accum 2**. 2–3 epochs.
68
+ - Smoke tests first: `python model.py`, `python data_adapters.py`,
69
+ `python search.py`, `python league.py`, `python distill.py`.
70
 
71
  ---
72
 
73
+ ## Stage B — RPO + AlphaZero-lite policy improvement (online, in sim)
74
 
75
  ### B.1 Rollouts
76
 
77
  - `model.act(..., rtg=rtg_actual)` per tick; store `logprob`, `value`,
78
+ `win_prob`. **8 envs/GPU × 256 ticks** on CPU workers.
79
+ - **Search rollouts (the planning loop)**: every 4th action, call
80
+ `Searcher(model, sims=64, max_depth=12).search(rgb, nums, rtg, mask)`
81
+ and execute the search-chosen action. Store the **visit distribution**
82
+ `visit_probs` alongside the transition (single-sample search; batch over
83
+ envs by running search per env — 64 sims × 12 depth ≈ 20–40 ms on T4,
84
+ well inside the 560 ms tick).
85
+
86
+ ### B.2 RPO loss (unchanged core)
87
+
88
+ `A_t = R_t − V(s_t, R_t)` (rtg-consistent critic), GAE(0.995, 0.95),
89
+ z-normalize, clip 0.2 on the action logprob, 0.5×clipped Huber value,
90
+ win-head CE on outcomes, entropy 0.01→0.002. 4 epochs/round, minibatch
91
+ 64/GPU, AdamW 3e-4 + cosine tail, grad clip 5.0, **fp16 + fp32 master**.
92
 
93
+ ### B.3 Search-target distillation (AlphaZero's policy improvement)
94
 
95
+ On rollout states where search ran, add:
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
+ ```
98
+ L_search = CE(kind_logits, kind_from_search)
99
+ + KL(softmax(cell_logits[·,kind]), visit_probs_kind)
100
+ + Huber(value, q_search)
101
+ λ_search = 0.5 (weighted by search-depth, first N=500k transitions)
102
+ ```
103
 
104
+ This lifts the policy toward the planner's improved distribution —
105
+ exactly the loop AlphaZero proved, scaled to a 3×1024 action space.
 
106
 
107
+ ### B.4 League-lite self-play
108
 
109
+ Use `league.py`: after each eval round, `update_elo` vs the pool; when the
110
+ current agent beats the pool (`maybe_promote`, threshold 0.55), freeze a
111
+ snapshot. Rollouts run vs **7 bots + 2 frozen past selves** picked by
112
+ `pick_opponents(2)` (alternating weakest/strongest — curriculum pressure).
113
 
114
+ ### B.5 KL guard
115
 
116
+ β=0.1 KL-to-Stage-A-prior; roll-back if mean KL > 0.15 for 3 rounds.
 
 
 
 
117
 
118
  ---
119
 
 
121
 
122
  - 100+ episodes vs **9 mixed bots**, fixed seeds; metric **win-rate +
123
  mean rank**; save best on rank; report binomial CI.
124
+ - **Wake-sleep** (`distill.py`): when PPO plateaus, distill the teacher
125
+ into the ~35M student (`small_config()`), including any stored
126
+ search targets. The student rolls out 2–3× faster → richer league data
127
+ → teacher trains again. Cap 3 cycles.
128
+ - **Search eval**: measure win-rate with search ON vs OFF (the pure
129
+ planning ablation — it isolates how much "thinking" is worth).
130
 
131
  ## Curriculum
132
 
 
138
  | # | Question | Change | Resolves |
139
  |---|---|---|---|
140
  | 1 | Aspiration rtg at play time | {0.5, 1.0, 1.5, 2.0} | the RPO knob |
141
+ | 2 | Return conditioning itself | rtg≡0 vs conditioned | Bet 1's value |
142
  | 3 | Intent mirrors | λt=λx=0 vs default | opponent modeling |
143
  | 4 | Dynamics head | λd=0 vs default | world-model value |
144
+ | 5 | **Search on/off** | Searcher vs policy-only at eval | how much MCTS is worth |
145
+ | 6 | **Search sims** | {16, 64, 128, 256} | compute vs strength |
146
+ | 7 | Value objective | Huber vs τ=0.9 expectile | robustness |
147
  | 8 | League-lite | pool vs no pool | self-play payoff |
148
  | 9 | Wake-sleep | 0 vs 3 distill cycles | scaling loop |
149
+ | 10 | Search-target distillation | λ_search ∈ {0, 0.5, 1.0} | policy-improvement op |
150
 
151
  ## Expected compute (2× T4, fp16)
152
 
153
+ - Stage A: ~10–16 h (≈290M incl. world-model losses).
154
+ - Stage B: ~2–3 updates/min; search on 8 envs every 4th tick adds
155
+ ~0.3 s/env/step of T4 time. One full experiment ≈ 1–2 days.
156
+ - Sanctioned trims (in order): `head_hidden` 3072→2048,
157
+ `cortex_layers` 6→4, `enc_ch` top 832→640, `sims` 64→32.
158
 
159
  ## Risk register
160
 
161
  | Risk | Mitigation |
162
  |---|---|
163
+ | fp16 NaN in attention | fp32 master, grad clip 5, warmup |
164
+ | Unlearning the BC prior | KL guard + roll-back (B.2) |
165
+ | Search too slow in rollouts | sims 32, top_k 8, depth 8; distill student |
166
+ | World model collapses (z→ẑ≈z) | residual dynamics + λz; monitor MSE curve |
167
+ | Threat/expand label imbalance | BCE weights 8:1 positive:negative |
168
+ | Aspiration OOD (rtg>2σ) | clamp rtg to ±2.5 |
169
+ | League pool drifts stale | promotion threshold 0.55 + periodic re-eval |
170
+ | GRU rollout complexity | default off; env sketch in README |