feat(moe): add DEGRADE_ZERO miss-slot zero-fill policy (issue #865) - #906
feat(moe): add DEGRADE_ZERO miss-slot zero-fill policy (issue #865)#906kritikagarg wants to merge 6 commits into
Conversation
…g#865) Introduce DEGRADE_ZERO=1 / DEGRADE_TAU=<f> (default 0.03): when a prefetch deadline is missed, experts whose aggregate gate weight across the batch is below tau are zero-filled instead of triggering a blocking demand-load. Issue JustVugg#865 measures tau=0.03 zeroes 21.8% of slots for only +2.9% perplexity — well within acceptable quality budget on NVMe-bound workloads where the stall cost dominates. Design constraints respected: - Decode-only (S<=4 guard): same invariant as EXPERT_BUDGET — dropping experts during prefill corrupts the KV cache (JustVugg#292) - Miss-only: pin/LRU hits are never dropped; they load for free - Rescue rule: no position is left with zero routed experts - Renormalises surviving weights for both norm_topk=1 (GLM-5.2) and norm_topk=0 (other MoE configs) to preserve output magnitude - Opt-in only (default OFF): output changes, must never be silent - Stats footer reports tau and cumulative zeroed slot count when active Adds tests/test_degrade_zero.c: 8 properties, 20 checks, standalone (no model or weights needed), auto-discovered by the Makefile test gate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two semantic fixes to match the measured spec the +2.9% ppl number was taken under: 1. Per-position tau gate: a miss expert is now kept if ANY position routes to it with weight >= tau, tested per-position independently. The old code aggregated gate weight across the batch before comparing — at S>1 this coupled positions and made the I/O savings lower than the measurements predict (at S=1 the two are identical). 2. No renorm: survivors keep their original weights after a drop. The old code renormalised surviving weights (norm_topk and non-norm paths), redistributing the dropped mass upward — a different approximation with no measured quality curve. The approximation IS the dropped mass; renorm hides it and biases the output. Tests: replace P4 (renorm-normtopk) and P5 (renorm-nonnorm) with P4 (no-renorm) and P5 (per-position-tau), all 20 checks pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
c7308cf to
ecd369c
Compare
|
Updated the implementation to address the two semantic points raised in #865: 1. Per-position τ gate (was: aggregate) 2. No renorm (was: renorm after drop) Tests: replaced P4 (renorm-normtopk) and P5 (renorm-nonnorm) with P4 |
…ustVugg#865) - Add [DEGRADE] stderr line at startup when DEGRADE_ZERO=1 is active, matching the pattern used by [CACHE_ROUTE] and per the maintainer's requirement that approximate mode is never silent. - Add P9 (bit-identical when off): verifies idxs[], ws[], keff[], and uniq[] are byte-identical to the input when g_degrade_zero=0, even when sub-tau experts are present. 25/25 checks pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Thank you for taking this — @outtodata's #865 is one of the better-measured proposals in the tracker and it deserved an implementation. I want to read it properly rather than fold it into a batch, because it is the first change here that makes the engine produce different tokens on purpose. Everything else in this repo is either exact or explicitly a quantisation choice made at conversion time; this is a runtime decision to skip work and accept the output moving. That is a legitimate capability and #865's numbers support it — zeroing slots below τ=0.03 costs +2.9% ppl on OLMoE while τ=0.05 costs +41%, so the operating point is real and narrow. Three things I will be looking for, said up front so you can point me at them or fix them before I do: Off by default, and loud when on. A run that silently approximates is indistinguishable from a run that is subtly broken, and six months later someone files a quality bug we cannot reproduce. The The gate on weight, not on count. #865 is explicit that the weight threshold is the control and the slot count is not: τ=0.03 zeroes 21.8% of slots for +2.9%, but "zero 21.8% of slots" chosen by any other rule would not give that number. A token-exactness assertion with the flag off. The existing oracles must stay bit-identical, so that enabling this is the only way to change output. +473 lines across 3 files and CI has not reported yet — I have approved the workflow run. I will come back to it with a real review rather than a checklist. One thing worth flagging because it affects where this pays off: #865's measurements are on OLMoE, and @outtodata says so plainly. This engine's own profile shows expert I/O dominating expert matmul by roughly 5:1 on a streaming box, so a policy that avoids waiting for a late read is aimed at exactly the right cost — but the ppl numbers that justify τ=0.03 are one model's. Worth stating in the docs that the default is calibrated on OLMoE, not measured on GLM or Kimi. |
|
Thanks for reading it this way — the three gates you named are exactly the ones the measurements support. Tying each back to the data, plus two places where an implementation can silently drift from them: Off by default, loud when on. Agreed, and the [PROF] counter is mandatory from our side too. One refinement worth asking for: report the zeroed share per layer, not just a global count. τ is a global knob but the drop share is not uniform across layers — a global "21.8% zeroed" can hide one layer zeroing far more, and that is where the ppl cost concentrates. A per-layer min/max next to the hit/miss line makes a silently-miscalibrated run visible instead of indistinguishable from a healthy one. I can pull the per-layer drop-share table from our grid run if that helps the review. Gate on weight, not on count. This is the load-bearing point, and I'm glad it's called out up front. The +2.9% at τ=0.03 comes from the weight threshold selecting which slots to drop — the slots contributing least to the MoE output under Token-exactness with the flag off. Should hold naturally: the gate sits before OLMoE-calibrated default. Fair, and worth stating in the docs exactly as you put it. For the record, the numbers behind τ=0.03: OLMoE-1B-7B, fp16 offload, ppl 13.9144 → 14.3194 (+2.9%), task_acc unchanged at 0.889, ~22% of slots dropped; τ=0.05 → +41% ppl, so the operating point is real and narrow. GLM ( |
release: v1.6.0 — the regression fixed, and prefill learns to read each expert once
release: v1.6.1 — the first day of real users, fixed the same day
Introduce DEGRADE_ZERO=1 / DEGRADE_TAU= (default 0.03): when a prefetch deadline is missed, experts whose aggregate gate weight across the batch is below tau are zero-filled instead of triggering a blocking demand-load. Issue #865 measures tau=0.03 zeroes 21.8% of slots for only +2.9% perplexity — well within acceptable quality budget on NVMe-bound workloads where the stall cost dominates.
Design constraints respected:
Adds tests/test_degrade_zero.c: 8 properties, 20 checks, standalone (no model or weights needed), auto-discovered by the Makefile test gate.
Summary
Describe the problem and the smallest change that solves it.
Validation
make -C c checkmake -C c cuda-test(if applicable)Compatibility