Qwen3.8-27B auf Strix Halo
Von 7,7 zu 30,9 tok/s — Faktor 4,0. Zwei unabhängige Hebel, keine Qualitätseinbußen. Der vollständige Optimierungsleitfaden für Dense-27B-Modelle auf AMD Strix Halo.
Ryzen AI MAX+ PRO 395 · Radeon 8060S (40 CUs) · LPDDR5X-8533 (128 GB) · ROCm gfx1151 · llama.cpp ≥ b10419
Die Reise: von 7,7 zu 30,9 tok/s
- 1
Ausgangslage: Q8_0
Vorher 7,7 tok/sNachher 7,7 tok/s+0 %Qwen3.8-27B als Q8_0-Quant — 28 GB Gewichte, volle Bandbreiten-Auslastung. Keine Optimierung möglich, die Hardware ist am Limit.
- 2
Hebel 1: IQ4_XS-Quantisierung
Vorher 7,7 tok/sNachher 13,3 tok/s+73 %Das Modell schrumpft von 28 auf 15 GB. Dadurch halbiert sich die Speicherlast pro Token — die GPU muss nur noch 15 GB statt 28 GB durch ihren Bus bewegen. Ergebnis: 92 % der theoretischen Bandbreiten-Grenze.
- 3
Hebel 2: MTP Speculative Decoding
Vorher 13,3 tok/sNachher 30,9 tok/s+132 %Qwen3.8 hat eine eingebaute Multi-Token-Prediction-Schicht. Der Rater generiert 3–4 Tokens in einem Durchgang, das Hauptmodell verifiziert sie. Bei Code liegt die Trefferquote bei ~73 % — 3,2 Tokens pro Verification-Durchgang. Mathematisch identisch zur normalen Generierung, keine Qualitätseinbuße.
$QUANT=IQ4_XS BACKEND=rocm ./run.sh start
Die Bandbreiten-Wand
| Quant | Größe | Theoretisch | Gemessen | Ausnutzung |
|---|---|---|---|---|
| IQ4_XS | 14,6 GiB | ~14,5 t/s | 13,3 t/s | 92 % |
| UD-Q4_K_XL | 17,1 GiB | ~12,5 t/s | 12,0 t/s | 96 % |
| Q8_0 | 28,0 GiB | ~7,7 t/s | 7,7 t/s | 100 % |
Dense 27B = Worst Case
MoE ändert die Rechnung
IQ4_XS gegen Q8_0 — der Quanten-Kompromiss
QUANT=. Die Entscheidung ist einfach.IQ4_XS — Standard
- 15 GB — halbiert die Speicherlast gegenüber Q8_0
- 13,3 tok/s Basis — 30,9 mit MTP
- 1–2 % Perplexity-Verlust (Literaturwert) — im Alltag nicht wahrnehmbar
- Tool-Calling: 10/10 Punkte im Hart-Test
Q8_0 — nur für Präzision
- 28 GB — doppelt so groß, kein Platz für Nebenmodelle
- 7,7 tok/s — 35–43 % langsamer als IQ4_XS
- Gegenüber BF16 praktisch verlustfrei
- MTP wirkt relativ stärker (2,61× gegen 2,32×)
Leistung je Quant und Backend
| Quant | Backend | pp512 (t/s) | tg128 (t/s) |
|---|---|---|---|
| IQ4_XS | rocm | 434,6 | 13,38 |
| IQ4_XS | vulkan-perf | 385,2 | 13,32 |
| IQ4_XS | vulkan | 378,4 | 13,29 |
| UD-Q4_K_XL | rocm | 403,0 | 11,70 |
| UD-Q4_K_XL | vulkan-perf | 388,1 | 11,98 |
| UD-Q4_K_XL | vulkan | 372,5 | 11,98 |
| Q8_0 | rocm | 388,4 | 7,72 |
| Q8_0 | vulkan-perf | 345,7 | 7,74 |
| Q8_0 | vulkan | 325,0 | 7,76 |
Das Backend ist bei der Generierung irrelevant — 13,29 gegen 13,38 sind unter 1 %. Beim Prompt-Processing gewinnt ROCm +15 % (compute-bound). Bei ≥ 8 parallelen Requests dreht sich das Bild.
$# IQ4_XS (Standard)
$QUANT=IQ4_XS BACKEND=rocm ./run.sh start
$# Q8_0 (höchste Präzision)
$QUANT=Q8_0 BACKEND=rocm ./run.sh start
MTP Speculative Decoding — der eigentliche Hebel
Qwen3.8 hat eine eingebaute Multi-Token-Prediction-Schicht (mtp_num_hidden_layers: 1). Kein separates Draft-Modell, kein Tokenizer-Mismatch. Einfach --spec-type draft-mtp.
Wie es funktioniert: Der Rater generiert 3–4 Tokens in einem Durchgang. Das Hauptmodell verifiziert sie alle parallel. Bei Code ~73 % Trefferquote — die getroffenen Tokens sind geschenkt, kein zusätzlicher Speicherdurchlauf nötig. Das Ergebnis ist mathematisch identisch mit normaler Generierung.
| Modell | Prompt-Art | Ohne | Mit MTP | Faktor |
|---|---|---|---|---|
| IQ4_XS | Code | 13,29 | 30,85 | 2,32× |
| IQ4_XS | Prosa | 13,28 | 25,02 | 1,88× |
| Q8_0 | Code | 7,69 | 20,03 | 2,61× |
| Q8_0 | Prosa | 7,69 | 14,34 | 1,86× |
Code profitiert mehr
Q8_0 profitiert relativ mehr
$# Standard-Start mit MTP
$./run.sh start
$# Oder manuell im Container:
$llama-server --model Qwen3.8-27B-IQ4_XS.gguf \
$ --spec-default --spec-type draft-mtp \
$ --fa 1 --no-mmap --split-mode layer
Tool-Calling: llama-server gegen Ollama
| Modell | Quant | Stack | Punkte | Ø Antwortzeit |
|---|---|---|---|---|
| Qwen3.8-27B | IQ4_XS | llama-server | 10/10 | 4,2 s |
| DeepSeek V4 Flash | IQ2_M | llama-server | 10/10 | 8,4 s |
| glm-4.7-flash | — | Ollama | 10/10 | 4,1 s |
| DeepSeek V4 Flash | IQ2_M | Ollama | 8/10 | 14,6 s |
Qualitativ gleichauf
Einschränkungen
Qwen3.8 gegen DeepSeek V4 Flash
| Modell | Verfahren | Code (t/s) | Prosa (t/s) | Speicher | Faktor |
|---|---|---|---|---|---|
| Qwen3.8-27B IQ4_XS | MTP | 30,85 | 25,02 | 15 GB | 2,32× |
| DeepSeek V4 Flash IQ2_M | DSpark | 21,91 | 15,65 | 95 GB | 1,43× |
Qwen3.8 gewinnt praktisch
Warum DSpark schwächer wirkt
$PROFILE=ds4 ./run.sh start
$./spec-test.py ds4
KV-Cache: klein, aber fein
| Kontext | f16 | q8_0 |
|---|---|---|
| 32k | ~2,0 GiB | ~1,1 GiB |
| 262k | ~16 GiB | ~8,5 GiB |
$# Empfohlen: q8_0 KV-Cache
$--cache-type k:q8_0 --cache-type v:q8_0
$# Für maximale Kontextlänge (262k) bei minimalem Speicher
$--ctx-size 262144 --cache-type k:q8_0 --cache-type v:q8_0
Fallstricke — was schiefgehen kann
KV-Cache q4_0/q4_1
Bei dieser Architektur bricht der Prefill um Faktor 20 ein (llama.cpp #27109). q8_0 ist sicher.
Split-Mode: layer, nicht tensor
Mit MTP führt --split-mode tensor zu Lockups (#27122). layer ist stabil.
-fa 1 und --no-mmap sind Pflicht
Ohne FlashAttention Abstürze, ohne --no-mmap massive Einbrüche. Diese Flags sind auf Strix Halo nicht optional.
Vision ist defekt
Auf AMD AI Max als defekt gemeldet (#27124). Der Textpfad läuft, Multimodalität wurde hier nicht verifiziert. Die mmproj-Datei liegt bereit, aber ungetestet.
Thinking-Mode ist Default
Per Default ist reasoning_effort: xhigh. Bei knappem max_tokens kommt leerer Content zurück. Abschalten: {"enable_thinking": false} oder reasoning_effort: "none".
llama.cpp ≥ b10419
Das System-llama.cpp ist zu alt. Alles läuft über die kyuz0-Container (aktuell b10450). Wer selbst baut, muss ≥ b10419 ziehen.
Werkzeuge: Kurzbefehl und Live-Dashboard
ki — der Kurzbefehl
monitor.py — Live-Dashboard
q.| Datei | Zweck |
|---|---|
| cockpit.py | Auswahlmenü: Modell, Backend, Spec, Kontext, Aktion |
| monitor.py | Live-Dashboard: Prefill/Decode, Draft-Trefferquote, GPU |
| run.sh | llama-server im Container: start|stop|status|logs|shell |
| bench.sh | Matrix Quant × Backend → ERGEBNISSE.md |
| spec-test.py | Speculative Decoding mit/ohne; Profil als Argument |
| autorun.sh | wartet auf Download, startet dann bench.sh |
$# Ein Befehl für alles
$ki
$# Oder direkt starten
$./run.sh start