bildgenerierung auf GPU

This commit is contained in:
Alexander Gabriel 2026-10-18 14:24:56 +02:00
parent 571652f480
commit 4e7f9425e3
6 changed files with 21 additions and 8 deletions

View File

@ -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=

View File

@ -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 |
|---|---|

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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)