Skip to content

Commit 74d04f8

Browse files
Irina NicolaeIrina Nicolae
authored andcommitted
Add epsilon as parameter in FGSM
1 parent d164140 commit 74d04f8

File tree

1 file changed

+20
-14
lines changed

1 file changed

+20
-14
lines changed

src/attacks/fast_gradient.py

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ class FastGradientMethod(Attack):
1313
Gradient Sign Method"). This implementation extends the attack to other norms, and is therefore called the Fast
1414
Gradient Method. Paper link: https://arxiv.org/abs/1412.6572
1515
"""
16-
attack_params = ['ord', 'y', 'y_val', 'targeted', 'clip_min', 'clip_max']
16+
attack_params = ['ord', 'eps', 'y', 'y_val', 'targeted', 'clip_min', 'clip_max']
1717

18-
def __init__(self, classifier, sess=None, ord=np.inf, y=None, targeted=False, clip_min=None, clip_max=None):
18+
def __init__(self, classifier, sess=None, ord=np.inf, eps=.3, y=None, targeted=False, clip_min=0, clip_max=1):
1919
"""Create a FastGradientMethod instance.
2020
:param ord: (optional) Order of the norm. Possible values: np.inf, 1 or 2.
21+
:param eps: (required float) attack step size (input variation)
2122
:param y: (optional) A placeholder for the model labels. Only provide this parameter if you'd like to use true
2223
labels when crafting adversarial samples. Otherwise, model predictions are used as labels to avoid the
2324
"label leaking" effect (explained in this paper: https://arxiv.org/abs/1611.01236). Default is None.
@@ -28,13 +29,13 @@ def __init__(self, classifier, sess=None, ord=np.inf, y=None, targeted=False, cl
2829
"""
2930
super(FastGradientMethod, self).__init__(classifier, sess)
3031

31-
kwargs = {'ord': ord, 'targeted': targeted, 'clip_min': clip_min, 'clip_max': clip_max, 'y': y}
32+
kwargs = {'ord': ord, 'eps': eps, 'targeted': targeted, 'clip_min': clip_min, 'clip_max': clip_max, 'y': y}
3233
self.set_params(**kwargs)
3334

34-
def generate_graph(self, x, eps, **kwargs):
35+
def generate_graph(self, x_op, eps_op, **kwargs):
3536
"""Generate symbolic graph for adversarial examples and return.
36-
:param x: The model's symbolic inputs.
37-
:param eps: (optional tf.placeholder) The placeholder for input variation (noise amplitude)
37+
:param x_op: The model's symbolic inputs.
38+
:param eps_op: (optional tf.placeholder) The placeholder for input variation (noise amplitude)
3839
:param ord: (optional) Order of the norm (mimics Numpy). Possible values: np.inf, 1 or 2.
3940
:param y: (optional) A placeholder for the model labels. Only provide this parameter if you'd like to use true
4041
labels when crafting adversarial samples. Otherwise, model predictions are used as labels to avoid the
@@ -45,7 +46,7 @@ def generate_graph(self, x, eps, **kwargs):
4546
"""
4647
self.set_params(**kwargs)
4748

48-
preds = self.classifier._get_predictions(x, log=False)
49+
preds = self.classifier._get_predictions(x_op, log=False)
4950

5051
if not hasattr(self, 'y') or self.y is None:
5152
# Use model predictions as correct outputs
@@ -59,20 +60,20 @@ def generate_graph(self, x, eps, **kwargs):
5960
loss = tf.nn.softmax_cross_entropy_with_logits(logits=preds, labels=y)
6061
if self.targeted:
6162
loss = -loss
62-
grad, = tf.gradients(loss, x)
63+
grad, = tf.gradients(loss, x_op)
6364

6465
# Apply norm bound
6566
if self.ord == np.inf:
6667
grad = tf.sign(grad)
6768
elif self.ord == 1:
68-
ind = list(range(1, len(x.get_shape())))
69+
ind = list(range(1, len(x_op.get_shape())))
6970
grad = grad / tf.reduce_sum(tf.abs(grad), reduction_indices=ind, keep_dims=True)
7071
elif self.ord == 2:
71-
ind = list(range(1, len(x.get_shape())))
72+
ind = list(range(1, len(x_op.get_shape())))
7273
grad = grad / tf.sqrt(tf.reduce_sum(tf.square(grad), reduction_indices=ind, keep_dims=True))
7374

7475
# Apply perturbation and clip
75-
x_adv_op = x + eps * grad
76+
x_adv_op = x_op + eps_op * grad
7677
if self.clip_min is not None and self.clip_max is not None:
7778
x_adv_op = tf.clip_by_value(x_adv_op, self.clip_min, self.clip_max)
7879

@@ -133,16 +134,17 @@ def generate(self, x_val, **kwargs):
133134
return self.minimal_perturbations(self._x, x_val, **kwargs)
134135

135136
# Generate computation graph
136-
self._x_adv = self.generate_graph(self._x, **kwargs)
137+
eps = tf.placeholder(tf.float32, None)
138+
self._x_adv = self.generate_graph(self._x, eps, **kwargs)
137139

138140
# Run symbolic graph without or with true labels
139141
if 'y_val' not in kwargs or kwargs['y_val'] is None:
140-
feed_dict = {self._x: x_val}
142+
feed_dict = {self._x: x_val, eps: self.eps}
141143
else:
142144
# Verify label placeholder was given in params if using true labels
143145
if self.y is None:
144146
raise Exception("True labels given but label placeholder not given.")
145-
feed_dict = {self._x: x_val, self.y: kwargs['y_val']}
147+
feed_dict = {self._x: x_val, self.y: kwargs['y_val'], eps: self.eps}
146148

147149
return self.sess.run(self._x_adv, feed_dict=feed_dict)
148150

@@ -152,6 +154,7 @@ def set_params(self, **kwargs):
152154
153155
Attack-specific parameters:
154156
:param ord: (optional) Order of the norm (mimics Numpy). Possible values: np.inf, 1 or 2.
157+
:param eps: (required float) attack step size (input variation)
155158
:param y: (optional) A placeholder for the model labels. Only provide this parameter if you'd like to use true
156159
labels when crafting adversarial samples. Otherwise, model predictions are used as labels to avoid the
157160
"label leaking" effect (explained in this paper: https://arxiv.org/abs/1611.01236). Default is None.
@@ -166,4 +169,7 @@ def set_params(self, **kwargs):
166169
if self.ord not in [np.inf, int(1), int(2)]:
167170
raise ValueError("Norm order must be either np.inf, 1, or 2.")
168171

172+
if self.eps <= self.clip_min or self.eps > self.clip_max:
173+
raise ValueError('The amount of perturbation has to be in the data range.')
174+
169175
return True

0 commit comments

Comments
 (0)