├── LICENSE
├── README.md
├── attack.py
├── demo.png
└── relationship.png
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Cihang Xie
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Improving Transferability of Adversarial Examples with Input Diversity
2 |
3 | This paper proposed to improve the transferability of adversarial examples by creating diverse input patterns (https://arxiv.org/abs/1803.06978). Instead of only using the original images to generate adversarial examples, the proposed method, Diverse Input Iterative Fast Gradient Sign
4 | Method (DI2-FGSM), applies random transformations to the input images at each iteration. The generated adversarial examples are much more transferable than those generated by FGSM and I-FGSM. An example is shown below:
5 |
6 | 
7 |
8 |
9 | ## Extension
10 | To improve the transferability further, we
11 | - integrate momentum term into the attack process (https://arxiv.org/abs/1710.06081);
12 | - attack multiple networks simultaneously (https://arxiv.org/abs/1611.02770).
13 |
14 | By evaluating this enhanced attack w.r.t. the top 3 defense submissions and 3 official baselines from NIPS 2017 adversarial competition (https://www.kaggle.com/c/nips-2017-non-targeted-adversarial-attack), it reaches an average success rate of 73.0%, which outperforms the top 1 attack submission in the NIPS competition by a large margin of 6.6%. Please refer to the Table 3 in the paper for details.
15 |
16 |
17 | ## Relationships between different attacks
18 |
19 | Different attacks can be related via different parameter settings, as shown below:
20 |
21 |
22 |
23 | ## Inception_v3 model
24 |
25 | - http://download.tensorflow.org/models/inception_v3_2016_08_28.tar.gz
26 |
27 | ## Acknowledgements
28 |
29 | - For the implementations of random resizing and random padding (https://arxiv.org/abs/1711.01991), the original version is available at https://github.com/cihangxie/NIPS2017_adv_challenge_defense. We adopt a more user-friendly re-implementation https://github.com/anishathalye/obfuscated-gradients in our repo only for releasing purpose.
30 |
31 | ## Citing this work
32 |
33 | If you find this work is useful in your research, please consider citing:
34 |
35 | @inproceedings{xie2019improving,
36 | title={Improving Transferability of Adversarial Examples with Input Diversity},
37 | author={Xie, Cihang and Zhang, Zhishuai and Zhou, Yuyin and Bai, Song and Wang, Jianyu and Ren, Zhou and Yuille, Alan},
38 | Booktitle = {Computer Vision and Pattern Recognition},
39 | year={2019},
40 | organization={IEEE}
41 | }
42 |
--------------------------------------------------------------------------------
/attack.py:
--------------------------------------------------------------------------------
1 | """Implementation of sample attack on Inception_v3"""
2 |
3 | from __future__ import absolute_import
4 | from __future__ import division
5 | from __future__ import print_function
6 |
7 | import os
8 |
9 | import numpy as np
10 | from PIL import Image
11 | from scipy.misc import imread, imresize, imsave
12 | from scipy.misc import imresize
13 |
14 | import tensorflow as tf
15 |
16 | from tensorflow.contrib.slim.nets import inception
17 |
18 | slim = tf.contrib.slim
19 |
20 | tf.flags.DEFINE_string(
21 | 'master', '', 'The address of the TensorFlow master to use.')
22 |
23 | tf.flags.DEFINE_string(
24 | 'checkpoint_path', '', 'Path to checkpoint for inception network.')
25 |
26 | tf.flags.DEFINE_string(
27 | 'input_dir', '', 'Input directory with images.')
28 |
29 | tf.flags.DEFINE_string(
30 | 'output_dir', '', 'Output directory with images.')
31 |
32 | tf.flags.DEFINE_integer(
33 | 'image_width', 299, 'Width of each input images.')
34 |
35 | tf.flags.DEFINE_integer(
36 | 'image_height', 299, 'Height of each input images.')
37 |
38 | tf.flags.DEFINE_integer(
39 | 'image_resize', 330, 'Height of each input images.')
40 |
41 | tf.flags.DEFINE_integer(
42 | 'batch_size', 10, 'How many images process at one time.')
43 |
44 | tf.flags.DEFINE_float(
45 | 'max_epsilon', 16.0, 'Maximum size of adversarial perturbation.')
46 |
47 | tf.flags.DEFINE_float(
48 | 'prob', 0.5, 'probability of using diverse inputs.')
49 |
50 | # if momentum = 1, this attack becomes M-DI-2-FGSM
51 | tf.flags.DEFINE_float(
52 | 'momentum', 0.0, 'Momentum.')
53 |
54 | tf.flags.DEFINE_string(
55 | 'GPU_ID', '0', 'which GPU to use.')
56 |
57 | FLAGS = tf.flags.FLAGS
58 |
59 | print("print all settings\n")
60 | print(FLAGS.master)
61 | print(FLAGS.__dict__)
62 |
63 | os.environ['CUDA_DEVICE_ORDER'] = 'PCI_BUS_ID'
64 | os.environ['CUDA_VISIBLE_DEVICES'] = FLAGS.GPU_ID
65 |
66 |
67 | def load_images(input_dir, output_dir, batch_shape):
68 | """Read png images from input directory in batches.
69 | Args:
70 | input_dir: input directory
71 | batch_shape: shape of minibatch array, i.e. [batch_size, height, width, 3]
72 | Yields:
73 | filenames: list file names without path of each image
74 | Lenght of this list could be less than batch_size, in this case only
75 | first few images of the result are elements of the minibatch.
76 | images: array with all images from this batch
77 | """
78 | images = np.zeros(batch_shape)
79 | filenames = []
80 | idx = 0
81 | batch_size = batch_shape[0]
82 | for filepath in tf.gfile.Glob(os.path.join(input_dir, '*.png')):
83 | temp_name = str.split(filepath, '/')
84 | output_name = output_dir + '/'+ temp_name[-1]
85 | # check if the file exist
86 | if os.path.isfile(output_name) == False:
87 | with tf.gfile.Open(filepath) as f:
88 | image = imread(f, mode='RGB').astype(np.float) / 255.0
89 | # Images for inception classifier are normalized to be in [-1, 1] interval.
90 | images[idx, :, :, :] = image * 2.0 - 1.0
91 | filenames.append(os.path.basename(filepath))
92 | idx += 1
93 | if idx == batch_size:
94 | yield filenames, images
95 | filenames = []
96 | images = np.zeros(batch_shape)
97 | idx = 0
98 | if idx > 0:
99 | yield filenames, images
100 |
101 |
102 | def save_images(images, filenames, output_dir):
103 | """Saves images to the output directory.
104 | Args:
105 | images: array with minibatch of images
106 | filenames: list of filenames without path
107 | If number of file names in this list less than number of images in
108 | the minibatch then only first len(filenames) images will be saved.
109 | output_dir: directory where to save images
110 | """
111 | for i, filename in enumerate(filenames):
112 | # Images for inception classifier are normalized to be in [-1, 1] interval,
113 | # so rescale them back to [0, 1].
114 | with tf.gfile.Open(os.path.join(output_dir, filename), 'w') as f:
115 | imsave(f, (images[i, :, :, :] + 1.0) * 0.5 * 255, format='png')
116 |
117 |
118 | def graph(x, y, i, x_max, x_min, grad):
119 | eps = 2.0 * FLAGS.max_epsilon / 255.0
120 | eps_iter = 2.0 / 255.0
121 | num_classes = 1001
122 | momentum = FLAGS.momentum
123 |
124 | with slim.arg_scope(inception.inception_v3_arg_scope()):
125 | logits, end_points = inception.inception_v3(
126 | input_diversity(x), num_classes=num_classes, is_training=False)
127 | pred = tf.argmax(end_points['Predictions'], 1)
128 |
129 | # here is the way to stable gt lables
130 | first_round = tf.cast(tf.equal(i, 0), tf.int64)
131 | y = first_round * pred + (1 - first_round) * y
132 |
133 | one_hot = tf.one_hot(y, num_classes)
134 | cross_entropy = tf.losses.softmax_cross_entropy(one_hot, logits)
135 |
136 | # compute the gradient info
137 | noise = tf.gradients(cross_entropy, x)[0]
138 | noise = noise / tf.reduce_mean(tf.abs(noise), [1,2,3], keep_dims=True)
139 | # accumulate the gradient
140 | noise = momentum * grad + noise
141 |
142 | x = x + eps_iter * tf.sign(noise)
143 | x = tf.clip_by_value(x, x_min, x_max)
144 | i = tf.add(i, 1)
145 | return x, y, i, x_max, x_min, noise
146 |
147 |
148 | def stop(x, y, i, x_max, x_min, grad):
149 | num_iter = int(min(FLAGS.max_epsilon+4, 1.25*FLAGS.max_epsilon))
150 | return tf.less(i, num_iter)
151 |
152 |
153 | def input_diversity(input_tensor):
154 | rnd = tf.random_uniform((), FLAGS.image_width, FLAGS.image_resize, dtype=tf.int32)
155 | rescaled = tf.image.resize_images(input_tensor, [rnd, rnd], method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)
156 | h_rem = FLAGS.image_resize - rnd
157 | w_rem = FLAGS.image_resize - rnd
158 | pad_top = tf.random_uniform((), 0, h_rem, dtype=tf.int32)
159 | pad_bottom = h_rem - pad_top
160 | pad_left = tf.random_uniform((), 0, w_rem, dtype=tf.int32)
161 | pad_right = w_rem - pad_left
162 | padded = tf.pad(rescaled, [[0, 0], [pad_top, pad_bottom], [pad_left, pad_right], [0, 0]], constant_values=0.)
163 | padded.set_shape((input_tensor.shape[0], FLAGS.image_resize, FLAGS.image_resize, 3))
164 | return tf.cond(tf.random_uniform(shape=[1])[0] < tf.constant(FLAGS.prob), lambda: padded, lambda: input_tensor)
165 |
166 |
167 | def main(_):
168 | eps = 2.0 * FLAGS.max_epsilon / 255.0
169 | batch_shape = [FLAGS.batch_size, FLAGS.image_height, FLAGS.image_width, 3]
170 |
171 | with tf.Graph().as_default():
172 | # Prepare graph
173 | x_input = tf.placeholder(tf.float32, shape=batch_shape)
174 | x_max = tf.clip_by_value(x_input + eps, -1.0, 1.0)
175 | x_min = tf.clip_by_value(x_input - eps, -1.0, 1.0)
176 |
177 | y = tf.constant(np.zeros([FLAGS.batch_size]), tf.int64)
178 | i = tf.constant(0)
179 | grad = tf.zeros(shape=batch_shape)
180 | x_adv, _, _, _, _, _ = tf.while_loop(stop, graph, [x_input, y, i, x_max, x_min, grad])
181 | # Run computation
182 | saver = tf.train.Saver()
183 | with tf.Session() as sess:
184 | saver.restore(sess, FLAGS.checkpoint_path)
185 | for filenames, images in load_images(FLAGS.input_dir, FLAGS.output_dir, batch_shape):
186 | adv_images = sess.run(x_adv, feed_dict={x_input: images})
187 | save_images(adv_images, filenames, FLAGS.output_dir)
188 |
189 |
190 | if __name__ == '__main__':
191 | tf.app.run()
192 |
--------------------------------------------------------------------------------
/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cihangxie/DI-2-FGSM/10ffd9b9e94585b6a3b9d6858a9a929dc488fc02/demo.png
--------------------------------------------------------------------------------
/relationship.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cihangxie/DI-2-FGSM/10ffd9b9e94585b6a3b9d6858a9a929dc488fc02/relationship.png
--------------------------------------------------------------------------------