Mehr Speed für die DGX Spark: Wie wir Gemma 4 auf über 100 tok/s katapultiert haben

Bild eines DGX Spark mit dem Text "More Spped for the DGX Spark: Catapulting Gemma 4 100tok/s"

Wer auf einer DGX Spark einen OpenAI-kompatiblen Inference-Endpunkt aufsetzen möchte, stolpert schnell über das Thema Latenz. Out-of-the-box läuft die Kiste oft weit unter ihren Möglichkeiten.

Wir haben ein Setup gebaut, das ~104 Tokens pro Sekunde (single-stream) liefert – und das mit einem stattlichen Gemma 4 26B Modell. Zum Vergleich: Die Standardkonfiguration dümpelt bei knapp 30 tok/s herum.

Das Geheimnis hinter diesem 3,6× Speedup (ohne jeglichen Qualitätsverlust!) liegt in der Kombination aus zwei Dingen: FP8-Quantisierung und Multi-Token Prediction (MTP) mittels eines Drafter-Modells.

Das Problem: Der unsichtbare Flaschenhals (HBM-Bandbreite)

Warum ist Single-Stream-Inference auf dem GB10-Chip der DGX Spark eigentlich standardmäßig so zäh? Das Zauberwort heißt Bandbreitenlimitierung.

Bei der Generierung von Text langweilt sich die Recheneinheit (Compute) der GPU meistens. Der echte Flaschenhals ist das Laden der Modellgewichte aus dem Speicher (HBM).

  • Bei einem 26B-Modell in FP8-Präzision müssen für jeden einzelnen erzeugten Token rund 26 GB an Daten einmal komplett durch den Speicher gezogen werden.

Hier kommt Multi-Token Prediction (MTP) – auch bekannt als spekulatives Dekodieren – ins Spiel:

  1. Der Assistent schlägt vor: Ein winziges, extrem schnelles "Drafter-Modell" rät 4 Tokens auf einmal im Voraus (das kostet kaum Rechenleistung).

  2. Der Chef prüft: Das große Hauptmodell (Target) verifiziert alle 4 Tokens in einem einzigen Rutsch.

  3. Die Entscheidung: Korrekte Tokens werden behalten. Sobald der Drafter falsch liegt, springt das Hauptmodell ein und korrigiert.

Das Geniale daran: Der Output ist mathematisch absolut identisch zur normalen Generierung. Wir opfern keine Qualität, sondern nutzen schlichtweg die freie Rechenleistung der GPU aus. Wenn der Drafter gut zum Hauptmodell passt, liegt die Trefferquote (Accept-Rate) bei stolzen 60–80 %.

Der Boxenstopp: Warum FP8 statt NVFP4 auf dem GB10?

Ein logischer Reflex wäre: "Wir quantisieren das Modell einfach auf das neue NVFP4-Format, dann schrumpft das Modell auf 16 GB und fliegt nur so durch den Speicher!" Was auf dicken Blackwell-Datacenter-Systemen (B200 mit SM100/SM120) wunderbar klappt, wird auf der DGX Spark zur Performance-Falle.

Achtung Architektur-Falle: Der GB10-Chip basiert auf der SM121-Architektur (eine GB202-Mobile/Workstation-Variante mit Unified Memory). Dieser Chip besitzt keine native FP4-Compute-Einheit.

Das bedeutet in der Praxis: Die NVFP4-Gewichte müssen zur Laufzeit mühsam auf FP8 oder FP16 dequantisiert werden, bevor die GPU damit rechnen kann. Das spart zwar Platz im VRAM, kostet aber so viel Rechen-Overhead, dass die Performance einbricht. Unsere NVFP4-Baseline lag bei enttäuschenden ~30 tok/s.

Das aktuelle Fazit für die Spark lautet daher: Finger weg von NVFP4, solange NVIDIA keine nativen Treiber-Updates dafür liefert. Setzt stattdessen auf FP8 + MTP.

Die Software-Hürde: vLLM für die Spark fit machen

Wer versucht, vLLM einfach via pip install vllm zu installieren, wird auf der DGX Spark scheitern. Die Standard-Pakete sind für die Datacenter-Chips gebaut, nicht für den SM121 der Spark. Zudem streiken FlashInfer und Triton ohne spezifische Patches.

Statt tagelang selbst zu patchen, nutzen wir die fertige Build-Pipeline von eugr/spark-vllm-docker. Das spart Wochen an Frustarbeit. Unsere CI baut daraus einmalig das Image für unser System.

Das Docker-Compose Setup

Wir steuern das Setup über ein sauberes Docker-Compose-File mit zwei Containern: Einem Init-Container, der die Modelle von Hugging Face synchronisiert, und dem eigentlichen vLLM-Server.

Die Modellauswahl steuern wir zentral über eine model.env:

Code-Snippet

HF_REPO=RedHatAI/gemma-4-26B-A4B-it-FP8-Dynamic
MODEL_PATH=/models/gemma-4-26b-a4b-it-fp8
DRAFTER_HF_REPO=google/gemma-4-26B-A4B-it-assistant
DRAFTER_MODEL_PATH=/models/gemma-4-26b-a4b-it-assistant

Der entscheidende vLLM-Befehl

In der docker-compose.yml rufen wir den vLLM-Server mit ein paar sehr spezifischen Flags auf:

YAML

exec vllm serve "$MODEL_PATH" \
  --host 0.0.0.0 --port 8000 \
  --gpu-memory-utilization 0.70 \
  --max-num-batched-tokens 8192 \
  --enable-prompt-tokens-details \
  --limit-mm-per-prompt '{"video":0,"image":0}' \
  --speculative-config "{\"method\":\"mtp\",\"model\":\"$DRAFTER_MODEL_PATH\",\"num_speculative_tokens\":4}"

Warum genau diese Flags? Hier sind die drei wichtigsten Insights:

  • --speculative-config ... "num_speculative_tokens":4: Das ist der absolute Sweet Spot für Gemma 4. Bei 8 Tokens wird der Drafter zu ungenau, bei 2 verschenken wir Speed.

  • --limit-mm-per-prompt '{"video":0,"image":0}': Schaltet die Multimodal-Pfade ab. Warum? Das Unified Memory der Spark verträgt sich nicht mit dem internen Speicher-Profiling von vLLM (nvmlDeviceGetMemoryInfo), was sonst direkt zum Absturz führt.

  • --gpu-memory-utilization 0.70: Höhere Werte führen wegen der speziellen Speicherverwaltung des Unified Memory schnell zu "Out of Memory" (OOM) Fehlern.

Ladezeiten verkürzen durch Cache-Mounts

vLLM kompiliert beim Start Triton- und FlashInfer-Kernel. Ohne persistenten Speicher wartet man bei jedem Neustart 5 bis 15 Minuten. Mit diesen Mounts startet das System in Sekunden:

YAML

volumes:
  - /srv/vllm-cache/vllm:/root/.cache/vllm
  - /srv/vllm-cache/flashinfer:/root/.cache/flashinfer
  - /srv/vllm-cache/triton:/root/.triton

Hinweis: Wichtig sind im Compose zudem shm_size: "64gb" für die interne GPU-Kommunikation und privileged: true, um die maximale GPU-Taktung (GPU_CLOCK_MAX=2600) für maximale Single-Stream-Performance zu erzwingen.

Schritt-für-Schritt Installationsanleitung

So bringt ihr das Setup auf einer frischen DGX Spark (mit Ubuntu und NVIDIA Container Toolkit) zum Laufen:

1. Repository vorbereiten

Bash

git clone <unser-repo> infrastructure && cd infrastructure

2. Das angepasste vLLM-Image bauen (Dauer: ca. 45 Min.)

Bash

git clone https://github.com/eugr/spark-vllm-docker.git ~/spark-vllm-docker
cd ~/spark-vllm-docker && ./build-and-copy.sh -t vllm-spark
cd -

3. Docker-Netzwerk und Umgebungsvariablen anlegen

Bash

docker network create dgx-net
cd dgx-spark/vllm-inference
cp .env.example .env
# Vergiss nicht, deinen HF_TOKEN in der .env einzutragen!

4. Container starten & Logs prüfen

Bash

docker compose up -d
# Zuerst den Modell-Download beobachten (~50 GB):
docker logs -f vllm-inference-model-sync
# Danach den vLLM-Start verfolgen:
docker logs -f vllm-inference

Sobald im Log Uvicorn running on http://0.0.0.0:8000 steht (beim ersten Mal nach ca. 8–15 Minuten inkl. Kompilierung), ist der Endpunkt bereit.

5. Der Smoke-Test

Mit folgendem Befehl könnt ihr testen, ob alles läuft:

Bash

curl -s http://localhost:8000/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "/models/gemma-4-26b-a4b-it-fp8",
    "messages": [{"role":"user","content":"Erklär mir MTP in zwei Sätzen."}],
    "stream": false
  }' | jq .

In der Server-Antwort solltet ihr nun einen Wert wie usage.acceptance_rate sehen. Werte zwischen 0.65 und 0.78 zeigen, dass das MTP-Gespann perfekt harmoniert.

Troubleshooting: Wenn der Speedup plötzlich einbricht

Sollte die Performance einbrechen, liegt das meist an einem dieser drei Gründe:

  1. Drafter-Mismatch: Der Assistant-Drafter muss exakt zum Hauptmodell passen (z. B. Instruct-Drafter zu Instruct-Target). Wer auf ein Base-Modell wechselt, muss auch den Drafter anpassen, sonst wird das System durch Fehlversuche langsamer als ohne MTP.

  2. Zu lange Prompts (Context): Bei Prompts mit mehr als 4.000 Tokens dominiert die Phase des Einlesens (Prefill). MTP zündet aber erst bei der Generierung (Decode). Das ist technisch bedingt.

  3. Hohe parallele Last (Batch Size > 1): MTP ist der König der Single-Stream-Latenz. Wenn viele Nutzer gleichzeitig Anfragen senden, lastet vLLMs eigenes Batching die Speicherbandbreite ohnehin aus. In diesem Fall solltet ihr Benchmarks machen und MTP eventuell deaktivieren.

Fazit

Die DGX Spark ist eine faszinierende, aber eigenwillige Maschine. Durch die Kombination aus Unified Memory und der SM121-Architektur muss man die Eigenheiten des Systems kennen.

Mit dem richtigen Rezept – FP8, MTP-Drafter und den passenden vLLM-Patches – holt man jedoch die Handbremse dauerhaft gelöst und betreibt einen rasend schnellen, produktionsbereiten OpenAI-Klon direkt auf einer Workstation, die problemlos unter den Schreibtisch passt.

Weiter
Weiter

KI-Souveränität 2026: Dein Weg zum komplett europäischen LLM-Stack