Repository navigation
Conversation
…TRATA_SPEC_PCUM, opt-in)
The serial decode loop's MTP window ended at the first draft below --spec-min-p. STRATA_SPEC_PCUM=base[,deep[,d0,d1]]
also ends it where the product of the drafted tokens' top-1 probabilities - the draft's estimate that the whole window
is accepted - falls below a threshold that follows the depth: base to position d0, deep from d1 (16384 / 49152 by
default), linear between. The drafter stops at the same place through the existing chain-rule hook (float compares and
a double product, operation for operation the window rule), so it drafts nothing the window drops. Per request:
strata_tune {"spec_p_cum": p} sets base and deep, {"spec_p_cum_deep": p} the deep value (serve/server.py passes both).
The concept is the depth-scheduled draft cutoff of https://github.com/Keoian/dual-p100-qwen-3-8-27b (branch
p100-optimizations, OPTLOG 198 / 218: product of drafted top-1 p, 0 below 16k rising to 0.22-0.3 at 48k). Here a
verify token also costs CPU expert rows at every depth.
Exact: only the window's length changes and every token is still verified. With the expert placement fixed
(--adapt-swaps 0 --prompt-cache 0, pcie_frac 0), 6 greedy prompts x 256 tokens give byte-identical text with the rule
off, at 0.6 and at 0.75. Unset: no rule, no chain callback - the default path is unchanged.
docs/DETAILS.md: the switch and its measurements on 2x RX 5700 XT. serve/test_server.py: the two request keys pass
through, out-of-range values do not.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keoian
marked this pull request as ready for review
November 1, 2026 15:05
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem and result
The serial decode loop ends an MTP window at the first draft below
--spec-min-p. Each draft is judged on its own, so a window can pass the floor token by token while the chance that the whole window is accepted is low (four drafts at p = 0.85 pass a 0.8 floor; all four are accepted about 52% of the time). Every drafted token is verified, and where a verify token is expensive the tail of such a window costs more than it returns.With
STRATA_SPEC_PCUM=base[,deep[,d0,d1]]the window also ends where the product of the drafted tokens' top-1 probabilities falls below a threshold that follows the depth. The drafter stops at the same token. Unset, nothing changes (byte-identical to main on the P100 machine below).Measured on two machines with Qwen3.8-Flash-Next, the gain is small or negative, because this model's verify cost hardly grows with depth:
--spec-min-pchanges (Validation).Related discussion
#4729 (scope). The idea comes from the depth-scheduled draft cutoff in https://github.com/Keoian/dual-p100-qwen-3-8-27b (branch
p100-optimizations,OPTLOG.mdattempts 198 and 218). That is a llama.cpp fork serving the dense Qwen3.8-27B, where every verify token costs an attention pass over the whole cache, so its numbers do not apply here. Qwen3.8-Flash-Next's sparse attention keeps the verify cost nearly flat with depth (#4729: a ~1.7-token window took 45.7 ms at 31K and 46.7 ms at 101K), which is why the rule saves little on this model.Approach
baseup to positiond0,deepfromd1(16384 / 49152 by default), and a straight line between.deepdefaults tobase.mtp.set_chain_rule): float compares and a double product, operation for operation the window rule, so it drafts nothing the window drops.strata_tunetakesspec_p_cum(base and deep) andspec_p_cum_deep;serve/server.pypasses both through, range 0-1.docs/DETAILS.md: the switch, and a row in "Opt-in switches measured and left off".Validation
2x RX 5700 XT (HIP)
Environment: 2x RX 5700 XT 8 GB (gfx1010, layer split 27), i7-3770 (AVX, no AVX2), 32 GB DDR3-1600, Ubuntu with kernel 7.0, ROCm 7.14.0a20260612 (TheRock gfx101X-dgpu), HIP build
-DCMAKE_HIP_ARCHITECTURES=gfx1010 -DSTRATA_ISA_FLOOR=avx, base 870aedd. Qwen3.8-Flash-Next ISTA-DASLab Q2_0,--spec 4 --spec-min-p 0.8 --mtp --kv int8, 256-token answers, thinking off.Passed:
Build of this branch (4fb2974),
ninja strata: 0 errors.python -m unittest serve.test_server: 359 tests OK. The new assertions intest_tune_keysfail against main'sserve/server.py.Exact, on this branch's build: a fixed expert placement (
--adapt-swaps 0 --prompt-cache 0,pcie_frac0),STRATA_SPEC_PCUM=0, 6 greedy prompts (up to 256 tokens). Rule off (spec_p_cum0) against 0.75: 6 of 6 texts byte-identical.Speed. These runs were on my fork's branch, which has this change plus the AVX-only CPU change ([Engine] AVX-only CPUs: a native pack's Q2_0 experts still run on ggml-cpu's vec_dot, not on q2_avx1.cpp #4728), gfx1010 SDWA dot4 and the HC_Q8 split gate ([Engine] HC_Q8: skip the layers' bf16 hyper-connection copies on a layer split too #2427), the same in every arm:
spec_min_p0.5 with product 0.7). That is noise.Per-run decode tok/s, sampled
Failed:
none observed.
Not run (this machine):
sycl/src/program/generate.cpp, which this PR does not change, so the variable has no effect there (not built).2x Tesla P100 (CUDA)
Environment: 2x Tesla P100-PCIE-16GB (sm_60; the second card on a PCH x4 slot, no P2P), i7-7700 (4 cores, AVX2), 47 GiB RAM, CUDA 12.4, driver 580, Linux. This branch (4fb2974) built with
-DSTRATA_ENABLE_CUDA=ON -DSTRATA_EXPERIMENTAL_SM60=ON, base 870aedd. Qwen3.8-Flash-Next ISTA-DASLab IQ3_XXS with a Q8_0 copy of the dense weights (tools/q8_dense_gguf.py),--resident-experts --layer-split 30 --spec 3 --spec-min-p 0.7 --mtp --kv int8 --max-context 262144,STRATA_Q8_SM60=1 STRATA_STAGE_TRIM=1,STRATA_SPEC_PCUM=0with the rule set per request (strata_tune.spec_p_cum), 256-token answers, thinking off. Six fixed prompts (story, code, explanation, math, list, advice).Passed:
CUDA build of this branch for sm_60,
ninja strata: 0 errors. One warning:pcum_curset but not used (src/program/generate.cpp:12334; requests usereq_pcum).python -m unittest serve.test_server: 359 tests OK.Unset path: this branch's build with the variable unset against main's engine (870aedd), fixed expert placement (
--adapt-swaps 0 --prompt-cache 0,pcie_frac0), 6 greedy prompts: 6 of 6 texts byte-identical.Speed, production placement (the adaptive expert cache on):
Per-run decode tok/s, sampled
Failed:
--adapt-swaps 0 --prompt-cache 0,pcie_frac0), 6 greedy prompts, and every arm in a fresh server, because later requests in a session also vary run to run on this machine. Rule off against main's engine: 6 of 6 identical. Rule on: 0.75 gives 0 of 6, 0.9 gives 1 of 6.Control without this PR: main's engine with
spec_min_p0.8 or 0.9 instead of 0.7 gives 0 of 6 and 1 of 6.So on this backend greedy text depends on where the draft window is cut, whatever cuts it. The texts part mid-answer into coherent alternatives ("he spotted something bobbing in the churning foam" / "he spotted a glint on the rocks"). The rule changes the text no more than
--spec-min-pdoes, but the byte-identity seen on the RX cards does not hold here.Not run (this machine):
Limits
On both machines the gain is small or negative for Qwen3.8-Flash-Next, so the switch stays off by default. It should only pay where a verify token's cost grows with depth (a dense model with full attention), which neither machine has measured with Strata.
🤖 Generated with Claude Code
https://claude.ai/code/session_01N976Q4DZqzvqFCT56yvVXy