CLIP: Wie sich der Schatz ungelabelter Bilddaten heben lässt


Fabian Gringel


many unlabeled images at one place

Die Digitalisierung und vor allem das Internet haben uns nicht nur eine scheinbar unerschöpfliche Quelle an Textdaten, sondern auch an Bildern beschert. Im Falle von Texten wurde dieser Schatz in Form von aufgabenagnostischem Pretraining durch Sprachmodelle wie BERT oder GPT-3 gehoben. Contrastive Language-Image Pretraining (kurz: CLIP) macht nun etwas Ähnliches mit Bildern, oder besser: der Kombination von Bildern und Texten.

In diesem Blog-Artikel gebe ich einen groben, nicht-technischen Überblick über die Funktionsweise von CLIP, und ich zeige auch, wie Sie CLIP selbst ausprobieren können! Wenn Sie eher technisch veranlagt sind und sich für die Details interessieren, dann empfehle ich Ihnen die Lektüre der Originalpublikation, die ich für gut geschrieben und verständlich halte.


Hintergrund


Trotz der enormen Fortschritte, die im letzten Jahrzehnt auf dem Gebiet des maschinellen und tiefen Lernens erzielt wurden, bleibt ein Kritikpunkt bestehen: Selbst die leistungsstärksten State-of-the-Art-Modelle lernen immer noch außerordentlich ineffizient.

Nehmen wir das maschinelle Sehen, insbesondere die Bildklassifikation: Wo ein Mensch ein Beispielbild oder vielleicht eine Handvoll braucht, um ein visuelles Konzept zu lernen und es in neuen Instanzen zu erkennen, brauchen ML-Modelle oft Tausende, um eine dem Menschen ähnliche Leistung zu erreichen.

Das Problem ist nicht, dass es nicht genügend Daten gäbe, mit denen man die ML-Modelle füttern könnte, sondern dass wir sie für die meisten Trainingsaufgaben erst labeln müssen - und das ist in der Regel sehr aufwändig.

Aber selbst wenn sich eine Menge manueller Labeler die Mühe macht, einen riesigen annotierten Datensatz wie ImageNet (14 Millionen gelabelte Bilder) zu erstellen, und wir unsere besten Modelle darauf trainieren und tatsächlich eine Genauigkeit auf menschlichem Niveau erreichen oder sie sogar übertreffen - dann hat sich gezeigt, dass die Modelle immer noch sehr schlecht auf Datensätzen abschneiden, die aus leicht unterschiedlichen Verteilungen stammen (z. B. erkennen Bildklassifizierungsmodelle, die auf Fotos trainiert wurden, oft keine Skizzen von Objekten) und können leicht durch "adversarial examples" getäuscht werden.

Kurz gesagt: Selbst die größten manuell gelabelten Datensätze, die wir haben, sind zu klein, um darauf trainierte Modelle gut verallgemeinern zu lassen. Es gibt zwei mögliche Lösungen für dieses Problem: Entweder bessere Modelle zu entwickeln, oder noch viel größere und vielfältigere Datensätze bereitzustellen. Es ist letzteres, was CLIP versucht.


Masked Language Modeling


Im Kontext von Aufgaben der natürlichen Sprachverarbeitung ist es bereits üblich, die Massen an (ungelabelten!) Textdaten zu nutzen, die in digitalisierter Form vorliegen (z. B. Wikipedia-Artikel, digitalisierte Bücher).

Der Trick dabei ist, Labels automatisch zu generieren. Eine Möglichkeit, dies zu tun, ist das sogenannte Masked Language Modeling. Es gibt verschiedene Varianten, aber eine einfache Version wäre, den Text in geeignete kleinere Stücke, z. B. Sätze, zu schneiden und ein Wort pro Satz auszublenden. Die Aufgabe besteht dann darin, das maskierte Wort zu erraten:

Dieses Verfahren erlaubt es, eine überwachte Lernaufgabe zu definieren, auf die NLP-Modelle wie BERT trainiert werden können, obwohl es keine manuellen Labels gibt.

All dies wäre nicht sehr interessant, wenn die auf diese Weise trainierten Modelle nur gut für die Vorhersage maskierter Wörter wären. Aber es stellt sich heraus, dass sie sozusagen nebenbei oft sinnvolle Worteinbettungen lernen, also solche Einbettungen, die statistische semantische Beziehungen kodieren, die für alle möglichen NLP-Aufgaben unglaublich nützlich sind.


CLIP - die Grundidee


Die Grundidee hinter CLIP ist recht einfach. So wie Sprachmodelle ohne manuelle Überwachung auf den riesigen Mengen von Texten, die im Internet verfügbar sind, trainiert werden können, macht CLIP etwas Ähnliches mit Bildern.

Dies funktioniert wie folgt:

  1. Scrapen Sie das Web, um einen Datensatz von Bildern zu erhalten, jedes mit einem kurzen Text, vorzugsweise einer Bildunterschrift, die den Inhalt des Bildes beschreibt (verwenden Sie z. B. nur die Titel oder Alt-Texte).

  2. Erstellen Sie ein Modell, das aus einem Text-Encoder (z. B. einem Transformer) und einem Bild-Encoder (z. B. einem ResNet oder einem Vision Transformer) besteht, die ihre Eingaben in einen gemeinsamen Vektorraum ("latenter Raum") einbetten, und geben Sie die Ähnlichkeit der beiden Einbettungen aus (z. B. über Cosinus-Ähnlichkeit).

  3. Generieren Sie Eingabe-Ziel-Paare, indem Sie die Eingabe als ein Bild zusammen mit einem zufällig gewählten Begleittext definieren und das Ziel auf 1 setzen, wenn es der Text ist, der ursprünglich dem Bild beigefügt war, und auf 0, wenn nicht.

  4. Trainieren Sie das Modell, um einen hohen Ähnlichkeitswert (≈1) für Bild-Text-Paare auszugeben, die ursprünglich zusammengehören, und niedrige Werte (≈0) für solche, die nicht zusammengehören.

Mit anderen Worten: CLIP geht davon aus, dass wir nützliche Informationen über Bilder aus dem Internet haben, die wir nutzen können, um eine überwachte Pretraining-Aufgabe zu definieren. Bildunterschriften sind ähnlich wie Klassenlabels in Bildklassifizierungsaufgaben, mit einem offensichtlichen Vorbehalt: Für letztere haben wir eine feste, normalerweise relativ kleine Anzahl von diskreten Klassen. Im Gegensatz dazu ähneln Bildlabels eher einem kontinuierlichen Raum von Klassen. Um diesem Raum zu strukturieren und seine Elemente mit Bildern vergleichbar zu machen, stützt sich CLIP auf einen Text-Encoder. Der latente Raum macht Bilder mit Texten kommensurabel, d.h. im latenten Raum kann man vergleichen, wie sehr der Inhalt eines Bildes dem ähnelt, was ein Text beschreibt.

Der besagte Unterschied zwischen Bildunterschriften und Klassenlabels ist auch der Grund, warum CLIP als Trainingsziel nicht die Generierung der Bildunterschrift aus dem Bild definiert (was einer Vorhersage der Klasse noch am nächsten käme), sondern das beschriebene "kontrastive" Trainingsziel verwendet, d. h. die Vorhersage, ob eine gegebene Bildunterschrift zu einem gegebenen Bild gehört oder nicht. Es wäre zu schwierig, die genaue Beschriftung im kontinuierlichen Labelraum zu bestimmen.

CLIP liefert jedoch mehr als nur eine nützliche Pretraining-Aufgabe, wie wir im nächsten Abschnitt sehen werden.


Zero-shot Lernen


Zero-Shot-Lernen bezieht sich auf die Fähigkeit eines vortrainierten Modells, Aufgaben auszuführen, für die es nicht trainiert wurde, ohne vorher Beispiele für die neuen Aufgaben zu sehen (es sieht null Beispiele, daher der Name).

Das CLIP-Modell ist in der Tat ein Zero-Shot-Bildklassifikator, der durch eine "Anweisung" angepasst werden kann. Wenn wir die Zeichenkette "Ein Hund mit spitzen Ohren." in den Text-Encoder eingeben, beginnt das Modell nach Bildern zu suchen, die Hunde mit spitzen Ohren zeigen. Und wenn Sie lieber Bilder von fetten roten Katzen klassifizieren wollen, sagen Sie dem Modell einfach, dass es das tun soll.

In der Tat ist es einfach, dies in der Praxis auszuprobieren. Dank OpenAI und Hugging Face benötigen Sie nur die folgenden Codezeilen:

from PIL import Image
import requests

from transformers import CLIPProcessor, CLIPModel

model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")

urls = [
    "https://upload.wikimedia.org/wikipedia/commons/4/4c/Blackcat-Lilith.jpg",
    "https://cdn.pixabay.com/photo/2016/11/08/18/10/dog-1809044_960_720.jpg",
    "https://upload.wikimedia.org/wikipedia/commons/7/73/Lion_waiting_in_Namibia.jpg",
    "https://live.staticflickr.com/65535/51018988161_f0ce02d495_b.jpg",
    "https://upload.wikimedia.org/wikipedia/commons/2/29/Big_Fat_Red_Cat.jpg"
]
images = [Image.open(requests.get(url, stream=True).raw) for url in urls]

inputs = processor(text=["A photo of a fat red cat.", "Not a photo of a fat red cat."], images=images, return_tensors="pt", padding=True)

outputs = model(**inputs)
logits_per_image = outputs.logits_per_image
probs = logits_per_image.softmax(dim=1)

Die URLs gehören zu Bildern, die ich ausgewählt habe, weil ich dachte, sie wären schwer von einem echten "Foto einer fetten roten Katze" zu unterscheiden. Die Aufgabe für CLIP ist dann zu beurteilen, ob diese Bilder besser durch "Ein Foto einer fetten roten Katze." oder "Kein Foto einer fetten roten Katze." beschrieben werden. (diese spezifische Negation ist vielleicht nicht die beste Art, die Klasse "etwas Anderes" zu definieren, probieren Sie ruhig andere Aufforderungen aus). CLIP gibt für jedes Bild zwei Ähnlichkeitsscores aus, die den beiden Klassen entsprechen und die wir leicht als Wahrscheinlichkeiten interpretieren können, indem wir den Softmax nehmen.

Dies sind die Ergebnisse:

Es stellt sich heraus, dass wir CLIP mit dem Hund täuschen konnten, aber mit keinem der anderen Bilder - nicht einmal mit der schlanken roten Katze.

CLIP wurde nicht auf diese spezielle Aufgabe trainiert - wahrscheinlich ist es im Trainingsset nie auf die Bildunterschrift "A photo of a fat red cat." gestoßen. Dennoch weiß es, nach welchen Bildern es suchen muss, weil es über den Text-Encoder ein Verständnis für die Wörter (und deren Beziehung zueinander) hat, die in den Bildunterschriften vorkommen.

Systematischer können wir ein vortrainiertes CLIP-Modell in einen Bildklassifikator umwandeln, indem wir alle Klassen in Bildunterschriften umwandeln, z. B. über "Ein Foto von [Klassenname]". Für ein gegebenes Foto berechnen wir die Kosinus-Ähnlichkeiten der Bildkodierung mit allen Bildunterschriftenkodierungen und wählen die Bildunterschrift (=Klasse) mit der höchsten Punktzahl als Vorhersage für den Klassifikator.

Wenn es nicht Fotos sind, die wir klassifizieren, sondern Skizzen oder sogar verschiedene Arten von Bildern, können wir die Beschriftungen natürlich anpassen.

Es stellt sich heraus, dass selbst auf speziellen "engen" Datensätzen wie ImageNet generische CLIP-basierte Klassifikatoren ähnlich gut abschneiden wie solche, die speziell auf diese Datensätze trainiert sind. Was noch wichtiger ist: CLIP-basierte Klassifikatoren scheinen viel robuster gegenüber Verteilungsänderungen und "adversarial examples" zu sein:

Der Grund für die Robustheit von CLIP scheint darin zu liegen, dass es bereits beim Training vielfältigere Beispiele gesehen hat. Tatsächlich generalisiert auch CLIP schlecht auf Arten von Bildern, die nicht im Trainingsdatensatz enthalten waren.

Es gibt weitere Beispiele für direkte Anwendungen von CLIP oder für kompliziertere Architekturen, die darauf aufbauen. Ein besonders interessanter Fall ist StyleCLIP, das CLIP einsetzt, um eine textbasierte Schnittstelle zur Bildmanipulation zu schaffen.


Fazit


Es gibt drei Aspekte des CLIP-Modells und seiner Anwendungen, die ich besonders erwähnenswert finde:

  1. CLIP löst das Versprechen von "Big Data" ein, d.h. das Versprechen, dass wir nur ausreichend große Datensätze brauchen, um viele Probleme lösen zu können. Oft sind Daten ohne Labels wertlos, und sie zu generieren ist kostspielig. CLIP knüpft an die jüngsten Erfolge des unüberwachten (zumindest nicht manuell überwachten) Pre-Trainings für NLP im Bereich des maschinellen Sehens an.

  2. Die Idee hinter CLIP ist sehr einfach, und doch ist es ein Schritt in Richtung einer allgemeineren Art von KI. Der Schlüssel zur Leistung von CLIP ist das Vorhandensein von leistungsfähigen Bild- und Text-Encodern, die in der Lage sind, sich an riesige Trainingsmengen effektiv anzupassen - und natürlich die Hardware, um dies in einer angemessenen Zeit zu tun.

  3. Nicht zuletzt zeigt CLIP das Potenzial für natürlichsprachliche Schnittstellen, über die wir mit einem Modell "kommunizieren" und damit die von ihm ausgeführte Aufgabe anpassen können.

Soviel zu einem Überblick über CLIP. Ich empfehle noch einmal, einen Blick in die Originalveröffentlichung zu werfen, die vieles von dem, was ich erwähnt habe, technisch präzisiert. Eine weitere nützliche Ressource ist der eigene Blogartikel von OpenAI, der ebenfalls etwas technischer ist als das, was ich hier besprochen habe.