docs: Qwen3.8 spec-matrix benchmark page; add matrix tools; final env n_max=5
Recording the 54-config matrix, the realistic-prompt correction (n_max=5 not 10), the ubatch findings (256 is the safe/fast point), and the premature-stop sampling-variance investigation.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Analyze the spec-matrix TSV: per-config median gen t/s, acceptance,
|
||||
sorted, with the top configs and per-spec-type bests."""
|
||||
import sys, statistics, collections
|
||||
|
||||
path = sys.argv[1] if len(sys.argv) > 1 else "/tmp/spec_matrix_results.tsv"
|
||||
rows = []
|
||||
with open(path) as f:
|
||||
header = f.readline().strip().split("\t")
|
||||
for line in f:
|
||||
p = line.rstrip("\n").split("\t")
|
||||
if len(p) < 9:
|
||||
continue
|
||||
spec, n_max, p_min, run, tps, pps, acc, dn, stop = p[:9]
|
||||
try:
|
||||
tps = float(tps)
|
||||
except ValueError:
|
||||
continue
|
||||
rows.append(dict(spec=spec, n_max=n_max, p_min=p_min, run=run,
|
||||
tps=tps, pps=float(pps or 0), acc=acc, dn=dn, stop=stop))
|
||||
|
||||
by_cfg = collections.defaultdict(list)
|
||||
for r in rows:
|
||||
by_cfg[(r["spec"], r["n_max"], r["p_min"])].append(r)
|
||||
|
||||
print("%-22s %5s %5s %8s %8s %10s" % ("spec", "n_max", "p_min", "med_tps", "med_pps", "accept"))
|
||||
summary = []
|
||||
for (spec, n_max, p_min), runs in by_cfg.items():
|
||||
tps_list = [r["tps"] for r in runs]
|
||||
med = statistics.median(tps_list)
|
||||
pps_list = [r["pps"] for r in runs]
|
||||
accs = [r["acc"] for r in runs if r["acc"] not in ("", "None")]
|
||||
acc_s = ""
|
||||
if accs:
|
||||
try:
|
||||
nums = [float(a) for a in accs]
|
||||
acc_s = "%.3f" % (sum(nums)/len(nums))
|
||||
except ValueError:
|
||||
pass
|
||||
summary.append((med, spec, n_max, p_min,
|
||||
statistics.median(pps_list), acc_s, len(runs)))
|
||||
|
||||
summary.sort(reverse=True)
|
||||
for med, spec, n_max, p_min, pps, acc, n in summary:
|
||||
print("%-22s %5s %5s %8.2f %8.2f %10s" % (spec, n_max, p_min, med, pps, acc))
|
||||
|
||||
print("\n=== TOP 12 CONFIGS ===")
|
||||
for med, spec, n_max, p_min, pps, acc, n in summary[:12]:
|
||||
print(" %5.2f t/s spec=%-22s n_max=%2s p_min=%s" % (med, spec, n_max, p_min))
|
||||
|
||||
print("\n=== BEST PER SPEC TYPE ===")
|
||||
best = {}
|
||||
for med, spec, n_max, p_min, pps, acc, n in summary:
|
||||
key = spec
|
||||
if key not in best:
|
||||
best[key] = (med, n_max, p_min, pps, acc)
|
||||
for k, v in best.items():
|
||||
print(" %-22s %5.2f t/s n_max=%s p_min=%s (pps=%s)" % (k, v[0], v[1], v[2], v[3]))
|
||||
|
||||
print("\n=== p_min 0.8 vs off (per spec/n_max, med delta) ===")
|
||||
from itertools import product
|
||||
for spec in sorted(set(r["spec"] for r in rows)):
|
||||
print(" spec:", spec)
|
||||
for n_max in sorted(set(int(r["n_max"]) for r in rows if r["spec"] == spec)):
|
||||
on = [r["tps"] for r in rows if r["spec"] == spec and r["n_max"] == str(n_max) and r["p_min"] == "0.8"]
|
||||
off = [r["tps"] for r in rows if r["spec"] == spec and r["n_max"] == str(n_max) and r["p_min"] == "none"]
|
||||
if on and off:
|
||||
d = statistics.median(on) - statistics.median(off)
|
||||
print(" n_max=%-2s on=%.2f off=%.2f delta=%+.2f" % (n_max,
|
||||
statistics.median(on), statistics.median(off), d))
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env bash
|
||||
# bench-spec-matrix.sh - Qwen3.8-27B UD-Q8_K_XL speculative-decode matrix.
|
||||
# Matrix: spec_type {draft-mtp,ngram-mod | draft-mtp | ngram-mod}
|
||||
# x --spec-draft-n-max {2..10} x --spec-draft-p-min {off, 0.8}
|
||||
# = 54 configs. Each: start llama-server, wait ready, 3 generations of a
|
||||
# 1100-token prompt (n_predict 200, default sampling), record timings.
|
||||
set -u
|
||||
|
||||
MODEL=/home/dank/models/Qwen3.8-27B-UD-Q8_K_XL.gguf
|
||||
LLAMA_SERVER=/home/dank/llama.cpp/build/bin/llama-server
|
||||
PORT=7890
|
||||
DEVICE=ROCm0
|
||||
OUT=/tmp/spec_matrix_results.tsv
|
||||
RUNLOG=/tmp/spec_matrix_run.log
|
||||
PROMPT=$(python3 -c "print(\"The fleet of inference servers must remain available at all times. Operators monitor memory, throughput, and queue depth. \"*50)")
|
||||
N_OUT=200
|
||||
RUNS=3
|
||||
|
||||
: > "$OUT"
|
||||
printf 'spec_type\tn_max\tp_min\trun\ttps\tpps\tdraft_acc\tdraft_n\tstop\n' >> "$OUT"
|
||||
|
||||
cfg=0
|
||||
for spec in "draft-mtp,ngram-mod" "draft-mtp" "ngram-mod"; do
|
||||
for n_max in 2 3 4 5 6 7 8 9 10; do
|
||||
for p_min in none 0.8; do
|
||||
cfg=$((cfg+1))
|
||||
echo "=== CONFIG $cfg/54: spec=$spec n_max=$n_max p_min=$p_min $(date +%T) ===" | tee -a "$RUNLOG"
|
||||
ARGS=(--model "$MODEL" --spec-type "$spec" --spec-draft-n-max "$n_max")
|
||||
# Qwen3.8 bundles its MTP drafter inside the target GGUF; no separate
|
||||
# --spec-draft-model file (llama.cpp auto-detects, b10411+).
|
||||
if [[ "$p_min" != none ]]; then
|
||||
ARGS+=(--spec-draft-p-min "$p_min")
|
||||
fi
|
||||
ARGS+=(--device "$DEVICE" --gpu-layers all --cache-type-k q8_0 --cache-type-v f16
|
||||
--ctx-size 2048 --parallel 1 --batch-size 512 --ubatch-size 128
|
||||
--temp 1.0 --top-k 20 --top-p 0.95 --min-p 0.0
|
||||
--host 127.0.0.1 --port "$PORT")
|
||||
"$LLAMA_SERVER" "${ARGS[@]}" > /tmp/matrix_server.log 2>&1 &
|
||||
SPID=$!
|
||||
ready=0
|
||||
for i in $(seq 1 150); do
|
||||
if curl -sf "http://127.0.0.1:$PORT/health" > /dev/null 2>&1; then ready=1; break; fi
|
||||
if ! kill -0 "$SPID" 2>/dev/null; then break; fi
|
||||
sleep 2
|
||||
done
|
||||
if [[ "$ready" != 1 ]]; then
|
||||
echo "NOT_READY: spec=$spec n_max=$n_max p_min=$p_min" | tee -a "$RUNLOG"
|
||||
tail -4 /tmp/matrix_server.log >> "$RUNLOG"
|
||||
kill "$SPID" 2>/dev/null; wait "$SPID" 2>/dev/null
|
||||
continue
|
||||
fi
|
||||
for r in 1 2 3; do
|
||||
curl -s -m 300 -X POST "http://127.0.0.1:$PORT/completion" -H "Content-Type: application/json" \
|
||||
-d "{\"prompt\": \"$PROMPT\", \"n_predict\": $N_OUT, \"stream\": false, \"cache_prompt\": false}" \
|
||||
| python3 -c "
|
||||
import json,sys
|
||||
try:
|
||||
d=json.load(sys.stdin)
|
||||
t=d.get('timings',{})
|
||||
row=[\"$spec\",\"$n_max\",\"$p_min\",\"$r\",
|
||||
str(round(t.get('predicted_per_second',0),2)),
|
||||
str(round(t.get('prompt_per_second',0),2)),
|
||||
str(t.get('draft_n_accepted','')),
|
||||
str(t.get('draft_n','')),
|
||||
str(d.get('stop_type',''))]
|
||||
with open(\"$OUT\",\"a\") as f:
|
||||
f.write('\t'.join(row)+'\n')
|
||||
except Exception as e:
|
||||
with open(\"$OUT\",\"a\") as f:
|
||||
f.write('\t'.join([\"$spec\",\"$n_max\",\"$p_min\",\"$r\",\"ERR\",str(e),\"\",\"\",\"\"])+'\n')
|
||||
"
|
||||
done
|
||||
kill "$SPID" 2>/dev/null; wait "$SPID" 2>/dev/null
|
||||
sleep 3
|
||||
done
|
||||
done
|
||||
done
|
||||
echo "=== MATRIX DONE $(date) ===" | tee -a "$RUNLOG"
|
||||
Reference in New Issue
Block a user