Ausgangslage

Für ArchivBlick sollen rund 150.000 Bilder aus einem SharePoint-Archiv automatisch beschrieben, kategorisiert und durchsuchbar gemacht werden. Die zentrale Frage: Welches Vision-Modell liefert die beste Qualität bei vertretbaren Kosten — und passt in eine einzelne Consumer-GPU?

Erste Versuche liefen lokal auf einem Mac mini M2 Pro mit Ollama und dem LLaVA-7B-Modell. Die Ergebnisse waren brauchbar, aber mit durchschnittlich 60 Zeichen pro Beschreibung viel zu knapp für eine sinnvolle semantische Suche. Außerdem dauerte die Verarbeitung eines einzelnen Bildes ~3 Sekunden — bei 150k Bildern wären das über 5 Tage Dauerlauf.

Die Lösung: Ein GPU-Server bei Trooper.AI mieten, dort leistungsfähigere Modelle laufen lassen und die Ergebnisse zurück auf den Mac mini transferieren.

Datenschutz Das gesamte Setup läuft ohne Cloud-APIs. Kein Bild verlässt das eigene Netzwerk in Richtung OpenAI, Google oder ähnliche Dienste. Die GPU wird direkt gemietet, die Modelle laufen lokal auf dem Server. Die Verbindung läuft über Tailscale (WireGuard-VPN).

Hardware & Setup

GPU NVIDIA GeForce RTX 4080 Super — 32 GB VRAM Die 32 GB VRAM sind entscheidend: Erst damit passen große 32B-Modelle mit AWQ-Quantisierung und genug KV-Cache für parallele Anfragen auf eine einzige Karte.
VRAM 32 GB GDDR6X — 18 GB Weights + 14 GB KV-Cache
CPU 16 Kerne Dediziert
Kosten 80 € pro Woche

Trooper.AI als Plattform

Trooper.AI ist ein deutscher GPU-Mietservice, bei dem man Server stunden- oder wochenweise buchen kann. Der Server kommt mit vorinstallierten Templates — für unseren Fall: vLLM OpenAPI (der Inference-Server) und Jupyter Notebook (für schnelle Tests).

Wichtige Besonderheiten, die wir gelernt haben:

  • SSH-Port ist randomisiert (5-stellig, 10000–59999), nicht Port 22
  • Kein UFW installieren! — Der Server hat eine native Network-Firewall davor
  • Tailscale funktioniert immer, auch wenn der öffentliche SSH-Port gelegentlich blockiert
  • Templates laufen als systemd-Services — Debugging über journalctl -u <name> -f
  • Immer in tmux arbeiten — SSH-Verbindungsabbrüche töten sonst laufende Jobs

Software-Stack

KomponenteVersionZweck
vLLMv0.20.1Inference-Server mit OpenAI-kompatibler API
Python3.10+Batch-Scripts mit asyncio + aiohttp
TailscaleaktuellVPN-Zugang (WireGuard), umgeht Firewall-Probleme
tmuxPersistente Terminal-Sessions für Langzeit-Jobs

vLLM ist der entscheidende Baustein: Es bietet Continuous Batching, das heißt mehrere Anfragen werden gleichzeitig auf der GPU verarbeitet. Im Vergleich zu Ollama (sequenziell) ist das 5–10× schneller bei gleicher Hardware.

Getestete Modelle

Drei Generationen von Vision-Modellen wurden mit denselben 500 Testbildern verglichen: 400 Einzelfotos und 100 Filmstrips (Video-Thumbnails in einem Bild).

LLaVA 7B
  • Laufzeit: Ollama (Mac mini)
  • Quantisierung: Q4_0
  • VRAM: ~4 GB
  • Ergebnis: ⌀ 60 Zeichen
  • Geschwindigkeit: ~1 Bild/3s
  • Nur Englisch
  • Keine strukturierte Ausgabe
Qwen2.5-VL 7B
  • Laufzeit: vLLM (Trooper)
  • Quantisierung: BF16 (full)
  • VRAM: ~16 GB
  • Ergebnis: ⌀ 500 Zeichen
  • Geschwindigkeit: ~30 Bilder/Min
  • Deutsch möglich
  • JSON-Output stabil

Warum AWQ statt FP8?

Das 32B-Modell in voller Präzision (FP16) benötigt ~64 GB VRAM — doppelt so viel wie unsere Karte hat. FP8-Quantisierung hätte ~32,5 GB gebraucht — das passt technisch, aber lässt keinen Raum für den KV-Cache, den vLLM für jede parallele Anfrage braucht.

AWQ 4-bit komprimiert die Weights auf ~18 GB und lässt damit ~14 GB für den KV-Cache übrig. Das reicht für 4 parallele Anfragen — genug für einen stabilen Batch-Betrieb.

Entscheidung

AWQ 4-bit statt FP8 8-bit

FP8 hätte theoretisch bessere Qualität geliefert, passt aber nicht in 32 GB VRAM wenn gleichzeitig Batch-Verarbeitung laufen soll. AWQ 4-bit ist der pragmatische Kompromiss — und die Qualitätsunterschiede sind in der Praxis kaum messbar.

Optimierungen

Der Weg zum stabilen 32B-Batch war nicht geradlinig. Drei Iterationen waren nötig, bis alles fehlerfrei lief.

Iteration 1: Erster Start (50% Fehler)

Der erste 32B-Batch-Lauf startete mit den gleichen Einstellungen wie beim 7B: Concurrency 8, Timeout 120 Sekunden, Standard-AWQ-Kernels. Ergebnis: 50% der JSON-Anfragen liefen in Timeouts.

Iteration 2: AWQ Marlin entdeckt

In den vLLM-Logs fand sich ein Hinweis:

WARNING: Using AWQ quantization. For better performance,
consider using 'awq_marlin'.

AWQ Marlin sind optimierte Matrix-Multiplikations-Kernels, die speziell für 4-bit-Gewichte entwickelt wurden. Sie nutzen die Tensor-Cores der GPU effizienter als die Standard-AWQ-Implementierung.

Iteration 3: Die drei Stellschrauben

ParameterVorherNachherWirkung
--quantizationawqawq_marlin~2× schnellere Inference
Concurrency84Mehr KV-Cache pro Request
Timeout120s300sSicherheitspuffer für JSON

Die finale vLLM-Konfiguration:

python -m vllm.entrypoints.openai.api_server \
  --model Qwen/Qwen2.5-VL-32B-Instruct-AWQ \
  --quantization awq_marlin \
  --limit-mm-per-prompt '{"image": 1}' \
  --max-num-seqs 4 \
  --max-model-len 8192 \
  --gpu-memory-utilization 0.92 \
  --dtype float16 \
  --port 8000
Erkenntnis

dtype muss float16 sein, nicht bfloat16

AWQ-quantisierte Modelle erwarten float16 als Datentyp. Mit bfloat16 (dem Standard bei vLLM) stürzt der Server beim Start ab. Das steht nicht prominent in der Dokumentation — man findet es erst in den Fehlermeldungen.

Erkenntnis

AWQ Marlin: Der unterschätzte Gamechanger

Der Wechsel von Standard-AWQ zu AWQ Marlin hat die Fehlerrate von 50% auf 0% gesenkt und die Geschwindigkeit verdoppelt — bei identischer Modellqualität. Die Marlin-Kernels sind keine Approximation, sondern einfach effizienterer Code für die gleiche Mathematik.

Ergebnisse im Vergleich

Erfolgsrate der Batch-Verarbeitung

7B Fotos 799/800 99,9% Erfolg
7B Filmstrips 197/200 98,5% Erfolg
32B Fotos 800/800 100% Erfolg
32B Filmstrips 157/200 78,5% Erfolg

Die Filmstrip-Fehler beim 32B entstehen durch das max-model-len von 8192 Tokens. Filmstrips sind große Bilder (6–12 Thumbnails nebeneinander), die mehr Tokens verbrauchen als Einzelfotos.

Geschwindigkeit (Bilder/Minute)

LLaVA 7B
~20/min
Qwen 7B
~30/min
Qwen 32B Marlin
~17/min

Textlänge (Ø Zeichen)

LLaVA 7B
⌀ 60
Qwen 7B
⌀ 500
Qwen 32B AWQ
⌀ 773

Die Textlänge allein ist kein Qualitätsmaß — aber sie zeigt, wie viel Detail das Modell wahrnimmt. LLaVA liefert Einzeiler wie „A lighthouse on a rocky coast". Qwen 7B beschreibt Szene, Stimmung und sichtbare Objekte. Qwen 32B ergänzt zusätzlich Tageszeit-Schätzungen, Perspektiven-Analyse und emotionale Einordnung.

Gesamtübersicht

EigenschaftLLaVA 7BQwen 7BQwen 32B AWQ
Beschreibungslänge⌀ 60 Zeichen⌀ 500 Zeichen⌀ 773 Zeichen
Sprachenur EnglischDeutschexzellentes Deutsch
JSON-Outputnicht möglichstabil (99,8%)fehlerfrei (100%)
Filmstrip-Verständnisschlechtgutsehr gut
Geschwindigkeit~20 Bilder/min~30 Bilder/min~17 Bilder/min
VRAM-Bedarf~4 GB~16 GB~18 GB + 14 GB KV
HardwareMac mini M2 ProRTX 4080 SuperRTX 4080 Super

Qualitätsanalyse

Ein direkter Textvergleich zeigt den Qualitätssprung am besten. Hier dasselbe Foto (ein Leuchtturm an der Küste) durch alle drei Modelle:

LLaVA 7B

A lighthouse on a cliff overlooking the ocean at dusk.

Qwen 7B

Das Bild zeigt eine Küstenlandschaft mit einem Leuchtturm, der auf einem felsigen Vorsprung steht. Der Himmel ist bewölkt und dunkel, was auf Dämmerung hindeutet. Im Vordergrund sind ein helles Muster auf dem Boden zu sehen. Die Stimmung ist ruhig und etwas geheimnisvoll.

Qwen 32B AWQ

Das Bild zeigt eine Szene bei Dämmerung oder frühem Abend, bei der ein Leuchtturm im Vordergrund steht. Der Leuchtturm ist weiß mit einem markanten roten Streifen und befindet sich auf einem Felsvorsprung über dem Meer. Der Himmel ist dunkel, mit einigen Wolken, die teilweise von einem schwachen Licht durchflutet sind. Im Vordergrund ist ein helles Muster auf dem Boden zu sehen, das möglicherweise ein Hubschrauberlandeplatz ist.

Der 32B erkennt Details, die dem 7B entgehen: den roten Streifen am Leuchtturm, interpretiert das Bodenmuster als möglichen Hubschrauberlandeplatz und analysiert die Lichtstimmung differenzierter.

Strukturierter JSON-Output (32B)

{
  "kurzbeschreibung": "Ein stürmischer Ozean mit großen Wellen,
                       die sich an Felsen brechen.",
  "ausfuehrlich": "Das Bild zeigt eine dynamische Meereslandschaft,
                   in der hohe Wellen sich an dunklen Felsen brechen...",
  "objekte": ["Wellen", "Felsen", "Meer"],
  "personen": "keine",
  "umgebung": "Ozean, Felsküste, stürmische Bedingungen",
  "stimmung": "dynamisch, energiegeladen, etwas bedrohlich",
  "farben": ["Blau", "Weiß", "Dunkelbraun"],
  "tageszeit": "Dämmerung",
  "perspektive": "Mittel",
  "tags": ["Ozean", "Wellen", "Felsen", "Sturm",
           "Meereslandschaft", "Natur", "Küste"],
  "text_im_bild": "kein Text"
}

Dieses JSON-Schema wird bei 100% der Fotos fehlerfrei eingehalten. Der 7B erreicht hier 99,8%. LLaVA unterstützt kein strukturiertes Output.

Filmstrip-Verarbeitung

Filmstrips sind besonders anspruchsvoll: 6–12 Video-Thumbnails in einem einzigen Bild. Das Modell muss erkennen, dass es sich um eine Sequenz handelt, und die Entwicklung der Szene beschreiben.

32B — Filmstrip: Leuchtturm-Küste

Das Video zeigt eine Küstenlandschaft mit einem markanten Leuchtturm, der auf einer felsigen Halbinsel steht. Der Hintergrund ist geprägt von einem offenen, ruhigen Ozean unter einem klaren Himmel mit einigen Wolken. Die Szene bleibt über die einzelnen Frames hinweg weitgehend unverändert, mit dem Fokus auf der majestätischen Natur und der ruhigen Atmosphäre.

Live-Test: GoPro-Kurvenfotos

Neben der Batch-Verarbeitung wurde das 32B-Modell auch für eine ungewöhnliche Aufgabe eingesetzt: Die Analyse von Motorrad-Kurvenfotos einer GoPro-Helmkamera — inklusive Schätzung von Kurvenradius und Schräglage.

Waldstraße-Kurve
SzenerieSchmale Waldstraße mit Herbstlaub, Motorrad in Linkskurve
Kurvenwinkelca. 60–70°
Schräglageca. 20–25°
BesonderheitenNasses Laub auf der Fahrbahn erkannt, Herbstlicht-Stimmung
Bergpanorama-Kurve
SzenerieBergstraße mit Panoramablick, Motorrad in Rechtskurve
Kurvenwinkelca. 45–55°
Schräglageca. 15–20°
BesonderheitenLeitplanke und Gegenverkehr-Spur erkannt, alpine Landschaft

Die Schätzungen sind keine exakten Messungen, aber sie zeigen, dass das Modell räumliche Geometrie versteht. Für eine semantische Suche im Archiv wäre das ausreichend genau.

Kosten & Wirtschaftlichkeit

Testlauf: 500 Bilder

ModellLaufzeitAnteilige Kosten
Qwen 7B (500 Bilder, 4 Aufgaben)~20 min~0,19 €
Qwen 32B AWQ Marlin (500 Bilder, 4 Aufgaben)~35 min~0,33 €

Hochrechnung: 150.000 Bilder

Option B: Qwen 32B AWQ

  • Laufzeit: ~16–20 Stunden
  • Kosten: ~10–12 €
  • Qualität: ⌀ 773 Zeichen, sehr gut
  • Fehlerrate: 0% (Fotos)

Beide Optionen sind wirtschaftlich — selbst der 32B-Lauf kostet weniger als ein einziges Cloud-API-Bild bei GPT-4o Vision.

Empfehlung

Empfehlung für den Produktionslauf

Den 7B für den Erst-Durchlauf über alle 150k Bilder verwenden — schnell, günstig, zuverlässig. Anschließend selektiv den 32B für wichtige oder komplexe Bilder nachfahren lassen.

Erkenntnisse

Erkenntnis

AWQ Marlin ist nicht optional

Der Wechsel von Standard-AWQ zu Marlin-Kernels hat die Fehlerrate von 50% auf 0% gesenkt und die Geschwindigkeit verdoppelt. Das war nicht Tuning — das war der Unterschied zwischen „funktioniert nicht" und „funktioniert perfekt".

Erkenntnis

Concurrency muss zum Modell passen

Der 7B läuft stabil mit 40 parallelen Anfragen. Der 32B bricht bei 8 schon zusammen. Die richtige Concurrency hängt vom VRAM-Bedarf des KV-Cache pro Request ab — nicht von CPU oder Netzwerk.

Erkenntnis

vLLM >> Ollama für Batch

Ollama ist großartig für interaktive Nutzung, aber für Batch-Verarbeitung ist vLLM mit Continuous Batching 5–10× schneller. Bei 150k Bildern ist das der Unterschied zwischen 1 Tag und 1 Woche.

Organisatorische Lessons Learned

  • Tailscale ist Pflicht: Der öffentliche SSH-Port war mehrfach nicht erreichbar. Tailscale funktioniert immer — und ist sicherer.
  • tmux vor allem anderen: SSH-Verbindungen brechen ab. Ohne tmux: Job tot. Mit tmux: einfach reconnecten.
  • Resume-Logik in jedem Batch-Script: Jedes Script prüft, welche Bilder schon verarbeitet sind. Ein Absturz bei Bild 80.000 kostet dann Sekunden, nicht Stunden.
  • Keine UFW auf Trooper: Die Plattform hat eine eigene Firewall. UFW würde den Zugriff blockieren.

Ausblick & nächste Schritte

01

Produktionslauf 150k Bilder

7B-Modell über alle Bilder. Geschätzte Laufzeit: 8–10 Stunden. Kosten: ~5–6 €.

02

Embeddings erzeugen

BGE-M3 für Text-Embeddings, SigLIP-2 für Bild-Embeddings. Auf dem gleichen Trooper-Server.

03

Qdrant + Such-UI

Vektordatenbank auf dem Mac mini, Streamlit-UI für die Suche. Dauerbetrieb ohne GPU-Kosten.

04

Weitere Modelle testen

InternVL2.5-8B oder Gemma 3 12B könnten ein besseres Preis-Leistungs-Verhältnis bieten.

ArchivBlick ist ein aktives Projekt. Mehr dazu im ersten ArchivBlick-Artikel und auf der Projektseite.