Files
evil_MoE/docs/spec/20260601_calibrated_tau_route2grad.md
T
wassnameandClaudypoo 8158adb543 refactor: route2 quarantine = scale-matched delta_S_hack, rip out 33M LoRA
The distinct-basis A_q/B_q LoRA (~33M params at rank-16) gave the quarantine a
~100x capacity edge over delta_S, so routing-everything-there was the low-
resistance path: qE pinned ~0.97 (energy into the thrown-away knob) while the
deployed delta_S learned nothing (job 54). The cause was capacity imbalance, not
the routing gate (calibrated-tau already separated hack/clean, hkgap>0).

Consolidate to one adapter type: the quarantine is now delta_S_hack, the second
diagonal in the same frozen SVD basis, shape [r], capacity-matched to delta_S,
zeroed at deploy. route2's calibrated-tau gate parks the flagged rollouts' grad
into delta_S_hack.grad (like proj.py's route parks its subspace projection);
delta_S keeps the unflagged. Both diagonals train at one shared lr.

Removed: A_q/B_q params, v_act + extract_v_act, the act-mask arm (a shared
diagonal can't be per-token gated), route2_mask / route2_quarantine_rank /
route2_quar_lr_scale knobs, the separate quar optimizer group. Arm name
routing2_{act,grad} -> routing2. v_grad refresh extracts from delta_S (main)
with the quarantine ablated.

SGTM check: their gradient routing uses a hard detach on capacity-matched
reserved dims, no soft/tanh/sigmoid gate -- balance is the fix, not gating.

Smoked clean: tau/hkgap/qE render, ||delta_S_hack||>0 assert passes, exit 0.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-01 02:52:02 +00:00

153 lines
8.2 KiB
Markdown

# Spec — per-step calibrated threshold τ for route2-grad routing
Status: APPROVED by user 2026-06-01, implement + smoke + queue + follow.
Context survives compaction here; resume from "Implementation" if context was lost.
## Hypothesis / why
route2-act and route2-grad both gate routing on `cos(·, v) > 0`. In high-dim,
`cos ≈ 0` for almost everything, so an absolute-zero threshold is a ~50% coin
flip -> over-routing -> half of ALL learning dumped into the deleted quarantine
-> collapse (job 46) or null. The fix is NOT to route by the detector flag (that
= SGTM, throws away the vector novelty: the flag only catches known hack A, the
whole point is the *direction* generalises to unknown B). The fix is to keep
routing by the v_hack DIRECTION but **calibrate the threshold per step** so it
rides the cos drift (we measured cin_t 0.27->0.07 over ~10 steps, so any fixed
τ goes stale and silently stops firing).
Driving principle (one): route by where a rollout falls on the v_hack axis
RELATIVE to the known-hack vs clean clouds, recalibrated each step.
## Mechanism (per module, per step, EMA-smoothed)
Anchors available every prompt without a new buffer:
- hack cloud = teacher rollouts (known-A hacks, always present) + detector-
flagged student rollouts (`hack_E` = loophole used; the allowed weak detector).
- clean cloud = NOT-flagged student rollouts. (Contaminated with unknown B -- that
is FINE and intended: it makes τ slightly conservative, and B, sharing the
direction, lands ABOVE τ and gets routed. Do NOT force-keep this set.)
Per module `name`, from this prompt's `cos_b` [G] (already computed in
`_route2_grad_filter`):
- μ_hack_prompt = mean(cos_b[hack_anchor]) ; μ_clean_prompt = mean(cos_b[clean_anchor])
- EMA across prompts/steps (β=0.9): ema_hack[name], ema_clean[name]
(EMA is the cheap equivalent of "last N hacks": teacher is the always-present
floor, recent student-flagged hacks sharpen it. Explicit rollout buffer =
TODO if teacher-anchor proves biased toward teacher-style hacks.)
- τ[name] = (ema_hack[name] + ema_clean[name]) / 2
- route_mask = hack_anchor | (cos_b > τ[name]) # force-route known hacks
(teacher + flagged student); τ-route the ambiguous rest (incl. unknown B).
Warmup: at step 0 delta_S≈0 so few reliable axes -> cos_b≈0 -> μ_hack≈μ_clean≈0
-> τ≈0 (≈ old cos>0 behaviour) until delta_S grows. Separation (hkgap) emerges
over the first few steps. Sanity: by a few steps μ_clean<~0.1, μ_hack>~0.2-ish
(the user's hardcode intuition, but self-calibrated).
## Logging (new columns, route2-grad only)
- `tau` = mean over modules of τ[name]
- `hkgap` = mean over modules of (ema_hack - ema_clean) <- the discrimination
gauge; generalises cin_t>cin_s. If hkgap collapses to ~0 the direction stopped
separating (the real failure signal, not a threshold-choice problem).
## Implementation (exact edits in src/projected_grpo/train.py)
1. Before the step loop (near `route_span_checked = False`, ~L1082): add
`ema_hack_cos: dict = {}`, `ema_clean_cos: dict = {}`, `route2_tau: dict = {}`
(persist across steps). EMA_BETA = 0.9.
2. Per-step lists near `step_flagged` (~L1192): `step_tau = []`, `step_hkgap = []`.
3. Per-prompt anchor masks: after grading (hack_E_flags built, ~L1396), before
the backward, when is_route2_grad build device bool tensors aligned to merged
rows [student 0..G_s-1, teacher G_s..]:
hack_anchor[i] = (not is_student[i]) or (is_student[i] and hack_E_flags[i])
clean_anchor[i] = is_student[i] and not hack_E_flags[i]
(hack_E_flags has length G_s = #student rows; teacher rows -> hack_anchor.)
4. `_route2_grad_filter` (~L1194): add params (hack_anchor, clean_anchor).
Replace `flagged = (cos_b > 0).float()` with the EMA-calibrated τ logic:
- update ema_hack_cos[name]/ema_clean_cos[name] from this prompt's anchors
(skip a cloud if it has no rows this prompt)
- τ = (ema_hack_cos.get(name,0)+ema_clean_cos.get(name,0))/2 ; route2_tau[name]=τ
- route = (cos_b > τ) | hack_anchor ; flagged = route.float()
- step_tau.append(τ); step_hkgap.append(ema_hack_cos.get(name,0)-ema_clean_cos.get(name,0))
Pass hack_anchor/clean_anchor through the call site (~L1518).
5. Row dict (~L1864): add `"tau": (mean(step_tau) if step_tau else float("nan"))`,
`"hkgap": (mean(step_hkgap) if step_hkgap else float("nan"))`.
6. StepLogger cols (~L711, after the routing2_act block): add
if arm == "routing2_grad":
_Col("tau", 6, "tau", "+.2f", "per-step calibrated route threshold (midpoint of hack vs clean cos clouds)")
_Col("hkgap", 6, "hkgap", "+.2f", "ema_hack_cos - ema_clean_cos; >0 = v_grad still separates hack from clean")
## Verify / queue / follow
- `just smoke-route2`: confirm tau/hkgap/qE columns render, routing fires
(flagged frac < ~0.5, not pinned at 0.5), exit 0.
- Queue (substrate, 60 steps, seed 41), label:
why: does per-step calibrated-τ vector routing (route2-grad) stop over-routing
(flagged<<0.5) and suppress held-out deploy-hack vs vanilla at matched solve;
resolve: qE bounded + hkgap>0 sustained + deploy file_marker hack < vanilla.
- `pueue follow <id> | tail` in background.
## No-cheat check
Detector flag (hack_E) only CALIBRATES μ_hack (known A) + anchors teacher hacks.
The routing GATE is cos>τ applied to ALL rollouts incl. unknown B. gt_pass never
touches routing. Compliant.
## Status: IMPLEMENTED + RUNNING (job 54)
Implemented in `6eb894f`, smoked (tau/hkgap render, exit 0). Running as job 54
(calibrated-τ + grad_clip 0.5, route2-grad, 60 steps, seed 41). job 52
(caltau-alone) killed and folded in; clip 0.5 is a no-op while gn<0.5 so 54 is
the strict superset.
### Live observation (steps 0-2, 2026-06-01)
The calibration works as a discriminator but does NOT fix over-routing-by-energy:
- `hkgap` positive and rising (0.00 -> 0.03 -> 0.08): the v_grad direction DOES
separate the hack cloud from the clean cloud. The vector is alive.
- `tau` tracking up with it (0.00 -> 0.02 -> 0.04): the threshold rides the drift
as designed.
- BUT `qE` 0.73 -> 0.97 -> 0.97: ~97% of gradient ENERGY lands in the deleted
quarantine by step 1, and `gt_s` 3 -> 7 -> 0 (solving collapsed).
Diagnosis: the failure was never the routing FRACTION (which τ fixes); it is the
always-summed 33M A_q/B_q quarantine MAGNITUDE. Even a correctly-thresholded route
sends the routed gradient into a knob whose per-param grads dwarf delta_S's, so
the energy ratio pins near 1 and the deployed adapter learns nothing. This is the
SYNTHESIS "next lever" prediction: if qE stays high while hkgap>0, the culprit is
quarantine magnitude, not the gate.
## DESIGN CHANGE (2026-06-01): one adapter, scale-matched quarantine
Acted on the magnitude diagnosis by removing the distinct-basis LoRA entirely.
The quarantine is now delta_S_hack -- the SECOND diagonal in the same frozen SVD
basis, shape [r] per module, identical capacity to delta_S. route2's calibrated-τ
gate parks the flagged rollouts' delta_S-grad contribution into delta_S_hack.grad
(via step_grad_hack in _route2_grad_filter), exactly as proj.py's `route` parks
its subspace-projected component; delta_S keeps the unflagged. Both diagonals
train at one shared lr; delta_S_hack is zeroed at deploy.
Rationale (user): a 33M LoRA vs a ~2k-param delta_S per module means "dump
everything in the quarantine" is the low-resistance path -- a capacity edge, not
honest absorption. Capacity-balanced diagonals remove that bias. SGTM's own
quarantine is capacity-matched (a split of the same layer, equal dims), and uses
a hard detach -- no soft/tanh/sigmoid gate -- confirming the fix is balance, not
gating.
Removed: A_q/B_q params, v_act buffer + extract_v_act, the act-mask arm (a shared
diagonal can't be per-token gated), route2_mask / route2_quarantine_rank /
route2_quar_lr_scale knobs, the separate quar optimizer group. arm name
"routing2_grad"/"routing2_act" -> "routing2".
v_grad refresh extracts from the MAIN knob (delta_S.grad) with the quarantine
ablated -- the deployed-model gradient is what we route, and both diagonals share
the basis so the direction is directly usable on delta_S's live gradient.
Smoked clean (tiny-random): tau/hkgap/qE render, ||delta_S_hack||=0.0074>0 assert
passes, deploy-ablation fires, exit 0. Queued on the substrate (seed 41, 60 steps).