JGU Logo JGU Logo JGU Logo JGU Logo

Institut für Informatik

Modellierung 2

Michael Wand
David Hartmann
Sommersemester 2021DIGITAL

Lehreinheit 13

Energiebasierte Generierung von Bildern
Letzte Änderung: 13. April 2021, 10:44 Uhr
Abgabe: Dienstag, der 14.06.2021, 13 Uhr

  /  



The Building Blocks of Interpretability

In A.I., the holy grail was how do you generate internal representations.

Geoffrey Hinton




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.
Wir gehen nun davon aus, dass das Netzwerk bereits trainiert wurde. Die Idee ist nun, die Netzwerkparameter nicht mehr zu verändern, sondern den Gradienten \(\nabla_x E(f(x), y)\) der Eingabe zu bestimmen und diese Anzupassen in der Hoffnung den Loss zu minimieren. Wir schauen uns dazu drei verschiedene Methoden an, die dieser Idee folgend Bilder generiert.
Im speziellen schauen wir uns wieder den Bilddatensatz CIFAR-10 an, da dieser leicht zu rechnen ist.


Beispielcode: Um Ihnen die Arbeit zu erleichtern, habe ich im folgenden ein Codeschnipsel angefügt, mit dem Sie arbeiten können. Das Skript lädt dazu vortrainierte Gewichte eines VGG-11 herunter und testet zuerst die Accuracy. Danach habe ich noch ein paar Zeilen angefügt, die Ihnen beim Bearbeiten der folgenden Aufgaben helfen sollte.


Codeschnipsel
# "you know the drill"
import torch
import torch.nn as nn
import torchvision
import matplotlib.pyplot as plt

# liste aller modelle:
# https://github.com/chenyaofo/pytorch-cifar-models

# num images to sample
batch_size = 16

# cifar-10 datensatz & normalisierung
mean = torch.tensor([0.4914, 0.4822, 0.4465])
std = torch.tensor([0.2023, 0.1994, 0.2010])
transform = torchvision.transforms.Compose([
    torchvision.transforms.ToTensor(),
    torchvision.transforms.Normalize(mean, std)
])
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True, num_workers=2)
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

# load pretrained model
model = model = torch.hub.load("chenyaofo/pytorch-cifar-models", "cifar10_vgg11_bn", pretrained=True)
model.eval() # make sure we are using eval-mode (see batch normalization section of lecture)

# check if accuracy converges to about 99.9% (for the test set it would be around 92.6%, just change train=True to train=False above)
# >>> remove this section if the accuracy is correct
# CE = nn.CrossEntropyLoss()
# num, correct = 0, 0
# for batch in trainloader:
#     imgs, classes = batch
#     pred = model(imgs)
#     correct += (pred.argmax(-1) == classes).sum()
#     num += len(imgs)
#     print("Accuracy=%f, CELoss=%f" % (correct/num, CE(pred, classes)))
# << remove until this point

# define energy-function

# create random data
x = torch.randn((batch_size, 3, 32, 32))

# alternative: get first batch from data set
x, y_real = next(iter(trainloader))

# save initial picture to show difference in plot later
x0 = x.clone()

# define optimizer w.r.t. the input *only*
x.requires_grad = True
optim = torch.optim.Adam([x], lr=1e-3) # adapt hyperparameters if needed
for i in range(1000):
    pred = model(x)
    E = x.sum() # just for testing optimization loop
    print("Step %i: E=%f, diff to init=%f" % (i,E, ((x0[0] - x[0])**2).sum()))
    optim.zero_grad()
    E.backward()
    optim.step()

# plot images
def plotimg(x, ax, label):
    x = x.detach()*std.reshape((3,1,1)) + mean.reshape((3,1,1))
    x = x.permute(1,2,0) # matplotlib requires channel dimension to be at the end
    ax.imshow(x)
    ax.set_title(label)

y_pred = model(x).argmax(-1)
fig, axs = plt.subplots(2,1)
plotimg(x0[0], ax=axs[0], label="Startbild "+classes[y_real[0].item()])
plotimg(x[0], ax=axs[1], label="Endbild "+classes[y_pred[0].item()])
plt.show()

Aufgabe 1: Generierte Gegenbeispiele / Adversarial Examples

Wir machen uns als erstes mit dem oben angegebenen Beispielcode vertraut und lösen das Problem der Generierung auf folgende Weise: Als erstes Testen wir, ob der Klassizierungsloss (Cross-Entropy) bereits hübsche Bilder erzeugen würde. Dazu definieren wir \(E := \operatorname{SoftmaxCrossEntropy}\).


Wie oben beschrieben bilden wir nun den Gradienten \(\nabla_x E\) der Eingabe und passen die Eingabe mithilfe eines vorgefertigten Optimizers (etwa Adam, SGD, etc.) oder alternativ durch die Updateregel \(x \leftarrow x + \eta \cdot \nabla_x E\) für eine feste Learning Rate \(\eta\) an.


  1. Wählen Sie ein festes Ziellabel und starten Sie mit einem Bild, das aus zufälligen Pixeln besteht (etwa Normalverteilt). Wie hat sich das Bild durch die Optimierung verändert?
  2. Wählen Sie nun ein Bild aus dem Traingsdatensatz und verändern Sie das Bild nun so, dass das Netz für das veränderte Bild auch das Ziellabel vorhersagt. Wie hat sich das Bild durch die Optimierung jetzt verändert?
  3. Was für Rückschlüsse können Sie aus dieser Beobachtung ziehen?

Aufgabe 2: (optional) Deep Dream

Statt nun den Klassifzierungsloss zu optimieren können wir mit genau der gleichen Technik visualisieren welche Features einzelne Layer oder Neuronen besonders stark aktiviert.


Wir wählen dazu ein oder mehrere Layer oder Neuronen aus und definieren das zu maximierende Energiefunktional als die Summe der Ausgaben.


Siehe auch / Beispiele: https://ai.googleblog.com/2015/06/inceptionism-going-deeper-into-neural.html


Hinweise:

Aufgabe 3: Energiebasierte Generatoren

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:

  1. Lesen Sie Abschnitt 1 des Papers für einen groben Überblick über die Methode. Die Methode selbst wird in Abschnitt 3 erklärt.
    Die Autoren geben in Abschnitt A.2 (A wie Anhang), A.11 und A.12 weitere Tipps, um die Methode zu stabilisieren.
  2. Implementieren und testen Sie die Methode für einen CIFAR-10 Klassifizierer.
  3. Im Falle eines „schönen“ generierten Beispiels bestimmen Sie die \(k\) nächsten Nachbarn des Bildes. Hier reicht der L2-Loss aus. Dies dient lediglich dazu zu visualisieren, dass es sich um echt neue Bilder handelt.