The LLM fleet documentation (deployment runbook, model runbooks, benchmarks, research archive, retired-topology history) joins the project knowledge base as docs/LLM/. Wikilinks resolve by filename, so no link updates are needed for the move.
7.5 KiB
SUPERSEDED 2026-08-17. The Frank redo retired this topology. See frank-redo-2026-08-17.md and deployment.md for the active configuration.
Qwen3.8-27B Speculative-Decoding Matrix
This page records the speculative-decoding benchmark history and the
production tuning for the Qwen3.8-27B service (frank-default-large),
now a pipeline-parallel head with a Dankserver worker.
Production state (2026-08-17: Q6_K, q8_0/f16 KV, split 0.68)
Current production, verified against the live process and journal (2026-08-17, load 02:06 + smoke tests). Topology detail: Pipeline Parallelism/Qwen3.8 PP Deployment.
- Devices:
RPC0(Dankserver RTX 3090) +ROCm0(Strix iGPU). The head passes no--deviceflag. Default selection puts RPC first and picks ROCm for the iGPU (HIP registers before Vulkan). The Vulkan0 side stays an option viaHEAD_BIN=.../build-vulkan-rpc. - Model:
Qwen3.8-27B-Uncensored-Q6_K.gguf(JonathanColetti, 22.43 GB, imatrix, 65 blocks, 866 tensors, NO bundled MTP head). The repo's standalone draft sidecarQwen3.8-27B-Uncensored-draft-Q8_0.gguf(3.16 GB) is loaded via--spec-draft-model; it runs on ROCm0 only (1718 MiB, zero worker impact). - Spec: MTP (standalone draft)
--spec-draft-n-max 4+ the--spec-defaultngram-mod fallback (48/64/24). Measured acceptance 0.83 then 0.75, mean len 4.0-4.3, per-position ~0.86/0.71/0.71/0.71 — stronger than the old bundled head (0.739/0.554/0.427/0.340). - KV: K q8_0 + V f16 (mismatched). 3136 B/token per FA layer =
784 MiB at 262144 (K 1088 + V 2048). RPC0 8624 MiB (11 FA), ROCm0
3920 MiB (5 FA); total 12544 = 16 x 784. Flash Attention stays
enabled with the mismatch (
resolve_fused_ops: Flash Attention enabled) via the GGML_CUDA_FA_ALL_QUANTS rebuild of both binaries at 9b05354ec — see the PP doc. - Split:
--tensor-split 0.68,0.32= 45 of 65 blocks (0-44) on the 3090, 69% of the layer weight. The maximum: 46 blocks -> ~0.3 GiB margin; 48 blocks (f >= 0.7197) adds FA block 47 -> KV 9408 -> OOM by ~0.85 GiB. Boundary math: the PP doc. - Context: pool 262144, 1 slot,
n_ctx_slot = 262144. The pimodels.jsondeclares 262144 (contextWindow = maxTokens, house convention). - Worker steady state: 23854/24576 MiB used on the 3090, ~273 MiB free (tight but stable; all allocations happen at load).
- Batch 8192 / ubatch 256,
--direct-io,--fit off,--gpu-layers all.
How MTP works on Qwen3.8 (bundled-head era)
The unsloth UD-* GGUFs keep the MTP (Multi-Token Prediction) head inside
the model file. llama.cpp b10411+ auto-detects it and creates the draft
context from the target model. Do not pass --spec-draft-model for those
files. This is superseded: the production Qwen3.8-27B-Uncensored-Q6_K.gguf
has NO bundled head, and the serve script passes the standalone draft
sidecar with --spec-draft-model (see Production state above).
The stock llama.cpp build must be b10411 or newer. The 2026-08-14 rebuild
on Dankclaw is b10433 (9b05354ec) with GGML_HIP + gfx1151 + Vulkan.
History (superseded configurations, 2026-08-14 to 08-16)
All superseded configs used Qwen3.8-27B-UD-Q8_K_XL.gguf (29.29 GiB,
bundled MTP) before the Q6_K swap. The ngram-mod preset survives as the
fallback layer under MTP. The Vulkan0 verdict from this era applies to the
standalone configuration only; the PP head runs ROCm0.
- 2026-08-14: bundled MTP —
draft-mtp, n_max 5, parallel 2, ctx 524288 (2 x 262144). ~13.3 t/s single, ~8 t/s per slot under 2 concurrent streams. No premature stop. - 2026-08-15: DSpark sidecar —
magnitudedev/Qwen3.8-27B-DSpark-GGUF(Q8_0, 1.36B, block_size 7), n_max 7, PARALLEL=1. Two concurrent 16k prose prompts crashed the ROCm backend withROCm error: an illegal memory accessincommon_speculative_impl_draft_dflash::draft(status 6/ABRT, systemd restart, ~503 during reload). DSpark reuses the DFlash block-diffusion machinery, which shares one draft context across parallel slots; concurrent block drafting faults in HIP stream sync. This is the same multi-slot bug class that retireddraft-dflash(premature EOS). The crash shows on 16k concurrent streams, not on a 67k pair — concurrency is the trigger, not size. Fix: PARALLEL=1 (requests queue safely). Retired the same day. - 2026-08-15 to 08-16:
--spec-default(ngram-mod), Vulkan0 — n_match 24 / n_min 48 / n_max 64, draftless, PARALLEL=2 (2 x 32k parallel stream test passes). Chosen for parallel safety after DSpark; kept as the fallback under MTP in the current config.
Benchmark Method
The matrix ran 54 configurations: 3 spec types (draft-mtp,ngram-mod,
draft-mtp, ngram-mod) x --spec-draft-n-max 2..10 x
--spec-draft-p-min {off, 0.8}. Each config loaded llama-server,
then ran 3 generations. The tool is scripts/spec-matrix-bench.sh;
analysis is scripts/analyze-spec-matrix.py.
Matrix Caveat: Benchmark Prompt
The matrix used a repetitive 1100-token prompt
(scripts/bench_live.sh style). MTP drafts that repeated sentence almost
perfectly, which inflated the numbers for long drafts. The matrix reported
draft-mtp n_max=10 at ~30 t/s. A realistic story prompt gave very
different results:
| n_max | median t/s (realistic) |
|---|---|
| 4 | 12.5 |
| 5 | 13.3 (peak) |
| 6 | 10.6 |
| 7 | 10.1 |
| 10 | 8.6 |
| none (baseline) | 7.2 |
Long drafts collapse to ~18% acceptance on real writing. n_max=5 balances acceptance against draft cost.
Premature Stop Investigation
Two failure patterns appeared during early production tests:
- Speed collapse.
ubatch >= 512reduced MTP acceptance to ~25% and generation to ~9 t/s.ubatch 128withbatch >= 2048triggered a premature instant-EOS under 2 concurrent slots.ubatch 256avoids both: ~30 t/s single, concurrent-safe. - Apparent premature-EOS. The repetitive benchmark prompt with
temp 1.0sometimes stops after 1-2 tokens because the model legitimately emits an EOS on a wall of repeated text. This is sampling variance, not a corruption bug. Realistic prompts never stop early.
High-Context Backend Comparison (2026-08-15)
Tool: scripts/bench-high-ctx.sh <device> <ctx>. Both runs at ctx 262144
with a ~200k-token realistic-prose prompt, --spec-default, batch 8192 /
ubatch 256, single slot, on scratch port 7892.
| Device | Prompt tokens | Prefill (t/s) | Generation (t/s) | Wall (single req) |
|---|---|---|---|---|
| ROCm0 | 202822 | 119.1 | 3.83 | 1770 s |
| Vulkan0 | 200235 | 106.3 | 5.68 | 1929 s |
Verdict: at very high context, Vulkan0 decodes 48% faster (5.68 vs
3.83 t/s); ROCm0 prefills 12% faster. Generation is the interactive cost
(users stream tokens). This verdict applies to the standalone
configuration; the PP head runs ROCm0 (HIP registers before Vulkan).
Both tg_3s values were rock-steady across the run (3.83 and 5.67 t/s).
High-context decode collapses on both backends versus ~25 t/s at 16k ctx;
that is the long-context attention penalty, not a spec artifact.
Production Configuration
The live tunables live in scripts/frank-default-large.env (head) and
scripts/frank-pp-worker.env (worker) in this repo. The Production
state section at the top of this page records the current values: Q6_K
model + standalone MTP draft, split 0.68/0.32, 262144 ctx, PARALLEL=1,
q8_0/f16 KV.