In den letzten Lehreinheiten haben wir Neuronalen Netzen das Klassifizieren von Eingabedaten beigebracht. In dieser Lehreinheit möchten wir Bilder einer gegebenen Klasse generieren. In der Vorlesung wurden dazu verschiedene Mechanismen vorgestellt, die diese Aufgabe lösen. Als Beispiel ist hier der Variational Autoencoder zu nennen, der die latenten Variablen an eine normalverteilte Zufallsvariable „fittet“ und beim ziehen aus dieser ungesehene Beispiele generiert. Ein anderes Beispiel sind Generative Adversarial Networks, bei denen zwei Netzwerkteile spieltheoretisch Motiviert gegen- und miteinander optimiert werden (siehe Vorlesung).
Beide Mechanismen sind leider mit aufwändigerem Training verbunden. Aus diesem Grund schauen wir uns Energiebasierte Modelle an. Überraschenderweise kann man nämlich mit einigen wenigen Tricks auch einen fertig trainierten Klassifizierer nutzen, um selbst wieder neue Bilder zu generieren. Die Einsicht ist eng damit verknüpft, dass Klassifizierer automatisch auch interne Repräsentationen bauen, um eben eine gute Vorhersage machen zu können.
Ich empfehle Ihnen dazu wärmstens den oben verlinkten interaktiven Blogartikel „The Building Blocks of Interpretability“ durchzusehen.
Abstrakte Idee:
Bei einem Klassizierungsproblem haben wir typischerweise zufällige Daten \(x\) (etwa Bilder), zugehöriges Ground Truth Wissen \(y\) (etwa Label) und eine differentierbare Zielfunktion \(E(f(x), y)\) gegeben, die die Qualität des Klassifizerers \(f\) (etwa ein Neuronales Netz) bewertet.
Stochastic Gradient Descent: Für alle Parameter \(\theta\) eines Modells \(f_\theta\) haben wir die Gradienten \(\nabla_\theta E(f_\theta(x), y)\) bestimmt, mit der Learning Rate skaliert und additiv angepasst.
Die zündende Idee ist nun, dass wir ja bereits ein Werkzeug haben müssten, dass uns erlaubt Bilder zu erzeugen: Black-Box-Optimization + Cross-Entropy (CE).
Die Cross-Entropy hat das Netz in der Art trainiert, dass die Ausgabe des Netzes möglichst gut auf die Labels (Ground Truth) des Datensatzes passen und die Black-Box-Optimizer verändern Gewichte in der Art, dass eine beliebigen lokal ableitbare Energie, die von diesen Gewichten abhängt minimiert wird.
Wie können wir das nutzen?
Datensätze:
Wir gehen nun davon aus, dass das Netzwerk bereits trainiert wurde. (Begründung kommt gleich). Im speziellen schauen wir uns wieder entweder den Bilddatensatz CIFAR-10 oder einen neuen Datensatz namens ImageNet an. Der Unterschied zwischen diesen Beiden ist im Prinzip lediglich die Datenmenge, die für das Training benutzt wird: Während CIFAR-10 aus 50.000 Bildern (und je 32 x 32 Pixel) mit einer zugehörigkeit zu einer von 10 Klassen besteht, enthält ImageNet nicht nur größere (und damit mehr Details) und mehr (1.2 Millionen) Bilder, sondern auch deutlich mehr Klassen (1000 Klassen). Beide Datensätze haben Vor- und Nachteile. Während der kleinere Datensatz (CIFAR-10) auch häufiger durch kleinere Netze abgebildet werde kann, sind die Berechnungen schneller und man sieht damit schneller ein Ergebnis. Der Nachteil ist, dass die Bilder aus CIFAR-10 so unscharf sind, dass die untenstehenden Ideen kaum zu guten Ergebnissen führen würden. Aus diesem Grund verwenden wir vortrainierte Netze1 (d.h. Gewichte und Netzdefinitionen, die bereits trainiert wurden und auch eine gute Klassifizierungsperformance erreichen).
[1] Ein solches Netz haben wir in dieser Veranstaltung leider nicht trainiert. Dies hat mehrere Gründe: Das Training dauert leider viel zu lang im Beispiel von ImageNet (in etwa 2 - 10 Tage Rechenzeit mit optimiertem Code und einer guten Grafikkarte, je nach Tricks & gewünschter Qualität) und selbst im Beispiel von CIFAR-10 benötigen wir für eine gute Qualität noch ein Paar Tools, die wir aus zeitlichen Grunden nicht in der Übung besprochen haben, die aber in der Vorlesung erwähnt wurden.
Im Sinne der Aufgabe reicht es glücklicherweise aus, nur vortrainierte Netze zu benutzen, da diese bereits die Struktur der Daten gelernt haben und wir dieses Wissen mit den unten stehenden Methoden wieder (zumindest zum Teil) extrahieren können.
Wir machen uns als erstes mit der Verwendung von vortrainierten Netzen vertraut. In PyTorch ist das laden solcher Netze sehr einfach:
Wir definieren also \(E := \operatorname{SoftmaxCrossEntropy}\) oder \(E := -i\text{-te Komponente der Netzausgabe}\) (das umgekehrte Vorzeichen ist hier wichtig).
Wir verfolgen die oben genannte Idee, nämlich die Netzwerkparameter nicht mehr zu verändern, sondern den Gradienten \(\nabla_x E(f(x), y)\) der Eingabe zu bestimmen und die Eingabe statt der Gewichte des Netzwerkse anzupassen mit dem Ziel auch hier die Energie \(E\) zu minimieren. Die simpelste Methode ist die Gradienten „einfach direkt” anzuwenden.
Wie oben beschrieben bilden wir also den Gradienten \(\nabla_x E\) des Losses nach der Eingabe und passen die Eingabe mithilfe eines vorgefertigten Optimizers (etwa Adam, SGD, etc.). (Optimieren Sie mehrere Schritte, am besten so lange, bis die Klasse klar vorhergesagt wird).
Die Methode oben hatte so Ihre Tücken. Aus dem Grund versuchen wir eine etwas andere Variante, die heute unter dem Namen Deep Dream bekannt ist: Statt der direkten Anwendung der Gradienten auf das Bild „verschmieren“ wir die Gradienteninformation um die Probleme der einfacher Variante von oben zu umgehen. Hierzu gibt es verschiedene Herangehensweisen, wir werden jedoch folgende Idee verfolgen:
Algorithmus:
Verbesserung (optional): Mit der oben genannten Methode werden wir nicht so schöne Ergebnisse sehen wie in den verlinkten Visualsierungen. Dennoch sollten sich Strukturen bilden. Besser wird das Ergebnis durch einen einfachen Trick:
Erweiterungen
(Wählen Sie mindestens eine der folgenden Varianten):
layer_outputs = {}
def hook_fn(module, input, output):
layer_outputs["#layer%i-%s" % (module.id, module)] = output
for id, m in enumerate(model.modules()):
if not isinstance(m, nn.Conv2d):
continue
m.id = id
m.register_forward_hook(hook_fn)
Wir möchten die vorgestellte Methode aus dem Paper Your Classifier is Secretly an Energy Based Model and You Should Treat it Like One nachimplementieren.
Sehr ähnliches Paper, nur unsupervised ist: Implicit Generation and Generalization in Energy-Based Models
Die Idee ist die folgende:
Aufgaben: