--- license: apache-2.0 license_link: https://huggingface.co/Qwen/Qwen3.8-27B/blob/main/LICENSE base_model: - Qwen/Qwen3.8-27B base_model_relation: quantized pipeline_tag: image-text-to-text library_name: llama.cpp language: - de - en tags: - gguf - llama.cpp - mtp - speculative-decoding - qwen3 - multimodal --- # Qwen3.8-27B GGUF — **mit separatem MTP-Draft** GGUF-Konvertierung von [Qwen/Qwen3.8-27B](https://huggingface.co/Qwen/Qwen3.8-27B), gebaut am 14.08.2026 aus den **BF16**-Originalgewichten. Der Grund für dieses Repo ist die Datei **`qwen3.8-27b-MTP-Q8_0.gguf`**: der Multi-Token-Prediction-Kopf als eigenständiges Draft-Modell, direkt nutzbar mit `--spec-type draft-mtp`. Die MTP-Gewichte stecken im Upstream-Checkpoint (`mtp_num_hidden_layers` in der `config.json`), werden von den üblichen GGUF-Repos aber nicht als getrennte Datei ausgeliefert — und ohne getrennte Datei kann `llama-server` sie nicht als Draft laden. **Es bringt Faktor 1,6 bis 2,7.** Gemessen, nicht geschätzt — siehe unten. ## Dateien | Datei | Größe | BPW | Zweck | |---|---|---|---| | `qwen3.8-27b-Q8_0.gguf` | 27,3 GB | 8,50 | Zielmodell — **empfohlen** | | `qwen3.8-27b-Q6_K.gguf` | 21,0 GB | 6,57 | kleinere Alternative | | `qwen3.8-27b-MTP-Q8_0.gguf` | 3,0 GB | — | **MTP-Draft** für spekulatives Dekodieren | | `qwen3.8-27b-mmproj-F16.gguf` | 0,9 GB | — | Vision/Video-Projektor | Die MTP-Tensoren sind aus den Zielmodellen **entfernt** (`--no-mtp`) und liegen ausschließlich in der Draft-Datei. Ziel- und Draft-Datei gehören zusammen. **Warum Q8_0 empfohlen ist, obwohl es größer ist:** In der Messung war es durchgehend **schneller** als Q6_K — 39,5 gegen 32,8 t/s bei Fließtext, gleiche Einstellungen. Die k-Quant-Blockstruktur von Q6_K braucht pro Gewicht mehr Rechenschritte zum Entpacken als das schlichtere Q8_0. Mehr Bytes, weniger Arbeit. Q8_0 ist also gleichzeitig schneller *und* genauer. ## Verwendung ```bash llama-server \ -m qwen3.8-27b-Q8_0.gguf \ --mmproj qwen3.8-27b-mmproj-F16.gguf \ -md qwen3.8-27b-MTP-Q8_0.gguf \ --spec-type draft-mtp --spec-draft-n-max 3 --spec-draft-ngl 99 \ --ctx-size 97000 --parallel 1 \ --n-gpu-layers 99 --tensor-split 1,1,1 \ --cache-type-k q8_0 --cache-type-v q8_0 \ --flash-attn on --jinja ``` Ohne Spekulation einfach `-md` und die drei `--spec-*`-Schalter weglassen. Ohne Bildeingabe zusätzlich `--mmproj` weglassen. ## Was MTP tatsächlich bringt Beide Läufe mit **identischer** Konfiguration (Q8_0, 97K Kontext, eine Session), einziger Unterschied ist das Draft-Modell. Deutsche Prompts, je 2–3 Durchgänge, ausgewertet wird der Median. Die Zahlen kommen aus `timings.predicted_per_second` bzw. `timings.draft_n` / `draft_n_accepted`, die `llama-server` pro Anfrage selbst meldet. | Textsorte | ohne Draft | **mit Draft** | **Faktor** | Draft-Trefferquote | |---|---|---|---|---| | Wiederholung | 22,9 t/s | **62,0 t/s** | **2,71×** | 85,0 % | | Aufzählung | 23,0 t/s | **61,6 t/s** | **2,68×** | 93,1 % | | Übersetzung | 22,9 t/s | **51,8 t/s** | **2,26×** | 70,9 % | | Struktur / JSON | 23,0 t/s | **47,6 t/s** | **2,07×** | 59,7 % | | Fachtext | 23,0 t/s | **41,7 t/s** | 1,81× | 48,0 % | | Code | 23,0 t/s | **41,1 t/s** | 1,79× | 48,9 % | | Fließtext | 22,9 t/s | **39,5 t/s** | 1,72× | 44,5 % | | Kreativtext | 23,0 t/s | **35,9 t/s** | **1,56×** | 37,4 % | Gesamt über alle Textsorten: **57,3 % Trefferquote** (4.491 von 7.842 Draft-Token). ### Der wichtigste Befund **Ohne Draft ist die Rate völlig flach — 22,9 bis 23,0 t/s, egal was man generiert.** Mit Draft spreizt sie sich um Faktor 1,7 auseinander, weil die Trefferquote massiv an der Textsorte hängt: vorhersagbarer Text wird zu über 90 Prozent korrekt geraten, freier Kreativtext nur zu gut einem Drittel. Wer MTP an einem Aufzählungs-Benchmark misst, kommt auf 2,7× und überschätzt den Nutzen für normale Chatlast deutlich. Der realistische Wert für Fließtext-Dialog liegt bei **rund 1,7×**. ### Was der Draft kostet * **3,0 GB** auf der Platte * **rund 2,7 GB VRAM** (`[spec] estimated memory usage of draft model is 2678.78 MiB` bei 97K Kontext; 1.953 MiB bei 4K) * Ladezeit steigt kaum — 7 bis 27 Sekunden je nach Kontextgröße Deutlich mehr als etwa der Gemma-4-12B-Draft mit 0,5 GB. Wer knapp an VRAM ist, muss das einplanen. ## Testaufbau * 3× NVIDIA RTX 3080 20 GB — **Ampere, SM 8.6** * AMD EPYC 7F32, 8 Kerne / 16 Threads * llama.cpp Build **10423** (`a94d563ed`), Container `ghcr.io/ggml-org/llama.cpp:full-cuda` * `--tensor-split 1,1,1`, KV-Cache `q8_0`, `--flash-attn on` * Eine Session (`--parallel 1`), 97.024 Token Kontext * Belegt: 31,2 GB von 60 GB — Modell 27,3 + Draft 2,7 + KV/Puffer Der Kontext ist praktisch gratis: dieselbe Konfiguration mit nur 4K statt 97K lieferte im Rahmen der Messstreuung dieselben Werte (58,8 gegen 60,5 t/s bei Aufzählungen). Man kann den großen Kontext also mitnehmen, ohne Durchsatz zu bezahlen. ## Wie diese Dateien gebaut wurden ```bash # Zielmodell ohne MTP-Tensoren convert_hf_to_gguf.py Qwen3.8-27B/ --outfile tmp-BF16.gguf --outtype bf16 --no-mtp # nur der MTP-Kopf, als Draft convert_hf_to_gguf.py Qwen3.8-27B/ --outfile qwen3.8-27b-MTP-Q8_0.gguf --outtype q8_0 --mtp # Vision/Video-Projektor convert_hf_to_gguf.py Qwen3.8-27B/ --outfile qwen3.8-27b-mmproj-F16.gguf --outtype f16 --mmproj # quantisieren llama-quantize tmp-BF16.gguf qwen3.8-27b-Q8_0.gguf Q8_0 16 llama-quantize tmp-BF16.gguf qwen3.8-27b-Q6_K.gguf Q6_K 16 ``` Die Flags `--mtp` und `--no-mtp` sind neu; ältere llama.cpp-Builds kennen sie nicht. Die Architektur `Qwen3_5ForConditionalGeneration` (Qwen3.8 nutzt sie unverändert weiter) erbt `supports_mtp_export = True` über `Qwen3_5TextModel → _LinearAttentionVReorderBase → Qwen3NextModel → _QwenMtpMixin`. Quelle: `Qwen/Qwen3.8-27B` in **BF16** (51,3 GB, 16,00 BPW), nicht das FP8-Release — also **keine** doppelte Quantisierung. ## Zwei Hinweise für Ampere-Besitzer **FP8 läuft auf Ampere nicht nativ.** SM 8.6 hat keine FP8-Tensorcores, die gibt es erst ab SM 8.9. Qwens FP8-Release lässt sich dort nur dequantisiert fahren — Speicher gespart, Tempo nicht. Für GGUF ist das gegenstandslos, weil `Q8_0` und `Q6_K` reine Integer-Formate mit nativen Ampere-Kernen sind. **vLLM scheitert hier an drei GPUs.** Das Modell hat 24 Attention-Heads, aber nur **4 KV-Heads**. vLLM verlangt, dass `tensor_parallel_size` die KV-Head-Zahl teilt — 4 durch 3 geht nicht auf. Bleiben TP=2 und damit eine ungenutzte Karte. llama.cpp kennt das Problem nicht, weil `--tensor-split` Layer verteilt statt Attention-Köpfe. **Für ungerade GPU-Zahlen ist llama.cpp hier der einzige Weg, alle Karten zu nutzen.** ## Reproduzieren Das Messkript ist beigelegt (`bench_mtp.py`, deutsche Prompts über acht Textsorten, Median aus N Durchgängen): ```bash python3 bench_mtp.py --port 8290 --runs 3 --max-tokens 300 --out ergebnis.md ``` Einzelmessungen schwanken um etwa ±6 Prozent, deshalb Median statt Einzelwert. ## Lizenz Apache 2.0, wie das Basismodell. Alle Rechte am Modell liegen beim Qwen-Team / Alibaba Cloud. Dieses Repo enthält ausschließlich formatkonvertierte Gewichte, kein zusätzliches Training und keine Änderung am Verhalten.