phase 1a v3 keep maps + phase 1b sweep audit (read-only) #
scope: scripts/select_and_eval_prunes.py (v3), scripts/replay_moe_cache.py, scripts/replay_moe_cache_fast.cpp, results/keep_maps/ (9), results/oos_prune_retention.json, results/phase1b_cache_moce_sweep.json, results/phase1b_heldout_cache_moce_sweep.json, checked against results/reap_saliency_v2.json (131,072 calib tok) and results/eval_reap_heldout.json (8,192 held-out tok). nothing in the repo was edited. the scratch differential test lives in /tmp/rpl/.
verdict: PASS (with minor notes). #93 can close. #
- the v2 shrink dead-expert bug is fixed: 0 of the 8 zero-hit experts (L0: 181,193,244,271,413,424; L1: 116; L47: 371) are kept in any of the 9 maps.
- the L47 max-norm outlier is fixed: the hybrid is now a per-layer rank-percentile average, and nothing normalizes across experts by max.
- C++ and Python replayers: identical math. with Python ties broken by lowest id (which is what C++ does), 96/96 configs match to 5e-7. that covers 6 policies, λ ∈ {0, .05, .12}, unpruned/K224/sparse-48 keep maps, and 22,297 forced-miss slots.
- the sweep outputs are internally consistent, and the in-sample and OOS sweeps cover the same 120 configs.
1. keep maps vs saliency (direct recompute) #
verify_invariantspasses on both the calib JSON and the held-out JSON.- all 9 maps are exactly reproduced by
compute_layer_scores+ the script's ranking (0 layer mismatches). every layer has K unique ids, and the maps nest 224 ⊂ 256 ⊂ 320 for every metric. - the
assert zero_hit_kept == 0is in place. shrink scores c=0 as 0, and the LCBmean − SEtimesc/(c+64)damping kills rare noise. experts kept with <100 calib hits: l2_sum 0, hybrid 0–2, shrink 2–3 (whole model). - L47: expert 143 (mean 5.56, 9,549 hits) is kept everywhere, which is legit since it has real support. L47 reap retention at K224: l2_sum .945, hybrid .935, shrink .877.
oos_prune_retention.json: I recomputed mean/min reap retention, mean prob retention and slot replacement from the held-out JSON. all 36 numbers match to 4 dp. OOS ranking is l2_sum > hybrid > shrink on every metric at every K (K256 mean reap: .797 / .782 / .734; slot replacement: .239 / .271 / .338).- note (not a falsifier): kept experts with 0 held-out hits number 7–69 per map. that's sampling noise at 8K tokens, since all of them have ≥74 calib hits.
2. C++ vs Python replayer #
matches, line for line:
- forced misses
max(0, k_used − n_chosen)go into both misses and total_picks, after warmup only. - MoCE bonus:
λ·(z0 − z[k−1])on top-j or cached experts. sort order is (score desc, rank asc), then eid. - eviction never evicts the current chosen set.
- lazy EMA:
mult *= 1/dbefore crediting, rescale at 1e100. credits for near_pick and inv_router are the same. - Belady: next-use is built from
ids[:k]and the pointer advances on chosen. it's only valid at λ=0, and the sweep has no Belady λ>0 rows ✓. - the
ntok==0header uses the actual token count in both (v2 edge 2 fixed). the remap is keep-list order and the JSON is sorted, so they agree.
differences (minor):
- tie-breaking: Python
min/maxover asetresolves ties in hash-iteration order, while C++ picks the lowest id. with the production Python as-is, 5/44 configs differed by ≤0.04% misses/tok. that's below sweep rounding and has no impact on conclusions. if you want bit-exact parity, addcas the last key in Python. - fp32 (C++) vs fp64 (Python) logits/bonus: no observable effect in the test.
- C++ hardening gaps, none triggered by the sweep: there's no
cache_cap >= k_usedcheck (otherwisevictim_idx = -1is UB), nofopennull check, and it hardcodes 48 layers in the keep loader, ≤512 experts,top_m ≤ 64, warmup 64, decay .99 and near_pick_n 48.
3. sweep outputs #
- 120 configs per file, with identical key sets: 10 variants. K512 and the l2_sum maps get all 6 policies plus λ ∈ {.05, .09, .12} × j ∈ {2, 3} for lru/near_pick/inv_router. hybrid and shrink get lru and near_pick at λ=0 only.
- derived fields check out on all 240 rows:
ssd_mb = misses·1.3824, the tok/s formulas for 3.9 and 6.8 GB/s + 12 ms, andmisses = 480·(1−hit). - Belady ≤ every λ=0 online policy per variant ✓. MoCE misses are monotone non-increasing in λ for every policy and variant ✓. j=2 vs j=3 differ by ≤0.01, so j is plumbed through but irrelevant.
- in-sample → OOS shift (misses/tok, 48L): K512 LRU 84.61 → 84.84, Belady 42.81 → 46.13, LRU λ.12 63.21 → 66.06. near_pick_ema λ.12 degrades most OOS (70.0 → 79.3). LRU is the best online policy everywhere, and LFU is the worst (155).
- caveat for interpretation: for pruned variants, misses only count cache traffic. substituted slots (24–41% at K224) are a quality cost that the miss numbers don't price. shrink/hybrid's slightly lower miss counts come from replacing more slots, so don't read them as better caching. both traces are also teacher-forced prefill, not decode.
recommendation #
the conclusion stands: reap_l2_sum is the prune metric (best OOS retention at every K), hybrid is the hedge ablation, and shrink can be dropped. use LRU + MoCE λ≈.12 as the online baseline.