Qwen3-32B manuell quantisieren – ein 32B-Modell auf 16 GB VRAM
Wie ich Qwen3-32B mit llama.cpp und einer Importance-Matrix so quantisiert habe, dass es auf einer 16-GB-GPU läuft: GGUF-Konvertierung, imatrix, Quant-Level im Vergleich, VRAM-Budget und Layer-Offload.

Ein dichtes 32-Milliarden-Parameter-Modell auf einer GPU mit 16 GB VRAM laufen lassen – klingt nach einer Nummer zu groß, und in voller Präzision ist es das auch. Mit manueller Quantisierung über llama.cpp und einer Importance- Matrix passt Qwen3-32B aber sehr wohl auf die Karte. Hier der komplette Weg, den ich gegangen bin – inklusive der Rechnung, warum es überhaupt klappt.
Das VRAM-Problem
Qwen3-32B hat ~32,8 Mrd. Parameter, verteilt auf 64 Transformer-Layer. Die reine Gewichtsgröße hängt linear an den Bits pro Gewicht:
| Präzision | Bits/Gewicht | Gewichte (≈) | Passt in 16 GB? |
|---|---|---|---|
| bf16 (Original) | 16 | ~66 GB | chancenlos |
| Q8_0 | 8 | ~35 GB | nein |
| Q6_K | ~6,6 | ~27 GB | nein |
| Q5_K_M | ~5,7 | ~23 GB | nein |
| Q4_K_M | ~4,8 | ~20 GB | knapp nicht ganz |
| IQ4_XS | ~4,3 | ~18 GB | fast |
| Q3_K_M | ~3,9 | ~16 GB | grenzwertig |
| IQ3_M | ~3,7 | ~15 GB | ja (mit Kontext) |
| IQ2_M | ~2,7 | ~11 GB | ja, aber Qualität ↓ |
(Zahlen gerundet – die tatsächliche Dateigröße variiert leicht.)
Daraus folgt die eigentliche Entscheidung: Q4_K_M (~20 GB) läuft nur mit Partial Offload (ein Teil der Layer auf die CPU), IQ3_M (~15 GB) passt fast komplett auf die GPU. Und genau hier wird die Importance-Matrix wichtig.
Schritt 1: Modell holen & nach GGUF konvertieren
# Original-Gewichte von Hugging Face
huggingface-cli download Qwen/Qwen3-32B --local-dir ./Qwen3-32B
# In ein GGUF in voller Präzision konvertieren (Ausgangspunkt für die Quantisierung)
python llama.cpp/convert_hf_to_gguf.py ./Qwen3-32B \
--outfile qwen3-32b-bf16.gguf \
--outtype bf16Das bf16.gguf ist die ~66-GB-Zwischenstufe – sie liegt nur auf der Platte, nicht im VRAM. Aus ihr entstehen alle quantisierten Varianten.
Schritt 2: Importance-Matrix (imatrix) berechnen
Naives Quantisieren behandelt jedes Gewicht gleich. Die imatrix misst stattdessen auf echtem Text, welche Gewichte für die Ausgaben wichtig sind, und schützt diese bei der Quantisierung. Bei niedrigen Bit-Breiten (alles unter 4 bit) ist das der Unterschied zwischen „brauchbar“ und „lallt Unsinn“.
# Kalibrierungstext: ein paar hundert KB, repräsentativ gemischt
# – Prosa, Code und ein Teil aus der eigenen Domäne
./llama-imatrix \
-m qwen3-32b-bf16.gguf \
-f calibration.txt \
-o qwen3-32b.imatrix \
--chunks 200 \
-ngl 20Wichtig ist die Zusammensetzung von calibration.txt: Wer das Modell später für Code nutzt, packt Code hinein; wer auf Deutsch arbeitet, deutschen Text. Die imatrix optimiert genau auf das, was sie zu sehen bekommt.
Schritt 3: Quantisieren
# Voll auf GPU – kleinstes brauchbares Level dank imatrix
./llama-quantize \
--imatrix qwen3-32b.imatrix \
qwen3-32b-bf16.gguf \
qwen3-32b-IQ3_M.gguf \
IQ3_M
# Höhere Qualität, dafür Partial Offload nötig
./llama-quantize \
--imatrix qwen3-32b.imatrix \
qwen3-32b-bf16.gguf \
qwen3-32b-Q4_K_M.gguf \
Q4_K_MVRAM-Budget & -ngl bestimmen
Gewichte sind nicht alles, was ins VRAM muss. Das reale Budget:
nutzbares VRAM ≈ 16 GB
− KV-Cache (wächst mit Kontextlänge)
− Compute-Buffer (~0,5–1 GB)
− OS/Treiber (~0,5–1 GB)Der KV-Cache ist der größte variable Posten. Qwen3-32B nutzt Grouped-Query Attention mit 8 KV-Heads – das hält den Cache klein, aber bei 8k Kontext in fp16 sind es trotzdem ~1–2 GB. Zwei Hebel drücken das:
--flash-attn # effizientere Attention, weniger Buffer
-ctk q8_0 -ctv q8_0 # KV-Cache selbst auf 8 bit quantisieren → ~halber BedarfDamit bleiben real ~13,5–14 GB für die Gewichte. Die Layer-Rechnung für Q4_K_M:
Gewichte ≈ 20 GB / 64 Layer ≈ 0,31 GB pro Layer
13,5 GB nutzbar / 0,31 GB ≈ 43–44 Layer auf die GPUAlso -ngl 44: 44 Layer laufen auf der GPU, der Rest auf der CPU. Bei IQ3_M (~15 GB) passen dagegen praktisch alle 64 Layer – -ngl 99 (llama.cpp deckelt auf das Maximum) – und es läuft komplett ohne CPU-Offload.
Schritt 4: Starten
# Variante A – IQ3_M, voll auf der GPU (schnell)
./llama-server \
-m qwen3-32b-IQ3_M.gguf \
-ngl 99 \
-c 8192 \
--flash-attn \
-ctk q8_0 -ctv q8_0 \
--host 0.0.0.0 --port 8080
# Variante B – Q4_K_M, Partial Offload (höhere Qualität, langsamer)
./llama-server \
-m qwen3-32b-Q4_K_M.gguf \
-ngl 44 \
-c 8192 \
--flash-attn \
-ctk q8_0 -ctv q8_0Optional: in Ollama einbinden
Da mein restliches Setup (LLM-Wiki nach Karpathy) auf Ollama läuft, wandert das fertige GGUF per Modelfile dorthin:
# Modelfile
FROM ./qwen3-32b-IQ3_M.gguf
PARAMETER num_ctx 8192
PARAMETER num_gpu 99ollama create qwen3-32b-local -f Modelfile
ollama run qwen3-32b-localErgebnis & Erkenntnisse
Qwen3-32B läuft auf 16 GB – und zwar sinnvoll. Was ich mitgenommen habe:
- Voll auf der GPU schlägt Partial Offload. Ein niedrigeres, komplett geladenes Quant (IQ3_M) ist spürbar schneller als ein höheres Quant, das zur Hälfte auf der CPU rechnet – der PCIe-Transfer pro Token kostet mehr, als das bessere Quant einbringt.
- Die imatrix ist bei <4 bit nicht optional. Ohne sie ist IQ3_M merklich dümmer; mit passender Kalibrierung liegt es überraschend nah an Q4.
- KV-Cache-Quantisierung + Flash-Attention sind der stille Gewinn: Sie schaffen den Spielraum, entweder mehr Kontext oder ein paar Layer mehr auf die GPU zu bekommen.
- Kalibrierungsdaten sind Domänensache. Die imatrix ist nur so gut wie der Text, den man ihr zeigt – für Code-Aufgaben gehört Code hinein.
Manuelle Quantisierung ist am Ende ein Budgetierungsproblem, kein Zauber: Bits pro Gewicht gegen KV-Cache gegen Layer-Offload abwägen, bis das große Modell in die kleine Karte passt.