From 4e7f9425e3f6b6353bb02f1385fb2ad6b54224c5 Mon Sep 17 00:00:00 2001 From: Alexander Gabriel Date: Sun, 18 Oct 2026 14:24:56 +0200 Subject: [PATCH] bildgenerierung auf GPU --- .env.example | 6 +++--- README.md | 4 ++-- docker-compose.yml | 6 ++++-- docs/webchat.md | 2 +- llama-swap/config.yaml | 8 ++++++++ scripts/start.sh | 3 +++ 6 files changed, 21 insertions(+), 8 deletions(-) diff --git a/.env.example b/.env.example index 4168b23..f1a9904 100644 --- a/.env.example +++ b/.env.example @@ -27,9 +27,9 @@ VIDEO_GID=983 # GPU-Auswahl (0 = erste ROCm-GPU; iGPU ausblenden) HIP_VISIBLE_DEVICES=0 -# GPU-Auswahl für Vulkan (sd-server). Vulkan zählt die iGPU mit – Reihenfolge steht -# beim Laden eines Bildmodells im Log: docker compose logs llama-swap | grep ggml_vulkan -VK_VISIBLE_DEVICES=1 +# GPU für Vulkan (whisper-/sd-server) als PCI-ID vendor:device – stabil, anders als +# die Geräte-Nummer, die zwischen Reboots wechselt: lspci -nn | grep -i vga +VK_DEVICE=1002:73a5 # Optional: Hugging-Face-Token für gated Modelle / höhere Download-Limits HF_TOKEN= diff --git a/README.md b/README.md index faed177..1f4fd78 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ curl -L -o models/sd/Qwen3-4B-Instruct-2507-Q8_0.gguf $HF/unsloth/Qwen3-4B-Instr ### Warum ein eigenes Image? `whisper-server` und `sd-server` gibt es nur im „unified“-Image von llama-swap, und das für AMD nur als Vulkan-Build. Unter Vulkan ist die Prompt-Verarbeitung von llama.cpp auf der RX 6950 XT aber nur halb so schnell wie unter ROCm (~555 statt ~1030 t/s). [`llama-swap/Dockerfile`](llama-swap/Dockerfile) nimmt deshalb das ROCm-Image als Basis und kopiert die beiden Server aus dem unified-Image dazu. `docker compose up -d --build` bzw. `scripts/start.sh` bauen es automatisch. Beide Tags stehen in `.env` (`LLAMA_SWAP_TAG`, `UNIFIED_TAG`). Bei einem Update beide auf dieselbe llama-swap-Version setzen und `./scripts/start.sh --pull` ausführen. -Vulkan zählt die iGPU des Ryzen mit. `VK_VISIBLE_DEVICES=1` in `.env` wählt die RX 6950 XT. +Vulkan sieht auch die iGPU des Ryzen, und die Geräte-Reihenfolge wechselt zwischen Reboots. `VK_DEVICE=1002:73a5` in `.env` (PCI-ID der RX 6950 XT, `lspci -nn | grep -i vga`) lässt Mesa nur diese Karte anzeigen. Kontrolle: `curl -s 127.0.0.1:8080/logs/stream/whisper | grep ggml_vulkan` muss die RX 6950 XT zeigen. ### Warum Caddy im Host-Netz? Ports, die Docker veröffentlicht, **umgehen ufw**. Deshalb ist llama-swap nur an `127.0.0.1` gebunden. Caddy läuft mit `network_mode: host`, dort greift ufw, und Caddy sieht die echte Quell-IP. Daraus ergeben sich zwei Schutzschichten: @@ -113,7 +113,7 @@ GPU-Layer und MoE-Auslagerung in den RAM verteilt llama.cpp automatisch (`--fit` 1. Den Ordner kopieren. `models/` kann man mitnehmen, um den Download zu sparen. 2. `.env` anpassen: `ALLOWED_NETS` (LAN-Subnetz, NetBird-Netz), `RENDER_GID`/`VIDEO_GID`, `HOST_UID`/`HOST_GID`. -3. Je nach GPU das Image in `.env` wählen (`LLAMA_SWAP_TAG`). Das eigene Image ([`llama-swap/Dockerfile`](llama-swap/Dockerfile)) ist für ROCm gebaut. Bei NVIDIA oder Vulkan nimmt man einfacher direkt das passende `unified-…`-Image (enthält whisper-/sd-server schon) und ersetzt `build:` in `docker-compose.yml` durch `image: ghcr.io/mostlygeek/llama-swap:unified-…`. `VK_VISIBLE_DEVICES` an die Geräte-Reihenfolge anpassen. +3. Je nach GPU das Image in `.env` wählen (`LLAMA_SWAP_TAG`). Das eigene Image ([`llama-swap/Dockerfile`](llama-swap/Dockerfile)) ist für ROCm gebaut. Bei NVIDIA oder Vulkan nimmt man einfacher direkt das passende `unified-…`-Image (enthält whisper-/sd-server schon) und ersetzt `build:` in `docker-compose.yml` durch `image: ghcr.io/mostlygeek/llama-swap:unified-…`. `VK_DEVICE` auf die PCI-ID der neuen GPU setzen. | GPU | Tag-Variante | |---|---| diff --git a/docker-compose.yml b/docker-compose.yml index c955e36..cc69265 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,8 +30,10 @@ services: HOME: /tmp LLAMA_CACHE: /models HIP_VISIBLE_DEVICES: "${HIP_VISIBLE_DEVICES:-0}" - # Vulkan (sd-server) zählt die iGPU mit – hier ist die RX 6950 XT Gerät 1 - GGML_VK_VISIBLE_DEVICES: "${VK_VISIBLE_DEVICES:-1}" + # Vulkan (whisper-/sd-server) sieht auch die iGPU, und die Reihenfolge wechselt + # zwischen Reboots. Mesa blendet deshalb alles außer der Karte mit dieser PCI-ID aus. + MESA_VK_DEVICE_SELECT: "${VK_DEVICE:?VK_DEVICE in .env setzen}" + MESA_VK_DEVICE_SELECT_FORCE_DEFAULT_DEVICE: "1" HF_TOKEN: "${HF_TOKEN:-}" volumes: - ./models:/models diff --git a/docs/webchat.md b/docs/webchat.md index 8fca930..97ad91a 100644 --- a/docs/webchat.md +++ b/docs/webchat.md @@ -25,7 +25,7 @@ Chat im Browser, ohne Client-Installation. Open WebUI läuft im selben Stack und | Spracheingabe (Mikrofon) | `whisper` | nur über HTTPS oder `localhost`, siehe unten | | Bilder (Bild-Knopf im Chat) | `z-image` | verdrängt das Chat-Modell; der nächste Chat lädt es neu | -Die Auswahlliste zeigt auch `qwen2.5-coder-1.5b`, `nomic-embed`, `whisper` und `z-image`. Diese Modelle taugen nicht zum Chatten. Ausblenden kann man sie unter *Admin-Bereich → Einstellungen → Modelle*. +Die Auswahlliste zeigt nur die Chat-Modelle. `qwen2.5-coder-1.5b`, `nomic-embed`, `whisper` und `z-image` sind in `llama-swap/config.yaml` als `unlisted: true` markiert, weil sie im Chat-Feld nur einen Fehler liefern würden. Bilder erzeugt man über den Bild-Knopf im Chat, nicht über die Modellauswahl. Die Chat-Modelle laufen mit `-np 1`, also mit einer Sitzung gleichzeitig. Wenn opencode gerade arbeitet, wartet der Web-Chat (und umgekehrt). Titel-Generierung nutzt dasselbe Modell und hängt sich hinten an. Autocomplete- und Folgefragen-Vorschläge sind deshalb abgeschaltet. diff --git a/llama-swap/config.yaml b/llama-swap/config.yaml index 95383e9..4f74a47 100644 --- a/llama-swap/config.yaml +++ b/llama-swap/config.yaml @@ -12,6 +12,10 @@ # - Embeddings laufen auf der CPU # - das Bildmodell (z-image) ist in der chat-Gruppe: es verdrängt das Chat-Modell # +# Hilfsmodelle (Autocomplete, Embeddings, Whisper, Bilder) sind "unlisted": Sie fehlen in +# /v1/models, damit man sie im Web-Chat nicht als Chat-Modell wählt. Per ID bleiben +# sie normal nutzbar. +# # whisper-server und sd-server kommen aus dem unified-Image (llama-swap/Dockerfile). # Ihre Modelle liegen fest in ./models/whisper und ./models/sd (kein -hf), siehe README. @@ -58,6 +62,7 @@ models: -hf ggml-org/Qwen2.5-Coder-1.5B-Q8_0-GGUF -ngl 99 ttl: 0 + unlisted: true # --- Embeddings (Continue @codebase) ----------------------------------- nomic-embed: @@ -67,6 +72,7 @@ models: -hf nomic-ai/nomic-embed-text-v1.5-GGUF:Q8_0 --embedding --pooling mean -c 8192 -b 8192 -ub 8192 -ngl 0 --threads 8 ttl: 0 + unlisted: true # --- Transkription (/v1/audio/transcriptions) -------------------------- whisper: @@ -81,6 +87,7 @@ models: -t 8 -l auto aliases: [whisper-1] ttl: 0 + unlisted: true # --- Bilder (/v1/images/generations), sd-server über Vulkan ------------ z-image: @@ -97,6 +104,7 @@ models: # Der OpenAI-Treiber (z. B. Laravel AI SDK) schickt seine eigenen Modellnamen aliases: [gpt-image-1, dall-e-3, dall-e-2] ttl: 600 + unlisted: true # Helfer-Modelle beim Container-Start laden (auch nach Reboot), damit # Autocomplete sofort reagiert. Das Chat-Modell lädt beim ersten Request diff --git a/scripts/start.sh b/scripts/start.sh index 492186e..d2970eb 100755 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -70,6 +70,9 @@ WEBUI_BACKEND_PORT="${WEBUI_BACKEND_PORT:-3000}" [[ -n "${LLM_API_KEY:-}" && "$LLM_API_KEY" != "CHANGE_ME" ]] || die "LLM_API_KEY in .env setzen (openssl rand -hex 32)" [[ -n "${WEBUI_SECRET_KEY:-}" && "$WEBUI_SECRET_KEY" != "CHANGE_ME" ]] || die "WEBUI_SECRET_KEY in .env setzen (openssl rand -hex 32)" ok ".env geladen" +if command -v lspci >/dev/null && [[ "$(lspci -nn)" != *"[${VK_DEVICE:-}]"* ]]; then + warn "VK_DEVICE=${VK_DEVICE:-} passt zu keiner GPU – whisper/sd-server laufen dann auf der CPU/iGPU (lspci -nn | grep -i vga)" +fi # Ports dürfen nur von unserem eigenen Stack belegt sein running=$(docker compose ps --status running -q 2>/dev/null | wc -l)