This notebook demonstrates optimizing the inputs, and adversarial examples.
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
import torchvision.models
%matplotlib inline
We will study AlexNet as an example.
import torchvision.models
alexnet = torchvision.models.alexnet(pretrained=True)
Our first experiment is to see whether we can generate the image of a Samoyed dog via backpropagation using AlexNet. In particular, we'll try to tune a random input so that AlexNet believes that the input is a Samoyed.
# Let's try to create an image that AlexNet thinks is a Samoyed
target_label = 258 # Samoyed dog. From https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a
Since we will not be tuning AlexNet weights in this entire example, we will
set the requires_grad parameter of AlexNet to False. This PyTorch setting
means that PyTorch will not compute gradients for the parameters of AlexNet.
alexnet.requires_grad = False # do not update AlexNet weights
Instead, we will be optimizing the input to AlexNet. Since AlexNet takes images of shape $3 \times 224 \times 224$, we will start with such a random image:
# Initialize a random image
image = torch.randn(1, 3, 224, 224) + 0.5
image = torch.clamp(image, 0, 1)
image.requires_grad = True
Note that we set requires_grad = True for this input, because we do want PyTorch
to be computing gradients, so we can optimize this input.
Actual optimization:
# Use an optimizer to optimize the *input image*
optimizer = optim.Adam([image], lr=0.005)
criterion = nn.CrossEntropyLoss()
# Training:
for i in range(100):
out = alexnet(torch.clamp(image, 0, 1))
loss = criterion(out, torch.Tensor([target_label]).long())
loss.backward()
optimizer.step()
optimizer.zero_grad()
if i % 10 == 0:
target_prediction = torch.softmax(out, dim=1)[0, target_label]
print("Iteration %d, Loss=%f, target prob=%f" % (
i, float(loss), float(target_prediction)))
Now let's see the image of the fluffy dog:
pltimg = torch.clamp(image, 0, 1).squeeze(0).transpose(0,1).transpose(1, 2).detach().numpy()
plt.figure()
plt.imshow(pltimg)
That's a disappointment! What happened?!
Try a different class (e.g. 987: Corn). Also will fail...
We used this picture as an input to AlexNet last class. Let's try and compute the gradient of AlexNet with repsect to this input.
import cv2
dog = plt.imread("dog2.jpg")
dog = cv2.resize(dog, (224, 224))
plt.imshow(dog)
dog = torch.Tensor(dog).transpose(0,2).transpose(1,2).unsqueeze(0)
torch.argmax(alexnet(dog))
Again, since we are computing the gradient with respect to this input, we need
to set requires_grad=True.
dog.requires_grad = True
Let's compute the gradient. Which pixels affect the prediction of our target (258 Samoyed) the most?
criterion = nn.CrossEntropyLoss()
target_label = 258
out = alexnet(dog)
loss = criterion(out, torch.Tensor([target_label]).long())
dog_grad = torch.autograd.grad(loss, dog, retain_graph=True)
Visualization:
dog_grad_np = dog_grad[0][0].transpose(0,1).transpose(1,2).numpy()
plt.imshow((dog_grad_np - dog_grad_np.min()) / (dog_grad_np.max() - dog_grad_np.min()))