test(frank-medium): A/B DFlash2 vs MTP on FP8 — DFlash2 wins on decode
DFlash2 (100.0 t/s decode, 287.1 t/s burst-4) beats MTP self-speculation (85.9 t/s, 179.7 t/s) despite a lower accept length (4.24 vs 5.66): the small separate drafter steps faster than the target's own MTP layer applied autoregressively. DFlash2 is the deployed shape; both swap-script paths now default to dflash/7. Docs updated.
This commit is contained in:
1 parent
1ae73db084
commit
f998a2d9f2
6 files changed
+111
-44
No files matched your search
@@ -54,7 +54,7 @@ From `dankserver/frank-medium/quadlet/frank-medium.container`:
|
||||
| Setting | Value |
|
||||
|---|---|
|
||||
| Model | `orcarouter/Qwen3.8-27B-Uncensored-FP8` (FP8 E4M3 block-wise 128×128, 30.9 GB / 7 shards) |
|
||||
| Speculative | `--speculative-config {"method":"mtp","num_speculative_tokens":8}` (the model's own single-layer MTP head; mean acceptance 5.66/8, 66.2% draft acceptance) |
|
||||
| Speculative | `--speculative-config {"method":"dflash","model":"/models/Qwen3.8-27B-DFlash2-FP8","num_speculative_tokens":7}` (the z-lab DFlash2 external drafter; mean acceptance 4.24/7. A/B tested against MTP self-speculation — DFlash2 wins on decode, see below) |
|
||||
| Parallelism | `--tensor-parallel-size 2` (`ROCR_VISIBLE_DEVICES=0,1`) |
|
||||
| Context | `--max-model-len 262144` |
|
||||
| Concurrency | `--max-num-seqs 8`, chunk 8192 |
|
||||
@@ -67,17 +67,43 @@ From `dankserver/frank-medium/quadlet/frank-medium.container`:
|
||||
| Chat template | `qwen-fixed-v22.3.jinja` (patch dir bind-mounted, `MM_MERGE_ENGINE=AXROW_SEPARATE` for Gemma4 vision) |
|
||||
|
||||
**The KV pool is auto-sized, not pinned.** Production ships no `KV_MEM` pin
|
||||
(`KV_MEM=0`): the pool comes up at whatever VRAM the weights leave. The FP8
|
||||
checkpoint is bigger than the MXFP4 one (30.9 vs 19.4 GiB of weights), so it
|
||||
leaves less for the pool: the 2026-09-20 FP8 start auto-sized to **461,540
|
||||
tokens = 1.76× the full window** (`GPU KV cache size: 461,540 tokens`,
|
||||
`Maximum concurrency for 262,144 tokens per request: 1.76x`). The MXFP4
|
||||
rollback target auto-sized to 943,581 tokens (3.59×) on the same cards.
|
||||
Per-token cost in steady state is 19,673 B — fp8 KV across the model's 16
|
||||
full-attention layers plus the MTP drafter's. After the first healthy start,
|
||||
(`KV_MEM=0`): the pool comes up at whatever VRAM the weights + drafter leave.
|
||||
The FP8 checkpoint is bigger than the MXFP4 one (30.9 vs 19.4 GiB of
|
||||
weights), and the DFlash2 drafter is a separate 2.1 GiB model, so the pool
|
||||
is the smallest of the three shapes: the 2026-09-20 DFlash2 start auto-sized
|
||||
to **384,238 tokens = 1.47× the full window** (`GPU KV cache size: 384,238
|
||||
tokens`, `Maximum concurrency for 262,144 tokens per request: 1.47x`). The
|
||||
MTP shape (no external drafter) auto-sized to 461,540 (1.76×); the MXFP4
|
||||
rollback target to 943,581 (3.59×). After the first healthy start,
|
||||
recalibrate with `calibrate-kv.sh` to use the extra VRAM on the 34.2 GiB
|
||||
cards.
|
||||
|
||||
## DFlash2 vs MTP — A/B on the FP8 checkpoint (2026-09-20)
|
||||
|
||||
The FP8 checkpoint carries its own single-layer MTP head, so it can self-
|
||||
speculate (`SPEC_METHOD=mtp`) or use the z-lab DFlash2 external drafter
|
||||
(`SPEC_METHOD=dflash`, a separate quantization-agnostic 2.1 GiB
|
||||
`DFlash2DraftModel`). Both were deployed and measured on the same FP8 target
|
||||
(`scripts/bench-conversation.py`, 10 real prompts, `max_tokens=512`, greedy,
|
||||
salted, `--burst 4`):
|
||||
|
||||
| Arm | Mean accept | Decode (geomean) | TTFT (mean) | Prefill (geomean) | Burst-4 aggregate | KV pool |
|
||||
|---|---|---|---|---|---|---|
|
||||
| **DFlash2** (depth 7) | 4.24/7 | **100.0 t/s** | 0.19 s | 923.0 t/s | **287.1 t/s** | 384,238 (1.47×) |
|
||||
| MTP self-spec (depth 8) | 5.66/8 | 85.9 t/s | 0.06 s | 1096.9 t/s | 179.7 t/s | 461,540 (1.76×) |
|
||||
|
||||
**DFlash2 wins on decode (+16 %) and burst-4 (+60 %); MTP wins on TTFT and
|
||||
prefill.** The counterintuitive part: DFlash2 accepts *fewer* tokens per step
|
||||
(4.24 vs 5.66) yet decodes *faster*. Accept length is a proxy, not the metric
|
||||
— throughput is `(accept + 1) / (draft time + verify time)`. The DFlash2
|
||||
drafter is a small separate model that steps fast; the MTP head is the
|
||||
target's own layer applied autoregressively 8×, so its draft is slower. The
|
||||
faster step more than makes up the lower accept length. FP8 + DFlash2 (100.0
|
||||
t/s) also beats the original MXFP4 + DFlash2 (92.4 t/s) — the higher-precision
|
||||
FP8 target verifies more of the drafter's proposals. The drafter costs 2.1 GiB
|
||||
of VRAM (the KV pool is 1.47× vs MTP's 1.76×), an acceptable trade for the
|
||||
decode win. **DFlash2 is the deployed shape.**
|
||||
|
||||
## Prefix caching — measured granularity (2026-09-20)
|
||||
|
||||
`--enable-prefix-caching` is on, and radiance says so at boot: *"Prefix caching
|
||||
|
||||
Reference in new issue
Block a user