perf(bonsai): gate/up stay in their ternary blocks, and packed batches past 8 rows read the whole FFN there on the int8 tensor cores (1.43x cb-decode @c16 on Ternary-Bonsai-2) - #1161
Conversation
sparkinfer bonsai auto-eval —
|
| metric | value |
|---|---|
| label | eval-bonsai:XL |
| model | Ternary-Bonsai-2-27B PTQ1_0 GGUF, default (folded) loader |
| scored at | decode + prefill @ 128/512/4k/16k/32k · concurrent decode @ c2/c4/c8/c16/c32 — 15 axes, each also a regression floor; the label is the best |
| tier from | bonsai-decode@128 (+28.3%) |
| accuracy vs main (teacher-forced) | ✅ top-1 0.9566 (bar ≥0.93) · KL 0.01550 (bar ≤0.03) · PPL ×1.0028 of main (bar ≤1.02) over 1177 tokens |
| prefill path vs main | ✅ batched prefill within main's spread at prefix 128/1024 |
| bonsai_regression.py | ✅ tensors · score · generate · serve |
| qwen3.6 guard | ✅ no regression (decode + prefill @ 32k) |
| modelopt qwen3.8 guard | ✅ no regression (decode + prefill @ 32k) |
| unsloth qwen3.8 guard | ✅ no regression (decode + prefill @ 32k) |
| muse glimmer guard | ✅ no regression (decode + prefill @ 32k) |
| PPL PR / main | 3.6999 / 3.6895 |
| Polaris receipt | collected, not signed (no key configured) |
| commit | 67b9e5e24, measured merged onto main 053ef27 (this round's baseline) |
| ctx | phase | main | PR | delta |
|---|---|---|---|---|
| 128 | decode | 99.01 | 127.01 | +28.3% |
| 128 | prefill | 4939.89 | 5126.23 | +3.8% |
| 512 | decode | 98.38 | 126.09 | +28.2% |
| 512 | prefill | 6611.15 | 7007.25 | +6.0% |
| 4k | decode | 96.84 | 123.62 | +27.7% |
| 4k | prefill | 8920.29 | 9119.79 | +2.2% |
| 16k | decode | 93.55 | 118.35 | +26.5% |
| 16k | prefill | 8924.31 | 8996.71 | +0.8% |
| 32k | decode | 88.59 | 110.51 | +24.7% |
| 32k | prefill | 8454.70 | 8496.10 | +0.5% |
Concurrent decode — aggregate tok/s with N requests in flight, median of 3 runs
| concurrency | main | PR | delta |
|---|---|---|---|
| c2 | 168.90 | 205.30 | +21.6% |
| c4 | 301.20 | 376.90 | +25.1% |
| c8 | 530.00 | 674.00 | +27.2% |
| c16 | 822.20 | 1013.50 | +23.3% |
| c32 | 1115.60 | 1389.10 | +24.5% |
Prefill path — batched prefill against the token loop, 64 teacher-forced positions, mean of 3 runs per side
| prefix | main top-1 | PR top-1 | top-1 bar | main KL | PR KL | KL bar |
|---|---|---|---|---|---|---|
| 128 | 0.984 | 0.984 | ≥0.884 | 0.0055 | 0.0039 | ≤0.0555 |
| 1024 | 0.969 | 0.964 | ≥0.869 | 0.0048 | 0.0046 | ≤0.0548 |
ok
Measured on the pinned RTX 5090 against a same-box origin/main from the same round. Any axis regressing below 98% of main is a REJECT; otherwise the label is the best measured delta. none only means no Ternary-Bonsai-2-27B speedup was measured, which is expected for a change aimed at another model. The round's best passing speedup is auto-merged as bonsai-merge-first (only at the exact commit scored); a separate comment says so. It does not close PRs.
…s past 8 rows read the whole FFN there on the int8 tensor cores (1.43x cb-decode @c16 on Ternary-Bonsai-2) The default Ternary-Bonsai-2 load keeps ffn_gate/ffn_up in their stored PTQ1_0 blocks (0.22 B/weight) instead of the Q4_K refit of the un-rotated weights (0.56 B/weight); the decode shadow then holds only down's ternary copy. 3.9 GB less resident. - packed decode above 8 rows, where the shadow's dp4a GEMMs stop paying and the step went back to the Q4_K fold: hn rotated and int8-quantized once (one scale per 128, the weight block's granularity), gate and up in one int8 tensor-core launch (mma.m16n8k32 u8 x s8, cp.async-staged weights and activation), SwiGLU folded into the FFN-width rotation, then down from the shadow's ternary copy with k split 4 ways (5120 rows are only 40 CTAs). Up to 8 rows keep the shadow's bit-exact path; single-row decode is unchanged. - prefill: the activation rotated and row-quantized in one pass; the fused quantized-B GEMM gets a PTQ1 arm, byte-identical to the materialize kernel used past its M limit, which also feeds the gate+up+SwiGLU epilogue GEMM. SPARKINFER_BONSAI_NATIVE=0 restores the all-folded load; SPARKINFER_BONSAI_CB_TERNARY_DOWN=0 keeps the folded down in the packed step.
67b9e5e to
4b27032
Compare
sparkinfer bonsai auto-eval —
|
| metric | value |
|---|---|
| label | eval-bonsai:XL |
| model | Ternary-Bonsai-2-27B PTQ1_0 GGUF, default (folded) loader |
| scored at | decode + prefill @ 128/512/4k/16k/32k · concurrent decode @ c2/c4/c8/c16/c32 — 15 axes, each also a regression floor; the label is the best |
| tier from | bonsai-cb-decode@c16 (+43.1%) |
| accuracy vs main (teacher-forced) | ✅ top-1 0.9864 (bar ≥0.93) · KL 0.00487 (bar ≤0.03) · PPL ×0.9970 of main (bar ≤1.02) over 1177 tokens |
| prefill path vs main | ✅ batched prefill within main's spread at prefix 128/1024 |
| bonsai_regression.py | |
| qwen3.6 guard | ✅ no regression (decode + prefill @ 32k) |
| modelopt qwen3.8 guard | ✅ no regression (decode + prefill @ 32k) |
| unsloth qwen3.8 guard | ✅ no regression (decode + prefill @ 32k) |
| muse glimmer guard | ✅ no regression (decode + prefill @ 32k) |
| PPL PR / main | 3.6713 / 3.6824 |
| Polaris receipt | collected, not signed (no key configured) |
| commit | 4b270325c, measured merged onto main 20a4fbd (this round's baseline) |
| ctx | phase | main | PR | delta |
|---|---|---|---|---|
| 128 | decode | 132.69 | 132.72 | +0.0% |
| 128 | prefill | 4932.59 | 5163.48 | +4.7% |
| 512 | decode | 131.98 | 131.92 | -0.0% |
| 512 | prefill | 6606.73 | 7043.06 | +6.6% |
| 4k | decode | 129.40 | 129.21 | -0.1% |
| 4k | prefill | 8997.80 | 9164.29 | +1.9% |
| 16k | decode | 123.80 | 123.54 | -0.2% |
| 16k | prefill | 8599.87 | 8675.32 | +0.9% |
| 32k | decode | 115.18 | 114.97 | -0.2% |
| 32k | prefill | 7972.11 | 8011.42 | +0.5% |
Concurrent decode — aggregate tok/s with N requests in flight, median of 3 runs
| concurrency | main | PR | delta |
|---|---|---|---|
| c2 | 207.70 | 208.40 | +0.3% |
| c4 | 361.00 | 363.50 | +0.7% |
| c8 | 555.00 | 563.10 | +1.5% |
| c16 | 801.50 | 1146.80 | +43.1% |
Concurrency c32 not scored this round — no paired measurement (a width that fails to run is dropped, never counted as a regression).
Prefill path — batched prefill against the token loop, 64 teacher-forced positions, mean of 3 runs per side
| prefix | main top-1 | PR top-1 | top-1 bar | main KL | PR KL | KL bar |
|---|---|---|---|---|---|---|
| 128 | 0.990 | 0.995 | ≥0.890 | 0.0069 | 0.0041 | ≤0.0569 |
| 1024 | 0.969 | 0.948 | ≥0.869 | 0.0065 | 0.0055 | ≤0.0565 |
ok
Measured on the pinned RTX 5090 against a same-box origin/main from the same round. Any axis regressing below 98% of main is a REJECT; otherwise the label is the best measured delta. none only means no Ternary-Bonsai-2-27B speedup was measured, which is expected for a change aimed at another model. The round's best passing speedup is auto-merged as bonsai-merge-first (only at the exact commit scored); a separate comment says so. It does not close PRs.
|
Auto-merged as the round's |
|
Note on this run's environment (not a PR result). This round ran on a newly provisioned eval box, and two gaps came from the box, not from this PR:
Neither is a finding against this PR. The tier comes from the measured concurrent-decode gain at c16 (+43.1%), with every accuracy gate and cross-model guard passing. |
Summary
Ternary-Bonsai-2's default load keeps
ffn_gateandffn_uponly in their stored PTQ1_0 blocks (0.22 B/weight), not in the Q4_K refit of the un-rotated weights (0.56 B/weight). Gate and up are already ternary, so the decode shadow's FFN copy is now down's alone. That is 3.9 GB less resident.hnis rotated into the weights' basis and quantized to int8 once, one scale per 128 values (the weight block's granularity, so each block's dot product is exact in int32). Gate and up run in one int8 tensor-core launch (mma.m16n8k32u8 x s8, weights and activation staged by cp.async) that decodes each weight block once for every row. SwiGLU is folded into the FFN-width rotation. Down reads the shadow's ternary copy with k split 4 ways; its 5120 rows are only 40 CTAs, and at 32 rows the split takes it from 71 to 26.5 us.SPARKINFER_BONSAI_NATIVE=0restores the all-folded load.SPARKINFER_BONSAI_CB_TERNARY_DOWN=0keeps the folded down in the packed step.Proof of speedup
sm_120)Target model(s)
Decode tok/s (end-to-end, from
bench/scripts/bench.sh— fill if this PR targets decode):Prefill pp tok/s (fill if this PR targets prefill; use
--ctx 4096,32768,65536, or131072and copy theprefill ppline — report your best context. Keep the row labels as-is):Best prefill context is 512. The numbers come from the bot's invocations on one RTX 5090, main
20a4fbdagainst this branch, with runs interleaved main, PR, PR, main. A sample was re-run if another process touched the GPU during it.qwen3_gguf_bench <gguf> 128 sweep(real prompt ids, REPS=3):qwen3_gguf_cb_bench <gguf> c 256 256 512, aggregate tok/s, 0 request errors:Accuracy.
qwen3_gguf_scoreover the bot'seval_corpus.txt, this PR against main (mean of 4 cross pairs): top-1 0.984, KL 0.0051, PPL 3.677 vs 3.672 (x1.001). Main against itself on the same box reads top-1 0.984 / KL 0.0044.qwen3_gguf_prefill_check(batched prefill against the token loop, 64 continuation positions, mean of 2 runs, top-1 / KL):eval/bonsai_regression.pyserve check (a row that outlives its batch against the same row asked alone): matches on both the default andSPARKINFER_BONSAI_NATIVE=allservers.