LibreVLM
Richte ein Vision-Language-Modell auf ein Bild, übergib ihm eine Liste von Wörtern und erhalte Boxen zurück. LibreVLM verwandelt Qwen3-VL, Florence-2 und ähnliche Modelle in Open-Vocabulary-Objektdetektoren, die exakt dieselbe Results-API wie jedes andere LibreYOLO-Modell verwenden.
Einführung
Ein klassischer Detektor wird mit einer festen, in seinen Head eingebauten Klassenliste ausgeliefert. LibreVLM hebt diese Einschränkung auf. Es bindet moderne, auf Anweisungen abgestimmte Vision-Language-Modelle ein, fordert sie zur Ausgabe von Bounding Boxes auf, parst den generierten Text und gibt dasselbe Results-Objekt zurück, das du bereits für YOLO9 und RF-DETR nutzt. Die Klassenliste ist lediglich eine Liste von Wörtern, die du zur Laufzeit übergibst. Das Hinzufügen einer neuen Kategorie kostet daher nichts und funktioniert per Zero-Shot.
- Offenes Vokabular. Erkenne
"pink car","license plate"oder"the small island", ohne je einen Head dafür zu trainieren. - Eine Factory, ein Vertrag.
LibreVLM(...)gibt die standardmäßigenResultsmitboxes.xyxy,boxes.clsundboxes.confsowie.plot()und.save()zurück. - Austauschbare Backends. Sechs Modellfamilien hinter einem Alias-String, von Florence-2 mit 230M bis Qwen3-VL mit 8B.
- Ein direkter Ausweg.
chat()ermöglicht freie Fragen zu Bildern, wenn du mehr als Boxen brauchst.
Warum eine eigene Stufe und eine eigene Seite?
LibreVLM bleibt bewusst außerhalb der Closed-Vocabulary-Factory LibreYOLO(...) und ihrer .pt-Registry. Diese Modelle werden von Prompts gesteuert, arbeiten mit offenem Vokabular und geben synthetische Confidence aus. Deshalb erfüllen sie einen anderen Vertrag. Eine eigene Stufe hält die Kerndokumentation zur Erkennung übersichtlich und macht transparent, was tatsächlich gemessen wird.
Auf dem dev-Branch
LibreVLM befindet sich derzeit auf dem Branch dev und ist für das Release v1.3 vorgesehen. Es ist nicht Teil von v1.2.0. Die Stufe bietet ausschließlich Python-Inferenz: Training, Validierung, Export und ein CLI-Pfad fehlen noch, und die Confidence-Werte sind Platzhalter. Lies den Abschnitt Einschränkungen, bevor du darauf aufbaust.
Installation
LibreVLM ist über das optionale Extra vlm verfügbar. Es installiert eine aktuelle Version von transformers und die Hilfsbibliotheken, die einige Prozessoren benötigen. Ohne das Extra löst der Import einer VLM-Familie einen ImportError aus, der auf diese Stelle verweist.
1 pip install 'libreyolo[vlm]'
Die Gewichte werden bei der ersten Verwendung vom Hugging Face Hub in einen lokalen Ordner weights/ heruntergeladen. Einige Familien werden unter Nicht-OSI-Lizenzen ausgeliefert und protokollieren vor dem Download einmalig einen Hinweis. Für die größeren Backends wird eine GPU empfohlen, aber mit device="cpu" läuft jedes Modell auch auf der CPU.
Schnellstart
Erstelle ein Modell, gib die relevanten Wörter an und führe die Vorhersage aus. Das Standard-Backend ist Qwen3-VL-4B, der stärkste Detektor dieser Stufe unter Apache-2.0-Lizenz.
1 from libreyolo import LibreVLM 2 3 # Qwen3-VL-4B by default; weights autodownload on first use 4 model = LibreVLM() 5 6 # The vocabulary is just words. Any words. 7 model.set_classes(["pink car", "wheel"]) 8 9 result = model.predict("street.jpg") 10 11 print(result.boxes.xyxy) # pixel [x1, y1, x2, y2] 12 print(result.boxes.cls) # ids into ["pink car", "wheel"] 13 result.plot() # same drawing helpers as any LibreYOLO model 14 result.save("out.jpg")
Das ist der gesamte Ablauf. Alles nach predict() verhält sich wie bei einem normalen Detektor, deshalb funktionieren vorhandener Visualisierungs-, Zuschneide- und Tracking-Code weiterhin.
Unterstützte Modelle
Wähle ein Backend über den Alias, den du an LibreVLM(...) übergibst. Ein allein stehender Familienname wird auf seine Standardgröße aufgelöst. Das allgemeine Standard-Backend ist qwen3-vl-4b. In der Praxis sind Qwen3-VL, LFM2-VL und Florence-2 die stärksten Detektoren.
| Familie | Aliasname | Größen (Parameter) | Lizenz | Hinweise |
|---|---|---|---|---|
| Qwen3-VL | qwen3-vl-2b / -4b / -8b | 2B / 4B / 8B | Apache-2.0 | Standard und stärkstes Modell. Als Einstieg empfohlen. |
| LFM2-VL | lfm2-vl-450m / -1.6b | 450M / 1.6B | LFM Open License | Für das Edge dimensioniert, überraschend starker kleiner Detektor. Hinweis erforderlich. |
| InternVL3 | internvl3-1b / -2b / -8b | 1B / 2B / 8B | Qwen License | Gutes Grounding bei 8B, kleine Größen sind schwach. Hinweis erforderlich. |
| Florence-2 | florence-2-base / -large | 0.23B / 0.77B | MIT | Speziell entwickeltes Grounding-Modell. Enge Boxen, kein chat(). |
| SmolVLM2 | smolvlm2-500m / -2.2b | 500M / 2.2B | Apache-2.0 | Winzig und schnell, aber schwächerer Detektor. Gut für schnelle Versuche. |
| Kosmos-2 | kosmos-2 | ~1.6B | MIT | Grounder aus dem Jahr 2023. Gröbere Boxen, kein chat(). |
Auswahl eines Backends
- Beste Qualität:
qwen3-vl-8boderqwen3-vl-4b(Standard). - Enge Boxen, kleiner Ressourcenbedarf:
florence-2-large. - Edge / CPU:
lfm2-vl-450modersmolvlm2-500m. - Vollständig permissive Lizenz: jede Größe von Qwen3-VL, SmolVLM2, Florence-2 oder Kosmos-2.
Lizenzierung
Qwen3-VL und SmolVLM2 stehen unter Apache-2.0, Florence-2 und Kosmos-2 unter MIT. LFM2-VL und InternVL3 tragen Nicht-OSI-Lizenzen und geben vor dem ersten Download einmalig einen Hinweis aus, damit du eine informierte Entscheidung zur kommerziellen Nutzung treffen kannst.
Festlegen des Vokabulars
Das Vokabular ist das Herzstück der Open-Vocabulary-Erkennung. Rufe set_classes() mit einer Liste von Label-Strings auf. Die Einstellung bleibt bestehen: Sie gilt für jeden späteren Aufruf von predict() und track(), bis du sie erneut setzt. Die Methode gibt self zurück und lässt sich daher verketten.
1 # Sticky and chainable 2 model = LibreVLM("qwen3-vl-2b").set_classes(["person", "dog", "cat"]) 3 4 # Set it once at construction instead 5 model = LibreVLM("lfm2-vl-450m", names=["boat"], device="cpu") 6 7 # Re-set any time to change what you are looking for 8 model.set_classes(["a red car", "a blue truck"])
Labels können beliebige Wortgruppen sein. Sie müssen unabhängig von Groß- und Kleinschreibung eindeutig sein, und du musst eine Liste statt eines einzelnen Strings übergeben. Wenn du set_classes() nie aufrufst, greift das Modell auf das COCO-80-Vokabular zurück. So liefert auch ein allein stehendes predict() ein sinnvolles Ergebnis.
Vorhersage
predict() und der gleichwertige Aufruf model(...) akzeptieren dieselben Quelltypen wie jeder LibreYOLO-Detektor: einen Pfad, ein PIL-Bild, ein NumPy-Array, eine URL, einen Ordner oder ein Video. stream=True und track() funktionieren ebenfalls.
1 result = model.predict( 2 source="image.jpg", # path | PIL | ndarray | URL | folder | video 3 conf=0.25, # see note below: scoring is synthetic 4 classes=[0], # optional: keep only these vocabulary ids 5 max_det=300, 6 )
Rückgabeform
Du erhältst das standardmäßige Results-Objekt zurück, genau wie bei einem Closed-Vocabulary-Detektor:
| Feld | Form / Typ | Bedeutung |
|---|---|---|
result.boxes.xyxy | N x 4 | Pixel-Boxen [x1, y1, x2, y2], auf das Originalbild skaliert. |
result.boxes.cls | N | Klassen-IDs, die dein set_classes()-Vokabular indizieren. |
result.boxes.conf | N | Synthetische Confidence: 1.0 für jede Box (siehe Einschränkungen). |
result.plot() / .save() | - | Die üblichen Hilfsfunktionen zum Zeichnen und Speichern. |
Intern parst LibreVLM die Modellausgabe tolerant, einschließlich Markdown-Blöcken, verstreuter Prosa, doppelter Boxen und abgeschnittener Arrays. Es ordnet Freitext-Labels wieder deinen Klassen-IDs zu und verwirft jedes Label, das nicht in deinem Vokabular enthalten ist. Dieser letzte Schritt lässt einen freien Generator wie einen Closed-Set-Detektor arbeiten.
Beispiele
Ein Objekt mit einer bestimmten Farbe erkennen
1 from libreyolo import LibreVLM 2 3 model = LibreVLM("qwen3-vl-4b") 4 model.set_classes(["red car"]) 5 6 result = model.predict("parking_lot.jpg") 7 print(f"Found {len(result.boxes.cls)} red car(s)") 8 result.save("red_cars.jpg")
Enge Boxen mit Florence-2
1 # Florence-2 is a purpose-built grounder: very tight pixel boxes. 2 model = LibreVLM("florence-2-large") 3 model.set_classes(["a red car", "license plate"]) 4 5 result = model.predict("car.jpg") 6 result.plot()
Dynamisch nach einer einzelnen Klasse filtern
1 model = LibreVLM("qwen3-vl-2b").set_classes(["person", "dog", "cat"]) 2 3 # classes= filters the configured vocabulary by id 4 people_only = model.predict("street.jpg", classes=[0])
Mit einem integrierten Beispielbild auf der CPU ausführen
1 from libreyolo import LibreVLM, SAMPLE_IMAGE 2 3 model = LibreVLM("lfm2-vl-450m", device="cpu") 4 # No set_classes() -> falls back to the COCO-80 vocabulary 5 result = model.predict(SAMPLE_IMAGE) 6 print(model.names[result.boxes.cls[0]]) # e.g. "person"
Batches, Ordner und Videos
1 model = LibreVLM().set_classes(["forklift", "pallet"]) 2 3 # A whole folder 4 for result in model.predict("warehouse_frames/", stream=True): 5 result.save() 6 7 # A video file (frames are processed one at a time) 8 model.predict("warehouse.mp4", save=True)
Roher Chat
Manchmal brauchst du das Modell statt des Detektors. Die Chat-Template-Familien stellen chat() bereit. Die Methode nimmt ein Bild und einen freien Prompt entgegen und gibt den dekodierten Text unverändert zurück. Nutze sie zum Zählen, für Bildbeschreibungen oder für schnelle visuelle Fragen.
1 model = LibreVLM("qwen3-vl-4b") 2 3 answer = model.chat("harbor.jpg", "How many boats are docked? Answer with a number.") 4 print(answer)
chat() ist für die Chat-Template-Familien Qwen3-VL, LFM2-VL, SmolVLM2 und InternVL3 verfügbar. Florence-2 und Kosmos-2 sind Task-Token-Grounder und lösen NotImplementedError aus. Nutze mit ihnen predict().
Unterschiede zwischen den Backends
Jede Familie gibt dieselben Results zurück, erreicht sie aber auf einem anderen Weg. Das ist selten wichtig, erklärt jedoch das Verhalten einiger Backends. Die Chat-Familien werden zur Ausgabe eines JSON-Arrays von Boxen aufgefordert, während die Grounder spezielle Task-Tokens verwenden.
| Familie | Prompt-Steuerung | Koordinatenraum | chat() |
|---|---|---|---|
| Qwen3-VL | JSON-Box-Prompt | 0 bis 1000, neu skaliert | Ja |
| LFM2-VL | JSON-Box-Prompt | Auf 0 bis 1 normalisiert | Ja |
| SmolVLM2 | JSON-Box-Prompt | Auf 0 bis 1 normalisiert | Ja |
| InternVL3 | JSON-Box-Prompt | 0 bis 1000, neu skaliert | Ja |
| Florence-2 | Task-Token | Native Pixel | Nein |
| Kosmos-2 | Grounding-Prompt | Normalisiert, neu skaliert | Nein |
Bei den Chat-Familien kannst du den Erkennungs-Prompt mit dem Konstruktorargument prompt= überschreiben und die Generierungslänge mit max_new_tokens= begrenzen. Gerät und Datentyp werden automatisch bestimmt: bf16 oder fp16 unter CUDA, fp32 auf der CPU.
Einschränkungen
LibreVLM ist leistungsfähig, aber noch jung. Wenn du die Grenzen vorab kennst, vermeidest du spätere Überraschungen.
- Synthetische Confidence. Jede Box erhält den Wert 1.0. Der Filter
conf=verhält sich daher nach dem Alles-oder-nichts-Prinzip statt wie ein echter Schwellenwert. - Keine mAP / Validierung.
val()löst einen Fehler aus, weil synthetische Werte die COCO-mAP irreführend machen würden. - Kein Training oder Export.
train()undexport()lösen Fehler aus. Führe stattdessen Upstream ein Fine-Tuning des VLM durch und lade die daraus entstandenen Gewichte. - Eingeschränktes Tracking.
track()läuft, aber einheitliche Werte setzen die Wiederherstellungsstufe des Trackers für niedrige Confidence außer Kraft. - Jeweils ein Bild. In v1 läuft die Generierung sequenziell, deshalb bringen größere Werte für
batch=keinen Geschwindigkeitsvorteil. - Nur Python-API. Die CLI
libreyololöst VLM-Aliasse noch nicht auf.
Stärken
Nutze LibreVLM, wenn die Klassenmenge offen ist, sich häufig ändert oder sich vorab nur schwer labeln lässt: für schnelles Prototyping, Long-Tail- oder seltene Kategorien und Workflows nach dem Muster „Finde das Objekt, das ich in Worten beschreibe“. Wenn du kalibrierte Confidence, Durchsatz oder ein ausrollbares Artefakt brauchst, trainiere ein Closed-Vocabulary-Modell wie YOLO9 oder RF-DETR aus der Kerndokumentation.