.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "beginner/fgsm_tutorial.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note Click :ref:`here ` to download the full example code .. rst-class:: sphx-glr-example-title .. _sphx_glr_beginner_fgsm_tutorial.py: Adversarial Example Generation ============================== **Author:** `Nathan Inkawhich `__ If you are reading this, hopefully you can appreciate how effective some machine learning models are. Research is constantly pushing ML models to be faster, more accurate, and more efficient. However, an often overlooked aspect of designing and training models is security and robustness, especially in the face of an adversary who wishes to fool the model. This tutorial will raise your awareness to the security vulnerabilities of ML models, and will give insight into the hot topic of adversarial machine learning. You may be surprised to find that adding imperceptible perturbations to an image *can* cause drastically different model performance. Given that this is a tutorial, we will explore the topic via example on an image classifier. Specifically, we will use one of the first and most popular attack methods, the Fast Gradient Sign Attack (FGSM), to fool an MNIST classifier. .. GENERATED FROM PYTHON SOURCE LINES 28-92 Threat Model ------------ For context, there are many categories of adversarial attacks, each with a different goal and assumption of the attacker’s knowledge. However, in general the overarching goal is to add the least amount of perturbation to the input data to cause the desired misclassification. There are several kinds of assumptions of the attacker’s knowledge, two of which are: **white-box** and **black-box**. A *white-box* attack assumes the attacker has full knowledge and access to the model, including architecture, inputs, outputs, and weights. A *black-box* attack assumes the attacker only has access to the inputs and outputs of the model, and knows nothing about the underlying architecture or weights. There are also several types of goals, including **misclassification** and **source/target misclassification**. A goal of *misclassification* means the adversary only wants the output classification to be wrong but does not care what the new classification is. A *source/target misclassification* means the adversary wants to alter an image that is originally of a specific source class so that it is classified as a specific target class. In this case, the FGSM attack is a *white-box* attack with the goal of *misclassification*. With this background information, we can now discuss the attack in detail. Fast Gradient Sign Attack ------------------------- One of the first and most popular adversarial attacks to date is referred to as the *Fast Gradient Sign Attack (FGSM)* and is described by Goodfellow et. al. in `Explaining and Harnessing Adversarial Examples `__. The attack is remarkably powerful, and yet intuitive. It is designed to attack neural networks by leveraging the way they learn, *gradients*. The idea is simple, rather than working to minimize the loss by adjusting the weights based on the backpropagated gradients, the attack *adjusts the input data to maximize the loss* based on the same backpropagated gradients. In other words, the attack uses the gradient of the loss w.r.t the input data, then adjusts the input data to maximize the loss. Before we jump into the code, let’s look at the famous `FGSM `__ panda example and extract some notation. .. figure:: /_static/img/fgsm_panda_image.png :alt: fgsm_panda_image From the figure, :math:`\mathbf{x}` is the original input image correctly classified as a “panda”, :math:`y` is the ground truth label for :math:`\mathbf{x}`, :math:`\mathbf{\theta}` represents the model parameters, and :math:`J(\mathbf{\theta}, \mathbf{x}, y)` is the loss that is used to train the network. The attack backpropagates the gradient back to the input data to calculate :math:`\nabla_{x} J(\mathbf{\theta}, \mathbf{x}, y)`. Then, it adjusts the input data by a small step (:math:`\epsilon` or :math:`0.007` in the picture) in the direction (i.e. :math:`sign(\nabla_{x} J(\mathbf{\theta}, \mathbf{x}, y))`) that will maximize the loss. The resulting perturbed image, :math:`x'`, is then *misclassified* by the target network as a “gibbon” when it is still clearly a “panda”. Hopefully now the motivation for this tutorial is clear, so lets jump into the implementation. .. GENERATED FROM PYTHON SOURCE LINES 92-102 .. code-block:: default 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 .. GENERATED FROM PYTHON SOURCE LINES 103-132 Implementation -------------- In this section, we will discuss the input parameters for the tutorial, define the model under attack, then code the attack and run some tests. Inputs ~~~~~~ There are only three inputs for this tutorial, and are defined as follows: - ``epsilons`` - List of epsilon values to use for the run. It is important to keep 0 in the list because it represents the model performance on the original test set. Also, intuitively we would expect the larger the epsilon, the more noticeable the perturbations but the more effective the attack in terms of degrading model accuracy. Since the data range here is :math:`[0,1]`, no epsilon value should exceed 1. - ``pretrained_model`` - path to the pretrained MNIST model which was trained with `pytorch/examples/mnist `__. For simplicity, download the pretrained model `here `__. - ``use_cuda`` - boolean flag to use CUDA if desired and available. Note, a GPU with CUDA is not critical for this tutorial as a CPU will not take much time. .. GENERATED FROM PYTHON SOURCE LINES 132-140 .. code-block:: default epsilons = [0, .05, .1, .15, .2, .25, .3] pretrained_model = "data/lenet_mnist_model.pth" use_cuda=True # Set random seed for reproducibility torch.manual_seed(42) .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 141-152 Model Under Attack ~~~~~~~~~~~~~~~~~~ As mentioned, the model under attack is the same MNIST model from `pytorch/examples/mnist `__. You may train and save your own MNIST model or you can download and use the provided model. The *Net* definition and test dataloader here have been copied from the MNIST example. The purpose of this section is to define the model and dataloader, then initialize the model and load the pretrained weights. .. GENERATED FROM PYTHON SOURCE LINES 152-201 .. code-block:: default # LeNet Model definition class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(1, 32, 3, 1) self.conv2 = nn.Conv2d(32, 64, 3, 1) self.dropout1 = nn.Dropout(0.25) self.dropout2 = nn.Dropout(0.5) self.fc1 = nn.Linear(9216, 128) self.fc2 = nn.Linear(128, 10) def forward(self, x): x = self.conv1(x) x = F.relu(x) x = self.conv2(x) x = F.relu(x) x = F.max_pool2d(x, 2) x = self.dropout1(x) x = torch.flatten(x, 1) x = self.fc1(x) x = F.relu(x) x = self.dropout2(x) x = self.fc2(x) output = F.log_softmax(x, dim=1) return output # MNIST Test dataset and dataloader declaration test_loader = torch.utils.data.DataLoader( datasets.MNIST('../data', train=False, download=True, transform=transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)), ])), batch_size=1, shuffle=True) # Define what device we are using print("CUDA Available: ",torch.cuda.is_available()) device = torch.device("cuda" if use_cuda and torch.cuda.is_available() else "cpu") # Initialize the network model = Net().to(device) # Load the pretrained model model.load_state_dict(torch.load(pretrained_model, map_location=device)) # Set the model in evaluation mode. In this case this is for the Dropout layers model.eval() .. rst-class:: sphx-glr-script-out .. code-block:: none Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz Failed to download (trying next): HTTP Error 503: Service Unavailable Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz to ../data/MNIST/raw/train-images-idx3-ubyte.gz 0%| | 0/9912422 [00:00 adversarial classification.” Notice, the perturbations start to become evident at :math:`\epsilon=0.15` and are quite evident at :math:`\epsilon=0.3`. However, in all cases humans are still capable of identifying the correct class despite the added noise. .. GENERATED FROM PYTHON SOURCE LINES 407-426 .. code-block:: default # Plot several examples of adversarial samples at each epsilon cnt = 0 plt.figure(figsize=(8,10)) for i in range(len(epsilons)): for j in range(len(examples[i])): cnt += 1 plt.subplot(len(epsilons),len(examples[0]),cnt) plt.xticks([], []) plt.yticks([], []) if j == 0: plt.ylabel(f"Eps: {epsilons[i]}", fontsize=14) orig,adv,ex = examples[i][j] plt.title(f"{orig} -> {adv}") plt.imshow(ex, cmap="gray") plt.tight_layout() plt.show() .. image-sg:: /beginner/images/sphx_glr_fgsm_tutorial_002.png :alt: 7 -> 7, 9 -> 9, 0 -> 0, 3 -> 3, 5 -> 5, 2 -> 8, 1 -> 3, 3 -> 5, 4 -> 6, 4 -> 9, 9 -> 4, 5 -> 6, 9 -> 5, 9 -> 5, 3 -> 2, 3 -> 5, 5 -> 3, 1 -> 6, 4 -> 9, 7 -> 9, 7 -> 2, 8 -> 2, 4 -> 8, 3 -> 7, 5 -> 3, 8 -> 3, 0 -> 8, 6 -> 5, 2 -> 3, 1 -> 8, 1 -> 9, 1 -> 8, 5 -> 8, 7 -> 8, 0 -> 2 :srcset: /beginner/images/sphx_glr_fgsm_tutorial_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 427-455 Where to go next? ----------------- Hopefully this tutorial gives some insight into the topic of adversarial machine learning. There are many potential directions to go from here. This attack represents the very beginning of adversarial attack research and since there have been many subsequent ideas for how to attack and defend ML models from an adversary. In fact, at NIPS 2017 there was an adversarial attack and defense competition and many of the methods used in the competition are described in this paper: `Adversarial Attacks and Defences Competition `__. The work on defense also leads into the idea of making machine learning models more *robust* in general, to both naturally perturbed and adversarially crafted inputs. Another direction to go is adversarial attacks and defense in different domains. Adversarial research is not limited to the image domain, check out `this `__ attack on speech-to-text models. But perhaps the best way to learn more about adversarial machine learning is to get your hands dirty. Try to implement a different attack from the NIPS 2017 competition, and see how it differs from FGSM. Then, try to defend the model from your own attacks. A further direction to go, depending on available resources, is to modify the code to support processing work in batch, in parallel, and or distributed vs working on one attack at a time in the above for each ``epsilon test()`` loop. .. rst-class:: sphx-glr-timing **Total running time of the script:** ( 3 minutes 54.156 seconds) .. _sphx_glr_download_beginner_fgsm_tutorial.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: fgsm_tutorial.py ` .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: fgsm_tutorial.ipynb ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_