This repository was archived by the owner on Mar 28, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 70
/
Copy pathfast_gradient.py
129 lines (101 loc) · 4 KB
/
fast_gradient.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import tensorflow as tf
__all__ = [
'fgm', # fast gradient method
'fgmt' # fast gradient method with target
]
def fgm(model, x, eps=0.01, epochs=1, sign=True, clip_min=0., clip_max=1.):
"""
Fast gradient method.
See https://arxiv.org/abs/1412.6572 and https://arxiv.org/abs/1607.02533
for details. This implements the revised version since the original FGM
has label leaking problem (https://arxiv.org/abs/1611.01236).
:param model: A wrapper that returns the output as well as logits.
:param x: The input placeholder.
:param eps: The scale factor for noise.
:param epochs: The maximum epoch to run.
:param sign: Use gradient sign if True, otherwise use gradient value.
:param clip_min: The minimum value in output.
:param clip_max: The maximum value in output.
:return: A tensor, contains adversarial samples for each input.
"""
xadv = tf.identity(x)
ybar = model(xadv)
yshape = ybar.get_shape().as_list()
ydim = yshape[1]
indices = tf.argmax(ybar, axis=1)
target = tf.cond(
tf.equal(ydim, 1),
lambda: tf.nn.relu(tf.sign(ybar - 0.5)),
lambda: tf.one_hot(indices, ydim, on_value=1.0, off_value=0.0))
if 1 == ydim:
loss_fn = tf.nn.sigmoid_cross_entropy_with_logits
else:
loss_fn = tf.nn.softmax_cross_entropy_with_logits
if sign:
noise_fn = tf.sign
else:
noise_fn = tf.identity
eps = tf.abs(eps)
def _cond(xadv, i):
return tf.less(i, epochs)
def _body(xadv, i):
ybar, logits = model(xadv, logits=True)
loss = loss_fn(labels=target, logits=logits)
dy_dx, = tf.gradients(loss, xadv)
xadv = tf.stop_gradient(xadv + eps*noise_fn(dy_dx))
xadv = tf.clip_by_value(xadv, clip_min, clip_max)
return xadv, i+1
xadv, _ = tf.while_loop(_cond, _body, (xadv, 0), back_prop=False,
name='fast_gradient')
return xadv
def fgmt(model, x, y=None, eps=0.01, epochs=1, sign=True, clip_min=0.,
clip_max=1.):
"""
Fast gradient method with target
See https://arxiv.org/pdf/1607.02533.pdf. This method is different from
FGM that instead of decreasing the probability for the correct label, it
increases the probability for the desired label.
:param model: A model that returns the output as well as logits.
:param x: The input placeholder.
:param y: The desired target label, set to the least-likely class if None.
:param eps: The noise scale factor.
:param epochs: Maximum epoch to run.
:param sign: Use gradient sign if True, otherwise gradient values.
:param clip_min: Minimum value in output.
:param clip_max: Maximum value in output.
"""
xadv = tf.identity(x)
ybar = model(xadv)
ydim = ybar.get_shape().as_list()[1]
n = tf.shape(ybar)[0]
if y is None:
indices = tf.argmin(ybar, axis=1)
else:
indices = tf.cond(tf.equal(0, tf.rank(y)),
lambda: tf.zeros([n], dtype=tf.int32) + y,
lambda: tf.zeros([n], dtype=tf.int32))
target = tf.cond(
tf.equal(ydim, 1),
lambda: 1 - ybar,
lambda: tf.one_hot(indices, ydim, on_value=1.0, off_value=0.0))
if 1 == ydim:
loss_fn = tf.nn.sigmoid_cross_entropy_with_logits
else:
loss_fn = tf.nn.softmax_cross_entropy_with_logits
if sign:
noise_fn = tf.sign
else:
noise_fn = tf.identity
eps = -tf.abs(eps)
def _cond(xadv, i):
return tf.less(i, epochs)
def _body(xadv, i):
ybar, logits = model(xadv, logits=True)
loss = loss_fn(labels=target, logits=logits)
dy_dx, = tf.gradients(loss, xadv)
xadv = tf.stop_gradient(xadv + eps*noise_fn(dy_dx))
xadv = tf.clip_by_value(xadv, clip_min, clip_max)
return xadv, i+1
xadv, _ = tf.while_loop(_cond, _body, (xadv, 0), back_prop=False,
name='fast_gradient_target')
return xadv