# Getting Started
# Installation
You can install the latest release from PyPI (opens new window) using pip
:
python3 -m pip install foolbox
Foolbox requires Python 3.8 or newer. To use it with PyTorch (opens new window), TensorFlow (opens new window), or JAX (opens new window), the respective framework needs to be installed separately. These frameworks are not declared as dependencies because not everyone wants to use and thus install all of them and because some of these packages have different builds for different architectures and CUDA versions. Besides that, all essential dependencies are automatically installed.
NOTE
Foolbox requires Python 3.8 or newer.
# Getting a Model
Once Foolbox is installed, you need to turn your PyTorch, TensorFlow, or JAX model into a Foolbox model.
# PyTorch
For PyTorch, you simply instantiate your torch.nn.Module
and then pass it
to fb.PyTorchModel
. Here we use a pretrained ResNet-18 from torchvision
.
Additionally, you should specify the preprocessing expected by the model
(e.g. subtracting mean
, and dividing by std
, along the third axis from the back)
and the bounds of the input space (before the preprocessing).
# PyTorch ResNet18
import torch
import torchvision
model = torchvision.models.resnet18(pretrained=True)
preprocessing = dict(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], axis=-3)
bounds = (0, 1)
fmodel = fb.PyTorchModel(model, bounds=bounds, preprocessing=preprocessing)
# TensorFlow
For TensorFlow, you simply instantiate your tf.keras.Model
and then pass it
to fb.TensorFlowModel
. Here we show three examples using pretrained ImageNet
models. Additionally, you should specify the preprocessing expected by the model
(e.g. flipping an axis, here from RGB to BGR, subtracting mean
,
and dividing by std
, along the third axis from the back)
and the bounds of the input space (before the preprocessing).
# TensorFlow ResNet50
import tensorflow as tf
model = tf.keras.applications.ResNet50(weights="imagenet")
preprocessing = dict(flip_axis=-1, mean=[103.939, 116.779, 123.68])
bounds = (0, 255)
fmodel = fb.TensorFlowModel(model, bounds=bounds, preprocessing=preprocessing)
# TensorFlow ResNet50V2
import tensorflow as tf
model = tf.keras.applications.ResNet50V2(weights="imagenet")
preprocessing = dict()
bounds = (-1, 1)
fmodel = fb.TensorFlowModel(model, bounds=bounds, preprocessing=preprocessing)
# TensorFlow MobileNetV2
import tensorflow as tf
model = tf.keras.applications.MobileNetV2(weights="imagenet")
preprocessing = dict()
bounds = (-1, 1)
fmodel = fb.TensorFlowModel(model, bounds=bounds, preprocessing=preprocessing)
# JAX
For JAX, you simply specify your model as a callable, i.e. an instance of a
class with a __call__
method or a simple function. It should take an
input array and return the array with predictions. You can then pass this
callable to fb.JAXModel
. Additionally, you should specify the
preprocessing (see previous examples) and
the bounds of the input space (before the preprocessing).
class Model:
def __call__(self, x):
# turn the inputs x into predictions y
y = x # replace with your real model
return y
model = Model()
bounds = (0, 1)
fmodel = fbn.JAXModel(model, bounds)
# Transform Bounds
Next you can optionally transform the bounds of the input space of our model. In the following, we want to work with a model that has (0, 1) bounds.
fmodel = fmodel.transform_bounds((0, 1))
If your model already had bounds (0, 1)
, this does not do anything.
But if your model had different bounds, e.g. (0, 255)
this would adjust
the preprocessing accordingly such that your model now expects inputs
between 0
and 1
. This is particularly useful if you work with
different models that have different bounds.
# Dataset
Before we can attack our model, we first need some data. For convenience, Foolbox comes with helper functions that provide a small set of sample images from different computer vision datasets.
images, labels = fb.utils.samples(fmodel, dataset='imagenet', batchsize=16)
Note that images and labels should be a batch of native tensors, i.e. PyTorch tensors, TensorFlow tensors, or JAX arrays, depending on which framework you use.
# Attacking the Model
Now we have everything ready to attack the model. Before we do that, we will quickly check its clean accuracy on our evaluation set.
fb.utils.accuracy(fmodel, images, labels)
# -> 0.9375 (depends on the model!)
To run an attack, we first instantiate the corresponding class.
attack = fb.attacks.LinfDeepFoolAttack()
And finally we can apply the attack on our model by passing
the input tensor (here images
), the corresponding true labels
,
and one or more epsilons
.
raw, clipped, is_adv = attack(fmodel, images, labels, epsilons=0.03)
The attack returns three tensors.
- The raw adversarial examples. This depends on the attack and we cannot make an guarantees about this output.
- The clipped adversarial examples. These are guaranteed to not be perturbed more than epsilon and thus are the actual adversarial examples you want to visualize. Note that some of them might not actually switch the class. To know which samples are actually adversarial, you should look at the third tensor.
- The third tensor contains a boolean for each sample, indicating which samples are true adversarials that are both misclassified and within the epsilon balls around the clean samples.
How to use these tensors will become more clear in a moment.
# Multiple Epsilons
Usually, you should not just look at a single epsilon, but at many different epislons from small to large. The most efficient way to obtain the corresponding results is by running the attack with multiple epsilons. It will automatically select the right strategy depending on the type of attack.
import numpy as np
epsilons = np.linspace(0.0, 0.005, num=20)
Let's rerun the attack for all epsilons
.
raw, clipped, is_adv = attack(fmodel, images, labels, epsilons=epsilons)
The returned tensors, raw
, clipped
, and is_adv
now have an additional batch dimension for the different epsilons
.
# Robust Accuracy
You can now obtain the robust accuracy by simply averaging is_adv
.
robust_accuracy = 1 - is_adv.float32().mean(axis=-1)
You can now plot the robust accuracy using Matplotlib.
import matplotlib.pyplot as plt
plt.plot(epsilons, robust_accuracy.numpy())
You can also visualize the adversarials using fb.plot.images
.
# Learn More
To learn more, have a look at our Tutorial (opens new window), the examples, the API docs (opens new window) and of course the README (opens new window).
← Introduction Examples →