Adversarial example generation

Maryam_Darei: <p>Hello,</p>
<p>I tried to run adversarial attack on my test images. I trained my model that is a Resnet50. I copied the function for adversarial attack from <a href="http://pytorch.org" rel="noopener nofollow ugc">pytorch.org</a>. I received an error and I could not understand what is the problem.</p>
<p>Thanks</p>
<pre><code class="lang-auto">from __future__ import print_function
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
import numpy as np
import matplotlib.pyplot as plt

# NOTE: This is a hack to get around "User-agent" limitations when downloading MNIST datasets
#       see, https://github.com/pytorch/vision/issues/3497 for more information
from six.moves import urllib
opener = urllib.request.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
urllib.request.install_opener(opener)

epsilons = [0, .05, .1, .15, .2, .25, .3]
model = model.eval()
#FGSM attack code
def fgsm_attack(image, epsilon, data_grad):
    # Collect the element-wise sign of the data gradient
    sign_data_grad = data_grad.sign()
    # Create the perturbed image by adjusting each pixel of the input image
    perturbed_image = image + epsilon*sign_data_grad
    # Adding clipping to maintain [0,1] range
    perturbed_image = torch.clamp(perturbed_image, 0, 1)
    # Return the perturbed image
    return perturbed_image

def test( model, device, test_loader, epsilon ):

    # Accuracy counter
    correct = 0
    adv_examples = []

    # Loop over all examples in test set
    for data, target in test_loader:

        # Send the data and label to the device
        data, target = data.to(device), target.to(device)

        # Set requires_grad attribute of tensor. Important for Attack
        data.requires_grad = True

        # Forward pass the data through the model
        output = model(data)
        init_pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability

        # If the initial prediction is wrong, dont bother attacking, just move on
        if init_pred.item() != target.item():
            continue

        # Calculate the loss
        loss = F.nll_loss(output, target)

        # Zero all existing gradients
        model.zero_grad()

        # Calculate gradients of model in backward pass
        loss.backward()

        # Collect datagrad
        data_grad = data.grad.data

        # Call FGSM Attack
        perturbed_data = fgsm_attack(data, epsilon, data_grad)

        # Re-classify the perturbed image
        output = model(perturbed_data)

        # Check for success
        final_pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability
        if final_pred.item() == target.item():
            correct += 1
            # Special case for saving 0 epsilon examples
            if (epsilon == 0) and (len(adv_examples) &lt; 5):
                adv_ex = perturbed_data.squeeze().detach().cpu().numpy()
                adv_examples.append( (init_pred.item(), final_pred.item(), adv_ex) )
        else:
            # Save some adv examples for visualization later
            if len(adv_examples) &lt; 5:
                adv_ex = perturbed_data.squeeze().detach().cpu().numpy()
                adv_examples.append( (init_pred.item(), final_pred.item(), adv_ex) )

    # Calculate final accuracy for this epsilon
    final_acc = correct/float(len(test_loader))
    print("Epsilon: {}\tTest Accuracy = {} / {} = {}".format(epsilon, correct, len(test_loader), final_acc))

    # Return the accuracy and an adversarial example
    return final_acc, adv_examples


accuracies = []
examples = []

# Run test for each epsilon
for eps in epsilons:
    acc, ex = test(model, device, test_loader, eps)
    accuracies.append(acc)
    examples.append(ex)


</code></pre>
<p>The error is:</p>
<p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/4/0/406408508bc9477cafaaa08374231b93ad5f4b30.png" data-download-href="https://discuss.pytorch.org/uploads/default/406408508bc9477cafaaa08374231b93ad5f4b30" title="Screen Shot 2023-03-17 at 3.14.25 PM"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/4/0/406408508bc9477cafaaa08374231b93ad5f4b30_2_690x251.png" alt="Screen Shot 2023-03-17 at 3.14.25 PM" data-base62-sha1="9bCSm3JXGcWX62eI7l3Lv1RVNUQ" width="690" height="251" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/4/0/406408508bc9477cafaaa08374231b93ad5f4b30_2_690x251.png, https://discuss.pytorch.org/uploads/default/optimized/3X/4/0/406408508bc9477cafaaa08374231b93ad5f4b30_2_1035x376.png 1.5x, https://discuss.pytorch.org/uploads/default/optimized/3X/4/0/406408508bc9477cafaaa08374231b93ad5f4b30_2_1380x502.png 2x" data-dominant-color="F6F5F8"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">Screen Shot 2023-03-17 at 3.14.25 PM</span><span class="informations">1748×636 79.5 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>

KFrank: <p>Hi Maryam!</p>
<aside class="quote no-group" data-username="Maryam_Darei" data-post="1" data-topic="175182" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/maryam_darei/48/54395_2.png" class="avatar"> Maryam_Darei:</div>
<blockquote>
<pre><code class="lang-auto">        output = model(perturbed_data)

        # Check for success
        final_pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability
        if final_pred.item() == target.item():
</code></pre>
</blockquote>
</aside>
<p>Let me speculate that <code>output</code> has shape <code>[nBatch, nClass]</code>.  Such a<br>
tensor will contain <code>nBatch * nClass</code> elements.</p>
<p>The <code>argmax()</code> operation (<code>max()[1]</code>) will reduce the <code>nClass</code> dimension<br>
to <code>1</code> so that <code>init_pred</code> will have shape <code>[nBatch, 1]</code>.  But if <code>nBatch &gt; 1</code>,<br>
<code>init_pred</code> will still consist of more than one element, so you can’t call<br>
<code>.item()</code> on it.</p>
<p>What is your batch size? Consider printing out  <code>data.shape</code>, <code>output.shape</code>,<br>
and <code>init_pred.shape</code> to see where your “more than one element” is<br>
coming from.</p>
<p>(As an aside, please don’t post screenshots of textual information.  Doing<br>
so breaks accessibility, searchability, an copy-paste.)</p>
<p>Best.</p>
<p>K. Frank</p>

Maryam_Darei: <p>Hello Frank,<br>
Thank for your useful explanation.</p>
<p>I pirated out and this is the outputs:</p>
<p>data.shape:  torch.Size([19, 3, 277, 277])<br>
target.shape: torch.Size([19])<br>
output.shape:  torch.Size([19, 1000])<br>
init_pred.shape:  torch.Size([19, 1])</p>
<p>What should I do in this case?</p>
<p>Also, I will take care of coping text instead of screenshots.</p>
<p>Thanks</p>

KFrank: <p>Hi Maryam!</p>
<aside class="quote no-group" data-username="Maryam_Darei" data-post="3" data-topic="175182" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/maryam_darei/48/54395_2.png" class="avatar"> Maryam_Darei:</div>
<blockquote>
<p>data.shape:  torch.Size([19, 3, 277, 277])<br>
target.shape: torch.Size([19])<br>
output.shape:  torch.Size([19, 1000])<br>
init_pred.shape:  torch.Size([19, 1])</p>
</blockquote>
</aside>
<p>The problem is that you are trying to get <code>item()</code> (a single python scalar)<br>
from a <em>batch</em> of predictions (that has batch size greater than one).  This<br>
isn’t permitted, hence the error you posted.</p>
<p>As I read it, your <code>data</code> is a batch of 19 three-channel images, your<br>
<code>target</code> is a batch of 19 class labels, your <code>output</code> is a batch of 19<br>
predictions for the (unnormalized) log-probabilities for each of 1000<br>
classes, and your <code>init_pred</code> is a <em>batch</em> (that happens to have a<br>
trailing singleton dimension) of 19  class-label predictions (obtained<br>
as the <code>argmax()</code> of the log-probabilities).</p>
<p>So, indeed, you can’t apply <code>.item()</code> to <code>init_pred</code>.</p>
<p>Your comment:</p>
<pre data-code-wrap="python"><code class="lang-python"># If the initial prediction is wrong, dont bother attacking, just move on
</code></pre>
<p>suggests that you do further processing if the prediction is right.</p>
<p>You have to decide whether you want to do this on a sample-by-sample<br>
basis or on a whole-batch-basis.</p>
<p>To skip further processing if <em>none</em> of the predictions in the batch are<br>
correct, you could test:</p>
<pre data-code-wrap="python"><code class="lang-python">        if  (init_pred.item() != target.item()).all():
            continue
</code></pre>
<p>But then, even if only one of the predictions in the batch were correct, you<br>
might end up performing further processing on all of the batch – even<br>
for those predictions in the batch that were incorrect.</p>
<p>Or you could loop over the predictions in the batch one by one, testing<br>
their correctness.</p>
<p>Best.</p>
<p>K. Frank</p>

Maryam_Darei: <p>Frank,</p>
<p>Thank you so much. I changed batch_size to 1 and error was gone. But I didn’t understand what I should do if I want have batch size bigger than one, for example 64 or 32. Do you mean remove “ if  (init_pred.item() != target.item()) “?</p>

J_Johnson: <p>If the final_pred and target are all PyTorch tensors of all 1s and 0s, you could get the accuracy this way, instead:</p>
<pre><code class="lang-auto">acc = (1-torch.abs(final_pred - target)).mean().item()
</code></pre>
<p>This is much simpler than loops and leverages tensor operations.</p>