Measure speculative decoding: all ngram modes lose to plain decoding
Verifying a K-token draft costs ~K times the CPU expert work, because each token routes to its own 8-of-256 experts and nothing is amortized. The loss is largest on structured code output (-51% for ngram-simple), i.e. exactly where speculation should have won. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -113,12 +113,36 @@ Generation falls off ~40% between empty and ~97k, which is the attention cost on
|
||||
10 full-attention layers. Prefill stays flat around 420–490 t/s, so filling the whole
|
||||
128k window takes roughly 4–5 minutes.
|
||||
|
||||
### 5. Rejected
|
||||
### 5. Speculative decoding makes it slower — don't enable it
|
||||
|
||||
Counter-intuitive but consistent, `--n-predict 400`, thinking disabled:
|
||||
|
||||
| workload | none | ngram-mod | ngram-simple | ngram-cache |
|
||||
|---|---|---|---|---|
|
||||
| rewrite (output ≈ copy of prompt) | **55.6** | 40.6 | 39.7 | 47.0 |
|
||||
| extend (structured code) | **55.3** | 32.7 | 27.2 | 38.1 |
|
||||
| prose (novel text, control) | **56.1** | 54.7 | 52.9 | 48.4 |
|
||||
|
||||
Every mode loses, and it loses *most* on exactly the structured workloads
|
||||
speculation is supposed to win. The reason is the CPU-side experts: verifying a
|
||||
K-token draft costs about K times the CPU expert work, because each token routes to
|
||||
its own subset of 8 out of 256 experts, so there is no weight reuse to amortize.
|
||||
On a fully GPU-resident model batch verification is nearly free; with
|
||||
`--n-cpu-moe` it is not. Reconsider only if the model ever fits entirely in VRAM.
|
||||
|
||||
### 6. Rejected
|
||||
|
||||
- `-ub 256`: frees only ~80 MiB per GPU (not the 469 MiB an extra layer needs) and
|
||||
costs **38% prefill** (556 → 347 t/s). Keep the default `-ub 512`.
|
||||
- Lower `-ts` toward CUDA1 (e.g. `23,17`): would leave CUDA1 at ~60 MiB free.
|
||||
|
||||
### A note on the CUDA0 headroom
|
||||
|
||||
Free VRAM on CUDA0 was observed drifting between ~1100 and ~1300 MiB across restarts
|
||||
purely from desktop compositor churn — a ~200 MiB swing with nothing else changing.
|
||||
That is why the default keeps >1 GiB spare there rather than the 388 MiB that
|
||||
`ncmoe=8` leaves.
|
||||
|
||||
## Deploy
|
||||
|
||||
```bash
|
||||
@@ -133,6 +157,7 @@ Loads in ~15 s (`--no-mmap`, weights read from NVMe).
|
||||
```bash
|
||||
python3 bench/bench.py --port 18008 --depths 512,8192,32768 --n-predict 128
|
||||
./bench/sweep.sh 10:24,16:8 8:24,16:8 # <ncmoe>:<tensor-split>:<threads>
|
||||
python3 bench/spec_bench.py --no-think # copy/code/prose generation workloads
|
||||
```
|
||||
|
||||
`bench.py` issues a warmup request first — without it the first measurement reads
|
||||
|
||||
Reference in New Issue
Block a user