# ADR-0006: Alte GPUs nur für llama.cpp, M4000 vorerst außer Betrieb, TTS auf Ada und CPU - Status: angenommen - Datum: 2026-10-12 ## Kontext - PyTorch unterstützt Maxwell und Pascal seit 2.8 nur noch in den cu126-Builds. **PyTorch 2.14 ist die letzte Version mit CUDA-12.x-Wheels** (Ankündigung vom 04.09.2026), danach geht es nur noch über einen eigenen Build. - Pascal hat weder bf16 noch schnelles FP16, und FlashAttention fehlt. Qwen3-TTS 1.7B erreicht auf einer Tesla P40 nur **RTF ~7,3** (Referenz-Implementierung, gemessen von tinycomputers.io). P2000 und M4000 sind schwächer. - llama.cpp unterstützt Maxwell und Pascal mit CUDA 12 weiterhin. FlashAttention läuft dort auch auf Maxwell. - Für die M4000 gibt es keine direkten Messungen. Geschätzt liegt sie bei 7B Q4 auf 12–25 Token/s, bei 120 W pro Karte. Die P2000 decken Embedding, Rerank und Verifier bereits ab. ## Entscheidung 1. **Engine-Grenzen im Katalog** (`catalog/models.yaml → engines`): `pytorch` ab Compute Capability 7.5, `vllm` ab 7.0, `llamacpp` ab 5.0. Das Placement setzt PyTorch-Workloads damit nie auf Maxwell/Pascal. 2. **M4000 vorerst außer Betrieb** (`disabled: true` im Inventar). Wieder aufgenommen werden sie nur nach `llama-bench` plus Strommessung am Deployment-Tag, und dann nur für llama.cpp-Rollen. 3. **TTS:** - `tts-de`: Piper auf der CPU im Infra-LXC. Schnell, robust, ohne GPU, zugleich Fallback. - `tts-de-hq`: Qwen3-TTS 1.7B (Apache 2.0, Deutsch, Stimmenklonen) in bf16 auf `gpu-flex`, im Wechsel mit Training und `tier1-flex`. Wenn TTS aktiv ist, sinkt der vLLM-Anteil am VRAM auf ~55 %. - Kein TTS auf P2000 oder M4000. ## Folgen - Bei `gpu-flex` muss sich der Lifecycle die Karte mit TTS teilen. Während des Trainings gehen sowohl `tier1-flex` als auch `tts-de-hq` auf `unavailable`, und LiteLLM fällt auf `tts-de` zurück. - Die tatsächlichen RTF-Werte misst `knaster bench tts` beim Deployment. Sie ersetzen die Schätzungen im Katalog. ## Nachtrag 2026-10-12: Ada-Rechner bleiben Windows (D3, vorgeschlagen, Bestätigung offen) - Die beiden RTX 4000 Ada (20 GB) stecken nicht in einem Proxmox-Knoten, sondern je eine in den Windows-Arbeitsplätzen GODE-PC-05 und GODE-PC-06 (64 GB RAM). Sie bleiben Windows, Mitarbeitende haben tagsüber Vorrang. - Vorschlag: `LocalLLMWorker.ps1` mit llama-server (CUDA) meldet sich über die Worker-Registry v2. `tier1-general` (gode-pc-05) und `tier1-flex` (gode-pc-06) lösen auf einen Worker auf, der online ist, sonst auf Stufe 0 über den LiteLLM mit PSE. - In `sites/knaster/registry.yaml` behalten die Ada-Slots vorerst ihre Engine, nur `pve_node` und `vmid` entfallen. Die Umstellung folgt in Task 6.4. - Folgen: vLLM und PyTorch laufen unter Windows nicht nativ. `tts-de-hq` (Qwen3-TTS), Multi-LoRA und QLoRA auf `gpu-flex` warten auf eine spätere WSL2-Entscheidung (Phase 9). Bis dahin trägt `tts-de` (Piper) die Sprachausgabe allein. ## Nachtrag 2026-10-12: Benchmark (Task 3.3, ohne Strommessung) Gemessen in `gpu-pve48` (pve48, VM 248: 4 vCPU i7-6700, 12 GB RAM, Treiber 580.178.04), beide Karten nacheinander, nie gleichzeitig. - **Builds:** llama.cpp `b6000` (Commit `4762ad7`, Compose-Pin aus `deploy/compose/gpu-llamacpp`), `.devops/cuda.Dockerfile` Stufe `build`, `CUDA_VERSION=12.4.0`, `CUDA_DOCKER_ARCH=52;61`. whisper.cpp `v1.9.5` (Commit `d1be6fd`) auf `nvidia/cuda:12.4.0-devel-ubuntu22.04`, `CMAKE_CUDA_ARCHITECTURES=52;61` (braucht `-Wl,--allow-shlib-undefined`, sonst fehlt `libcuda` beim Linken im Container). - **Modelle** (liegen in `/srv/models` von `gpu-pve48`, dort auch `SOURCES.txt`): | Datei | Quelle (Hugging Face, Revision) | SHA-256 | |---|---|---| | `Qwen3-Embedding-0.6B-Q8_0.gguf` | `Qwen/Qwen3-Embedding-0.6B-GGUF@370f27d` | `06507c7b42688469c4e7298b0a1e16deff06caf291cf0a5b278c308249c3e439` | | `Qwen3-4B-Q4_K_M.gguf` | `Qwen/Qwen3-4B-GGUF@bc64014` | `7485fe6f11af29433bc51cab58009521f205840f5b4ae3a32fa7f92e8534fdf5` | | `Qwen3-8B-Q4_K_M.gguf` | `Qwen/Qwen3-8B-GGUF@7c41481` | `d98cdcbd03e17ce47681435b5150e34c1417f50b5c0019dd560e4882c5745785` | | `ggml-large-v3-turbo.bin` (nach der Messung gelöscht, nicht im Katalog) | `ggerganov/whisper.cpp@5359861` | `1fc70f774d38eb169993ac391eea357ef47c88757ef72ee5943879b7e8e2bc69` | **llama.cpp** (`llama-bench`, `-ngl 99`, Werte t/s ohne/mit Flash-Attention; VRAM = belegter Speicher mit `llama-server` beim Katalog-Kontext). Als „7B Q4“ wurde das Katalogmodell `qwen3-8b-q4km` (8B) gemessen. | Karte | Modell | pp512 | tg128 | VRAM (Kontext) | |---|---|---|---|---| | M4000 (CC 5.2) | Qwen3-Embedding 0.6B Q8 | 929 | – | 2,8 GiB (8192, `-ub 8192`) | | P2000 (CC 6.1) | Qwen3-Embedding 0.6B Q8 | 1009 | – | 2,8 GiB (8192, `-ub 8192`) | | M4000 | Qwen3-4B Q4_K_M | 197 / 204 | 15,1 / 15,3 | 4,1 GiB (8192) | | P2000 | Qwen3-4B Q4_K_M | 271 / 275 | 14,5 / 14,8 | 4,1 GiB (8192) | | M4000 | Qwen3-8B Q4_K_M | 115 / 118 | 10,0 / 10,1 | 7,7 GiB (16384) | | P2000 | Qwen3-8B Q4_K_M | 152 / 135 | 9,0 / 8,2 | **passt nicht** bei 16384 (KV-Cache scheitert), nur mit 512 Kontext (4,9 GiB) | **whisper.cpp** `large-v3-turbo`, `-l de`, Standard-Dekodierung (Beam 5), Testaudio selbst mit Piper erzeugt (Hausverwaltungs-Brief, keine Kundendaten, danach gelöscht). Rechenzeit ohne Modell-Laden (Laden: P2000 1,1 s, M4000 0,7 s; ein Server lädt nur einmal), Median aus 3 Läufen nach einem Aufwärmlauf: | Karte | 10-s-Clip | 33-s-Clip, umgerechnet je 10 s | VRAM | Flash-Attention aus | |---|---|---|---|---| | P2000 | 3,5 s | 2,5 s | 2,0–2,2 GiB | 3,9 s bzw. 2,9 s | | M4000 | 2,7 s | 2,1 s | 2,0–2,2 GiB | 3,2 s bzw. 2,3 s | Erkennung fehlerfrei bis auf „Milltonnen“ (statt „Mülltonnen“); synthetische Sprache ist leichter als echtes Diktat. Zum Vergleich der Dienst `nex-stt` auf der M4000 in `gpu-pve52` (v1.9.4, Task 6.2): 10 s → 2,94 s. **Piper** (`knaster bench tts` gegen das Image aus `deploy/docker/tts-piper.Dockerfile`, `de_DE-thorsten-medium`, 4 vCPU): RTF 0,17 bei 241 Zeichen (≈ 17 s Audio, 2,9 s Rechenzeit), RTF 0,11 bei 596 Zeichen (≈ 33 s Audio, 3,6 s). **Leistungsaufnahme laut GPU-Sensor** (`nvidia-smi`, nur die Karte, keine Steckdosenmessung): M4000 Leerlauf 13,5 W (P8), unter llama.cpp 94–102 W, unter whisper 92–99 W. P2000 Leerlauf 6,5 W, unter Last 46–52 W (Grenze 75 W). Ohne Persistence-Modus zeigt ein einzelner `nvidia-smi`-Aufruf kurz P0 mit 46 W bzw. 20 W an; erst nach einigen Sekunden fällt die Karte auf P8. Weitere Befunde: - **CC 5.2 rechnet:** llama.cpp b6000 und whisper.cpp 1.9.5 laufen mit CUDA 12.4 auf der M4000, Flash-Attention eingeschlossen. - Die Token-Erzeugung (tg) ist auf beiden Karten etwa gleich schnell und liegt deutlich unter der Speicherbandbreite. Die Karte ist dabei voll ausgelastet (P2000 99 %), es liegt also nicht an der CPU der VM. b6000 ist über ein Jahr alt (aktuell `b11574`); vor einer Anhebung des Compose-Pins nachmessen. - Die P2000 hängt in pve48 nur mit PCIe 3.0 x4 an (M4000 x16). Das bremst nur das Laden. - **Kartenwahl in Compose:** `deploy/compose/gpu-llamacpp` reserviert `count: 1`. Docker gibt dann die erste Karte heraus, und das ist die M4000 (geprüft: `docker run --gpus 1 … nvidia-smi -L` → Quadro M4000). Für die P2000 in Task 6.1 `device_ids` (Index 1 oder UUID) statt `count` setzen. ### Empfehlung: M4000 wieder aufnehmen – **ja, aber nur gezielt** - **pve52 (nur eine M4000): ja**, für STT (whisper.cpp, 2,1 s je 10 s, schneller als die P2000). Ohne sie hat der Knoten keine GPU-Rolle, und die M4000 läuft dort für `nex-stt` ohnehin. - **pve44, pve46, pve48: vorerst nein** für die heutigen Rollen. Embedding und Verifier laufen auf der P2000 gleich schnell oder schneller (Prefill +37 %) bei etwa halber Leistungsaufnahme. Bedingung: Embedding und Rerank passen mit `-ub 8192` gemeinsam auf die P2000 (Embedding allein 2,8 GiB, Rerank ungemessen). Passt das nicht, kommt Rerank auf die M4000 in derselben VM (dann „ja“ für pve44/46), oder `-ub` wird gesenkt. Die M4000 lohnt sich dort nur für Rollen, die mehr als 5 GB brauchen: `qwen3-8b-q4km` mit 16k Kontext (7,7 GiB), eine zweite STT-Instanz oder ein zweiter Verifier zur Lastverteilung. - Nur für llama.cpp und whisper.cpp; PyTorch, vLLM und TTS bleiben ausgeschlossen (Entscheidung 1 und 3 unverändert). - Eine gesperrte, aber eingebaute M4000 verbraucht im Leerlauf weiter etwa 13 W, solange der Treiber in der VM geladen ist. Bleibt sie dauerhaft ungenutzt, ausbauen. - Vorbehalt: Die Steckdosenmessung je Knoten (Leerlauf und Volllast) steht aus. Das Flag `disabled` im Inventar ist nicht geändert; die Freigabe für pve52 setzt der Nutzer nach dieser Messung.