├── .gitignore ├── .pydevproject ├── README.md ├── cascade_adv_training ├── README.md ├── cifar_load.py ├── convert_pickle.py ├── dataset.py ├── evaluation.py ├── helpers.py ├── layers.py ├── lenet.py ├── main.py ├── model.py ├── provider.py ├── re_li_attack.py ├── re_li_attack_notanh.py ├── resnet.py ├── resnet_layers.py ├── run_all_gpu0 ├── runstep.npz ├── tf_rename_variables.py └── utils.py ├── confusion.py ├── guided-denoiser ├── LICENSE.txt ├── README.md ├── dataset.py ├── defense.py ├── helpers.py ├── inception.py ├── inceptionresnet.py ├── inceptionresnetv2.py ├── inres.py ├── metadata.json ├── provider.py ├── re_li_attack.py ├── re_li_attack_notanh.py ├── res152_wide.py ├── resnet.py ├── resnext.py ├── resnext101.py ├── resnext_features │ ├── __init__.py │ ├── resnext101_32x4d_features.py │ └── resnext101_64x4d_features.py └── v3.py ├── inputtransformations ├── .gitignore ├── README.md ├── bitdepth.ipynb ├── crop.ipynb ├── defense.py ├── helpers.py ├── imagenet_labels.py ├── inceptionv3.py ├── jpeg.ipynb ├── quilt.ipynb ├── quilt_preprocess.py ├── re_l2_attack.py ├── re_l2_attack_clipimage.py ├── re_l2_attack_clipimage_notanh.py ├── re_li_attack.py ├── robustml_attack.py ├── robustml_model.py ├── robustml_model_origin.py ├── setup.sh ├── tv.ipynb └── utils.py ├── lid ├── README.md ├── attack_lid.py ├── cifar10_input.py ├── detect_adv_samples.py ├── evaluation.py ├── evaluation_bpda.py ├── extract_artifacts.py ├── helpers.py ├── re_li_attack.py └── util.py ├── pixel-deflection ├── README.md ├── demo.ipynb ├── helpers.py ├── imagenet_labels.json ├── images │ ├── n02443114_00000055.png │ ├── n02443114_00032317.png │ └── n02447366_00008562.png ├── main.py ├── maps │ ├── n02443114_00000055.png │ ├── n02443114_00032317.png │ └── n02447366_00008562.png ├── methods.py ├── originals │ ├── n02443114_00000055.png │ ├── n02443114_00032317.png │ └── n02447366_00008562.png ├── re_li_attack.py └── utils.py ├── randomization ├── .gitignore ├── README.md ├── defense.py ├── defense_batch.py ├── getperturb_li_attack32_tfmultigpu.py ├── helpers.py ├── imagenet_labels.py ├── inceptionv3.py ├── nohup.out ├── provider.py ├── re_li_attack.py ├── re_li_attack299.py ├── re_li_attack32.py ├── re_li_attack32_multigpu.py ├── re_li_attack32_tf.py ├── re_li_attack32_tfmultigpu.py ├── re_li_attack32_tfmultigpu_notanh.py ├── robustml_attack.py ├── robustml_model.py ├── setup.sh └── utils.py ├── robustnet ├── LICENSE ├── README.md ├── attack.py ├── evaluation.py ├── helpers.py ├── main.py ├── main2.py ├── models │ ├── __init__.py │ ├── densenet.py │ ├── dpn.py │ ├── googlenet.py │ ├── layer.py │ ├── lenet.py │ ├── mobilenet.py │ ├── preact_resnet.py │ ├── resnet.py │ ├── resnext.py │ ├── senet.py │ ├── shufflenet.py │ └── vgg.py ├── plot_accu.py ├── re_li_attack.py ├── run.sh ├── test.py ├── utils.py └── utils2.py ├── sap ├── README.md ├── cifar10_input.py ├── cifar_model.py ├── evaluation.py ├── evaluation_bpda.py ├── helpers.py ├── re_li_attack.py ├── robustml_attack.py ├── robustml_model.py └── sap_model.py ├── therm-adv ├── README.md ├── cifar10_input.py ├── cifar_model.py ├── discretization_attacks.py ├── discretization_utils.py ├── evaluation.py ├── evaluation_bpda.py ├── helpers.py ├── re_li_attack.py ├── re_li_attack_notanh.py ├── robustml_attack.py ├── robustml_model.py └── train.py └── wideresnet28 ├── README.md ├── cifar10_input.py ├── cifar_model.py ├── config.json ├── discretization_attacks.py ├── discretization_utils.py ├── evaluation.py ├── helpers.py ├── setup.sh ├── test.py ├── test_wres.py └── train.py /.gitignore: -------------------------------------------------------------------------------- 1 | cifar10_data/ 2 | all_models/ 3 | imageNetTest/ 4 | data/ 5 | *.tar 6 | *.pyc 7 | *.ckpt 8 | *.pth 9 | *.pkl 10 | *.log 11 | .idea/ 12 | .settings/ 13 | .project 14 | *.zip 15 | 16 | 17 | -------------------------------------------------------------------------------- /.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | Default 4 | python interpreter 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NATTACK: A STRONG AND UNIVERSAL GAUSSIAN BLACK-BOX ADVERSARIAL ATTACK 2 | 3 | 4 | Data and model can be found here: [data and model](https://knightsucfedu39751-my.sharepoint.com/:f:/g/personal/liyandong_knights_ucf_edu/EnmkFaQkvwdDq0xcqIbbEfYBAhSkQK16ONPgjMJncbCwmg). 5 | 6 | 7 | Please download the data&&model and unzip them to './cifar-data' and './all_models' 8 | 9 | 10 | Below is Table 1 from our paper, where we show the robustness of each accepted defense to the adversarial examples we can construct: 11 | 12 | 13 | 14 | | Defense | Dataset | Distance | Success rate | 15 | |---|---|---|---| 16 | | ADV-TRAIN [Madry et al. (2018)](https://arxiv.org/abs/1706.06083) | CIFAR | 0.031 (linf) | 47.9% | 17 | | ADV-BNN [Liu et al. (2019)](https://arxiv.org/abs/1810.01279) | CIFAR | 0.035 (linf) | 75.3% | 18 | | THERM-ADV [Buckman et al. (2018)](https://openreview.net/forum?id=S18Su--CW)[Madry et al. (2018)](https://arxiv.org/abs/1706.06083) | CIFAR | 0.031 (linf) | 91.2% | 19 | | CAS-ADV [Na et al. (2018)](https://arxiv.org/abs/1708.02582) | CIFAR | 0.031 (linf) | 97.7% | 20 | | ADV-GAN [Wang & Yu (2019)](https://openreview.net/forum?id=S1lIMn05F7) | CIFAR | 0.015 (linf) | 98.3% | 21 | | LID [Ma et al. (2018)](https://arxiv.org/abs/1801.02613) | CIFAR | 0.031 (linf) | 100.0% | 22 | | THERM [Buckman et al. (2018)](https://openreview.net/forum?id=S18Su--CW) | CIFAR | 0.031 (linf) | 100.0% | 23 | | SAP [Dhillon et al. (2018)](https://arxiv.org/abs/1803.01442) | CIFAR | 0.031 (linf) | 100.0% | 24 | | RSE [Liu et al. (2018)](https://arxiv.org/abs/1712.00673) | CIFAR | 0.031 (linf) | 100.0% | 25 | | GUIDED DENOISER [(Liao et al., 2018)](https://arxiv.org/abs/1711.00117) | ImageNet | 0.031 (linf) | 95.5% | 26 | | RANDOMIZATION [Xie et al. (2018)](https://arxiv.org/abs/1711.01991) | ImageNet | 0.031 (linf) | 96.5% | 27 | | INPUT-TRANS [Guo et al. (2018)](https://arxiv.org/abs/1711.00117) | ImageNet | 0.05 (l2) | 100.0% | 28 | | PIXEL DEFLECTION [Prakash et al. (2018)](https://arxiv.org/abs/1801.08926) | ImageNet | 0.031 (linf) | 100.0% | 29 | 30 | 31 | 32 | 33 | ## Paper 34 | 35 | **Abstract:** 36 | 37 | Powerful adversarial attack methods are vital for understanding how to construct robust deep neural networks (DNNs) and for thoroughly testing defense techniques. In this paper, we propose a black-box adversarial attack algorithm that can defeat both vanilla DNNs and those generated by various defense techniques developed recently. Instead of searching for an "optimal" adversarial example for a benign input to a targeted DNN, our algorithm finds a probability density distribution over a small region centered around the input, such that a sample drawn from this distribution is likely an adversarial example, without the need of accessing the DNN's internal layers or weights. Our approach is universal as it can successfully attack different neural networks by a single algorithm. It is also strong; according to the testing against 2 vanilla DNNs and 13 defended ones, it outperforms state-of-the-art black-box or white-box attack methods for most test cases. Additionally, our results reveal that adversarial training remains one of the best defense techniques, and the adversarial examples are not as transferable across defended DNNs as them across vanilla DNNs. 38 | 39 | 40 | ## Source code 41 | 42 | This repository contains our implemenation of the black-box attack algorithm described in our paper, six defense methods (SAP, LID, RANDOMIZATION, INPUT-TRANS, THERM, and THERM-DAV) borrowed from the code of Anish et al. (2018), two defended models (GUIDED DENOISER and PIXEL DEFLECTION) based on the code of Athalye & Carlini, (2018), and two defended models (RSE and CAS-ADV) from the original papers. 43 | 44 | ## Note 45 | -------------------------------------------------------------------------------- /cascade_adv_training/README.md: -------------------------------------------------------------------------------- 1 | # Cascade Adversarial Training Regularized with a Unified Embedding 2 | 3 | 4 |
5 | “[Cascade Adversarial Machine Learning Regularized with a Unified Embedding](https://arxiv.org/pdf/1708.02582.pdf),” 6 |
7 | Taesik Na, Jong Hwan Ko and Saibal Mukhopadhyay, 8 | International Conference on Learning Representations (ICLR), Apr 2018 9 | 10 | 11 | ## Requirements 12 | 13 | The code was tested with Python 2.7.12 and Tensorflow 1.4.0. 14 | 15 | ## [NATTACK] evaluation 16 | 17 | Run with: 18 | 19 | ```bash 20 | python re_li_attack.py 21 | -------------------------------------------------------------------------------- /cascade_adv_training/cifar_load.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import os 3 | import tarfile 4 | from six.moves import urllib 5 | import sys 6 | 7 | 8 | CIFAR10_DATA_URL = 'http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz' 9 | CIFAR100_DATA_URL = 'http://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz' 10 | 11 | def maybe_download_and_extract(dest_directory, is_cifar10): 12 | """Download and extract the tarball from Alex's website.""" 13 | if not os.path.exists(dest_directory): 14 | os.makedirs(dest_directory) 15 | DATA_URL = CIFAR10_DATA_URL if is_cifar10 else CIFAR100_DATA_URL 16 | filename = DATA_URL.split('/')[-1] 17 | filepath = os.path.join(dest_directory, filename) 18 | if not os.path.exists(filepath): 19 | def _progress(count, block_size, total_size): 20 | sys.stdout.write('\r>> Downloading %s %.1f%%' % (filename, 21 | float(count * block_size) / float(total_size) * 100.0)) 22 | sys.stdout.flush() 23 | filepath, _ = urllib.request.urlretrieve(DATA_URL, filepath, _progress) 24 | print() 25 | statinfo = os.stat(filepath) 26 | print('Successfully downloaded', filename, statinfo.st_size, 'bytes.') 27 | 28 | tarfile.open(filepath, 'r:gz').extractall(dest_directory) 29 | 30 | 31 | def one_hot(x, n): 32 | """ 33 | convert index representation to one-hot representation 34 | """ 35 | x = np.array(x) 36 | assert x.ndim == 1 37 | return np.eye(n)[x] 38 | 39 | 40 | def _load_batch_cifar10(data_dir, filename, dtype='float32'): 41 | """ 42 | load a batch in the CIFAR-10 format 43 | """ 44 | #data_dir_cifar10 = os.path.join(data_dir, "cifar-10-batches-py") 45 | data_dir_cifar10 = data_dir 46 | path = os.path.join(data_dir_cifar10, filename) 47 | batch = np.load(path) 48 | data = batch['data'] 49 | data = data.reshape([-1, 3, 32, 32]) 50 | data = data.transpose([0, 2, 3, 1]) 51 | # convert labels to one-hot representation 52 | labels = one_hot(batch['labels'], n=10) 53 | return data.astype(dtype), labels.astype(dtype) 54 | 55 | 56 | def _grayscale(a): 57 | return np.expand_dims(a.reshape(-1, 32, 32, 3).mean(3), 3) 58 | # return a.reshape(a.shape[0], 32, 32, 3).mean(3).reshape(a.shape[0], -1) 59 | 60 | 61 | def cifar10(data_dir, dtype='float32', grayscale=False): 62 | # train 63 | x_train = [] 64 | t_train = [] 65 | for k in range(5): 66 | x, t = _load_batch_cifar10(data_dir, "data_batch_%d" % (k + 1), dtype=dtype) 67 | x_train.append(x) 68 | t_train.append(t) 69 | 70 | x_train = np.concatenate(x_train, axis=0) 71 | t_train = np.concatenate(t_train, axis=0) 72 | 73 | # test 74 | x_test, t_test = _load_batch_cifar10(data_dir, "test_batch", dtype=dtype) 75 | 76 | if grayscale: 77 | x_train = _grayscale(x_train) 78 | x_test = _grayscale(x_test) 79 | 80 | return x_train, t_train, x_test, t_test 81 | 82 | 83 | def _load_batch_cifar100(data_dir, filename, dtype='float32'): 84 | """ 85 | load a batch in the CIFAR-100 format 86 | """ 87 | data_dir_cifar100 = os.path.join(data_dir, "cifar-100-python") 88 | path = os.path.join(data_dir_cifar100, filename) 89 | batch = np.load(path) 90 | data = batch['data'] 91 | data = data.reshape([-1, 3, 32, 32]) 92 | data = data.transpose([0, 2, 3, 1]) 93 | labels = one_hot(batch['fine_labels'], n=100) 94 | return data.astype(dtype), labels.astype(dtype) 95 | 96 | 97 | def cifar100(data_dir, dtype='float32', grayscale=False): 98 | x_train, t_train = _load_batch_cifar100(data_dir, "train", dtype=dtype) 99 | x_test, t_test = _load_batch_cifar100(data_dir, "test", dtype=dtype) 100 | 101 | if grayscale: 102 | x_train = _grayscale(x_train) 103 | x_test = _grayscale(x_test) 104 | 105 | return x_train, t_train, x_test, t_test 106 | 107 | -------------------------------------------------------------------------------- /cascade_adv_training/convert_pickle.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os 3 | 4 | y=[] 5 | dirs = os.listdir('./') 6 | for x in dirs: 7 | if 'perturb' in x and ('cascade' not in x and 'thermo' not in x): 8 | y.append(x) 9 | files = os.listdir(x) 10 | for z in files: 11 | temp = pickle.load(open(x + '/' +z,'rb')) 12 | pickle.dump(temp, open(x + '/' +z,'wb'), protocol=2) 13 | -------------------------------------------------------------------------------- /cascade_adv_training/dataset.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | 16 | from __future__ import absolute_import 17 | from __future__ import division 18 | from __future__ import print_function 19 | 20 | import numpy 21 | from six.moves import xrange 22 | 23 | from tensorflow.python.framework import dtypes 24 | 25 | class DataSet(object): 26 | 27 | def __init__(self, 28 | images, 29 | labels, 30 | fake_data=False, 31 | one_hot=False, 32 | dtype=dtypes.float32, 33 | reshape=True): 34 | """Construct a DataSet. 35 | one_hot arg is used only if fake_data is true. `dtype` can be either 36 | `uint8` to leave the input as `[0, 255]`, or `float32` to rescale into 37 | `[0, 1]`. 38 | """ 39 | dtype = dtypes.as_dtype(dtype).base_dtype 40 | if dtype not in (dtypes.uint8, dtypes.float32): 41 | raise TypeError('Invalid image dtype %r, expected uint8 or float32' % 42 | dtype) 43 | if fake_data: 44 | self._num_examples = 10000 45 | self.one_hot = one_hot 46 | else: 47 | assert images.shape[0] == labels.shape[0], ( 48 | 'images.shape: %s labels.shape: %s' % (images.shape, labels.shape)) 49 | self._num_examples = images.shape[0] 50 | 51 | # Convert shape from [num examples, rows, columns, depth] 52 | # to [num examples, rows*columns] (assuming depth == 1) 53 | if reshape: 54 | assert images.shape[3] == 1 55 | images = images.reshape(images.shape[0], 56 | images.shape[1] * images.shape[2]) 57 | if dtype == dtypes.float32: 58 | # Convert from [0, 255] -> [0.0, 1.0]. 59 | images = images.astype(numpy.float32) 60 | images = numpy.multiply(images, 1.0 / 255.0) 61 | self._images = images 62 | self._labels = labels 63 | self._epochs_completed = 0 64 | self._index_in_epoch = 0 65 | 66 | @property 67 | def images(self): 68 | return self._images 69 | 70 | @property 71 | def labels(self): 72 | return self._labels 73 | 74 | @property 75 | def num_examples(self): 76 | return self._num_examples 77 | 78 | @property 79 | def epochs_completed(self): 80 | return self._epochs_completed 81 | 82 | def next_batch(self, batch_size, fake_data=False, perm=None): 83 | """Return the next `batch_size` examples from this data set.""" 84 | if fake_data: 85 | fake_image = [1] * 784 86 | if self.one_hot: 87 | fake_label = [1] + [0] * 9 88 | else: 89 | fake_label = 0 90 | return [fake_image for _ in xrange(batch_size)], [ 91 | fake_label for _ in xrange(batch_size)], None 92 | start = self._index_in_epoch 93 | self._index_in_epoch += batch_size 94 | if self._index_in_epoch > self._num_examples: 95 | # Finished epoch 96 | self._epochs_completed += 1 97 | # Shuffle the data 98 | if perm is None: 99 | perm = numpy.arange(self._num_examples) 100 | numpy.random.shuffle(perm) 101 | self._images = self._images[perm] 102 | self._labels = self._labels[perm] 103 | # Start next epoch 104 | start = 0 105 | self._index_in_epoch = batch_size 106 | assert batch_size <= self._num_examples 107 | else: 108 | perm = None 109 | end = self._index_in_epoch 110 | return self._images[start:end], self._labels[start:end], perm 111 | 112 | 113 | -------------------------------------------------------------------------------- /cascade_adv_training/helpers.py: -------------------------------------------------------------------------------- 1 | import operator as op 2 | import functools as ft 3 | import numpy as np 4 | 5 | 6 | '''reduce_* helper functions reduce tensors on all dimensions but the first. 7 | They are intended to be used on batched tensors where dim 0 is the batch dim. 8 | ''' 9 | 10 | 11 | def reduce_sum(x, keepdim=True): 12 | # silly PyTorch, when will you get proper reducing sums/means? 13 | for a in reversed(range(1, x.dim())): 14 | x = x.sum(a, keepdim=keepdim) 15 | return x 16 | 17 | 18 | def reduce_mean(x, keepdim=True): 19 | numel = ft.reduce(op.mul, x.size()[1:]) 20 | x = reduce_sum(x, keepdim=keepdim) 21 | return x / numel 22 | 23 | 24 | def reduce_min(x, keepdim=True): 25 | for a in reversed(range(1, x.dim())): 26 | x = x.min(a, keepdim=keepdim)[0] 27 | return x 28 | 29 | 30 | def reduce_max(x, keepdim=True): 31 | for a in reversed(range(1, x.dim())): 32 | x = x.max(a, keepdim=keepdim)[0] 33 | return x 34 | 35 | 36 | def torch_arctanh(x, eps=1e-6): 37 | x *= (1. - eps) 38 | return (np.log((1 + x) / (1 - x))) * 0.5 39 | 40 | 41 | def l2r_dist(x, y, keepdim=True, eps=1e-8): 42 | d = (x - y)**2 43 | d = reduce_sum(d, keepdim=keepdim) 44 | d += eps # to prevent infinite gradient at 0 45 | return d.sqrt() 46 | 47 | 48 | def l2_dist(x, y, keepdim=True): 49 | d = (x - y)**2 50 | return reduce_sum(d, keepdim=keepdim) 51 | 52 | 53 | def l1_dist(x, y, keepdim=True): 54 | d = torch.abs(x - y) 55 | return reduce_sum(d, keepdim=keepdim) 56 | 57 | 58 | def l2_norm(x, keepdim=True): 59 | norm = reduce_sum(x*x, keepdim=keepdim) 60 | return norm.sqrt() 61 | 62 | 63 | def l1_norm(x, keepdim=True): 64 | return reduce_sum(x.abs(), keepdim=keepdim) 65 | 66 | 67 | def rescale(x, x_min=-1., x_max=1.): 68 | return x * (x_max - x_min) + x_min 69 | 70 | 71 | def tanh_rescale(x, x_min=-1., x_max=1.): 72 | return (torch.tanh(x) + 1) * 0.5 * (x_max - x_min) + x_min 73 | -------------------------------------------------------------------------------- /cascade_adv_training/lenet.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | 16 | """Builds the CIFAR-10 network. 17 | 18 | Summary of available functions: 19 | 20 | # Compute input images and labels for training. If you would like to run 21 | # evaluations, use inputs() instead. 22 | inputs, labels = distorted_inputs() 23 | 24 | # Compute inference on the model inputs to make a prediction. 25 | predictions = inference(inputs) 26 | 27 | # Compute the total loss of the prediction with respect to the labels. 28 | loss = loss(predictions, labels) 29 | 30 | # Create a graph to run one step of training with respect to the loss. 31 | train_op = train(loss, global_step) 32 | """ 33 | # pylint: disable=missing-docstring 34 | import tensorflow as tf 35 | 36 | from layers import * 37 | 38 | def lenet(images, img_size, num_channels, num_classes, 39 | embedding_at=2): 40 | # conv1 41 | with tf.variable_scope('gated_conv1') as scope: 42 | pre_activation = gated_conv(images, 5, 5, num_channels, 64, None) 43 | conv1 = tf.nn.relu(pre_activation, name=scope.name) 44 | activation_summary(conv1) 45 | # pool1 46 | pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], 47 | padding='SAME', name='pool1') 48 | # norm1 49 | norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, 50 | name='norm1') 51 | 52 | if embedding_at == 1: 53 | nrof_embeddings = img_size*img_size*16 54 | embedding = tf.reshape(norm1, [-1, nrof_embeddings]) 55 | 56 | # conv2 57 | with tf.variable_scope('gated_conv2') as scope: 58 | pre_activation = gated_conv(norm1, 5, 5, 64, 64, None) 59 | conv2 = tf.nn.relu(pre_activation, name=scope.name) 60 | activation_summary(conv2) 61 | # norm2 62 | norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, 63 | name='norm2') 64 | # pool2 65 | pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], 66 | strides=[1, 2, 2, 1], padding='SAME', name='pool2') 67 | 68 | assert pool2.get_shape().as_list()[1:] == [img_size/4, img_size/4, 64] 69 | 70 | dim_unroll = img_size*img_size*4 71 | reshape = tf.reshape(pool2, [-1, dim_unroll]) 72 | if embedding_at == 2: 73 | embedding = reshape 74 | 75 | # local3 76 | with tf.variable_scope('local3') as scope: 77 | # Move everything into depth so we can perform a single matrix multiply. 78 | pre_activation = fc(reshape, 79 | dim_unroll, 384, 0.04, 0.004, 80 | 'pre_' + scope.name) 81 | local3 = tf.nn.relu(pre_activation, name=scope.name) 82 | activation_summary(local3) 83 | 84 | if embedding_at == 3: 85 | embedding = local3 86 | 87 | # local4 88 | with tf.variable_scope('local4') as scope: 89 | pre_activation = fc(local3, 90 | 384, 192, 0.04, 0.004, 91 | 'pre_' + scope.name) 92 | local4 = tf.nn.relu(pre_activation, name=scope.name) 93 | activation_summary(local4) 94 | 95 | if embedding_at == 4: 96 | embedding = local4 97 | 98 | # linear layer(WX + b), 99 | # We don't apply softmax here because 100 | # tf.nn.sparse_softmax_cross_entropy_with_logits accepts the unscaled logits 101 | # and performs the softmax internally for efficiency. 102 | with tf.variable_scope('logit') as scope: 103 | logit = fc(local4, 104 | 192, num_classes, 1/192.0, 0.0, 105 | scope.name) 106 | activation_summary(logit) 107 | 108 | if embedding_at > 4: 109 | embedding = logit 110 | 111 | return embedding, logit 112 | 113 | -------------------------------------------------------------------------------- /cascade_adv_training/run_all_gpu0: -------------------------------------------------------------------------------- 1 | # Initial Training 2 | CUDA_VISIBLE_DEVICES=0 python main.py --max_epochs=10 --is_train=True --adversarial=False --train_dir=./ref/resnet20_cifar10 3 | # Adversarial Training 4 | CUDA_VISIBLE_DEVICES=0 python main.py --is_train=True --adversarial=True --restore=True --checkpoint_dir=./ref/resnet20_cifar10 --train_dir=./checkpoint/resnet20_cifar10_adv 5 | # Training with Pivot 6 | CUDA_VISIBLE_DEVICES=0 python main.py --is_train=True --adversarial=True --pivot_loss_factor=0.0001 --restore=True --checkpoint_dir=./ref/resnet20_cifar10 --train_dir=./checkpoint/resnet20_cifar10_pivot 7 | # Cascade Training with Pivot 8 | CUDA_VISIBLE_DEVICES=0 python main.py --is_train=False --restore_inplace=True --save_iter_fgsm_images=True --test_data_from=train --train_dir=./checkpoint/resnet20_cifar10_pivot 9 | CUDA_VISIBLE_DEVICES=0 python main.py --is_train=True --adversarial=True --pivot_loss_factor=0.0001 --cascade=True --saved_iter_fgsm_dir=./checkpoint/resnet20_cifar10_pivot --restore=True --checkpoint_dir=./ref/resnet20_cifar10 --train_dir=./checkpoint/resnet20_cifar10_pivot_cascade 10 | 11 | # Ensemble Training with Pivot 12 | CUDA_VISIBLE_DEVICES=0 python main.py --is_train=True --adversarial=False --train_dir=./checkpoint/r20_ens_source 13 | CUDA_VISIBLE_DEVICES=0 python main.py --is_train=True --adversarial=False --resnet_n=18 --train_dir=./checkpoint/r110_ens_source 14 | CUDA_VISIBLE_DEVICES=0 python tf_rename_variables.py --checkpoint_dir=checkpoint/r20_ens_source --replace_from=main --replace_to=r20_ens_source 15 | CUDA_VISIBLE_DEVICES=0 python tf_rename_variables.py --checkpoint_dir=checkpoint/r110_ens_source --replace_from=main --replace_to=r110_ens_source 16 | CUDA_VISIBLE_DEVICES=0 python main.py --is_train=True --adversarial=True --pivot_loss_factor=0.0001 --ensemble=True --restore=True --checkpoint_dir=./ref/resnet20_cifar10 --train_dir=./checkpoint/resnet20_cifar10_pivot_ensemble 17 | 18 | # Test with adversarial images from different source network 19 | CUDA_VISIBLE_DEVICES=0 python main.py --is_train=False --restore_inplace=True --save_adver_images=True --test_data_from=validation --train_dir=./checkpoint/resnet20_cifar10_pivot 20 | CUDA_VISIBLE_DEVICES=0 python main.py --is_train=False --restore_inplace=True --use_saved_images=True --saved_data_dir=./checkpoint/resnet20_cifar10_pivot --train_dir=./checkpoint/resnet20_cifar10_pivot_cascade 21 | 22 | -------------------------------------------------------------------------------- /cascade_adv_training/runstep.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cold-Winter/Nattack/2c5ce052f0298d52a2972dfce8bbfd9fed6a6fcb/cascade_adv_training/runstep.npz -------------------------------------------------------------------------------- /cascade_adv_training/tf_rename_variables.py: -------------------------------------------------------------------------------- 1 | # This code is from 2 | # https://gist.github.com/batzner/7c24802dd9c5e15870b4b56e22135c96 3 | 4 | import sys, getopt 5 | 6 | import tensorflow as tf 7 | 8 | usage_str = 'python tensorflow_rename_variables.py --checkpoint_dir=path/to/dir/ ' \ 9 | '--replace_from=substr --replace_to=substr --add_prefix=abc --dry_run' 10 | 11 | 12 | def rename(checkpoint_dir, replace_from, replace_to, add_prefix, dry_run): 13 | checkpoint = tf.train.get_checkpoint_state(checkpoint_dir) 14 | with tf.Session() as sess: 15 | for var_name, _ in tf.contrib.framework.list_variables(checkpoint_dir): 16 | # Load the variable 17 | var = tf.contrib.framework.load_variable(checkpoint_dir, var_name) 18 | 19 | # Set the new name 20 | new_name = var_name 21 | if None not in [replace_from, replace_to]: 22 | new_name = new_name.replace(replace_from, replace_to) 23 | if add_prefix: 24 | new_name = add_prefix + new_name 25 | 26 | if dry_run: 27 | print('%s would be renamed to %s.' % (var_name, new_name)) 28 | else: 29 | print('Renaming %s to %s.' % (var_name, new_name)) 30 | # Rename the variable 31 | var = tf.Variable(var, name=new_name) 32 | 33 | if not dry_run: 34 | # Save the variables 35 | saver = tf.train.Saver() 36 | sess.run(tf.global_variables_initializer()) 37 | saver.save(sess, checkpoint.model_checkpoint_path) 38 | 39 | 40 | def main(argv): 41 | checkpoint_dir = None 42 | replace_from = None 43 | replace_to = None 44 | add_prefix = None 45 | dry_run = False 46 | 47 | try: 48 | opts, args = getopt.getopt(argv, 'h', ['help=', 'checkpoint_dir=', 'replace_from=', 49 | 'replace_to=', 'add_prefix=', 'dry_run']) 50 | except getopt.GetoptError: 51 | print(usage_str) 52 | sys.exit(2) 53 | for opt, arg in opts: 54 | if opt in ('-h', '--help'): 55 | print(usage_str) 56 | sys.exit() 57 | elif opt == '--checkpoint_dir': 58 | checkpoint_dir = arg 59 | elif opt == '--replace_from': 60 | replace_from = arg 61 | elif opt == '--replace_to': 62 | replace_to = arg 63 | elif opt == '--add_prefix': 64 | add_prefix = arg 65 | elif opt == '--dry_run': 66 | dry_run = True 67 | 68 | if not checkpoint_dir: 69 | print('Please specify a checkpoint_dir. Usage:') 70 | print(usage_str) 71 | sys.exit(2) 72 | 73 | rename(checkpoint_dir, replace_from, replace_to, add_prefix, dry_run) 74 | 75 | 76 | if __name__ == '__main__': 77 | main(sys.argv[1:]) 78 | -------------------------------------------------------------------------------- /confusion.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import itertools 4 | 5 | target_names = ['THERM','THERM-ADV','LID','SAP','RSE','CAS-ADV','ORIGIN','WRES-28'] 6 | cm = np.array([[100.00 ,2.90 , 3.27 , 5.38 , 7.67 , 1.80 , 5.30,11.06], 7 | [2.01 , 100 , 1.11 , 1.47 , 1.73, 1.42 , 1.69, 1.9], 8 | [10.77 , 10.34 , 100 , 6.68, 11.27, 6.18,28.58, 15.66], 9 | [20.00 , 6.13 , 4.14 , 100 , 17.98 , 4.70 , 10.72,26.63], 10 | [ 15.85 , 3.74 , 4.84 , 8.51 , 100 , 2.28 , 10.83,18.11], 11 | [3.70 , 7.42 , 1.67 , 3.83 , 2.76 , 100 , 11.66, 12.88], 12 | [ 9.14 , 6.16 ,15.64 ,4.89 , 10.29 , 4.69, 100.00, 12.49], 13 | [26.51,4.95,7.05,14.75,20.26,4.15,14.59,100.0]]) 14 | 15 | # target_names = ['SAP','THERM-ADV','THERM','LID','ORIGIN','WRES-28'] 16 | # cm = np.array([[100,19.64,80.02 ,30.54, 2.12, 8.51], 17 | # [4.13, 100, 2.15, 3.14, 1.23, 1.13], 18 | # [67.11, 20.02 ,100 ,52.66, 1.34 ,2.17], 19 | # [30.1, 20.83, 34.26, 100, 8.92, 3.15], 20 | # [22.15, 12.75, 25.16, 48.51, 100, 0.21], 21 | # [97.62, 17.1, 88.23, 37.93, 0.36 ,100]]) 22 | 23 | 24 | #if cmap is None: 25 | cmap = plt.get_cmap('tab20b') ### RdGy cool tab20b tab20c 26 | 27 | plt.figure(figsize=(8, 6.5)) 28 | #plt.subplot(1,2,1) 29 | 30 | plt.imshow(cm, interpolation='nearest', cmap=cmap) 31 | #plt.title('Confusion Matrix') 32 | plt.colorbar() 33 | 34 | if target_names is not None: 35 | tick_marks = np.arange(len(target_names)) 36 | plt.xticks(tick_marks, target_names, rotation=45) 37 | plt.yticks(tick_marks, target_names) 38 | 39 | #if normalize: 40 | #cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] 41 | 42 | 43 | thresh = cm.max() / 100 44 | 45 | for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): 46 | plt.text(j, i, "{:0.2f}".format(cm[i, j]), 47 | horizontalalignment="center", 48 | color="white" if cm[i, j] > thresh else "black", fontsize= 12) 49 | # plt.text(j, i, "{:,}".format(cm[i, j]), 50 | # horizontalalignment="center", 51 | # color="white" if cm[i, j] > thresh else "black") 52 | 53 | 54 | plt.tight_layout() 55 | #plt.ylabel('Defense methods', fontsize = 16) 56 | #plt.xlabel('Perturbation', fontsize = 16) 57 | 58 | #plt.subplot(1,2,2) 59 | 60 | 61 | plt.show() 62 | -------------------------------------------------------------------------------- /guided-denoiser/README.md: -------------------------------------------------------------------------------- 1 | # Paper 2 | https://arxiv.org/abs/1712.02976 3 | 4 | # Description 5 | 6 | This code is based on the defense solution of team TSAIL in the NIPS 2017: Defense Against Adversarial Attack competition, which is the winner of the competition. 7 | 8 | Our basic idea of defense is to put a denoiser before the a baseline neural network. The denoiser is trained to reduce the pertubation of adversarial examples. And a denoiser is specifically trained for a baseline neural network. 9 | 10 | The solution is an ensemble of 4 independent models and their denoiser (ResNet, ResNext, InceptionV3, inceptionResNetV2). 11 | 12 | 14 | 15 | 16 | ## Requirements 17 | 18 | * Python2 + pytorch0.3.1 19 | 20 | ## [NATTACK] evaluation 21 | 22 | Run with: 23 | 24 | ```bash 25 | python re_li_attack.py --imagenet-path 26 | 27 | -------------------------------------------------------------------------------- /guided-denoiser/dataset.py: -------------------------------------------------------------------------------- 1 | import torch.utils.data as data 2 | 3 | from PIL import Image 4 | import os 5 | import re 6 | import torch 7 | 8 | IMG_EXTENSIONS = ['.png', '.jpg', '.jpeg'] 9 | 10 | 11 | def natural_key(string_): 12 | """See http://www.codinghorror.com/blog/archives/001018.html""" 13 | return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', string_.lower())] 14 | 15 | 16 | def find_images_and_targets(folder, types=IMG_EXTENSIONS, class_to_idx=None, leaf_name_only=True, sort=True): 17 | if class_to_idx is None: 18 | class_to_idx = dict() 19 | build_class_idx = True 20 | else: 21 | build_class_idx = False 22 | labels = [] 23 | filenames = [] 24 | for root, subdirs, files in os.walk(folder, topdown=False): 25 | rel_path = os.path.relpath(root, folder) if (root != folder) else '' 26 | label = os.path.basename(rel_path) if leaf_name_only else rel_path.replace(os.path.sep, '_') 27 | if build_class_idx and not subdirs: 28 | class_to_idx[label] = 0 29 | for f in files: 30 | base, ext = os.path.splitext(f) 31 | if ext.lower() in types: 32 | filenames.append(os.path.join(root,f)) 33 | labels.append(label) 34 | if build_class_idx: 35 | classes = sorted(class_to_idx.keys(), key=natural_key) 36 | for idx, c in enumerate(classes): 37 | class_to_idx[c] = idx 38 | images_and_targets = zip(filenames, [class_to_idx[l] for l in labels]) 39 | if sort: 40 | images_and_targets = sorted(images_and_targets, key=lambda k: natural_key(k[0])) 41 | if build_class_idx: 42 | return images_and_targets, classes, class_to_idx 43 | else: 44 | return images_and_targets 45 | 46 | 47 | class Dataset(data.Dataset): 48 | 49 | def __init__(self, root, transform=None): 50 | imgs, classes, class_to_idx = find_images_and_targets(root) 51 | if len(imgs) == 0: 52 | raise(RuntimeError("Found 0 images in subfolders of: " + root + "\n" 53 | "Supported image extensions are: " + ",".join(IMG_EXTENSIONS))) 54 | 55 | self.root = root 56 | self.imgs = imgs 57 | self.classes = classes 58 | self.class_to_idx = class_to_idx 59 | self.transform = transform 60 | 61 | def __getitem__(self, index): 62 | path, target = self.imgs[index] 63 | img = Image.open(path).convert('RGB') 64 | if self.transform is not None: 65 | img = self.transform(img) 66 | if target is None: 67 | target = torch.zeros(1).long() 68 | return img, target 69 | 70 | def __len__(self): 71 | return len(self.imgs) 72 | 73 | def filenames(self, indices=[]): 74 | if indices: 75 | return [self.imgs[i][0] for i in indices] 76 | else: 77 | return [x[0] for x in self.imgs] 78 | -------------------------------------------------------------------------------- /guided-denoiser/helpers.py: -------------------------------------------------------------------------------- 1 | import operator as op 2 | import functools as ft 3 | import numpy as np 4 | 5 | 6 | '''reduce_* helper functions reduce tensors on all dimensions but the first. 7 | They are intended to be used on batched tensors where dim 0 is the batch dim. 8 | ''' 9 | 10 | 11 | def reduce_sum(x, keepdim=True): 12 | # silly PyTorch, when will you get proper reducing sums/means? 13 | for a in reversed(range(1, x.dim())): 14 | x = x.sum(a, keepdim=keepdim) 15 | return x 16 | 17 | 18 | def reduce_mean(x, keepdim=True): 19 | numel = ft.reduce(op.mul, x.size()[1:]) 20 | x = reduce_sum(x, keepdim=keepdim) 21 | return x / numel 22 | 23 | 24 | def reduce_min(x, keepdim=True): 25 | for a in reversed(range(1, x.dim())): 26 | x = x.min(a, keepdim=keepdim)[0] 27 | return x 28 | 29 | 30 | def reduce_max(x, keepdim=True): 31 | for a in reversed(range(1, x.dim())): 32 | x = x.max(a, keepdim=keepdim)[0] 33 | return x 34 | 35 | 36 | def torch_arctanh(x, eps=1e-6): 37 | x *= (1. - eps) 38 | return (np.log((1 + x) / (1 - x))) * 0.5 39 | 40 | 41 | def l2r_dist(x, y, keepdim=True, eps=1e-8): 42 | d = (x - y)**2 43 | d = reduce_sum(d, keepdim=keepdim) 44 | d += eps # to prevent infinite gradient at 0 45 | return d.sqrt() 46 | 47 | 48 | def l2_dist(x, y, keepdim=True): 49 | d = (x - y)**2 50 | return reduce_sum(d, keepdim=keepdim) 51 | 52 | 53 | def l1_dist(x, y, keepdim=True): 54 | d = torch.abs(x - y) 55 | return reduce_sum(d, keepdim=keepdim) 56 | 57 | 58 | def l2_norm(x, keepdim=True): 59 | norm = reduce_sum(x*x, keepdim=keepdim) 60 | return norm.sqrt() 61 | 62 | 63 | def l1_norm(x, keepdim=True): 64 | return reduce_sum(x.abs(), keepdim=keepdim) 65 | 66 | 67 | def rescale(x, x_min=-1., x_max=1.): 68 | return x * (x_max - x_min) + x_min 69 | 70 | 71 | def tanh_rescale(x, x_min=-1., x_max=1.): 72 | return (torch.tanh(x) + 1) * 0.5 * (x_max - x_min) + x_min 73 | -------------------------------------------------------------------------------- /guided-denoiser/inres.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | from inceptionresnet import get_net, Conv, Bottleneck 4 | 5 | config = dict() 6 | config['flip'] = True 7 | config['loss_idcs'] = [4] 8 | config['net_type'] = 'inceptionresnetv2' 9 | 10 | input_size = [299, 299] 11 | block = [Conv, None, None, None, None] 12 | fwd_out = [ 13 | [64, 128, 256, 256, 256], 14 | [], 15 | [], 16 | [], 17 | []] 18 | num_fwd = [ 19 | [2, 3, 3, 3, 3], 20 | [], 21 | [], 22 | [], 23 | []] 24 | back_out = [ 25 | [64, 128, 256, 256], 26 | [], 27 | [], 28 | [], 29 | []] 30 | num_back = [ 31 | [2, 3, 3, 3], 32 | [], 33 | [], 34 | [], 35 | []] 36 | n = 1 37 | hard_mining = 0 38 | loss_norm = False 39 | 40 | def get_model(): 41 | net = get_net(input_size, block, fwd_out, num_fwd, back_out, num_back, n, hard_mining, loss_norm) 42 | return config, net 43 | -------------------------------------------------------------------------------- /guided-denoiser/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "defense", 3 | "container":"floydhub/pytorch:0.2.0-py2.11", 4 | "container_gpu": "floydhub/pytorch:0.2.0-gpu-py2.11", 5 | "entry_point": "run_defense.sh" 6 | } 7 | -------------------------------------------------------------------------------- /guided-denoiser/res152_wide.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | from resnet import get_net, Conv, Bottleneck 4 | 5 | config = dict() 6 | config['flip'] = True 7 | config['loss_idcs'] = [4] 8 | 9 | net_type = 'resnet152' 10 | input_size = [299, 299] 11 | block = [Conv, None, None, None, None] 12 | fwd_out = [ 13 | [64, 128, 256, 256, 256], 14 | [128, 256, 256, 256], 15 | [], 16 | [], 17 | []] 18 | num_fwd = [ 19 | [2, 3, 3, 3, 3], 20 | [2, 3, 3, 3], 21 | [], 22 | [], 23 | []] 24 | back_out = [ 25 | [64, 128, 256, 256], 26 | [128, 256, 256], 27 | [], 28 | [], 29 | []] 30 | num_back = [ 31 | [2, 3, 3, 3], 32 | [2, 3, 3], 33 | [], 34 | [], 35 | []] 36 | n = 1 37 | hard_mining = 0 38 | loss_norm = False 39 | 40 | def get_model(): 41 | net = get_net(net_type, input_size, block, fwd_out, num_fwd, back_out, num_back, n, hard_mining, loss_norm) 42 | return config, net 43 | -------------------------------------------------------------------------------- /guided-denoiser/resnext101.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | from resnext import get_net, Conv, Bottleneck 4 | 5 | config = dict() 6 | config['flip'] = True 7 | config['loss_idcs'] = [1] 8 | 9 | net_type = 'resnext101' 10 | config['net_type'] = net_type 11 | input_size = [299, 299] 12 | block = Conv 13 | fwd_out = [64, 128, 256, 256, 256] 14 | num_fwd = [2, 3, 3, 3, 3] 15 | back_out = [64, 128, 256, 256] 16 | num_back = [2, 3, 3, 3] 17 | n = 1 18 | hard_mining = 0 19 | loss_norm = False 20 | 21 | def get_model(): 22 | net = get_net(input_size, block, fwd_out, num_fwd, back_out, num_back, n, hard_mining, loss_norm) 23 | return config, net 24 | -------------------------------------------------------------------------------- /guided-denoiser/resnext_features/__init__.py: -------------------------------------------------------------------------------- 1 | from .resnext101_32x4d_features import resnext101_32x4d_features 2 | from .resnext101_64x4d_features import resnext101_64x4d_features -------------------------------------------------------------------------------- /guided-denoiser/v3.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | from inception import get_net, Conv, Bottleneck 4 | 5 | config = dict() 6 | config['flip'] = True 7 | config['loss_idcs'] = [1] 8 | config['net_type'] = 'inceptionresnetv2' 9 | input_size = [299, 299] 10 | block = Conv 11 | fwd_out = [64, 128, 256, 256, 256] 12 | num_fwd = [2, 3, 3, 3, 3] 13 | back_out = [64, 128, 256, 256] 14 | num_back = [2, 3, 3, 3] 15 | n = 1 16 | hard_mining = 0 17 | loss_norm = False 18 | 19 | def get_model(): 20 | net = get_net(input_size, block, fwd_out, num_fwd, back_out, num_back, n, hard_mining, loss_norm) 21 | 22 | 23 | return config, net 24 | -------------------------------------------------------------------------------- /inputtransformations/.gitignore: -------------------------------------------------------------------------------- 1 | quilt_db.npy 2 | -------------------------------------------------------------------------------- /inputtransformations/README.md: -------------------------------------------------------------------------------- 1 | # Countering Adversarial Images using Input Transformations 2 | 3 | Paper: [Guo et al. 2018](https://arxiv.org/abs/1711.00117) 4 | 5 | 6 | ## Requirements 7 | 8 | * Python3 + tensorflow 9 | 10 | ## [NATTACK] evaluation 11 | 12 | Run with: 13 | 14 | ```bash 15 | python re_l2_attack_clipimage.py --imagenet-path 16 | ```` 17 | You can define the defense type in re_l2_attack_clipimage.py 18 | Where `` is one of `bitdepth`, `jpeg`, `crop`, `quilt`, or `tv`. 19 | 20 | [robustml]: https://github.com/robust-ml/robustml 21 | -------------------------------------------------------------------------------- /inputtransformations/helpers.py: -------------------------------------------------------------------------------- 1 | import operator as op 2 | import functools as ft 3 | import numpy as np 4 | 5 | 6 | '''reduce_* helper functions reduce tensors on all dimensions but the first. 7 | They are intended to be used on batched tensors where dim 0 is the batch dim. 8 | ''' 9 | 10 | 11 | def reduce_sum(x, keepdim=True): 12 | # silly PyTorch, when will you get proper reducing sums/means? 13 | for a in reversed(range(1, x.dim())): 14 | x = x.sum(a, keepdim=keepdim) 15 | return x 16 | 17 | 18 | def reduce_mean(x, keepdim=True): 19 | numel = ft.reduce(op.mul, x.size()[1:]) 20 | x = reduce_sum(x, keepdim=keepdim) 21 | return x / numel 22 | 23 | 24 | def reduce_min(x, keepdim=True): 25 | for a in reversed(range(1, x.dim())): 26 | x = x.min(a, keepdim=keepdim)[0] 27 | return x 28 | 29 | 30 | def reduce_max(x, keepdim=True): 31 | for a in reversed(range(1, x.dim())): 32 | x = x.max(a, keepdim=keepdim)[0] 33 | return x 34 | 35 | 36 | def torch_arctanh(x, eps=1e-6): 37 | x *= (1. - eps) 38 | return (np.log((1 + x) / (1 - x))) * 0.5 39 | 40 | 41 | def l2r_dist(x, y, keepdim=True, eps=1e-8): 42 | d = (x - y)**2 43 | d = reduce_sum(d, keepdim=keepdim) 44 | d += eps # to prevent infinite gradient at 0 45 | return d.sqrt() 46 | 47 | 48 | def l2_dist(x, y, keepdim=True): 49 | d = (x - y)**2 50 | return reduce_sum(d, keepdim=keepdim) 51 | 52 | 53 | def l1_dist(x, y, keepdim=True): 54 | d = torch.abs(x - y) 55 | return reduce_sum(d, keepdim=keepdim) 56 | 57 | 58 | def l2_norm(x, keepdim=True): 59 | norm = reduce_sum(x*x, keepdim=keepdim) 60 | return norm.sqrt() 61 | 62 | 63 | def l1_norm(x, keepdim=True): 64 | return reduce_sum(x.abs(), keepdim=keepdim) 65 | 66 | 67 | def rescale(x, x_min=-1., x_max=1.): 68 | return x * (x_max - x_min) + x_min 69 | 70 | 71 | def tanh_rescale(x, x_min=-1., x_max=1.): 72 | return (torch.tanh(x) + 1) * 0.5 * (x_max - x_min) + x_min 73 | -------------------------------------------------------------------------------- /inputtransformations/inceptionv3.py: -------------------------------------------------------------------------------- 1 | from utils import optimistic_restore 2 | import tensorflow as tf 3 | import tensorflow.contrib.slim as slim 4 | import tensorflow.contrib.slim.nets as nets 5 | import functools 6 | import os 7 | 8 | _INCEPTION_CHECKPOINT_NAME = 'inception_v3.ckpt' 9 | INCEPTION_CHECKPOINT_PATH = os.path.join( 10 | os.path.dirname(__file__), 11 | 'data', 12 | _INCEPTION_CHECKPOINT_NAME 13 | ) 14 | INCEPTION_CHECKPOINT_PATH = '../all_models/random/inception_v3.ckpt' 15 | def _get_model(reuse): 16 | arg_scope = nets.inception.inception_v3_arg_scope(weight_decay=0.0) 17 | func = nets.inception.inception_v3 18 | @functools.wraps(func) 19 | def network_fn(images): 20 | with slim.arg_scope(arg_scope): 21 | return func(images, 1001, is_training=False, reuse=reuse) 22 | if hasattr(func, 'default_image_size'): 23 | network_fn.default_image_size = func.default_image_size 24 | return network_fn 25 | 26 | def _preprocess(image, height, width, scope=None): 27 | with tf.name_scope(scope, 'eval_image', [image, height, width]): 28 | if image.dtype != tf.float32: 29 | image = tf.image.convert_image_dtype(image, dtype=tf.float32) 30 | image = tf.image.resize_bilinear(image, [height, width], align_corners=False) 31 | image = tf.subtract(image, 0.5) 32 | image = tf.multiply(image, 2.0) 33 | return image 34 | 35 | # input is [batch, ?, ?, 3], pixels in [0, 1] 36 | # it's rescaled to [batch, 299, 299, 3] and shifted to [-1, 1] 37 | # output is [batch, 1000] (imagenet classes) 38 | _inception_initialized = False 39 | def model(sess, image): 40 | global _inception_initialized 41 | network_fn = _get_model(reuse=_inception_initialized) 42 | size = network_fn.default_image_size 43 | preprocessed = _preprocess(image, size, size) 44 | logits, _ = network_fn(preprocessed) 45 | logits = logits[:,1:] # ignore background class 46 | predictions = tf.argmax(logits, 1) 47 | 48 | if not _inception_initialized: 49 | optimistic_restore(sess, INCEPTION_CHECKPOINT_PATH) 50 | _inception_initialized = True 51 | 52 | return logits, predictions 53 | -------------------------------------------------------------------------------- /inputtransformations/quilt_preprocess.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import PIL 4 | import PIL.Image 5 | import numpy as np 6 | import sys 7 | 8 | 9 | SAMPLES = 1000000 10 | DIM = 5 11 | RESIZE = True 12 | RESIZE_DIM = 300 13 | OUTPUT_FILE = 'quilt_db.npy' 14 | 15 | def main(argv): 16 | imagenet_train_dir = argv[1] 17 | 18 | assert SAMPLES % 1000 == 0 19 | 20 | db = np.zeros((SAMPLES, DIM, DIM, 3), dtype=np.float32) 21 | 22 | idx = 0 23 | files = [] 24 | for d in os.listdir(imagenet_train_dir): 25 | d = os.path.join(imagenet_train_dir, d) 26 | files.extend(os.path.join(d, i) for i in os.listdir(d) if i.endswith('.JPEG')) 27 | for f in random.sample(files, SAMPLES): 28 | img = load_image(f) 29 | h, w, _ = img.shape 30 | h_start = random.randint(0, h - DIM) 31 | w_start = random.randint(0, w - DIM) 32 | crop = img[h_start:h_start+DIM, w_start:w_start+DIM, :] 33 | db[idx, :, :, :] = crop 34 | idx += 1 35 | 36 | if idx % 100 == 0: 37 | print('%.2f%% done' % (100 * (float(idx) / SAMPLES))) 38 | 39 | np.save(OUTPUT_FILE, db) 40 | 41 | 42 | def load_image(path): 43 | image = PIL.Image.open(path) 44 | if RESIZE: 45 | if image.height > image.width: 46 | image = image.resize((int(float(image.width) / image.height * RESIZE_DIM), RESIZE_DIM)) 47 | elif image.width > image.height: 48 | image = image.resize((RESIZE_DIM, int(float(image.height) / image.width * RESIZE_DIM))) 49 | img = np.asarray(image).astype(np.float32) / 255.0 50 | if img.ndim == 2: 51 | img = np.repeat(img[:,:,np.newaxis], repeats=3, axis=2) 52 | if img.shape[2] == 4: 53 | # alpha channel 54 | img = img[:,:,:3] 55 | return img 56 | 57 | 58 | if __name__ == '__main__': 59 | main(sys.argv) 60 | 61 | -------------------------------------------------------------------------------- /inputtransformations/robustml_attack.py: -------------------------------------------------------------------------------- 1 | import robustml 2 | from robustml_model_origin import InputTransformations 3 | import sys 4 | import argparse 5 | import tensorflow as tf 6 | import numpy as np 7 | import time 8 | 9 | class BPDA(robustml.attack.Attack): 10 | def __init__(self, sess, model, epsilon, max_steps=1000, learning_rate=0.1, lam=1e-6, debug=False): 11 | self._sess = sess 12 | 13 | self._model = model 14 | self._input = model.input 15 | self._l2_input = tf.placeholder(tf.float32, self._input.shape) # using BPDA, so we want this to pass the original adversarial example 16 | self._original = tf.placeholder(tf.float32, self._input.shape) 17 | self._label = tf.placeholder(tf.int32, ()) 18 | one_hot = tf.expand_dims(tf.one_hot(self._label, 1000), axis=0) 19 | ensemble_labels = tf.tile(one_hot, (model.logits.shape[0], 1)) 20 | self._l2 = tf.sqrt(2*tf.nn.l2_loss(self._l2_input - self._original)) 21 | self._xent = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=model.logits, labels=ensemble_labels)) 22 | self._loss = lam * tf.maximum(self._l2 - epsilon, 0) + self._xent 23 | self._grad, = tf.gradients(self._loss, self._input) 24 | 25 | self._epsilon = epsilon 26 | self._max_steps = max_steps 27 | self._learning_rate = learning_rate 28 | self._debug = debug 29 | 30 | def run(self, x, y, target): 31 | if target is not None: 32 | raise NotImplementedError 33 | adv = np.copy(x) 34 | for i in range(self._max_steps): 35 | adv_def = self._model.defend(adv) 36 | p, ll2, lxent, g = self._sess.run( 37 | [self._model.predictions, self._l2, self._xent, self._grad], 38 | {self._input: adv_def, self._label: y, self._l2_input: adv, self._original: x} 39 | ) 40 | if self._debug: 41 | print( 42 | 'attack: step %d/%d, xent loss = %g, l2 loss = %g (max %g), (true %d, predicted %s)' % ( 43 | i+1, 44 | self._max_steps, 45 | lxent, 46 | ll2, 47 | self._epsilon, 48 | y, 49 | p 50 | ), 51 | file=sys.stderr 52 | ) 53 | if y not in p and ll2 < self._epsilon: 54 | # we're done 55 | if self._debug: 56 | print('returning early', file=sys.stderr) 57 | break 58 | adv += self._learning_rate * g 59 | adv = np.clip(adv, 0, 1) 60 | return adv 61 | 62 | def main(): 63 | parser = argparse.ArgumentParser() 64 | parser.add_argument('--imagenet-path', type=str, required=True, 65 | help='directory containing `val.txt` and `val/` folder') 66 | parser.add_argument('--defense', type=str, required=True, 67 | help='bitdepth | jpeg | crop | quilt | tv') 68 | parser.add_argument('--start', type=int, default=0) 69 | parser.add_argument('--end', type=int, default=100) 70 | parser.add_argument('--debug', action='store_true') 71 | args = parser.parse_args() 72 | 73 | # set up TensorFlow session 74 | sess = tf.Session() 75 | start = time.time() 76 | # initialize a model 77 | model = InputTransformations(sess, args.defense) 78 | print(model.threat_model.targeted) 79 | 80 | # initialize an attack (it's a white box attack, and it's allowed to look 81 | # at the internals of the model in any way it wants) 82 | # XXX restore 83 | attack = BPDA(sess, model, model.threat_model.epsilon, debug=args.debug) 84 | 85 | # initialize a data provider for ImageNet images 86 | provider = robustml.provider.ImageNet(args.imagenet_path, model.dataset.shape) 87 | 88 | success_rate = robustml.evaluate.evaluate( 89 | model, 90 | attack, 91 | provider, 92 | start=args.start, 93 | end=args.end, 94 | deterministic=True, 95 | debug=args.debug, 96 | ) 97 | print('attack time',time.time()-start) 98 | 99 | print('attack success rate: %.2f%% (over %d data points)' % (success_rate*100, args.end-args.start)) 100 | 101 | if __name__ == '__main__': 102 | main() 103 | -------------------------------------------------------------------------------- /inputtransformations/robustml_model.py: -------------------------------------------------------------------------------- 1 | import robustml 2 | from defense import * 3 | from inceptionv3 import model as inceptionv3_model 4 | import tensorflow as tf 5 | 6 | class InputTransformations(robustml.model.Model): 7 | def __init__(self, sess, defense): 8 | self._sess = sess 9 | self._input = tf.placeholder(tf.float32, (None, 299, 299, 3)) 10 | #input_expanded = tf.expand_dims(self._input, axis=0) 11 | 12 | if defense == 'crop': 13 | cropped_xs = defend_crop(self._input) 14 | self._logits, _ = inceptionv3_model(sess, cropped_xs) 15 | self._probs = tf.reduce_mean(tf.nn.softmax(self._logits), axis=0, keepdims=True) 16 | else: 17 | self._logits, _ = inceptionv3_model(sess, self._input) 18 | self._probs = tf.nn.softmax(self._logits) 19 | 20 | self._predictions = tf.argmax(self._probs, 1) 21 | 22 | if defense == 'bitdepth': 23 | self._defend = defend_reduce 24 | elif defense == 'jpeg': 25 | self._defend = defend_jpeg 26 | elif defense == 'crop': 27 | self._defend = lambda x: x # implemented as part of model so it's differentiable 28 | elif defense == 'quilt': 29 | self._defend = make_defend_quilt(sess) 30 | elif defense == 'tv': 31 | self._defend = defend_tv 32 | else: 33 | raise ValueError('invalid defense: %s' % defense) 34 | 35 | self._dataset = robustml.dataset.ImageNet((299, 299, 3)) 36 | #self._threat_model = robustml.threat_model.L2(epsilon=0.005*(299*299)) 37 | self._threat_model = robustml.threat_model.L2(epsilon=0.05*299) 38 | 39 | @property 40 | def dataset(self): 41 | return self._dataset 42 | 43 | @property 44 | def threat_model(self): 45 | return self._threat_model 46 | 47 | def classify(self, x): 48 | x_defended = self.defend(x) 49 | return self._sess.run(self._predictions, {self._input: x_defended})[0] 50 | 51 | def outlogits(self, x): 52 | x_defended = self.defend(x) 53 | return self._sess.run(self._logits, {self._input: x_defended}) 54 | 55 | def outlogits_modify(self, x): 56 | x_defended = self.defend(x) 57 | return self._sess.run(self._logits, {self._input: x_defended}) 58 | 59 | # expose internals for white box attacks 60 | 61 | def defend(self, x): 62 | return self._defend(x) 63 | 64 | @property 65 | def input(self): 66 | return self._input 67 | 68 | @property 69 | def logits(self): 70 | return self._logits 71 | 72 | @property 73 | def predictions(self): 74 | return self._predictions 75 | -------------------------------------------------------------------------------- /inputtransformations/robustml_model_origin.py: -------------------------------------------------------------------------------- 1 | import robustml 2 | from defense import * 3 | from inceptionv3 import model as inceptionv3_model 4 | import tensorflow as tf 5 | 6 | class InputTransformations(robustml.model.Model): 7 | def __init__(self, sess, defense): 8 | self._sess = sess 9 | self._input = tf.placeholder(tf.float32, (299, 299, 3)) 10 | input_expanded = tf.expand_dims(self._input, axis=0) 11 | 12 | if defense == 'crop': 13 | cropped_xs = defend_crop(self._input) 14 | self._logits, _ = inceptionv3_model(sess, cropped_xs) 15 | self._probs = tf.reduce_mean(tf.nn.softmax(self._logits), axis=0, keepdims=True) 16 | else: 17 | self._logits, _ = inceptionv3_model(sess, input_expanded) 18 | self._probs = tf.nn.softmax(self._logits) 19 | 20 | self._predictions = tf.argmax(self._probs, 1) 21 | 22 | if defense == 'bitdepth': 23 | self._defend = defend_reduce 24 | elif defense == 'jpeg': 25 | self._defend = defend_jpeg 26 | elif defense == 'crop': 27 | self._defend = lambda x: x # implemented as part of model so it's differentiable 28 | elif defense == 'quilt': 29 | self._defend = make_defend_quilt(sess) 30 | elif defense == 'tv': 31 | self._defend = defend_tv 32 | else: 33 | raise ValueError('invalid defense: %s' % defense) 34 | 35 | self._dataset = robustml.dataset.ImageNet((299, 299, 3)) 36 | #self._threat_model = robustml.threat_model.L2(epsilon=0.005*(299*299)) 37 | self._threat_model = robustml.threat_model.L2(epsilon=2.58942) 38 | 39 | @property 40 | def dataset(self): 41 | return self._dataset 42 | 43 | @property 44 | def threat_model(self): 45 | return self._threat_model 46 | 47 | def classify(self, x): 48 | x_defended = self.defend(x) 49 | return self._sess.run(self._predictions, {self._input: x_defended})[0] 50 | 51 | def outlogits(self, x): 52 | x_defended = self.defend(x) 53 | return self._sess.run(self._logits, {self._input: x_defended}) 54 | 55 | # expose internals for white box attacks 56 | 57 | def defend(self, x): 58 | return self._defend(x) 59 | 60 | @property 61 | def input(self): 62 | return self._input 63 | 64 | @property 65 | def logits(self): 66 | return self._logits 67 | 68 | @property 69 | def predictions(self): 70 | return self._predictions 71 | -------------------------------------------------------------------------------- /inputtransformations/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname "$0")" # cd to directory of this script 4 | 5 | # $1 is filename 6 | # $2 is expected sha 7 | check_sha1() { 8 | computed=$(sha1sum "$1" 2>/dev/null | awk '{print $1}') || return 1 9 | if [ "$computed" == "$2" ]; then 10 | return 0; 11 | else 12 | return 1; 13 | fi 14 | } 15 | 16 | # $1 is URL 17 | # $2 is extracted file name 18 | # $3 is the checksum 19 | fetch() { 20 | if check_sha1 $2 $3; then 21 | echo "$2 already downloaded" 22 | return 23 | fi 24 | echo "downloading $1" 25 | f=${1##*/} 26 | wget -q $1 -O $f 27 | tar xf $f 28 | rm -f $f 29 | if check_sha1 $2 $3; then 30 | echo "downloaded $2" 31 | else 32 | echo "HASH MISMATCH, SHA1($2) != $3" 33 | fi 34 | } 35 | 36 | cd data 37 | 38 | fetch \ 39 | http://download.tensorflow.org/models/inception_v3_2016_08_28.tar.gz \ 40 | inception_v3.ckpt 606fd6953c58c817c56fd3bc2f0384fc2ecaba92 41 | 42 | fetch \ 43 | https://github.com/anishathalye/obfuscated-gradients/releases/download/v0/quilt_db.tar.gz \ 44 | quilt_db.npy ff4b94f45c9e8441b341fd5ffcf2adb0a8049873 45 | -------------------------------------------------------------------------------- /inputtransformations/utils.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | from tensorflow.python.framework import ops 3 | import numpy as np 4 | import PIL.Image 5 | from imagenet_labels import label_to_name 6 | #import matplotlib.pyplot as plt 7 | 8 | def one_hot(index, total): 9 | arr = np.zeros((total)) 10 | arr[index] = 1.0 11 | return arr 12 | 13 | def optimistic_restore(session, save_file): 14 | reader = tf.train.NewCheckpointReader(save_file) 15 | saved_shapes = reader.get_variable_to_shape_map() 16 | var_names = sorted([(var.name, var.name.split(':')[0]) for var in tf.global_variables() 17 | if var.name.split(':')[0] in saved_shapes]) 18 | restore_vars = [] 19 | with tf.variable_scope('', reuse=True): 20 | for var_name, saved_var_name in var_names: 21 | curr_var = tf.get_variable(saved_var_name) 22 | var_shape = curr_var.get_shape().as_list() 23 | if var_shape == saved_shapes[saved_var_name]: 24 | restore_vars.append(curr_var) 25 | saver = tf.train.Saver(restore_vars) 26 | saver.restore(session, save_file) 27 | 28 | def load_image(path): 29 | return (np.asarray(PIL.Image.open(path).resize((299, 299)))/255.0).astype(np.float32) 30 | 31 | def make_classify(sess, input_, probs): 32 | def classify(img, correct_class=None, target_class=None): 33 | #fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 8)) 34 | fig.sca(ax1) 35 | p = sess.run(probs, feed_dict={input_: img})[0] 36 | ax1.imshow(img) 37 | fig.sca(ax1) 38 | 39 | topk = list(p.argsort()[-10:][::-1]) 40 | topprobs = p[topk] 41 | barlist = ax2.bar(range(10), topprobs) 42 | if target_class in topk: 43 | barlist[topk.index(target_class)].set_color('r') 44 | if correct_class in topk: 45 | barlist[topk.index(correct_class)].set_color('g') 46 | #plt.sca(ax2) 47 | #plt.ylim([0, 1.1]) 48 | #plt.xticks(range(10), 49 | # [label_to_name(i)[:15] for i in topk], 50 | # rotation='vertical') 51 | fig.subplots_adjust(bottom=0.2) 52 | #plt.show() 53 | return classify 54 | -------------------------------------------------------------------------------- /lid/README.md: -------------------------------------------------------------------------------- 1 | # Characterizing Adversarial Subspaces Using Local Intrinsic Dimensionality 2 | 3 | Paper: [Ma et al. 2018](https://arxiv.org/abs/1801.02613) 4 | 5 | ## Requirements 6 | 7 | * Python3 + tensorflow 8 | 9 | ## [NATTACK] evaluation 10 | 11 | Run with: 12 | 13 | ```bash 14 | python re_li_attack.py --cifar-path 15 | ```` 16 | 17 | [robustml]: https://github.com/robust-ml/robustml 18 | -------------------------------------------------------------------------------- /lid/attack_lid.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | from keras.models import load_model 5 | import pickle 6 | import keras.backend as K 7 | from util import get_model 8 | from extract_artifacts import get_lid 9 | import collections 10 | from detect_adv_samples import detect 11 | 12 | import robustml 13 | 14 | 15 | class Attack: 16 | def __init__(self, model, tol, num_steps, step_size, random_start): 17 | self.model = model 18 | self.tol = tol 19 | self.num_steps = num_steps 20 | self.step_size = step_size 21 | self.rand = random_start 22 | 23 | self.xs = tf.Variable(np.zeros((1000, 32, 32, 3), dtype=np.float32), 24 | name='modifier') 25 | self.orig_xs = tf.placeholder(tf.float32, [None, 32, 32, 3]) 26 | 27 | self.ys = tf.placeholder(tf.int32, [None]) 28 | 29 | self.epsilon = 8.0/255 30 | 31 | delta = tf.clip_by_value(self.xs, 0, 255) - self.orig_xs 32 | delta = tf.clip_by_value(delta, -self.epsilon, self.epsilon) 33 | 34 | self.do_clip_xs = tf.assign(self.xs, self.orig_xs+delta) 35 | 36 | self.logits = logits = model(self.xs) 37 | 38 | label_mask = tf.one_hot(self.ys, 10) 39 | correct_logit = tf.reduce_sum(label_mask * logits, axis=1) 40 | wrong_logit = tf.reduce_max((1-label_mask) * logits - 1e4*label_mask, axis=1) 41 | 42 | self.loss = (correct_logit - wrong_logit) 43 | 44 | start_vars = set(x.name for x in tf.global_variables()) 45 | optimizer = tf.train.AdamOptimizer(step_size*1) 46 | 47 | grad,var = optimizer.compute_gradients(self.loss, [self.xs])[0] 48 | self.train = optimizer.apply_gradients([(tf.sign(grad),var)]) 49 | 50 | end_vars = tf.global_variables() 51 | self.new_vars = [x for x in end_vars if x.name not in start_vars] 52 | 53 | def perturb(self, x, y, sess): 54 | sess.run(tf.variables_initializer(self.new_vars)) 55 | sess.run(self.xs.initializer) 56 | sess.run(self.do_clip_xs, 57 | {self.orig_xs: x}) 58 | 59 | for i in range(self.num_steps): 60 | 61 | sess.run(self.train, feed_dict={self.ys: y}) 62 | sess.run(self.do_clip_xs, 63 | {self.orig_xs: x}) 64 | 65 | return sess.run(self.xs) 66 | 67 | provider = robustml.provider.CIFAR10("../cifar10_data/test_batch") 68 | model = get_model("cifar", softmax=True) 69 | model.load_weights("data/lid_model_cifar.h5") 70 | model_logits = get_model("cifar", softmax=False) 71 | model_logits.load_weights("data/lid_model_cifar.h5") 72 | sess = K.get_session() 73 | attack = Attack(model_logits, 74 | 1, 75 | 100, 76 | 1/255.0, 77 | False) 78 | xs = tf.placeholder(tf.float32, (1, 32, 32, 3)) 79 | 80 | x_input = tf.placeholder(tf.float32, [None, 32, 32, 3]) 81 | real_logits = model_logits(x_input) 82 | 83 | succImages = 0 84 | faillist = [] 85 | start = 0 86 | end = 1000 87 | totalImages = 0 88 | outpath = 'perturb/lid_' 89 | for i in range(start, end): 90 | outpath_pkl = outpath + str(i) + '.pkl' 91 | success = False 92 | inputs, targets= provider[i] 93 | logits = sess.run(real_logits, feed_dict={x_input: [inputs]}) 94 | if np.argmax(logits) != targets: 95 | print('skip the wrong example ', i) 96 | continue 97 | totalImages += 1 98 | 99 | adversarial = attack.perturb([inputs], [targets], sess) 100 | 101 | if np.argmax(sess.run(real_logits, {x_input: adversarial[1:2]})) != targets: 102 | succImages += 1 103 | pickle.dump(adversarial[1:2],open(outpath_pkl,'wb'),-1) 104 | success = True 105 | if not success: 106 | faillist.append(i) 107 | print(faillist) 108 | success_rate = succImages/float(totalImages) 109 | print('succc rate', success_rate) 110 | 111 | 112 | -------------------------------------------------------------------------------- /lid/evaluation.py: -------------------------------------------------------------------------------- 1 | import robustml 2 | import time 3 | import pickle 4 | from util import get_model 5 | import sys 6 | import argparse 7 | import tensorflow as tf 8 | import numpy as np 9 | from helpers import * 10 | import keras.backend as K 11 | import os 12 | import cv2 13 | 14 | npop = 300 # population size 15 | sigma = 0.1 # noise standard deviation 16 | alpha = 0.008 # learning rate 17 | # alpha = 0.001 # learning rate 18 | boxmin = 0 19 | boxmax = 1 20 | boxplus = (boxmin + boxmax) / 2. 21 | boxmul = (boxmax - boxmin) / 2. 22 | folder = './liclipadvImages/' 23 | epsi = 0.031 24 | 25 | 26 | def softmax(x): 27 | return np.divide(np.exp(x), np.sum(np.exp(x), -1, keepdims=True)) 28 | 29 | def main(): 30 | 31 | parser = argparse.ArgumentParser() 32 | parser.add_argument('--cifar-path', type=str, default='../cifar10_data/test_batch', 33 | help='path to the test_batch file from http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz') 34 | parser.add_argument('--perturb', type=str, default='perturb') 35 | parser.add_argument('--start', type=int, default=0) 36 | parser.add_argument('--end', type=int, default=100) 37 | parser.add_argument('--debug', action='store_true') 38 | args = parser.parse_args() 39 | 40 | test_loss = 0 41 | correct = 0 42 | total = 0 43 | totalImages = 0 44 | succImages = 0 45 | faillist = [] 46 | 47 | 48 | 49 | # set up TensorFlow session 50 | 51 | config = tf.ConfigProto() 52 | config.gpu_options.allow_growth = True 53 | sess = tf.Session(config=config) 54 | K.set_session(sess) 55 | 56 | 57 | # initialize a model 58 | model = get_model('cifar', softmax=False) 59 | ### change lid model path llj 60 | model.load_weights("./data/lid_model_cifar.h5") 61 | 62 | # initialize an attack (it's a white box attack, and it's allowed to look 63 | # at the internals of the model in any way it wants) 64 | # attack = BPDA(sess, model, epsilon=model.threat_model.epsilon, debug=args.debug) 65 | # attack = Attack(sess, model.model, epsilon=model.threat_model.epsilon) 66 | 67 | # initialize a data provider for CIFAR-10 images 68 | provider = robustml.provider.CIFAR10(args.cifar_path) 69 | input_xs = tf.placeholder(tf.float32, [None, 32, 32, 3]) 70 | start = 0 71 | end = 10000 72 | total = 0 73 | real_logits0 = model(input_xs) 74 | real_logits = tf.nn.softmax(real_logits0) 75 | successlist = [] 76 | printlist = [] 77 | 78 | start_time = time.time() 79 | 80 | perturb_files = os.listdir(args.perturb) 81 | numbers = [] 82 | for x in perturb_files: 83 | number = x.split('_')[1] 84 | name = x.split('_')[0] 85 | number1 = int(number.split('.pkl')[0]) 86 | numbers.append(number1) 87 | 88 | for i in numbers: 89 | success = False 90 | print('evaluating %d of [%d, %d)' % (i, start, end), file=sys.stderr) 91 | inputs, targets= provider[i] 92 | modify = np.random.randn(1,3,32,32) * 0.001 93 | in_pkl = name + '_' + str(i)+'.pkl' 94 | ##### thermometer encoding 95 | 96 | logits = sess.run(real_logits,feed_dict={input_xs: [inputs]}) 97 | if np.argmax(logits) != targets: 98 | print('skip the wrong example ', i) 99 | continue 100 | totalImages += 1 101 | modify = pickle.load(open(in_pkl, 'rb')) 102 | if 'cascade' in in_pkl: 103 | modify = cv2.resize(modify.transpose(1,2,0), dsize=(32,32), interpolation=cv2.INTER_LINEAR) 104 | modify = modify.transpose(2, 0, 1) 105 | newimg = torch_arctanh((inputs - boxplus) / boxmul).transpose(2, 0, 1) 106 | realinputimg = np.tanh(newimg + modify) * boxmul + boxplus 107 | realdist = realinputimg - (np.tanh(newimg) * boxmul + boxplus) 108 | realclipdist = np.clip(realdist, -epsi, epsi) 109 | realclipinput = realclipdist + (np.tanh(newimg) * boxmul + boxplus) 110 | l2real = np.sum((realclipinput - (np.tanh(newimg) * boxmul + boxplus)) ** 2) ** 0.5 111 | outputsreal = sess.run(real_logits, feed_dict={input_xs: realclipinput.transpose(0, 2, 3, 1)}) 112 | if (np.argmax(outputsreal) != targets) and (np.abs(realclipdist).max() <= epsi): 113 | succImages += 1 114 | 115 | success_rate = succImages / float(totalImages) 116 | print('succ rate', success_rate) 117 | print('succ {} , total {}'.format(succImages, totalImages)) 118 | 119 | 120 | if __name__ == '__main__': 121 | main() 122 | -------------------------------------------------------------------------------- /lid/evaluation_bpda.py: -------------------------------------------------------------------------------- 1 | import robustml 2 | import time 3 | import pickle 4 | from util import get_model 5 | import sys 6 | import argparse 7 | import tensorflow as tf 8 | import numpy as np 9 | from helpers import * 10 | import keras.backend as K 11 | import os 12 | import cv2 13 | 14 | npop = 300 # population size 15 | sigma = 0.1 # noise standard deviation 16 | alpha = 0.008 # learning rate 17 | # alpha = 0.001 # learning rate 18 | boxmin = 0 19 | boxmax = 1 20 | boxplus = (boxmin + boxmax) / 2. 21 | boxmul = (boxmax - boxmin) / 2. 22 | folder = './liclipadvImages/' 23 | epsi = 0.032 24 | 25 | 26 | def softmax(x): 27 | return np.divide(np.exp(x), np.sum(np.exp(x), -1, keepdims=True)) 28 | 29 | def main(): 30 | 31 | parser = argparse.ArgumentParser() 32 | parser.add_argument('--cifar-path', type=str, default='../cifar10_data/test_batch', 33 | help='path to the test_batch file from http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz') 34 | parser.add_argument('--perturb', type=str, default='perturb') 35 | parser.add_argument('--start', type=int, default=0) 36 | parser.add_argument('--end', type=int, default=100) 37 | parser.add_argument('--debug', action='store_true') 38 | args = parser.parse_args() 39 | 40 | test_loss = 0 41 | correct = 0 42 | total = 0 43 | totalImages = 0 44 | succImages = 0 45 | faillist = [] 46 | 47 | 48 | 49 | # set up TensorFlow session 50 | 51 | config = tf.ConfigProto() 52 | config.gpu_options.allow_growth = True 53 | sess = tf.Session(config=config) 54 | K.set_session(sess) 55 | 56 | 57 | # initialize a model 58 | model = get_model('cifar', softmax=False) 59 | ### change lid model path llj 60 | model.load_weights("./data/lid_model_cifar.h5") 61 | 62 | # initialize an attack (it's a white box attack, and it's allowed to look 63 | # at the internals of the model in any way it wants) 64 | # attack = BPDA(sess, model, epsilon=model.threat_model.epsilon, debug=args.debug) 65 | # attack = Attack(sess, model.model, epsilon=model.threat_model.epsilon) 66 | 67 | # initialize a data provider for CIFAR-10 images 68 | provider = robustml.provider.CIFAR10(args.cifar_path) 69 | input_xs = tf.placeholder(tf.float32, [None, 32, 32, 3]) 70 | start = 0 71 | end = 10000 72 | total = 0 73 | real_logits0 = model(input_xs) 74 | real_logits = tf.nn.softmax(real_logits0) 75 | successlist = [] 76 | printlist = [] 77 | 78 | start_time = time.time() 79 | 80 | perturb_files = os.listdir(args.perturb) 81 | numbers = [] 82 | for x in perturb_files: 83 | number = x.split('_')[-1] 84 | name = x.split('_')[0] 85 | number1 = int(number.split('.pkl')[0]) 86 | numbers.append(number1) 87 | 88 | for i in numbers: 89 | success = False 90 | print('evaluating %d of [%d, %d)' % (i, start, end), file=sys.stderr) 91 | inputs, targets= provider[i] 92 | modify = np.random.randn(1,3,32,32) * 0.001 93 | in_pkl = args.perturb+ name + '_' + str(i)+'.pkl' 94 | ##### thermometer encoding 95 | 96 | logits = sess.run(real_logits,feed_dict={input_xs: [inputs]}) 97 | if np.argmax(logits) != targets: 98 | print('skip the wrong example ', i) 99 | continue 100 | totalImages += 1 101 | modify = pickle.load(open(in_pkl, 'rb')) 102 | if 'cascade' in in_pkl: 103 | modify = cv2.resize(modify.transpose(1,2,0), dsize=(32,32), interpolation=cv2.INTER_LINEAR) 104 | modify = modify.transpose(2, 0, 1) 105 | print(modify.shape) 106 | realclipinput = modify.reshape(1,32,32,3)+0.5 107 | realclipdist = realclipinput - inputs 108 | # print(np.abs(realclipdist).max()) 109 | outputsreal = sess.run(real_logits, feed_dict={input_xs: realclipinput}) 110 | print(np.abs(realclipdist).max()) 111 | 112 | if (np.argmax(outputsreal) != targets) and (np.abs(realclipdist).max() <= epsi): 113 | succImages += 1 114 | 115 | success_rate = succImages / float(totalImages) 116 | print('succ rate', success_rate) 117 | print('succ {} , total {}'.format(succImages, totalImages)) 118 | 119 | 120 | if __name__ == '__main__': 121 | main() 122 | -------------------------------------------------------------------------------- /lid/helpers.py: -------------------------------------------------------------------------------- 1 | import operator as op 2 | import functools as ft 3 | import numpy as np 4 | 5 | 6 | '''reduce_* helper functions reduce tensors on all dimensions but the first. 7 | They are intended to be used on batched tensors where dim 0 is the batch dim. 8 | ''' 9 | 10 | 11 | def reduce_sum(x, keepdim=True): 12 | # silly PyTorch, when will you get proper reducing sums/means? 13 | for a in reversed(range(1, x.dim())): 14 | x = x.sum(a, keepdim=keepdim) 15 | return x 16 | 17 | 18 | def reduce_mean(x, keepdim=True): 19 | numel = ft.reduce(op.mul, x.size()[1:]) 20 | x = reduce_sum(x, keepdim=keepdim) 21 | return x / numel 22 | 23 | 24 | def reduce_min(x, keepdim=True): 25 | for a in reversed(range(1, x.dim())): 26 | x = x.min(a, keepdim=keepdim)[0] 27 | return x 28 | 29 | 30 | def reduce_max(x, keepdim=True): 31 | for a in reversed(range(1, x.dim())): 32 | x = x.max(a, keepdim=keepdim)[0] 33 | return x 34 | 35 | 36 | def torch_arctanh(x, eps=1e-6): 37 | x *= (1. - eps) 38 | return (np.log((1 + x) / (1 - x))) * 0.5 39 | 40 | 41 | def l2r_dist(x, y, keepdim=True, eps=1e-8): 42 | d = (x - y)**2 43 | d = reduce_sum(d, keepdim=keepdim) 44 | d += eps # to prevent infinite gradient at 0 45 | return d.sqrt() 46 | 47 | 48 | def l2_dist(x, y, keepdim=True): 49 | d = (x - y)**2 50 | return reduce_sum(d, keepdim=keepdim) 51 | 52 | 53 | def l1_dist(x, y, keepdim=True): 54 | d = torch.abs(x - y) 55 | return reduce_sum(d, keepdim=keepdim) 56 | 57 | 58 | def l2_norm(x, keepdim=True): 59 | norm = reduce_sum(x*x, keepdim=keepdim) 60 | return norm.sqrt() 61 | 62 | 63 | def l1_norm(x, keepdim=True): 64 | return reduce_sum(x.abs(), keepdim=keepdim) 65 | 66 | 67 | def rescale(x, x_min=-1., x_max=1.): 68 | return x * (x_max - x_min) + x_min 69 | 70 | 71 | def tanh_rescale(x, x_min=-1., x_max=1.): 72 | return (torch.tanh(x) + 1) * 0.5 * (x_max - x_min) + x_min 73 | -------------------------------------------------------------------------------- /pixel-deflection/README.md: -------------------------------------------------------------------------------- 1 | # Deflecting Adversarial Attacks with Pixel Deflection 2 | 3 | ![deflecting pixels](https://i.imgur.com/BhxmVwx.png) 4 | 5 | Code for paper: https://arxiv.org/abs/1801.08926 6 | 7 | Blog with demo: https://iamaaditya.github.io/2018/02/demo-for-pixel-deflection/ 8 | 9 | Requirements: 10 | 11 | 1. Keras 2.0+ 12 | (only used for classification - Pixel Deflection itself is deep learning platform independent) 13 | 14 | 2. Scipy 1.0+ 15 | 16 | (Older version of scipy wavelet transform does not have BayesShrink) 17 | 18 | * Python3 + tensorflow 19 | 20 | ## [NATTACK] evaluation 21 | 22 | Run with: 23 | 24 | ```bash 25 | python re_li_attack.py --imagenet-path 26 | ```` 27 | -------------------------------------------------------------------------------- /pixel-deflection/helpers.py: -------------------------------------------------------------------------------- 1 | import operator as op 2 | import functools as ft 3 | import numpy as np 4 | 5 | 6 | '''reduce_* helper functions reduce tensors on all dimensions but the first. 7 | They are intended to be used on batched tensors where dim 0 is the batch dim. 8 | ''' 9 | 10 | 11 | def reduce_sum(x, keepdim=True): 12 | # silly PyTorch, when will you get proper reducing sums/means? 13 | for a in reversed(range(1, x.dim())): 14 | x = x.sum(a, keepdim=keepdim) 15 | return x 16 | 17 | 18 | def reduce_mean(x, keepdim=True): 19 | numel = ft.reduce(op.mul, x.size()[1:]) 20 | x = reduce_sum(x, keepdim=keepdim) 21 | return x / numel 22 | 23 | 24 | def reduce_min(x, keepdim=True): 25 | for a in reversed(range(1, x.dim())): 26 | x = x.min(a, keepdim=keepdim)[0] 27 | return x 28 | 29 | 30 | def reduce_max(x, keepdim=True): 31 | for a in reversed(range(1, x.dim())): 32 | x = x.max(a, keepdim=keepdim)[0] 33 | return x 34 | 35 | 36 | def torch_arctanh(x, eps=1e-6): 37 | x *= (1. - eps) 38 | return (np.log((1 + x) / (1 - x))) * 0.5 39 | 40 | 41 | def l2r_dist(x, y, keepdim=True, eps=1e-8): 42 | d = (x - y)**2 43 | d = reduce_sum(d, keepdim=keepdim) 44 | d += eps # to prevent infinite gradient at 0 45 | return d.sqrt() 46 | 47 | 48 | def l2_dist(x, y, keepdim=True): 49 | d = (x - y)**2 50 | return reduce_sum(d, keepdim=keepdim) 51 | 52 | 53 | def l1_dist(x, y, keepdim=True): 54 | d = torch.abs(x - y) 55 | return reduce_sum(d, keepdim=keepdim) 56 | 57 | 58 | def l2_norm(x, keepdim=True): 59 | norm = reduce_sum(x*x, keepdim=keepdim) 60 | return norm.sqrt() 61 | 62 | 63 | def l1_norm(x, keepdim=True): 64 | return reduce_sum(x.abs(), keepdim=keepdim) 65 | 66 | 67 | def rescale(x, x_min=-1., x_max=1.): 68 | return x * (x_max - x_min) + x_min 69 | 70 | 71 | def tanh_rescale(x, x_min=-1., x_max=1.): 72 | return (torch.tanh(x) + 1) * 0.5 * (x_max - x_min) + x_min 73 | -------------------------------------------------------------------------------- /pixel-deflection/images/n02443114_00000055.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cold-Winter/Nattack/2c5ce052f0298d52a2972dfce8bbfd9fed6a6fcb/pixel-deflection/images/n02443114_00000055.png -------------------------------------------------------------------------------- /pixel-deflection/images/n02443114_00032317.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cold-Winter/Nattack/2c5ce052f0298d52a2972dfce8bbfd9fed6a6fcb/pixel-deflection/images/n02443114_00032317.png -------------------------------------------------------------------------------- /pixel-deflection/images/n02447366_00008562.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cold-Winter/Nattack/2c5ce052f0298d52a2972dfce8bbfd9fed6a6fcb/pixel-deflection/images/n02447366_00008562.png -------------------------------------------------------------------------------- /pixel-deflection/main.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import os, sys, argparse, multiprocessing 3 | from joblib import Parallel, delayed 4 | from glob import glob 5 | import numpy as np 6 | from utils import * 7 | from methods import pixel_deflection, denoiser 8 | os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' # silences the TF INFO messages 9 | 10 | def get_arguments(): 11 | parser = argparse.ArgumentParser() 12 | parser.add_argument('-image' , type=str , default= 'images/n02447366_00008562.png') 13 | parser.add_argument('-map' , type=str , default= 'maps/n02447366_00008562.png') 14 | parser.add_argument('-directory' , type=str , default= './images/') 15 | parser.add_argument('-disable_map' , action='store_true') 16 | parser.add_argument('-process_batch' , action='store_true') 17 | parser.add_argument('-classifier' , type=str , default= 'resnet50', help='options: resnet50, inception_v3, vgg19, xception') 18 | parser.add_argument('-denoiser' , type=str , default= 'wavelet', help='options: wavelet, TVM, bilateral, deconv, NLM') 19 | parser.add_argument('-batch_size' , type=int, default= 64) 20 | parser.add_argument('-sigma' , type=float, default= 0.04) 21 | parser.add_argument('-window' , type=int, default= 10) 22 | parser.add_argument('-deflections' , type=int, default= 200) 23 | return parser.parse_args() 24 | 25 | def classify_images(images, class_names, supress_print=False): 26 | total, top1, top5 = 0,0,0 27 | images = preprocess_input(np.stack(images,axis=0)) 28 | predictions = decode_predictions(model.predict(images),top=5) 29 | for p,true_class in zip(predictions,class_names): 30 | ans= [' {0}:{1:.2f} '.format(i[1],i[2]) for i in p] 31 | if not supress_print: print('Predicted Class {}'.format(','.join(ans))) 32 | total += 1 33 | r = [i[0] for i in p] 34 | top1 += int(true_class == r[0]) 35 | top5 += int(true_class in r) 36 | return top1*100.0/total, top5*100.0/total 37 | 38 | def process_image(args, image_name, defend=True): 39 | image = get_img(image_name) 40 | # assumes map is same name as image but inside maps directory 41 | if not args.disable_map: 42 | map = get_map('./maps/'+image_name.split('/')[-1]) 43 | else: 44 | map = np.zeros((image.shape[0],image.shape[1])) 45 | 46 | if defend: 47 | img = pixel_deflection(image, map, args.deflections, args.window, args.sigma) 48 | return denoiser(args.denoiser, img/255.0, args.sigma)*255.0 49 | else: 50 | return image 51 | 52 | def process_image_parallel(args): 53 | num_cores = multiprocessing.cpu_count() 54 | scores = [] 55 | for image_names in batches(glob(args.directory+'/*'), args.batch_size): 56 | images = Parallel(n_jobs=num_cores)(delayed(process_image)(args, image_name) for image_name in image_names) 57 | class_names = [image_name.split('/')[-1].split('_')[0] for image_name in image_names] 58 | scores.append(classify_images(images, class_names, supress_print=True)) 59 | 60 | t1,t5 = sum([i[0] for i in scores])/len(scores), sum([i[1] for i in scores])/len(scores) 61 | print('After recovery Top 1 accuracy is {0:.2f} and Top 5 accuracy is {1:.2f}'.format(t1,t5)) 62 | 63 | if __name__ == '__main__': 64 | args = get_arguments() 65 | if args.classifier == 'resnet50': 66 | from keras.applications.resnet50 import ResNet50, preprocess_input, decode_predictions 67 | model = ResNet50(weights='imagenet') 68 | elif args.classifier == 'inception_v3': 69 | from keras.applications.inception_v3 import InceptionV3, preprocess_input, decode_predictions 70 | model = InceptionV3(weights='imagenet') 71 | elif args.classifier == 'vgg19': 72 | from keras.applications.vgg19 import VGG19, preprocess_input, decode_predictions 73 | model = VGG19(weights='imagenet') 74 | elif args.classifier == 'xception': 75 | from keras.applications.xception import Xception, preprocess_input, decode_predictions 76 | model = Xception(weights='imagenet') 77 | else: 78 | raise Exception('Incorrect classifier mentioned. Options: resnet50, inception_v3, vgg19, xception') 79 | 80 | imagenet_labels = get_imagenet_labels() 81 | if args.process_batch: 82 | images = process_image_parallel(args) 83 | else: 84 | class_name = args.image.split('/')[-1].split('_')[0] 85 | print("Image: {}, True Class: '{}'".format(args.image, imagenet_labels[class_name])) 86 | print('Before Defense :') 87 | image = process_image(args, args.image, defend=False) 88 | classify_images([image], [class_name]) 89 | print('After Defense :') 90 | image = process_image(args, args.image, defend=True) 91 | classify_images([image], [class_name]) 92 | -------------------------------------------------------------------------------- /pixel-deflection/maps/n02443114_00000055.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cold-Winter/Nattack/2c5ce052f0298d52a2972dfce8bbfd9fed6a6fcb/pixel-deflection/maps/n02443114_00000055.png -------------------------------------------------------------------------------- /pixel-deflection/maps/n02443114_00032317.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cold-Winter/Nattack/2c5ce052f0298d52a2972dfce8bbfd9fed6a6fcb/pixel-deflection/maps/n02443114_00032317.png -------------------------------------------------------------------------------- /pixel-deflection/maps/n02447366_00008562.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cold-Winter/Nattack/2c5ce052f0298d52a2972dfce8bbfd9fed6a6fcb/pixel-deflection/maps/n02447366_00008562.png -------------------------------------------------------------------------------- /pixel-deflection/methods.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | from random import randint, uniform 3 | import os, sys, argparse, matplotlib, multiprocessing 4 | matplotlib.use('Agg') 5 | from keras.preprocessing import image 6 | from scipy.misc import imread 7 | #from joblib import Parallel, delayed 8 | from glob import glob 9 | import numpy as np 10 | os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' 11 | norm = matplotlib.colors.Normalize() 12 | 13 | 14 | def denoiser(denoiser_name, img,sigma): 15 | from skimage.restoration import (denoise_tv_chambolle, denoise_bilateral, denoise_wavelet, denoise_nl_means, wiener) 16 | if denoiser_name == 'wavelet': 17 | return denoise_wavelet(img,sigma=sigma, mode='soft', multichannel=True,convert2ycbcr=True)#, method='BayesShrink') 18 | elif denoiser_name == 'TVM': 19 | return denoise_tv_chambolle(img, multichannel=True) 20 | elif denoiser_name == 'bilateral': 21 | return denoise_bilateral(img, bins=1000, multichannel=True) 22 | elif denoiser_name == 'deconv': 23 | return wiener(img) 24 | elif denoiser_name == 'NLM': 25 | return denoise_nl_means(img, multichannel=True) 26 | else: 27 | raise Exception('Incorrect denoiser mentioned. Options: wavelet, TVM, bilateral, deconv, NLM') 28 | 29 | def pixel_deflection(img, rcam_prob, deflections, window, sigma): 30 | H, W, C = img.shape 31 | while deflections > 0: 32 | for c in range(C): 33 | x,y = randint(0,H-1), randint(0,W-1) 34 | 35 | if uniform(0,1) < rcam_prob[x,y]: 36 | continue 37 | 38 | while True: #this is to ensure that PD pixel lies inside the image 39 | a,b = randint(-1*window,window), randint(-1*window,window) 40 | if x+a < H and x+a > 0 and y+b < W and y+b > 0: break 41 | img[x,y,c] = img[x+a,y+b,c] 42 | deflections -= 1 43 | return img 44 | -------------------------------------------------------------------------------- /pixel-deflection/originals/n02443114_00000055.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cold-Winter/Nattack/2c5ce052f0298d52a2972dfce8bbfd9fed6a6fcb/pixel-deflection/originals/n02443114_00000055.png -------------------------------------------------------------------------------- /pixel-deflection/originals/n02443114_00032317.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cold-Winter/Nattack/2c5ce052f0298d52a2972dfce8bbfd9fed6a6fcb/pixel-deflection/originals/n02443114_00032317.png -------------------------------------------------------------------------------- /pixel-deflection/originals/n02447366_00008562.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cold-Winter/Nattack/2c5ce052f0298d52a2972dfce8bbfd9fed6a6fcb/pixel-deflection/originals/n02447366_00008562.png -------------------------------------------------------------------------------- /pixel-deflection/utils.py: -------------------------------------------------------------------------------- 1 | import matplotlib 2 | import numpy as np 3 | from keras.preprocessing import image 4 | from scipy.misc import imread 5 | import json 6 | 7 | def batches(array, batch_size): 8 | return (array[i:i + batch_size] for i in range(0, len(array), batch_size)) 9 | 10 | def rgb2ycc(im): 11 | xform = np.array([[.299, .587, .114], [-.1687, -.3313, .5], [.5, -.4187, -.0813]]) 12 | ycbcr = im.dot(xform.T) 13 | ycbcr[:,:,[1,2]] += 128 14 | return ycbcr 15 | 16 | def ycc2rgb(im): 17 | xform = np.array([[1, 0, 1.402], [1, -0.34414, -.71414], [1, 1.772, 0]]) 18 | rgb = im.astype(np.float) 19 | rgb[:,:,[1,2]] -= 128 20 | return rgb.dot(xform.T) 21 | 22 | 23 | def get_img(file): 24 | img = image.load_img(file, target_size=(224, 224)) 25 | return image.img_to_array(img) 26 | 27 | def get_map(file): 28 | norm = matplotlib.colors.Normalize() 29 | return norm(imread(file)) 30 | 31 | def get_imagenet_labels(): 32 | imagenet = json.load(open('./imagenet_labels.json')) 33 | return {i[0]:i[1] for i in imagenet.values()} 34 | 35 | -------------------------------------------------------------------------------- /randomization/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cold-Winter/Nattack/2c5ce052f0298d52a2972dfce8bbfd9fed6a6fcb/randomization/.gitignore -------------------------------------------------------------------------------- /randomization/README.md: -------------------------------------------------------------------------------- 1 | # Mitigating Adversarial Effects Through Randomization 2 | 3 | Paper: [Xie et al. 2018](https://arxiv.org/abs/1711.01991) 4 | 5 | ## Requirements 6 | 7 | * Python3 + tensorflow 8 | 9 | 10 | ## [robustml] evaluation 11 | 12 | Run with: 13 | 14 | ```bash 15 | python re_li_attack32_tfmultigpu.py --imagenet-path 16 | ```` 17 | 18 | [robustml]: https://github.com/robust-ml/robustml 19 | -------------------------------------------------------------------------------- /randomization/defense.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | # implements defense described in https://openreview.net/forum?id=Sk9yuql0Z 4 | # 5 | # except they don't mention what value they pad with, so we assume it's 0.5 6 | PAD_VALUE = 0.5 7 | 8 | # input_tensor should be of shape [1, 299, 299, 3] 9 | # output is of shape [1, 331, 331, 3] 10 | def defend(input_tensor): 11 | rnd = tf.random_uniform((), 299, 331, dtype=tf.int32) 12 | rescaled = tf.image.crop_and_resize(input_tensor, [[0, 0, 1, 1]], [0], [rnd, rnd]) 13 | h_rem = 331 - rnd 14 | w_rem = 331 - rnd 15 | pad_left = tf.random_uniform((), 0, w_rem, dtype=tf.int32) 16 | pad_right = w_rem - pad_left 17 | pad_top = tf.random_uniform((), 0, h_rem, dtype=tf.int32) 18 | pad_bottom = h_rem - pad_top 19 | padded = tf.pad(rescaled, [[0, 0], [pad_top, pad_bottom], [pad_left, pad_right], [0, 0]], constant_values=PAD_VALUE) 20 | padded.set_shape((1, 331, 331, 3)) 21 | return padded 22 | -------------------------------------------------------------------------------- /randomization/defense_batch.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | # implements defense described in https://openreview.net/forum?id=Sk9yuql0Z 4 | # 5 | # except they don't mention what value they pad with, so we assume it's 0.5 6 | PAD_VALUE = 0.5 7 | 8 | # input_tensor should be of shape [300, 299, 299, 3] 9 | # output is of shape [300, 331, 331, 3] 10 | def defend_batch(input_tensor): 11 | rnd = tf.random_uniform([tf.to_int32(input_tensor.shape[0]),1], 299, 331, dtype=tf.int32) 12 | tensor = tf.tile([[0,0,1,1]],[tf.to_int32(input_tensor.shape[0]),1]) 13 | rescaled = tf.image.crop_and_resize(input_tensor, tf.to_float(tensor), tf.range(input_tensor.shape[0]), [rnd, rnd]) 14 | h_rem = 331 - rnd 15 | w_rem = 331 - rnd 16 | pad_left = tf.random_uniform([tf.to_int32(input_tensor.shape[0]),1], 0, w_rem, dtype=tf.int32) 17 | pad_right = w_rem - pad_left 18 | pad_top = tf.random_uniform([tf.to_int32(input_tensor.shape[0]),1], 0, h_rem, dtype=tf.int32) 19 | pad_bottom = h_rem - pad_top 20 | padded = tf.pad(rescaled, [[0, 0], [pad_top, pad_bottom], [pad_left, pad_right], [0, 0]], constant_values=PAD_VALUE) 21 | padded.set_shape((tf.to_int32(input_tensor.shape[0]), 331, 331, 3)) 22 | return padded -------------------------------------------------------------------------------- /randomization/helpers.py: -------------------------------------------------------------------------------- 1 | import operator as op 2 | import functools as ft 3 | import numpy as np 4 | 5 | 6 | '''reduce_* helper functions reduce tensors on all dimensions but the first. 7 | They are intended to be used on batched tensors where dim 0 is the batch dim. 8 | ''' 9 | 10 | 11 | def reduce_sum(x, keepdim=True): 12 | # silly PyTorch, when will you get proper reducing sums/means? 13 | for a in reversed(range(1, x.dim())): 14 | x = x.sum(a, keepdim=keepdim) 15 | return x 16 | 17 | 18 | def reduce_mean(x, keepdim=True): 19 | numel = ft.reduce(op.mul, x.size()[1:]) 20 | x = reduce_sum(x, keepdim=keepdim) 21 | return x / numel 22 | 23 | 24 | def reduce_min(x, keepdim=True): 25 | for a in reversed(range(1, x.dim())): 26 | x = x.min(a, keepdim=keepdim)[0] 27 | return x 28 | 29 | 30 | def reduce_max(x, keepdim=True): 31 | for a in reversed(range(1, x.dim())): 32 | x = x.max(a, keepdim=keepdim)[0] 33 | return x 34 | 35 | 36 | def torch_arctanh(x, eps=1e-6): 37 | x *= (1. - eps) 38 | return (np.log((1 + x) / (1 - x))) * 0.5 39 | 40 | 41 | def l2r_dist(x, y, keepdim=True, eps=1e-8): 42 | d = (x - y)**2 43 | d = reduce_sum(d, keepdim=keepdim) 44 | d += eps # to prevent infinite gradient at 0 45 | return d.sqrt() 46 | 47 | 48 | def l2_dist(x, y, keepdim=True): 49 | d = (x - y)**2 50 | return reduce_sum(d, keepdim=keepdim) 51 | 52 | 53 | def l1_dist(x, y, keepdim=True): 54 | d = torch.abs(x - y) 55 | return reduce_sum(d, keepdim=keepdim) 56 | 57 | 58 | def l2_norm(x, keepdim=True): 59 | norm = reduce_sum(x*x, keepdim=keepdim) 60 | return norm.sqrt() 61 | 62 | 63 | def l1_norm(x, keepdim=True): 64 | return reduce_sum(x.abs(), keepdim=keepdim) 65 | 66 | 67 | def rescale(x, x_min=-1., x_max=1.): 68 | return x * (x_max - x_min) + x_min 69 | 70 | 71 | def tanh_rescale(x, x_min=-1., x_max=1.): 72 | return (torch.tanh(x) + 1) * 0.5 * (x_max - x_min) + x_min 73 | -------------------------------------------------------------------------------- /randomization/inceptionv3.py: -------------------------------------------------------------------------------- 1 | from utils import optimistic_restore 2 | import tensorflow as tf 3 | import tensorflow.contrib.slim as slim 4 | import tensorflow.contrib.slim.nets as nets 5 | import functools 6 | import os 7 | 8 | _INCEPTION_CHECKPOINT_NAME = '../all_models/random/inception_v3.ckpt' 9 | # INCEPTION_CHECKPOINT_PATH = os.path.join( 10 | # os.path.dirname(__file__), 11 | # 'data', 12 | # _INCEPTION_CHECKPOINT_NAME 13 | # ) 14 | INCEPTION_CHECKPOINT_PATH = '../all_models/random/inception_v3.ckpt' 15 | 16 | def _get_model(reuse): 17 | arg_scope = nets.inception.inception_v3_arg_scope(weight_decay=0.0) 18 | func = nets.inception.inception_v3 19 | @functools.wraps(func) 20 | def network_fn(images): 21 | with slim.arg_scope(arg_scope): 22 | return func(images, 1001, is_training=False, reuse=reuse) 23 | if hasattr(func, 'default_image_size'): 24 | network_fn.default_image_size = func.default_image_size 25 | return network_fn 26 | 27 | def _preprocess(image, height, width, scope=None): 28 | with tf.name_scope(scope, 'eval_image', [image, height, width]): 29 | if image.dtype != tf.float32: 30 | image = tf.image.convert_image_dtype(image, dtype=tf.float32) 31 | image = tf.image.resize_bilinear(image, [height, width], align_corners=False) 32 | image = tf.subtract(image, 0.5) 33 | image = tf.multiply(image, 2.0) 34 | return image 35 | 36 | # input is [batch, ?, ?, 3], pixels in [0, 1] 37 | # it's rescaled to [batch, 299, 299, 3] and shifted to [-1, 1] 38 | # output is [batch, 1000] (imagenet classes) 39 | _inception_initialized = False 40 | def model(sess, image): 41 | global _inception_initialized 42 | network_fn = _get_model(reuse=_inception_initialized) 43 | size = network_fn.default_image_size 44 | preprocessed = _preprocess(image, size, size) 45 | logits, _ = network_fn(preprocessed) 46 | logits = logits[:,1:] # ignore background class 47 | predictions = tf.argmax(logits, 1) 48 | 49 | if not _inception_initialized: 50 | optimistic_restore(sess, INCEPTION_CHECKPOINT_PATH) 51 | _inception_initialized = True 52 | 53 | return logits, predictions 54 | -------------------------------------------------------------------------------- /randomization/nohup.out: -------------------------------------------------------------------------------- 1 | 2018-09-20 23:54:29.729038: I tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 AVX512F FMA 2 | 2018-09-20 23:54:33.178383: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Found device 0 with properties: 3 | name: Graphics Device major: 6 minor: 1 memoryClockRate(GHz): 1.582 4 | pciBusID: 0000:18:00.0 5 | totalMemory: 11.90GiB freeMemory: 11.75GiB 6 | 2018-09-20 23:54:33.780051: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Found device 1 with properties: 7 | name: Graphics Device major: 6 minor: 1 memoryClockRate(GHz): 1.582 8 | pciBusID: 0000:3b:00.0 9 | totalMemory: 11.90GiB freeMemory: 11.75GiB 10 | 2018-09-20 23:54:34.279893: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Found device 2 with properties: 11 | name: Graphics Device major: 6 minor: 1 memoryClockRate(GHz): 1.582 12 | pciBusID: 0000:86:00.0 13 | totalMemory: 11.90GiB freeMemory: 11.75GiB 14 | 2018-09-20 23:54:34.766308: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Found device 3 with properties: 15 | name: Graphics Device major: 6 minor: 1 memoryClockRate(GHz): 1.582 16 | pciBusID: 0000:af:00.0 17 | totalMemory: 11.90GiB freeMemory: 11.75GiB 18 | 2018-09-20 23:54:34.766743: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Device peer to peer matrix 19 | 2018-09-20 23:54:34.766826: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1051] DMA: 0 1 2 3 20 | 2018-09-20 23:54:34.766842: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1061] 0: Y N N N 21 | 2018-09-20 23:54:34.766849: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1061] 1: N Y N N 22 | 2018-09-20 23:54:34.766856: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1061] 2: N N Y N 23 | 2018-09-20 23:54:34.766863: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1061] 3: N N N Y 24 | 2018-09-20 23:54:34.766876: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: Graphics Device, pci bus id: 0000:18:00.0, compute capability: 6.1) 25 | 2018-09-20 23:54:34.766886: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:1) -> (device: 1, name: Graphics Device, pci bus id: 0000:3b:00.0, compute capability: 6.1) 26 | 2018-09-20 23:54:34.766894: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:2) -> (device: 2, name: Graphics Device, pci bus id: 0000:86:00.0, compute capability: 6.1) 27 | 2018-09-20 23:54:34.766901: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:3) -> (device: 3, name: Graphics Device, pci bus id: 0000:af:00.0, compute capability: 6.1) 28 | /home/yandong/anaconda3/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: compiletime version 3.5 of module 'tensorflow.python.framework.fast_tensor_util' does not match runtime version 3.6 29 | return f(*args, **kwds) 30 | /home/yandong/anaconda3/lib/python3.6/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`. 31 | from ._conv import register_converters as _register_converters 32 | Traceback (most recent call last): 33 | File "re_li_attack32_tfmultigpu.py", line 194, in 34 | main() 35 | File "re_li_attack32_tfmultigpu.py", line 48, in main 36 | sess = tf.Session(config=config) 37 | File "/home/yandong/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 1482, in __init__ 38 | super(Session, self).__init__(target, graph, config=config) 39 | File "/home/yandong/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 622, in __init__ 40 | self._session = tf_session.TF_NewDeprecatedSession(opts, status) 41 | KeyboardInterrupt 42 | -------------------------------------------------------------------------------- /randomization/robustml_attack.py: -------------------------------------------------------------------------------- 1 | import robustml 2 | from defense import defend 3 | from inceptionv3 import model as inceptionv3_model 4 | from robustml_model import Randomization 5 | import sys 6 | import argparse 7 | import tensorflow as tf 8 | import numpy as np 9 | import time 10 | class EOT(robustml.attack.Attack): 11 | def __init__(self, sess, epsilon, sample_size=30, max_steps=1000, learning_rate=0.1, debug=False): 12 | self._sess = sess 13 | 14 | self._input = tf.placeholder(tf.float32, (299, 299, 3)) 15 | x_expanded = tf.expand_dims(self._input, axis=0) 16 | ensemble_xs = tf.concat([defend(x_expanded) for _ in range(sample_size)], axis=0) 17 | self._logits, self._preds = inceptionv3_model(sess, ensemble_xs) 18 | 19 | self._label = tf.placeholder(tf.int32, ()) 20 | one_hot = tf.expand_dims(tf.one_hot(self._label, 1000), axis=0) 21 | ensemble_labels = tf.tile(one_hot, (self._logits.shape[0], 1)) 22 | self._loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=self._logits, labels=ensemble_labels)) 23 | self._grad, = tf.gradients(self._loss, self._input) 24 | 25 | self._epsilon = epsilon 26 | self._max_steps = max_steps 27 | self._learning_rate = learning_rate 28 | self._debug = debug 29 | 30 | def run(self, x, y, target): 31 | if target is not None: 32 | raise NotImplementedError 33 | adv = np.copy(x) 34 | lower = np.clip(x - self._epsilon, 0, 1) 35 | upper = np.clip(x + self._epsilon, 0, 1) 36 | for i in range(self._max_steps): 37 | p, l, g = self._sess.run( 38 | [self._preds, self._loss, self._grad], 39 | {self._input: adv, self._label: y} 40 | ) 41 | if self._debug: 42 | print( 43 | 'attack: step %d/%d, loss = %g (true %d, predicted %s)' % (i+1, self._max_steps, l, y, p), 44 | file=sys.stderr 45 | ) 46 | if y not in p: 47 | # we're done 48 | if self._debug: 49 | print('returning early', file=sys.stderr) 50 | break 51 | adv += self._learning_rate * g 52 | adv = np.clip(adv, lower, upper) 53 | return adv 54 | 55 | def main(): 56 | parser = argparse.ArgumentParser() 57 | parser.add_argument('--imagenet-path', type=str, required=True, 58 | help='directory containing `val.txt` and `val/` folder') 59 | parser.add_argument('--start', type=int, default=0) 60 | parser.add_argument('--end', type=int, default=100) 61 | parser.add_argument('--debug', action='store_true') 62 | args = parser.parse_args() 63 | 64 | # set up TensorFlow session 65 | sess = tf.Session() 66 | 67 | # initialize a model 68 | model = Randomization(sess) 69 | 70 | # initialize an attack (it's a white box attack, and it's allowed to look 71 | # at the internals of the model in any way it wants) 72 | attack = EOT(sess, model.threat_model.epsilon, debug=args.debug) 73 | 74 | # initialize a data provider for ImageNet images 75 | provider = robustml.provider.ImageNet(args.imagenet_path, model.dataset.shape) 76 | attack_start = time.time() 77 | success_rate = robustml.evaluate.evaluate( 78 | model, 79 | attack, 80 | provider, 81 | start=args.start, 82 | end=args.end, 83 | deterministic=True, 84 | debug=args.debug, 85 | ) 86 | print('attack time : ', time.time()-attack_start,flush=True) 87 | print('attack success rate: %.2f%% (over %d data points)' % (success_rate*100, args.end-args.start)) 88 | 89 | if __name__ == '__main__': 90 | main() 91 | -------------------------------------------------------------------------------- /randomization/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname "$0")" # cd to directory of this script 4 | 5 | # $1 is filename 6 | # $2 is expected sha 7 | check_sha1() { 8 | computed=$(sha1sum "$1" 2>/dev/null | awk '{print $1}') || return 1 9 | if [ "$computed" == "$2" ]; then 10 | return 0; 11 | else 12 | return 1; 13 | fi 14 | } 15 | 16 | # $1 is URL 17 | # $2 is extracted file name 18 | # $3 is the checksum 19 | fetch() { 20 | if check_sha1 $2 $3; then 21 | echo "$2 already downloaded" 22 | return 23 | fi 24 | echo "downloading $1" 25 | f=${1##*/} 26 | wget -q $1 -O $f 27 | tar xf $f 28 | rm -f $f 29 | if check_sha1 $2 $3; then 30 | echo "downloaded $2" 31 | else 32 | echo "HASH MISMATCH, SHA1($2) != $3" 33 | fi 34 | } 35 | 36 | cd data 37 | 38 | fetch \ 39 | http://download.tensorflow.org/models/inception_v3_2016_08_28.tar.gz \ 40 | inception_v3.ckpt 606fd6953c58c817c56fd3bc2f0384fc2ecaba92 41 | -------------------------------------------------------------------------------- /randomization/utils.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | from tensorflow.python.framework import ops 3 | import numpy as np 4 | import PIL.Image 5 | from imagenet_labels import label_to_name 6 | import matplotlib.pyplot as plt 7 | 8 | def one_hot(index, total): 9 | arr = np.zeros((total)) 10 | arr[index] = 1.0 11 | return arr 12 | 13 | def optimistic_restore(session, save_file): 14 | reader = tf.train.NewCheckpointReader(save_file) 15 | saved_shapes = reader.get_variable_to_shape_map() 16 | var_names = sorted([(var.name, var.name.split(':')[0]) for var in tf.global_variables() 17 | if var.name.split(':')[0] in saved_shapes]) 18 | restore_vars = [] 19 | with tf.variable_scope('', reuse=True): 20 | for var_name, saved_var_name in var_names: 21 | curr_var = tf.get_variable(saved_var_name) 22 | var_shape = curr_var.get_shape().as_list() 23 | if var_shape == saved_shapes[saved_var_name]: 24 | restore_vars.append(curr_var) 25 | saver = tf.train.Saver(restore_vars) 26 | saver.restore(session, save_file) 27 | 28 | def load_image(path): 29 | return (np.asarray(PIL.Image.open(path).resize((299, 299)))/255.0).astype(np.float32) 30 | 31 | def make_classify(sess, input_, probs): 32 | def classify(img, correct_class=None, target_class=None): 33 | fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 8)) 34 | fig.sca(ax1) 35 | p = sess.run(probs, feed_dict={input_: img})[0] 36 | ax1.imshow(img) 37 | fig.sca(ax1) 38 | 39 | topk = list(p.argsort()[-10:][::-1]) 40 | topprobs = p[topk] 41 | barlist = ax2.bar(range(10), topprobs) 42 | if target_class in topk: 43 | barlist[topk.index(target_class)].set_color('r') 44 | if correct_class in topk: 45 | barlist[topk.index(correct_class)].set_color('g') 46 | plt.sca(ax2) 47 | plt.ylim([0, 1.1]) 48 | plt.xticks(range(10), 49 | [label_to_name(i)[:15] for i in topk], 50 | rotation='vertical') 51 | fig.subplots_adjust(bottom=0.2) 52 | plt.show() 53 | return classify -------------------------------------------------------------------------------- /robustnet/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Xuanqing Liu 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 | -------------------------------------------------------------------------------- /robustnet/README.md: -------------------------------------------------------------------------------- 1 | # Towards robust neural networks via random self-ensemble 2 | 3 | Paper: [Liu et al. (2018)](https://arxiv.org/abs/1712.00673) 4 | ## Requirements 5 | 6 | * Python3 + pytorch0.4.0 7 | 8 | ## [NATTACK] evaluation 9 | 10 | Run with: 11 | 12 | ```bash 13 | python re_li_attack.py --cifar-path 14 | ```` 15 | 16 | [robustml]: https://github.com/robust-ml/robustml 17 | -------------------------------------------------------------------------------- /robustnet/attack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import torch 5 | from torch.autograd import Variable 6 | import torch.optim as optim 7 | import torchvision.transforms as tfs 8 | import torchvision.datasets as dst 9 | from torch.utils.data import DataLoader 10 | import matplotlib.pyplot as plt 11 | from models import * 12 | import numpy as np 13 | 14 | classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') 15 | 16 | def attack(input_v, label_v, net, c, TARGETED=False): 17 | n_class = len(classes) 18 | index = label_v.data.cpu().view(-1,1) 19 | label_onehot = torch.FloatTensor(input_v.size()[0] , n_class) 20 | label_onehot.zero_() 21 | label_onehot.scatter_(1,index,1) 22 | label_onehot_v = Variable(label_onehot, requires_grad = False).cuda() 23 | #print(label_onehot.scatter) 24 | adverse = input_v.data #torch.FloatTensor(input_v.size()).zero_().cuda() 25 | adverse_v = Variable(adverse, requires_grad=True) 26 | optimizer = optim.Adam([adverse_v], lr=0.1) 27 | for _ in range(300): 28 | optimizer.zero_grad() 29 | diff = adverse_v - input_v 30 | output = net(adverse_v) 31 | real = torch.sum(torch.max(torch.mul(output, label_onehot_v), 1)[0]) 32 | other = torch.sum(torch.max(torch.mul(output, (1-label_onehot_v))-label_onehot_v*10000,1)[0]) 33 | error = c * torch.sum(diff * diff) 34 | #print(error.size()) 35 | if TARGETED: 36 | error += torch.clamp(other - real, min=0) 37 | else: 38 | error += torch.clamp(real - other, min=0) 39 | error.backward() 40 | optimizer.step() 41 | return adverse_v 42 | 43 | def weights_init(m): 44 | classname = m.__class__.__name__ 45 | if classname.find('Linear') != -1: 46 | m.weight.data.normal_(0.0, 0.02) 47 | elif classname.find('Conv') != -1: 48 | m.weight.data.normal_(0.0, 0.02) 49 | elif classname.find('BatchNorm') != -1 and m.affine: 50 | m.weight.data.normal_(1.0, 0.02) 51 | m.bias.data.fill_(0) 52 | 53 | 54 | if __name__ == "__main__": 55 | parser = argparse.ArgumentParser() 56 | parser.add_argument('--modelIn', type=str, default=None) 57 | parser.add_argument('--c', type=float, default=1.0) 58 | parser.add_argument('--noise', type=float, default=0) 59 | opt = parser.parse_args() 60 | 61 | net = VGG("VGG16", opt.noise) 62 | net = nn.DataParallel(net, device_ids=range(1)) 63 | loss_f = nn.CrossEntropyLoss() 64 | net.apply(weights_init) 65 | if opt.modelIn is not None: 66 | net.load_state_dict(torch.load(opt.modelIn)) 67 | net.cuda() 68 | loss_f.cuda() 69 | mean = (0.4914, 0.4822, 0.4465) 70 | mean_t = torch.FloatTensor(mean).resize_(1, 3, 1, 1).cuda() 71 | std = (0.2023, 0.1994, 0.2010) 72 | std_t = torch.FloatTensor(std).resize_(1, 3, 1, 1).cuda() 73 | transform_train = tfs.Compose([ 74 | tfs.ToTensor(), 75 | tfs.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 76 | ]) 77 | transform_test = tfs.Compose([ 78 | tfs.ToTensor(), 79 | tfs.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 80 | ]) 81 | data = dst.CIFAR10("/home/luinx/data/cifar10-py", download=True, train=True, transform=transform_train) 82 | data_test = dst.CIFAR10("/home/luinx/data/cifar10-py", download=True, train=False, transform=transform_test) 83 | assert data, data_test 84 | dataloader = DataLoader(data, batch_size=100, shuffle=True, num_workers=2) 85 | dataloader_test = DataLoader(data_test, batch_size=100, shuffle=True, num_workers=2) 86 | count, count2 = 0, 0 87 | for input, output in dataloader_test: 88 | input_v, label_v = Variable(input.cuda()), Variable(output.cuda()) 89 | adverse_v = attack(input_v, label_v, net, opt.c) 90 | _, idx = torch.max(net(input_v), 1) 91 | _, idx2 = torch.max(net(adverse_v), 1) 92 | count += torch.sum(label_v.eq(idx)).data[0] 93 | count2 += torch.sum(label_v.eq(idx2)).data[0] 94 | print("Count: {}, Count2: {}".format(count, count2)) 95 | 96 | adverse_v.data = adverse_v.data * std_t + mean_t 97 | input_v.data = input_v.data * std_t + mean_t 98 | adverse_np = adverse_v.cpu().data.numpy().swapaxes(1, 3) 99 | input_np = input_v.cpu().data.numpy().swapaxes(1, 3) 100 | plt.subplot(121) 101 | plt.imshow(np.abs(input_np[0, :, :, :].squeeze())) 102 | plt.subplot(122) 103 | plt.imshow(np.abs(adverse_np[0, :, :, :].squeeze())) 104 | plt.show() 105 | 106 | print("Accuracy: {}, Attach: {}".format(count / len(data), count2 / len(data))) 107 | -------------------------------------------------------------------------------- /robustnet/helpers.py: -------------------------------------------------------------------------------- 1 | import operator as op 2 | import functools as ft 3 | import numpy as np 4 | 5 | 6 | '''reduce_* helper functions reduce tensors on all dimensions but the first. 7 | They are intended to be used on batched tensors where dim 0 is the batch dim. 8 | ''' 9 | 10 | 11 | def reduce_sum(x, keepdim=True): 12 | # silly PyTorch, when will you get proper reducing sums/means? 13 | for a in reversed(range(1, x.dim())): 14 | x = x.sum(a, keepdim=keepdim) 15 | return x 16 | 17 | 18 | def reduce_mean(x, keepdim=True): 19 | numel = ft.reduce(op.mul, x.size()[1:]) 20 | x = reduce_sum(x, keepdim=keepdim) 21 | return x / numel 22 | 23 | 24 | def reduce_min(x, keepdim=True): 25 | for a in reversed(range(1, x.dim())): 26 | x = x.min(a, keepdim=keepdim)[0] 27 | return x 28 | 29 | 30 | def reduce_max(x, keepdim=True): 31 | for a in reversed(range(1, x.dim())): 32 | x = x.max(a, keepdim=keepdim)[0] 33 | return x 34 | 35 | 36 | def torch_arctanh(x, eps=1e-6): 37 | x *= (1. - eps) 38 | return (np.log((1 + x) / (1 - x))) * 0.5 39 | 40 | 41 | def l2r_dist(x, y, keepdim=True, eps=1e-8): 42 | d = (x - y)**2 43 | d = reduce_sum(d, keepdim=keepdim) 44 | d += eps # to prevent infinite gradient at 0 45 | return d.sqrt() 46 | 47 | 48 | def l2_dist(x, y, keepdim=True): 49 | d = (x - y)**2 50 | return reduce_sum(d, keepdim=keepdim) 51 | 52 | 53 | def l1_dist(x, y, keepdim=True): 54 | d = torch.abs(x - y) 55 | return reduce_sum(d, keepdim=keepdim) 56 | 57 | 58 | def l2_norm(x, keepdim=True): 59 | norm = reduce_sum(x*x, keepdim=keepdim) 60 | return norm.sqrt() 61 | 62 | 63 | def l1_norm(x, keepdim=True): 64 | return reduce_sum(x.abs(), keepdim=keepdim) 65 | 66 | 67 | def rescale(x, x_min=-1., x_max=1.): 68 | return x * (x_max - x_min) + x_min 69 | 70 | 71 | def tanh_rescale(x, x_min=-1., x_max=1.): 72 | return (torch.tanh(x) + 1) * 0.5 * (x_max - x_min) + x_min 73 | -------------------------------------------------------------------------------- /robustnet/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | '''Train CIFAR10 with PyTorch.''' 3 | from __future__ import print_function 4 | 5 | import torch 6 | import torch.nn as nn 7 | import torch.optim as optim 8 | import torch.nn.functional as F 9 | import torch.backends.cudnn as cudnn 10 | 11 | import torchvision 12 | import torchvision.transforms as transforms 13 | 14 | import os 15 | import argparse 16 | 17 | from models import * 18 | from utils import progress_bar 19 | from torch.autograd import Variable 20 | 21 | 22 | parser = argparse.ArgumentParser(description='PyTorch CIFAR10 Training') 23 | parser.add_argument('--lr', default=0.1, type=float, help='learning rate') 24 | parser.add_argument('--resume', '-r', action='store_true', help='resume from checkpoint') 25 | args = parser.parse_args() 26 | 27 | use_cuda = torch.cuda.is_available() 28 | best_acc = 0 # best test accuracy 29 | start_epoch = 0 # start from epoch 0 or last checkpoint epoch 30 | 31 | # Data 32 | print('==> Preparing data..') 33 | transform_train = transforms.Compose([ 34 | transforms.RandomCrop(32, padding=4), 35 | transforms.RandomHorizontalFlip(), 36 | transforms.ToTensor(), 37 | transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 38 | ]) 39 | 40 | transform_test = transforms.Compose([ 41 | transforms.ToTensor(), 42 | transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 43 | ]) 44 | 45 | trainset = torchvision.datasets.CIFAR10(root='/home/luinx/data', train=True, download=True, transform=transform_train) 46 | trainloader = torch.utils.data.DataLoader(trainset, batch_size=128, shuffle=True, num_workers=2) 47 | 48 | testset = torchvision.datasets.CIFAR10(root='/home/luinx/data', train=False, download=True, transform=transform_test) 49 | testloader = torch.utils.data.DataLoader(testset, batch_size=100, shuffle=False, num_workers=2) 50 | 51 | classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') 52 | 53 | # Model 54 | if args.resume: 55 | # Load checkpoint. 56 | print('==> Resuming from checkpoint..') 57 | assert os.path.isdir('checkpoint'), 'Error: no checkpoint directory found!' 58 | checkpoint = torch.load('./checkpoint/ckpt.t7') 59 | net = checkpoint['net'] 60 | best_acc = checkpoint['acc'] 61 | start_epoch = checkpoint['epoch'] 62 | else: 63 | print('==> Building model..') 64 | net = VGG('VGG16', 0) 65 | # net = ResNet18() 66 | # net = PreActResNet18() 67 | # net = GoogLeNet() 68 | # net = DenseNet121() 69 | # net = ResNeXt29_2x64d() 70 | # net = MobileNet() 71 | # net = DPN92() 72 | # net = ShuffleNetG2() 73 | # net = SENet18() 74 | 75 | if use_cuda: 76 | net.cuda() 77 | net = torch.nn.DataParallel(net, device_ids=range(torch.cuda.device_count())) 78 | cudnn.benchmark = True 79 | 80 | criterion = nn.CrossEntropyLoss() 81 | optimizer = optim.SGD(net.parameters(), lr=args.lr, momentum=0.9, weight_decay=5e-4) 82 | 83 | # Training 84 | def train(epoch): 85 | print('\nEpoch: %d' % epoch) 86 | net.train() 87 | train_loss = 0 88 | correct = 0 89 | total = 0 90 | for batch_idx, (inputs, targets) in enumerate(trainloader): 91 | if use_cuda: 92 | inputs, targets = inputs.cuda(), targets.cuda() 93 | optimizer.zero_grad() 94 | inputs, targets = Variable(inputs), Variable(targets) 95 | outputs = net(inputs) 96 | loss = criterion(outputs, targets) 97 | loss.backward() 98 | optimizer.step() 99 | 100 | train_loss += loss.data[0] 101 | _, predicted = torch.max(outputs.data, 1) 102 | total += targets.size(0) 103 | correct += predicted.eq(targets.data).cpu().sum() 104 | 105 | progress_bar(batch_idx, len(trainloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)' 106 | % (train_loss/(batch_idx+1), 100.*correct/total, correct, total)) 107 | 108 | def test(epoch): 109 | global best_acc 110 | net.eval() 111 | test_loss = 0 112 | correct = 0 113 | total = 0 114 | for batch_idx, (inputs, targets) in enumerate(testloader): 115 | if use_cuda: 116 | inputs, targets = inputs.cuda(), targets.cuda() 117 | inputs, targets = Variable(inputs, volatile=True), Variable(targets) 118 | outputs = net(inputs) 119 | loss = criterion(outputs, targets) 120 | 121 | test_loss += loss.data[0] 122 | _, predicted = torch.max(outputs.data, 1) 123 | total += targets.size(0) 124 | correct += predicted.eq(targets.data).cpu().sum() 125 | 126 | progress_bar(batch_idx, len(testloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)' 127 | % (test_loss/(batch_idx+1), 100.*correct/total, correct, total)) 128 | 129 | # Save checkpoint. 130 | acc = 100.*correct/total 131 | if acc > best_acc: 132 | print('Saving..') 133 | state = { 134 | 'net': net.module if use_cuda else net, 135 | 'acc': acc, 136 | 'epoch': epoch, 137 | } 138 | if not os.path.isdir('checkpoint'): 139 | os.mkdir('checkpoint') 140 | torch.save(state, './checkpoint/ckpt.t7') 141 | best_acc = acc 142 | 143 | 144 | for epoch in range(start_epoch, start_epoch+200): 145 | train(epoch) 146 | test(epoch) 147 | -------------------------------------------------------------------------------- /robustnet/main2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import numpy as np 5 | import torch 6 | import torch.optim as optim 7 | import torch.nn as nn 8 | from torch.autograd import Variable 9 | import torchvision.datasets as dst 10 | import torchvision.transforms as tfs 11 | from models import * 12 | from torch.utils.data import DataLoader 13 | import time 14 | 15 | def accuracy(dataloader, net): 16 | data_iter = iter(dataloader) 17 | count = 0 18 | total = 0 19 | for x, y in data_iter: 20 | vx = Variable(x, volatile=True).cuda() 21 | tmp = torch.sum(torch.eq(y.cuda(), torch.max(net(vx), dim=1)[1]).data) 22 | count += int(tmp) 23 | total += y.size()[0] 24 | return count / total 25 | 26 | def loss(dataloader, net, loss_f): 27 | data_iter = iter(dataloader) 28 | total_loss = 0.0 29 | count = 0 30 | for x, y in data_iter: 31 | vx = Variable(x, volatile=True).cuda() 32 | vy = Variable(y).cuda() 33 | total_loss += torch.sum(loss_f(net(vx), vy).data) 34 | count += y.size()[0] 35 | return total_loss / count 36 | 37 | def train_other(dataloader, dataloader_test, net, loss_f, lr, name='adam', max_epoch=10): 38 | run_time = 0.0 39 | if name == 'adam': 40 | optimizer = optim.Adam(net.parameters(), lr=lr) 41 | elif name == 'rmsprop': 42 | optimizer = optim.RMSprop(net.parameters(), lr=lr) 43 | elif name == 'momsgd': 44 | optimizer = optim.SGD(net.parameters(), lr=lr, momentum=0.9, weight_decay=5.0e-4) 45 | else: 46 | print('Not implemented') 47 | exit(-1) 48 | for epoch in range(max_epoch): 49 | beg = time.time() 50 | data_iter = iter(dataloader) 51 | for x, y in data_iter: 52 | vx, vy = Variable(x).cuda(), Variable(y).cuda() 53 | optimizer.zero_grad() 54 | lossv = loss_f(net(vx), vy) 55 | lossv.backward() 56 | optimizer.step() 57 | run_time += time.time() - beg 58 | print("[Epoch {}] Time: {}, Train loss: {}, Train accuracy: {}, Test loss: {}, Test accuracy: {}".format(epoch, run_time, loss(dataloader, net, loss_f), accuracy(dataloader, net), loss(dataloader_test, net, loss_f), accuracy(dataloader_test, net))) 59 | 60 | 61 | def weights_init(m): 62 | classname = m.__class__.__name__ 63 | if classname.find('Linear') != -1: 64 | m.weight.data.normal_(0.0, 0.02) 65 | elif classname.find('Conv') != -1: 66 | m.weight.data.normal_(0.0, 0.02) 67 | elif classname.find('BatchNorm') != -1 and m.affine: 68 | m.weight.data.normal_(1.0, 0.02) 69 | m.bias.data.fill_(0) 70 | 71 | def main(): 72 | parser = argparse.ArgumentParser() 73 | parser.add_argument('--batchSize', type=int, default=128) 74 | parser.add_argument('--epoch', type=int, default=300) 75 | parser.add_argument('--lr', type=float, default=1.0) 76 | parser.add_argument('--ngpu', type=int, default=1) 77 | parser.add_argument('--modelIn', type=str, default=None) 78 | parser.add_argument('--modelOut', type=str, default=None) 79 | parser.add_argument('--method', type=str, default="momsgd") 80 | parser.add_argument('--noise', type=float, default=0.0) 81 | opt = parser.parse_args() 82 | print(opt) 83 | net = VGG("VGG16", opt.noise) 84 | #net = densenet_cifar() 85 | #net = GoogLeNet() 86 | #net = MobileNet(num_classes=100) 87 | #net = stl10(32) 88 | net = nn.DataParallel(net, device_ids=range(opt.ngpu)) 89 | #net = Test() 90 | net.apply(weights_init) 91 | if opt.modelIn is not None: 92 | net.load_state_dict(torch.load(opt.modelIn)) 93 | loss_f = nn.CrossEntropyLoss() 94 | net.cuda() 95 | loss_f.cuda() 96 | transform_train = tfs.Compose([ 97 | tfs.RandomCrop(32, padding=4), 98 | tfs.RandomHorizontalFlip(), 99 | tfs.ToTensor(), 100 | tfs.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 101 | ]) 102 | 103 | transform_test = tfs.Compose([ 104 | tfs.ToTensor(), 105 | tfs.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 106 | ]) 107 | data = dst.CIFAR10("../cifar10_data", download=True, train=True, transform=transform_train) 108 | data_test = dst.CIFAR10("../cifar10_data", download=True, train=False, transform=transform_test) 109 | assert data, data_test 110 | dataloader = DataLoader(data, batch_size=opt.batchSize, shuffle=True, num_workers=2) 111 | dataloader_test = DataLoader(data_test, batch_size=opt.batchSize, shuffle=True, num_workers=2) 112 | for period in range(opt.epoch // 100): 113 | train_other(dataloader, dataloader_test, net, loss_f, opt.lr, opt.method, 100) 114 | opt.lr /= 10 115 | # save model 116 | if opt.modelOut is not None: 117 | torch.save(net.state_dict(), opt.modelOut) 118 | 119 | if __name__ == "__main__": 120 | main() 121 | -------------------------------------------------------------------------------- /robustnet/models/__init__.py: -------------------------------------------------------------------------------- 1 | from .vgg import * 2 | from .dpn import * 3 | from .lenet import * 4 | from .senet import * 5 | from .resnet import * 6 | from .resnext import * 7 | from .densenet import * 8 | from .googlenet import * 9 | from .mobilenet import * 10 | from .shufflenet import * 11 | from .preact_resnet import * 12 | -------------------------------------------------------------------------------- /robustnet/models/densenet.py: -------------------------------------------------------------------------------- 1 | '''DenseNet in PyTorch.''' 2 | import math 3 | 4 | import torch 5 | import torch.nn as nn 6 | import torch.nn.functional as F 7 | 8 | from torch.autograd import Variable 9 | 10 | 11 | class Bottleneck(nn.Module): 12 | def __init__(self, in_planes, growth_rate): 13 | super(Bottleneck, self).__init__() 14 | self.bn1 = nn.BatchNorm2d(in_planes) 15 | self.conv1 = nn.Conv2d(in_planes, 4*growth_rate, kernel_size=1, bias=False) 16 | self.bn2 = nn.BatchNorm2d(4*growth_rate) 17 | self.conv2 = nn.Conv2d(4*growth_rate, growth_rate, kernel_size=3, padding=1, bias=False) 18 | 19 | def forward(self, x): 20 | out = self.conv1(F.relu(self.bn1(x))) 21 | out = self.conv2(F.relu(self.bn2(out))) 22 | out = torch.cat([out,x], 1) 23 | return out 24 | 25 | 26 | class Transition(nn.Module): 27 | def __init__(self, in_planes, out_planes): 28 | super(Transition, self).__init__() 29 | self.bn = nn.BatchNorm2d(in_planes) 30 | self.conv = nn.Conv2d(in_planes, out_planes, kernel_size=1, bias=False) 31 | 32 | def forward(self, x): 33 | out = self.conv(F.relu(self.bn(x))) 34 | out = F.avg_pool2d(out, 2) 35 | return out 36 | 37 | 38 | class DenseNet(nn.Module): 39 | def __init__(self, block, nblocks, growth_rate=12, reduction=0.5, num_classes=10): 40 | super(DenseNet, self).__init__() 41 | self.growth_rate = growth_rate 42 | 43 | num_planes = 2*growth_rate 44 | self.conv1 = nn.Conv2d(3, num_planes, kernel_size=3, padding=1, bias=False) 45 | 46 | self.dense1 = self._make_dense_layers(block, num_planes, nblocks[0]) 47 | num_planes += nblocks[0]*growth_rate 48 | out_planes = int(math.floor(num_planes*reduction)) 49 | self.trans1 = Transition(num_planes, out_planes) 50 | num_planes = out_planes 51 | 52 | self.dense2 = self._make_dense_layers(block, num_planes, nblocks[1]) 53 | num_planes += nblocks[1]*growth_rate 54 | out_planes = int(math.floor(num_planes*reduction)) 55 | self.trans2 = Transition(num_planes, out_planes) 56 | num_planes = out_planes 57 | 58 | self.dense3 = self._make_dense_layers(block, num_planes, nblocks[2]) 59 | num_planes += nblocks[2]*growth_rate 60 | out_planes = int(math.floor(num_planes*reduction)) 61 | self.trans3 = Transition(num_planes, out_planes) 62 | num_planes = out_planes 63 | 64 | self.dense4 = self._make_dense_layers(block, num_planes, nblocks[3]) 65 | num_planes += nblocks[3]*growth_rate 66 | 67 | self.bn = nn.BatchNorm2d(num_planes) 68 | self.linear = nn.Linear(num_planes, num_classes) 69 | 70 | def _make_dense_layers(self, block, in_planes, nblock): 71 | layers = [] 72 | for i in range(nblock): 73 | layers.append(block(in_planes, self.growth_rate)) 74 | in_planes += self.growth_rate 75 | return nn.Sequential(*layers) 76 | 77 | def forward(self, x): 78 | out = self.conv1(x) 79 | out = self.trans1(self.dense1(out)) 80 | out = self.trans2(self.dense2(out)) 81 | out = self.trans3(self.dense3(out)) 82 | out = self.dense4(out) 83 | out = F.avg_pool2d(F.relu(self.bn(out)), 4) 84 | out = out.view(out.size(0), -1) 85 | out = self.linear(out) 86 | return out 87 | 88 | def DenseNet121(): 89 | return DenseNet(Bottleneck, [6,12,24,16], growth_rate=32) 90 | 91 | def DenseNet169(): 92 | return DenseNet(Bottleneck, [6,12,32,32], growth_rate=32) 93 | 94 | def DenseNet201(): 95 | return DenseNet(Bottleneck, [6,12,48,32], growth_rate=32) 96 | 97 | def DenseNet161(): 98 | return DenseNet(Bottleneck, [6,12,36,24], growth_rate=48) 99 | 100 | def densenet_cifar(): 101 | return DenseNet(Bottleneck, [6,12,24,16], growth_rate=12) 102 | 103 | def test_densenet(): 104 | net = densenet_cifar() 105 | x = torch.randn(1,3,32,32) 106 | y = net(Variable(x)) 107 | print(y) 108 | 109 | # test_densenet() 110 | -------------------------------------------------------------------------------- /robustnet/models/dpn.py: -------------------------------------------------------------------------------- 1 | '''Dual Path Networks in PyTorch.''' 2 | import torch 3 | import torch.nn as nn 4 | import torch.nn.functional as F 5 | 6 | from torch.autograd import Variable 7 | 8 | 9 | class Bottleneck(nn.Module): 10 | def __init__(self, last_planes, in_planes, out_planes, dense_depth, stride, first_layer): 11 | super(Bottleneck, self).__init__() 12 | self.out_planes = out_planes 13 | self.dense_depth = dense_depth 14 | 15 | self.conv1 = nn.Conv2d(last_planes, in_planes, kernel_size=1, bias=False) 16 | self.bn1 = nn.BatchNorm2d(in_planes) 17 | self.conv2 = nn.Conv2d(in_planes, in_planes, kernel_size=3, stride=stride, padding=1, groups=32, bias=False) 18 | self.bn2 = nn.BatchNorm2d(in_planes) 19 | self.conv3 = nn.Conv2d(in_planes, out_planes+dense_depth, kernel_size=1, bias=False) 20 | self.bn3 = nn.BatchNorm2d(out_planes+dense_depth) 21 | 22 | self.shortcut = nn.Sequential() 23 | if first_layer: 24 | self.shortcut = nn.Sequential( 25 | nn.Conv2d(last_planes, out_planes+dense_depth, kernel_size=1, stride=stride, bias=False), 26 | nn.BatchNorm2d(out_planes+dense_depth) 27 | ) 28 | 29 | def forward(self, x): 30 | out = F.relu(self.bn1(self.conv1(x))) 31 | out = F.relu(self.bn2(self.conv2(out))) 32 | out = self.bn3(self.conv3(out)) 33 | x = self.shortcut(x) 34 | d = self.out_planes 35 | out = torch.cat([x[:,:d,:,:]+out[:,:d,:,:], x[:,d:,:,:], out[:,d:,:,:]], 1) 36 | out = F.relu(out) 37 | return out 38 | 39 | 40 | class DPN(nn.Module): 41 | def __init__(self, cfg): 42 | super(DPN, self).__init__() 43 | in_planes, out_planes = cfg['in_planes'], cfg['out_planes'] 44 | num_blocks, dense_depth = cfg['num_blocks'], cfg['dense_depth'] 45 | 46 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) 47 | self.bn1 = nn.BatchNorm2d(64) 48 | self.last_planes = 64 49 | self.layer1 = self._make_layer(in_planes[0], out_planes[0], num_blocks[0], dense_depth[0], stride=1) 50 | self.layer2 = self._make_layer(in_planes[1], out_planes[1], num_blocks[1], dense_depth[1], stride=2) 51 | self.layer3 = self._make_layer(in_planes[2], out_planes[2], num_blocks[2], dense_depth[2], stride=2) 52 | self.layer4 = self._make_layer(in_planes[3], out_planes[3], num_blocks[3], dense_depth[3], stride=2) 53 | self.linear = nn.Linear(out_planes[3]+(num_blocks[3]+1)*dense_depth[3], 10) 54 | 55 | def _make_layer(self, in_planes, out_planes, num_blocks, dense_depth, stride): 56 | strides = [stride] + [1]*(num_blocks-1) 57 | layers = [] 58 | for i,stride in enumerate(strides): 59 | layers.append(Bottleneck(self.last_planes, in_planes, out_planes, dense_depth, stride, i==0)) 60 | self.last_planes = out_planes + (i+2) * dense_depth 61 | return nn.Sequential(*layers) 62 | 63 | def forward(self, x): 64 | out = F.relu(self.bn1(self.conv1(x))) 65 | out = self.layer1(out) 66 | out = self.layer2(out) 67 | out = self.layer3(out) 68 | out = self.layer4(out) 69 | out = F.avg_pool2d(out, 4) 70 | out = out.view(out.size(0), -1) 71 | out = self.linear(out) 72 | return out 73 | 74 | 75 | def DPN26(): 76 | cfg = { 77 | 'in_planes': (96,192,384,768), 78 | 'out_planes': (256,512,1024,2048), 79 | 'num_blocks': (2,2,2,2), 80 | 'dense_depth': (16,32,24,128) 81 | } 82 | return DPN(cfg) 83 | 84 | def DPN92(): 85 | cfg = { 86 | 'in_planes': (96,192,384,768), 87 | 'out_planes': (256,512,1024,2048), 88 | 'num_blocks': (3,4,20,3), 89 | 'dense_depth': (16,32,24,128) 90 | } 91 | return DPN(cfg) 92 | 93 | 94 | def test(): 95 | net = DPN92() 96 | x = Variable(torch.randn(1,3,32,32)) 97 | y = net(x) 98 | print(y) 99 | 100 | # test() 101 | -------------------------------------------------------------------------------- /robustnet/models/googlenet.py: -------------------------------------------------------------------------------- 1 | '''GoogLeNet with PyTorch.''' 2 | import torch 3 | import torch.nn as nn 4 | import torch.nn.functional as F 5 | 6 | from torch.autograd import Variable 7 | 8 | 9 | class Inception(nn.Module): 10 | def __init__(self, in_planes, n1x1, n3x3red, n3x3, n5x5red, n5x5, pool_planes): 11 | super(Inception, self).__init__() 12 | # 1x1 conv branch 13 | self.b1 = nn.Sequential( 14 | nn.Conv2d(in_planes, n1x1, kernel_size=1), 15 | nn.BatchNorm2d(n1x1), 16 | nn.ReLU(True), 17 | ) 18 | 19 | # 1x1 conv -> 3x3 conv branch 20 | self.b2 = nn.Sequential( 21 | nn.Conv2d(in_planes, n3x3red, kernel_size=1), 22 | nn.BatchNorm2d(n3x3red), 23 | nn.ReLU(True), 24 | nn.Conv2d(n3x3red, n3x3, kernel_size=3, padding=1), 25 | nn.BatchNorm2d(n3x3), 26 | nn.ReLU(True), 27 | ) 28 | 29 | # 1x1 conv -> 5x5 conv branch 30 | self.b3 = nn.Sequential( 31 | nn.Conv2d(in_planes, n5x5red, kernel_size=1), 32 | nn.BatchNorm2d(n5x5red), 33 | nn.ReLU(True), 34 | nn.Conv2d(n5x5red, n5x5, kernel_size=3, padding=1), 35 | nn.BatchNorm2d(n5x5), 36 | nn.ReLU(True), 37 | nn.Conv2d(n5x5, n5x5, kernel_size=3, padding=1), 38 | nn.BatchNorm2d(n5x5), 39 | nn.ReLU(True), 40 | ) 41 | 42 | # 3x3 pool -> 1x1 conv branch 43 | self.b4 = nn.Sequential( 44 | nn.MaxPool2d(3, stride=1, padding=1), 45 | nn.Conv2d(in_planes, pool_planes, kernel_size=1), 46 | nn.BatchNorm2d(pool_planes), 47 | nn.ReLU(True), 48 | ) 49 | 50 | def forward(self, x): 51 | y1 = self.b1(x) 52 | y2 = self.b2(x) 53 | y3 = self.b3(x) 54 | y4 = self.b4(x) 55 | return torch.cat([y1,y2,y3,y4], 1) 56 | 57 | 58 | class GoogLeNet(nn.Module): 59 | def __init__(self): 60 | super(GoogLeNet, self).__init__() 61 | self.pre_layers = nn.Sequential( 62 | nn.Conv2d(3, 192, kernel_size=3, padding=1), 63 | nn.BatchNorm2d(192), 64 | nn.ReLU(True), 65 | ) 66 | 67 | self.a3 = Inception(192, 64, 96, 128, 16, 32, 32) 68 | self.b3 = Inception(256, 128, 128, 192, 32, 96, 64) 69 | 70 | self.maxpool = nn.MaxPool2d(3, stride=2, padding=1) 71 | 72 | self.a4 = Inception(480, 192, 96, 208, 16, 48, 64) 73 | self.b4 = Inception(512, 160, 112, 224, 24, 64, 64) 74 | self.c4 = Inception(512, 128, 128, 256, 24, 64, 64) 75 | self.d4 = Inception(512, 112, 144, 288, 32, 64, 64) 76 | self.e4 = Inception(528, 256, 160, 320, 32, 128, 128) 77 | 78 | self.a5 = Inception(832, 256, 160, 320, 32, 128, 128) 79 | self.b5 = Inception(832, 384, 192, 384, 48, 128, 128) 80 | 81 | self.avgpool = nn.AvgPool2d(8, stride=1) 82 | self.linear = nn.Linear(1024, 10) 83 | 84 | def forward(self, x): 85 | out = self.pre_layers(x) 86 | out = self.a3(out) 87 | out = self.b3(out) 88 | out = self.maxpool(out) 89 | out = self.a4(out) 90 | out = self.b4(out) 91 | out = self.c4(out) 92 | out = self.d4(out) 93 | out = self.e4(out) 94 | out = self.maxpool(out) 95 | out = self.a5(out) 96 | out = self.b5(out) 97 | out = self.avgpool(out) 98 | out = out.view(out.size(0), -1) 99 | out = self.linear(out) 100 | return out 101 | 102 | # net = GoogLeNet() 103 | # x = torch.randn(1,3,32,32) 104 | # y = net(Variable(x)) 105 | # print(y.size()) 106 | -------------------------------------------------------------------------------- /robustnet/models/layer.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | 4 | class Noise(nn.Module): 5 | def __init__(self, std): 6 | super(Noise, self, ).__init__() 7 | self.std = std 8 | self.buffer = None 9 | 10 | def forward(self, x): 11 | if self.training and self.std > 1.0e-6: 12 | if self.buffer is None: 13 | self.buffer = torch.Tensor(x.size()).normal_(0, self.std).cuda() 14 | else: 15 | self.buffer.resize_(x.size()).normal_(0, self.std) 16 | x.data += self.buffer 17 | return x 18 | 19 | -------------------------------------------------------------------------------- /robustnet/models/lenet.py: -------------------------------------------------------------------------------- 1 | '''LeNet in PyTorch.''' 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | 5 | class LeNet(nn.Module): 6 | def __init__(self): 7 | super(LeNet, self).__init__() 8 | self.conv1 = nn.Conv2d(3, 6, 5) 9 | self.conv2 = nn.Conv2d(6, 16, 5) 10 | self.fc1 = nn.Linear(16*5*5, 120) 11 | self.fc2 = nn.Linear(120, 84) 12 | self.fc3 = nn.Linear(84, 10) 13 | 14 | def forward(self, x): 15 | out = F.relu(self.conv1(x)) 16 | out = F.max_pool2d(out, 2) 17 | out = F.relu(self.conv2(out)) 18 | out = F.max_pool2d(out, 2) 19 | out = out.view(out.size(0), -1) 20 | out = F.relu(self.fc1(out)) 21 | out = F.relu(self.fc2(out)) 22 | out = self.fc3(out) 23 | return out 24 | -------------------------------------------------------------------------------- /robustnet/models/mobilenet.py: -------------------------------------------------------------------------------- 1 | '''MobileNet in PyTorch. 2 | 3 | See the paper "MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications" 4 | for more details. 5 | ''' 6 | import torch 7 | import torch.nn as nn 8 | import torch.nn.functional as F 9 | 10 | from torch.autograd import Variable 11 | 12 | 13 | class Block(nn.Module): 14 | '''Depthwise conv + Pointwise conv''' 15 | def __init__(self, in_planes, out_planes, stride=1): 16 | super(Block, self).__init__() 17 | self.conv1 = nn.Conv2d(in_planes, in_planes, kernel_size=3, stride=stride, padding=1, groups=in_planes, bias=False) 18 | self.bn1 = nn.BatchNorm2d(in_planes) 19 | self.conv2 = nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False) 20 | self.bn2 = nn.BatchNorm2d(out_planes) 21 | 22 | def forward(self, x): 23 | out = F.relu(self.bn1(self.conv1(x))) 24 | out = F.relu(self.bn2(self.conv2(out))) 25 | return out 26 | 27 | 28 | class MobileNet(nn.Module): 29 | # (128,2) means conv planes=128, conv stride=2, by default conv stride=1 30 | cfg = [64, (128,2), 128, (256,2), 256, (512,2), 512, 512, 512, 512, 512, (1024,2), 1024] 31 | 32 | def __init__(self, num_classes=10): 33 | super(MobileNet, self).__init__() 34 | self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1, bias=False) 35 | self.bn1 = nn.BatchNorm2d(32) 36 | self.layers = self._make_layers(in_planes=32) 37 | self.linear = nn.Linear(1024, num_classes) 38 | 39 | def _make_layers(self, in_planes): 40 | layers = [] 41 | for x in self.cfg: 42 | out_planes = x if isinstance(x, int) else x[0] 43 | stride = 1 if isinstance(x, int) else x[1] 44 | layers.append(Block(in_planes, out_planes, stride)) 45 | in_planes = out_planes 46 | return nn.Sequential(*layers) 47 | 48 | def forward(self, x): 49 | out = F.relu(self.bn1(self.conv1(x))) 50 | out = self.layers(out) 51 | out = F.avg_pool2d(out, 2) 52 | out = out.view(out.size(0), -1) 53 | out = self.linear(out) 54 | return out 55 | 56 | 57 | def test(): 58 | net = MobileNet() 59 | x = torch.randn(1,3,32,32) 60 | y = net(Variable(x)) 61 | print(y.size()) 62 | 63 | # test() 64 | -------------------------------------------------------------------------------- /robustnet/models/preact_resnet.py: -------------------------------------------------------------------------------- 1 | '''Pre-activation ResNet in PyTorch. 2 | 3 | Reference: 4 | [1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun 5 | Identity Mappings in Deep Residual Networks. arXiv:1603.05027 6 | ''' 7 | import torch 8 | import torch.nn as nn 9 | import torch.nn.functional as F 10 | 11 | from torch.autograd import Variable 12 | 13 | 14 | class PreActBlock(nn.Module): 15 | '''Pre-activation version of the BasicBlock.''' 16 | expansion = 1 17 | 18 | def __init__(self, in_planes, planes, stride=1): 19 | super(PreActBlock, self).__init__() 20 | self.bn1 = nn.BatchNorm2d(in_planes) 21 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 22 | self.bn2 = nn.BatchNorm2d(planes) 23 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) 24 | 25 | if stride != 1 or in_planes != self.expansion*planes: 26 | self.shortcut = nn.Sequential( 27 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False) 28 | ) 29 | 30 | def forward(self, x): 31 | out = F.relu(self.bn1(x)) 32 | shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x 33 | out = self.conv1(out) 34 | out = self.conv2(F.relu(self.bn2(out))) 35 | out += shortcut 36 | return out 37 | 38 | 39 | class PreActBottleneck(nn.Module): 40 | '''Pre-activation version of the original Bottleneck module.''' 41 | expansion = 4 42 | 43 | def __init__(self, in_planes, planes, stride=1): 44 | super(PreActBottleneck, self).__init__() 45 | self.bn1 = nn.BatchNorm2d(in_planes) 46 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False) 47 | self.bn2 = nn.BatchNorm2d(planes) 48 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 49 | self.bn3 = nn.BatchNorm2d(planes) 50 | self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False) 51 | 52 | if stride != 1 or in_planes != self.expansion*planes: 53 | self.shortcut = nn.Sequential( 54 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False) 55 | ) 56 | 57 | def forward(self, x): 58 | out = F.relu(self.bn1(x)) 59 | shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x 60 | out = self.conv1(out) 61 | out = self.conv2(F.relu(self.bn2(out))) 62 | out = self.conv3(F.relu(self.bn3(out))) 63 | out += shortcut 64 | return out 65 | 66 | 67 | class PreActResNet(nn.Module): 68 | def __init__(self, block, num_blocks, num_classes=10): 69 | super(PreActResNet, self).__init__() 70 | self.in_planes = 64 71 | 72 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) 73 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) 74 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) 75 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) 76 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) 77 | self.linear = nn.Linear(512*block.expansion, num_classes) 78 | 79 | def _make_layer(self, block, planes, num_blocks, stride): 80 | strides = [stride] + [1]*(num_blocks-1) 81 | layers = [] 82 | for stride in strides: 83 | layers.append(block(self.in_planes, planes, stride)) 84 | self.in_planes = planes * block.expansion 85 | return nn.Sequential(*layers) 86 | 87 | def forward(self, x): 88 | out = self.conv1(x) 89 | out = self.layer1(out) 90 | out = self.layer2(out) 91 | out = self.layer3(out) 92 | out = self.layer4(out) 93 | out = F.avg_pool2d(out, 4) 94 | out = out.view(out.size(0), -1) 95 | out = self.linear(out) 96 | return out 97 | 98 | 99 | def PreActResNet18(): 100 | return PreActResNet(PreActBlock, [2,2,2,2]) 101 | 102 | def PreActResNet34(): 103 | return PreActResNet(PreActBlock, [3,4,6,3]) 104 | 105 | def PreActResNet50(): 106 | return PreActResNet(PreActBottleneck, [3,4,6,3]) 107 | 108 | def PreActResNet101(): 109 | return PreActResNet(PreActBottleneck, [3,4,23,3]) 110 | 111 | def PreActResNet152(): 112 | return PreActResNet(PreActBottleneck, [3,8,36,3]) 113 | 114 | 115 | def test(): 116 | net = PreActResNet18() 117 | y = net(Variable(torch.randn(1,3,32,32))) 118 | print(y.size()) 119 | 120 | # test() 121 | -------------------------------------------------------------------------------- /robustnet/models/resnet.py: -------------------------------------------------------------------------------- 1 | '''ResNet in PyTorch. 2 | 3 | For Pre-activation ResNet, see 'preact_resnet.py'. 4 | 5 | Reference: 6 | [1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun 7 | Deep Residual Learning for Image Recognition. arXiv:1512.03385 8 | ''' 9 | import torch 10 | import torch.nn as nn 11 | import torch.nn.functional as F 12 | 13 | from torch.autograd import Variable 14 | 15 | 16 | class BasicBlock(nn.Module): 17 | expansion = 1 18 | 19 | def __init__(self, in_planes, planes, stride=1): 20 | super(BasicBlock, self).__init__() 21 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 22 | self.bn1 = nn.BatchNorm2d(planes) 23 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) 24 | self.bn2 = nn.BatchNorm2d(planes) 25 | 26 | self.shortcut = nn.Sequential() 27 | if stride != 1 or in_planes != self.expansion*planes: 28 | self.shortcut = nn.Sequential( 29 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), 30 | nn.BatchNorm2d(self.expansion*planes) 31 | ) 32 | 33 | def forward(self, x): 34 | out = F.relu(self.bn1(self.conv1(x))) 35 | out = self.bn2(self.conv2(out)) 36 | out += self.shortcut(x) 37 | out = F.relu(out) 38 | return out 39 | 40 | 41 | class Bottleneck(nn.Module): 42 | expansion = 4 43 | 44 | def __init__(self, in_planes, planes, stride=1): 45 | super(Bottleneck, self).__init__() 46 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False) 47 | self.bn1 = nn.BatchNorm2d(planes) 48 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 49 | self.bn2 = nn.BatchNorm2d(planes) 50 | self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False) 51 | self.bn3 = nn.BatchNorm2d(self.expansion*planes) 52 | 53 | self.shortcut = nn.Sequential() 54 | if stride != 1 or in_planes != self.expansion*planes: 55 | self.shortcut = nn.Sequential( 56 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), 57 | nn.BatchNorm2d(self.expansion*planes) 58 | ) 59 | 60 | def forward(self, x): 61 | out = F.relu(self.bn1(self.conv1(x))) 62 | out = F.relu(self.bn2(self.conv2(out))) 63 | out = self.bn3(self.conv3(out)) 64 | out += self.shortcut(x) 65 | out = F.relu(out) 66 | return out 67 | 68 | 69 | class ResNet(nn.Module): 70 | def __init__(self, block, num_blocks, num_classes=10): 71 | super(ResNet, self).__init__() 72 | self.in_planes = 64 73 | 74 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) 75 | self.bn1 = nn.BatchNorm2d(64) 76 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) 77 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) 78 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) 79 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) 80 | self.linear = nn.Linear(512*block.expansion, num_classes) 81 | 82 | def _make_layer(self, block, planes, num_blocks, stride): 83 | strides = [stride] + [1]*(num_blocks-1) 84 | layers = [] 85 | for stride in strides: 86 | layers.append(block(self.in_planes, planes, stride)) 87 | self.in_planes = planes * block.expansion 88 | return nn.Sequential(*layers) 89 | 90 | def forward(self, x): 91 | out = F.relu(self.bn1(self.conv1(x))) 92 | out = self.layer1(out) 93 | out = self.layer2(out) 94 | out = self.layer3(out) 95 | out = self.layer4(out) 96 | out = F.avg_pool2d(out, 4) 97 | out = out.view(out.size(0), -1) 98 | out = self.linear(out) 99 | return out 100 | 101 | 102 | def ResNet18(): 103 | return ResNet(BasicBlock, [2,2,2,2]) 104 | 105 | def ResNet34(): 106 | return ResNet(BasicBlock, [3,4,6,3]) 107 | 108 | def ResNet50(): 109 | return ResNet(Bottleneck, [3,4,6,3]) 110 | 111 | def ResNet101(): 112 | return ResNet(Bottleneck, [3,4,23,3]) 113 | 114 | def ResNet152(): 115 | return ResNet(Bottleneck, [3,8,36,3]) 116 | 117 | 118 | def test(): 119 | net = ResNet18() 120 | y = net(Variable(torch.randn(1,3,32,32))) 121 | print(y.size()) 122 | 123 | # test() 124 | -------------------------------------------------------------------------------- /robustnet/models/resnext.py: -------------------------------------------------------------------------------- 1 | '''ResNeXt in PyTorch. 2 | 3 | See the paper "Aggregated Residual Transformations for Deep Neural Networks" for more details. 4 | ''' 5 | import torch 6 | import torch.nn as nn 7 | import torch.nn.functional as F 8 | 9 | from torch.autograd import Variable 10 | from . import layer 11 | 12 | Noise = layer.Noise 13 | 14 | class Block(nn.Module): 15 | '''Grouped convolution block.''' 16 | expansion = 2 17 | 18 | def __init__(self, in_planes, cardinality=32, bottleneck_width=4, stride=1): 19 | super(Block, self).__init__() 20 | group_width = cardinality * bottleneck_width 21 | self.conv1 = nn.Conv2d(in_planes, group_width, kernel_size=1, bias=False) 22 | self.bn1 = nn.BatchNorm2d(group_width) 23 | self.conv2 = nn.Conv2d(group_width, group_width, kernel_size=3, stride=stride, padding=1, groups=cardinality, bias=False) 24 | self.bn2 = nn.BatchNorm2d(group_width) 25 | self.conv3 = nn.Conv2d(group_width, self.expansion*group_width, kernel_size=1, bias=False) 26 | self.bn3 = nn.BatchNorm2d(self.expansion*group_width) 27 | 28 | self.shortcut = nn.Sequential() 29 | if stride != 1 or in_planes != self.expansion*group_width: 30 | self.shortcut = nn.Sequential( 31 | nn.Conv2d(in_planes, self.expansion*group_width, kernel_size=1, stride=stride, bias=False), 32 | nn.BatchNorm2d(self.expansion*group_width) 33 | ) 34 | 35 | def forward(self, x): 36 | out = F.relu(self.bn1(self.conv1(x))) 37 | out = F.relu(self.bn2(self.conv2(out))) 38 | out = self.bn3(self.conv3(out)) 39 | out += self.shortcut(x) 40 | out = F.relu(out) 41 | return out 42 | 43 | 44 | class ResNeXt(nn.Module): 45 | def __init__(self, num_blocks, cardinality, bottleneck_width, num_classes=10): 46 | super(ResNeXt, self).__init__() 47 | self.cardinality = cardinality 48 | self.bottleneck_width = bottleneck_width 49 | self.in_planes = 64 50 | 51 | self.conv1 = nn.Conv2d(3, 64, kernel_size=1, bias=False) 52 | self.bn1 = nn.BatchNorm2d(64) 53 | self.layer1 = self._make_layer(num_blocks[0], 1) 54 | self.layer2 = self._make_layer(num_blocks[1], 2) 55 | self.layer3 = self._make_layer(num_blocks[2], 2) 56 | # self.layer4 = self._make_layer(num_blocks[3], 2) 57 | self.linear = nn.Linear(cardinality*bottleneck_width*8, num_classes) 58 | 59 | def _make_layer(self, num_blocks, stride): 60 | strides = [stride] + [1]*(num_blocks-1) 61 | layers = [] 62 | for stride in strides: 63 | layers.append(Block(self.in_planes, self.cardinality, self.bottleneck_width, stride)) 64 | self.in_planes = Block.expansion * self.cardinality * self.bottleneck_width 65 | # Increase bottleneck_width by 2 after each stage. 66 | self.bottleneck_width *= 2 67 | return nn.Sequential(*layers) 68 | 69 | def forward(self, x): 70 | out = F.relu(self.bn1(self.conv1(x))) 71 | out = self.layer1(out) 72 | out = self.layer2(out) 73 | out = self.layer3(out) 74 | # out = self.layer4(out) 75 | out = F.avg_pool2d(out, 8) 76 | out = out.view(out.size(0), -1) 77 | out = self.linear(out) 78 | return out 79 | 80 | 81 | def ResNeXt29_2x64d(): 82 | return ResNeXt(num_blocks=[3,3,3], cardinality=2, bottleneck_width=64) 83 | 84 | def ResNeXt29_4x64d(): 85 | return ResNeXt(num_blocks=[3,3,3], cardinality=4, bottleneck_width=64) 86 | 87 | def ResNeXt29_8x64d(): 88 | return ResNeXt(num_blocks=[3,3,3], cardinality=8, bottleneck_width=64) 89 | 90 | def ResNeXt29_32x4d(): 91 | return ResNeXt(num_blocks=[3,3,3], cardinality=32, bottleneck_width=4) 92 | 93 | def test_resnext(): 94 | net = ResNeXt29_2x64d() 95 | x = torch.randn(1,3,32,32) 96 | y = net(Variable(x)) 97 | print(y.size()) 98 | 99 | # test_resnext() 100 | -------------------------------------------------------------------------------- /robustnet/models/senet.py: -------------------------------------------------------------------------------- 1 | '''SENet in PyTorch. 2 | 3 | SENet is the winner of ImageNet-2017. The paper is not released yet. 4 | ''' 5 | import torch 6 | import torch.nn as nn 7 | import torch.nn.functional as F 8 | 9 | from torch.autograd import Variable 10 | 11 | 12 | class BasicBlock(nn.Module): 13 | def __init__(self, in_planes, planes, stride=1): 14 | super(BasicBlock, self).__init__() 15 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 16 | self.bn1 = nn.BatchNorm2d(planes) 17 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) 18 | self.bn2 = nn.BatchNorm2d(planes) 19 | 20 | self.shortcut = nn.Sequential() 21 | if stride != 1 or in_planes != planes: 22 | self.shortcut = nn.Sequential( 23 | nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride, bias=False), 24 | nn.BatchNorm2d(planes) 25 | ) 26 | 27 | # SE layers 28 | self.fc1 = nn.Conv2d(planes, planes//16, kernel_size=1) # Use nn.Conv2d instead of nn.Linear 29 | self.fc2 = nn.Conv2d(planes//16, planes, kernel_size=1) 30 | 31 | def forward(self, x): 32 | out = F.relu(self.bn1(self.conv1(x))) 33 | out = self.bn2(self.conv2(out)) 34 | 35 | # Squeeze 36 | w = F.avg_pool2d(out, out.size(2)) 37 | w = F.relu(self.fc1(w)) 38 | w = F.sigmoid(self.fc2(w)) 39 | # Excitation 40 | out = out * w # New broadcasting feature from v0.2! 41 | 42 | out += self.shortcut(x) 43 | out = F.relu(out) 44 | return out 45 | 46 | 47 | class PreActBlock(nn.Module): 48 | def __init__(self, in_planes, planes, stride=1): 49 | super(PreActBlock, self).__init__() 50 | self.bn1 = nn.BatchNorm2d(in_planes) 51 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 52 | self.bn2 = nn.BatchNorm2d(planes) 53 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) 54 | 55 | if stride != 1 or in_planes != planes: 56 | self.shortcut = nn.Sequential( 57 | nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride, bias=False) 58 | ) 59 | 60 | # SE layers 61 | self.fc1 = nn.Conv2d(planes, planes//16, kernel_size=1) 62 | self.fc2 = nn.Conv2d(planes//16, planes, kernel_size=1) 63 | 64 | def forward(self, x): 65 | out = F.relu(self.bn1(x)) 66 | shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x 67 | out = self.conv1(out) 68 | out = self.conv2(F.relu(self.bn2(out))) 69 | 70 | # Squeeze 71 | w = F.avg_pool2d(out, out.size(2)) 72 | w = F.relu(self.fc1(w)) 73 | w = F.sigmoid(self.fc2(w)) 74 | # Excitation 75 | out = out * w 76 | 77 | out += shortcut 78 | return out 79 | 80 | 81 | class SENet(nn.Module): 82 | def __init__(self, block, num_blocks, num_classes=10): 83 | super(SENet, self).__init__() 84 | self.in_planes = 64 85 | 86 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) 87 | self.bn1 = nn.BatchNorm2d(64) 88 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) 89 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) 90 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) 91 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) 92 | self.linear = nn.Linear(512, num_classes) 93 | 94 | def _make_layer(self, block, planes, num_blocks, stride): 95 | strides = [stride] + [1]*(num_blocks-1) 96 | layers = [] 97 | for stride in strides: 98 | layers.append(block(self.in_planes, planes, stride)) 99 | self.in_planes = planes 100 | return nn.Sequential(*layers) 101 | 102 | def forward(self, x): 103 | out = F.relu(self.bn1(self.conv1(x))) 104 | out = self.layer1(out) 105 | out = self.layer2(out) 106 | out = self.layer3(out) 107 | out = self.layer4(out) 108 | out = F.avg_pool2d(out, 4) 109 | out = out.view(out.size(0), -1) 110 | out = self.linear(out) 111 | return out 112 | 113 | 114 | def SENet18(): 115 | return SENet(PreActBlock, [2,2,2,2]) 116 | 117 | 118 | def test(): 119 | net = SENet18() 120 | y = net(Variable(torch.randn(1,3,32,32))) 121 | print(y.size()) 122 | 123 | # test() 124 | -------------------------------------------------------------------------------- /robustnet/models/shufflenet.py: -------------------------------------------------------------------------------- 1 | '''ShuffleNet in PyTorch. 2 | 3 | See the paper "ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile Devices" for more details. 4 | ''' 5 | import torch 6 | import torch.nn as nn 7 | import torch.nn.functional as F 8 | 9 | from torch.autograd import Variable 10 | 11 | 12 | class ShuffleBlock(nn.Module): 13 | def __init__(self, groups): 14 | super(ShuffleBlock, self).__init__() 15 | self.groups = groups 16 | 17 | def forward(self, x): 18 | '''Channel shuffle: [N,C,H,W] -> [N,g,C/g,H,W] -> [N,C/g,g,H,w] -> [N,C,H,W]''' 19 | N,C,H,W = x.size() 20 | g = self.groups 21 | return x.view(N,g,C/g,H,W).permute(0,2,1,3,4).contiguous().view(N,C,H,W) 22 | 23 | 24 | class Bottleneck(nn.Module): 25 | def __init__(self, in_planes, out_planes, stride, groups): 26 | super(Bottleneck, self).__init__() 27 | self.stride = stride 28 | 29 | mid_planes = out_planes/4 30 | g = 1 if in_planes==24 else groups 31 | self.conv1 = nn.Conv2d(in_planes, mid_planes, kernel_size=1, groups=g, bias=False) 32 | self.bn1 = nn.BatchNorm2d(mid_planes) 33 | self.shuffle1 = ShuffleBlock(groups=g) 34 | self.conv2 = nn.Conv2d(mid_planes, mid_planes, kernel_size=3, stride=stride, padding=1, groups=mid_planes, bias=False) 35 | self.bn2 = nn.BatchNorm2d(mid_planes) 36 | self.conv3 = nn.Conv2d(mid_planes, out_planes, kernel_size=1, groups=groups, bias=False) 37 | self.bn3 = nn.BatchNorm2d(out_planes) 38 | 39 | self.shortcut = nn.Sequential() 40 | if stride == 2: 41 | self.shortcut = nn.Sequential(nn.AvgPool2d(3, stride=2, padding=1)) 42 | 43 | def forward(self, x): 44 | out = F.relu(self.bn1(self.conv1(x))) 45 | out = self.shuffle1(out) 46 | out = F.relu(self.bn2(self.conv2(out))) 47 | out = self.bn3(self.conv3(out)) 48 | res = self.shortcut(x) 49 | out = F.relu(torch.cat([out,res], 1)) if self.stride==2 else F.relu(out+res) 50 | return out 51 | 52 | 53 | class ShuffleNet(nn.Module): 54 | def __init__(self, cfg): 55 | super(ShuffleNet, self).__init__() 56 | out_planes = cfg['out_planes'] 57 | num_blocks = cfg['num_blocks'] 58 | groups = cfg['groups'] 59 | 60 | self.conv1 = nn.Conv2d(3, 24, kernel_size=1, bias=False) 61 | self.bn1 = nn.BatchNorm2d(24) 62 | self.in_planes = 24 63 | self.layer1 = self._make_layer(out_planes[0], num_blocks[0], groups) 64 | self.layer2 = self._make_layer(out_planes[1], num_blocks[1], groups) 65 | self.layer3 = self._make_layer(out_planes[2], num_blocks[2], groups) 66 | self.linear = nn.Linear(out_planes[2], 10) 67 | 68 | def _make_layer(self, out_planes, num_blocks, groups): 69 | layers = [] 70 | for i in range(num_blocks): 71 | stride = 2 if i == 0 else 1 72 | cat_planes = self.in_planes if i == 0 else 0 73 | layers.append(Bottleneck(self.in_planes, out_planes-cat_planes, stride=stride, groups=groups)) 74 | self.in_planes = out_planes 75 | return nn.Sequential(*layers) 76 | 77 | def forward(self, x): 78 | out = F.relu(self.bn1(self.conv1(x))) 79 | out = self.layer1(out) 80 | out = self.layer2(out) 81 | out = self.layer3(out) 82 | out = F.avg_pool2d(out, 4) 83 | out = out.view(out.size(0), -1) 84 | out = self.linear(out) 85 | return out 86 | 87 | 88 | def ShuffleNetG2(): 89 | cfg = { 90 | 'out_planes': [200,400,800], 91 | 'num_blocks': [4,8,4], 92 | 'groups': 2 93 | } 94 | return ShuffleNet(cfg) 95 | 96 | def ShuffleNetG3(): 97 | cfg = { 98 | 'out_planes': [240,480,960], 99 | 'num_blocks': [4,8,4], 100 | 'groups': 3 101 | } 102 | return ShuffleNet(cfg) 103 | 104 | 105 | def test(): 106 | net = ShuffleNetG2() 107 | x = Variable(torch.randn(1,3,32,32)) 108 | y = net(x) 109 | print(y) 110 | 111 | # test() 112 | -------------------------------------------------------------------------------- /robustnet/models/vgg.py: -------------------------------------------------------------------------------- 1 | '''VGG11/13/16/19 in Pytorch.''' 2 | import torch 3 | import torch.nn as nn 4 | from torch.autograd import Variable 5 | from . import layer 6 | 7 | Noise = layer.Noise 8 | 9 | cfg = { 10 | 'VGG11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'], 11 | 'VGG13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'], 12 | 'VGG16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'], 13 | 'VGG19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'], 14 | } 15 | 16 | 17 | class VGG(nn.Module): 18 | def __init__(self, vgg_name, std): 19 | super(VGG, self).__init__() 20 | self.std = std 21 | self.features = self._make_layers(cfg[vgg_name]) 22 | self.classifier = nn.Linear(512, 10) 23 | self.init_noise = Noise(std) 24 | 25 | def forward(self, x): 26 | out = self.features(x) 27 | out = out.view(out.size(0), -1) 28 | out = self.init_noise(out) 29 | out = self.classifier(out) 30 | return out 31 | 32 | def _make_layers(self, cfg): 33 | layers = [] 34 | in_channels = 3 35 | for x in cfg: 36 | if x == 'M': 37 | layers += [nn.MaxPool2d(kernel_size=2, stride=2)] 38 | else: 39 | layers += [nn.Conv2d(in_channels, x, kernel_size=3, padding=1), 40 | Noise(self.std), 41 | nn.BatchNorm2d(x), 42 | nn.ReLU(inplace=True)] 43 | in_channels = x 44 | layers += [nn.AvgPool2d(kernel_size=1, stride=1)] 45 | return nn.Sequential(*layers) 46 | 47 | # net = VGG('VGG11') 48 | # x = torch.randn(2,3,32,32) 49 | # print(net(Variable(x)).size()) 50 | -------------------------------------------------------------------------------- /robustnet/plot_accu.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | 7 | def parse_line(l): 8 | train = float(l.split(',')[2].split(':')[1].strip()) 9 | test = float(l.split(',')[4].split(':')[1].strip()) 10 | return train, test 11 | 12 | def read_f(fn): 13 | train_noise = [] 14 | test_noise = [] 15 | for l in open(fn, 'r'): 16 | if l[0] != '[': 17 | continue 18 | train, test = parse_line(l) 19 | train_noise.append(train) 20 | test_noise.append(test) 21 | return train_noise, test_noise 22 | 23 | 24 | def data(): 25 | model = "./vgg16/" 26 | noise_level = ["0", "0.1", "0.2", "0.3"] 27 | level_color = ['firebrick', 'olivedrab', 'deepskyblue', 'darkorchid'] 28 | dataf = [model + 'log_noise_{}.txt'.format(level) for level in noise_level] 29 | data = {} 30 | for i, level in enumerate(noise_level): 31 | data_level = {'train': [], 'test': []} 32 | f = dataf[i] 33 | train_noise, test_noise = read_f(f) 34 | data_level['train'] = train_noise 35 | data_level['test'] = test_noise 36 | data[level] = data_level 37 | 38 | for col, level in zip(level_color, noise_level): 39 | plt.plot(100 - 100 * np.array(data[level]['train']), color=col, linestyle='-', label='train, noise='+level) 40 | plt.plot(100 - 100 * np.array(data[level]['test']), color=col, linestyle='--', label='test, noise='+level) 41 | plt.legend() 42 | plt.ylim(0, 30) 43 | plt.show() 44 | 45 | if __name__ == "__main__": 46 | data() 47 | -------------------------------------------------------------------------------- /robustnet/run.sh: -------------------------------------------------------------------------------- 1 | model=vgg16 2 | noise=0.3 3 | CUDA_VISIBLE_DEVICES=3 ./main2.py --lr 0.1 --noise ${noise} --modelOut ./${model}/noise_${noise}.pth > ./${model}/log_noise_${noise}.txt 4 | 5 | -------------------------------------------------------------------------------- /robustnet/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import numpy as np 5 | import torch 6 | import torch.optim as optim 7 | import torch.nn as nn 8 | from torch.autograd import Variable 9 | import torchvision.datasets as dst 10 | import torchvision.transforms as tfs 11 | from models import * 12 | from torch.utils.data import DataLoader 13 | import time 14 | 15 | def accuracy(dataloader, net): 16 | data_iter = iter(dataloader) 17 | count = 0 18 | total = 0 19 | for x, y in data_iter: 20 | vx = Variable(x, volatile=True).cuda() 21 | tmp = torch.sum(torch.eq(y.cuda(), torch.max(net(vx), dim=1)[1]).data) 22 | count += int(tmp) 23 | total += y.size()[0] 24 | return count / total 25 | 26 | def loss(dataloader, net, loss_f): 27 | data_iter = iter(dataloader) 28 | total_loss = 0.0 29 | count = 0 30 | for x, y in data_iter: 31 | vx = Variable(x, volatile=True).cuda() 32 | vy = Variable(y).cuda() 33 | total_loss += torch.sum(loss_f(net(vx), vy).data) 34 | count += y.size()[0] 35 | return total_loss / count 36 | 37 | def train_other(dataloader_test, net, loss_f, lr, name='adam', max_epoch=10): 38 | run_time = 0.0 39 | for epoch in range(max_epoch): 40 | beg = time.time() 41 | run_time += time.time() - beg 42 | print("[Epoch {}] Time: {}, Test loss: {}, Test accuracy: {}".format(epoch, run_time, loss(dataloader_test, net, loss_f), accuracy(dataloader_test, net))) 43 | 44 | 45 | def weights_init(m): 46 | classname = m.__class__.__name__ 47 | if classname.find('Linear') != -1: 48 | m.weight.data.normal_(0.0, 0.02) 49 | elif classname.find('Conv') != -1: 50 | m.weight.data.normal_(0.0, 0.02) 51 | elif classname.find('BatchNorm') != -1 and m.affine: 52 | m.weight.data.normal_(1.0, 0.02) 53 | m.bias.data.fill_(0) 54 | 55 | def main(): 56 | parser = argparse.ArgumentParser() 57 | parser.add_argument('--batchSize', type=int, default=20) 58 | parser.add_argument('--epoch', type=int, default=300) 59 | parser.add_argument('--lr', type=float, default=1.0) 60 | parser.add_argument('--ngpu', type=int, default=1) 61 | parser.add_argument('--modelIn', type=str, default=None) 62 | parser.add_argument('--modelOut', type=str, default=None) 63 | parser.add_argument('--method', type=str, default="momsgd") 64 | parser.add_argument('--noise', type=float, default=0.0) 65 | opt = parser.parse_args() 66 | print(opt) 67 | net = VGG("VGG16", opt.noise) 68 | #net = densenet_cifar() 69 | #net = GoogLeNet() 70 | #net = MobileNet(num_classes=100) 71 | #net = stl10(32) 72 | net = nn.DataParallel(net, device_ids=range(opt.ngpu)) 73 | #net = Test() 74 | net.apply(weights_init) 75 | if opt.modelIn is not None: 76 | net.load_state_dict(torch.load(opt.modelIn)) 77 | loss_f = nn.CrossEntropyLoss() 78 | net.cuda() 79 | loss_f.cuda() 80 | 81 | net.eval() 82 | transform_test = tfs.Compose([ 83 | tfs.ToTensor(), 84 | tfs.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 85 | ]) 86 | 87 | data_test = dst.CIFAR10("../cifar10_data", download=True, train=False, transform=transform_test) 88 | assert data_test 89 | dataloader_test = DataLoader(data_test, batch_size=opt.batchSize, shuffle=False, num_workers=2) 90 | for period in range(opt.epoch // 100): 91 | train_other(dataloader_test, net, loss_f, opt.lr, opt.method, 100) 92 | opt.lr /= 10 93 | # save model 94 | if opt.modelOut is not None: 95 | torch.save(net.state_dict(), opt.modelOut) 96 | 97 | if __name__ == "__main__": 98 | main() 99 | -------------------------------------------------------------------------------- /robustnet/utils.py: -------------------------------------------------------------------------------- 1 | '''Some helper functions for PyTorch, including: 2 | - get_mean_and_std: calculate the mean and std value of dataset. 3 | - msr_init: net parameter initialization. 4 | - progress_bar: progress bar mimic xlua.progress. 5 | ''' 6 | import os 7 | import sys 8 | import time 9 | import math 10 | 11 | import torch.nn as nn 12 | import torch.nn.init as init 13 | 14 | 15 | def get_mean_and_std(dataset): 16 | '''Compute the mean and std value of dataset.''' 17 | dataloader = torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=True, num_workers=2) 18 | mean = torch.zeros(3) 19 | std = torch.zeros(3) 20 | print('==> Computing mean and std..') 21 | for inputs, targets in dataloader: 22 | for i in range(3): 23 | mean[i] += inputs[:,i,:,:].mean() 24 | std[i] += inputs[:,i,:,:].std() 25 | mean.div_(len(dataset)) 26 | std.div_(len(dataset)) 27 | return mean, std 28 | 29 | def init_params(net): 30 | '''Init layer parameters.''' 31 | for m in net.modules(): 32 | if isinstance(m, nn.Conv2d): 33 | init.kaiming_normal(m.weight, mode='fan_out') 34 | if m.bias: 35 | init.constant(m.bias, 0) 36 | elif isinstance(m, nn.BatchNorm2d): 37 | init.constant(m.weight, 1) 38 | init.constant(m.bias, 0) 39 | elif isinstance(m, nn.Linear): 40 | init.normal(m.weight, std=1e-3) 41 | if m.bias: 42 | init.constant(m.bias, 0) 43 | 44 | 45 | 46 | TOTAL_BAR_LENGTH = 65. 47 | last_time = time.time() 48 | begin_time = last_time 49 | 50 | def format_time(seconds): 51 | days = int(seconds / 3600/24) 52 | seconds = seconds - days*3600*24 53 | hours = int(seconds / 3600) 54 | seconds = seconds - hours*3600 55 | minutes = int(seconds / 60) 56 | seconds = seconds - minutes*60 57 | secondsf = int(seconds) 58 | seconds = seconds - secondsf 59 | millis = int(seconds*1000) 60 | 61 | f = '' 62 | i = 1 63 | if days > 0: 64 | f += str(days) + 'D' 65 | i += 1 66 | if hours > 0 and i <= 2: 67 | f += str(hours) + 'h' 68 | i += 1 69 | if minutes > 0 and i <= 2: 70 | f += str(minutes) + 'm' 71 | i += 1 72 | if secondsf > 0 and i <= 2: 73 | f += str(secondsf) + 's' 74 | i += 1 75 | if millis > 0 and i <= 2: 76 | f += str(millis) + 'ms' 77 | i += 1 78 | if f == '': 79 | f = '0ms' 80 | return f 81 | -------------------------------------------------------------------------------- /robustnet/utils2.py: -------------------------------------------------------------------------------- 1 | '''Some helper functions for PyTorch, including: 2 | - get_mean_and_std: calculate the mean and std value of dataset. 3 | - msr_init: net parameter initialization. 4 | - progress_bar: progress bar mimic xlua.progress. 5 | ''' 6 | import os 7 | import sys 8 | import time 9 | import math 10 | 11 | import torch.nn as nn 12 | import torch.nn.init as init 13 | 14 | 15 | def get_mean_and_std(dataset): 16 | '''Compute the mean and std value of dataset.''' 17 | dataloader = torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=True, num_workers=2) 18 | mean = torch.zeros(3) 19 | std = torch.zeros(3) 20 | print('==> Computing mean and std..') 21 | for inputs, targets in dataloader: 22 | for i in range(3): 23 | mean[i] += inputs[:,i,:,:].mean() 24 | std[i] += inputs[:,i,:,:].std() 25 | mean.div_(len(dataset)) 26 | std.div_(len(dataset)) 27 | return mean, std 28 | 29 | def init_params(net): 30 | '''Init layer parameters.''' 31 | for m in net.modules(): 32 | if isinstance(m, nn.Conv2d): 33 | init.kaiming_normal(m.weight, mode='fan_out') 34 | if m.bias: 35 | init.constant(m.bias, 0) 36 | elif isinstance(m, nn.BatchNorm2d): 37 | init.constant(m.weight, 1) 38 | init.constant(m.bias, 0) 39 | elif isinstance(m, nn.Linear): 40 | init.normal(m.weight, std=1e-3) 41 | if m.bias: 42 | init.constant(m.bias, 0) 43 | 44 | 45 | _, term_width = os.popen('stty size', 'r').read().split() 46 | term_width = int(term_width) 47 | 48 | TOTAL_BAR_LENGTH = 65. 49 | last_time = time.time() 50 | begin_time = last_time 51 | def progress_bar(current, total, msg=None): 52 | global last_time, begin_time 53 | if current == 0: 54 | begin_time = time.time() # Reset for new bar. 55 | 56 | cur_len = int(TOTAL_BAR_LENGTH*current/total) 57 | rest_len = int(TOTAL_BAR_LENGTH - cur_len) - 1 58 | 59 | sys.stdout.write(' [') 60 | for i in range(cur_len): 61 | sys.stdout.write('=') 62 | sys.stdout.write('>') 63 | for i in range(rest_len): 64 | sys.stdout.write('.') 65 | sys.stdout.write(']') 66 | 67 | cur_time = time.time() 68 | step_time = cur_time - last_time 69 | last_time = cur_time 70 | tot_time = cur_time - begin_time 71 | 72 | L = [] 73 | L.append(' Step: %s' % format_time(step_time)) 74 | L.append(' | Tot: %s' % format_time(tot_time)) 75 | if msg: 76 | L.append(' | ' + msg) 77 | 78 | msg = ''.join(L) 79 | sys.stdout.write(msg) 80 | for i in range(term_width-int(TOTAL_BAR_LENGTH)-len(msg)-3): 81 | sys.stdout.write(' ') 82 | 83 | # Go back to the center of the bar. 84 | for i in range(term_width-int(TOTAL_BAR_LENGTH/2)+2): 85 | sys.stdout.write('\b') 86 | sys.stdout.write(' %d/%d ' % (current+1, total)) 87 | 88 | if current < total-1: 89 | sys.stdout.write('\r') 90 | else: 91 | sys.stdout.write('\n') 92 | sys.stdout.flush() 93 | 94 | def format_time(seconds): 95 | days = int(seconds / 3600/24) 96 | seconds = seconds - days*3600*24 97 | hours = int(seconds / 3600) 98 | seconds = seconds - hours*3600 99 | minutes = int(seconds / 60) 100 | seconds = seconds - minutes*60 101 | secondsf = int(seconds) 102 | seconds = seconds - secondsf 103 | millis = int(seconds*1000) 104 | 105 | f = '' 106 | i = 1 107 | if days > 0: 108 | f += str(days) + 'D' 109 | i += 1 110 | if hours > 0 and i <= 2: 111 | f += str(hours) + 'h' 112 | i += 1 113 | if minutes > 0 and i <= 2: 114 | f += str(minutes) + 'm' 115 | i += 1 116 | if secondsf > 0 and i <= 2: 117 | f += str(secondsf) + 's' 118 | i += 1 119 | if millis > 0 and i <= 2: 120 | f += str(millis) + 'ms' 121 | i += 1 122 | if f == '': 123 | f = '0ms' 124 | return f 125 | -------------------------------------------------------------------------------- /sap/README.md: -------------------------------------------------------------------------------- 1 | # Stochastic activation pruning for robust adversarial defense 2 | 3 | Paper: [Dhillon et al. 2018](https://openreview.net/pdf?id=H1uR4GZRZ) 4 | ## Requirements 5 | 6 | * Python3 + tensorflow 7 | 8 | ## [NATTACK] evaluation 9 | 10 | Run with: 11 | 12 | ```bash 13 | python re_li_attack.py --cifar-path 14 | ```` 15 | 16 | [robustml]: https://github.com/robust-ml/robustml 17 | -------------------------------------------------------------------------------- /sap/evaluation.py: -------------------------------------------------------------------------------- 1 | import robustml 2 | import pickle 3 | from robustml_model import SAP 4 | import sys 5 | import argparse 6 | import tensorflow as tf 7 | import numpy as np 8 | from helpers import * 9 | import time 10 | import os 11 | import cv2 12 | 13 | 14 | npop = 300 # population size 15 | sigma = 0.1 # noise standard deviation 16 | alpha = 0.008 # learning rate 17 | # alpha = 0.001 # learning rate 18 | boxmin = 0 19 | boxmax = 1 20 | boxplus = (boxmin + boxmax) / 2. 21 | boxmul = (boxmax - boxmin) / 2. 22 | folder = './liclipadvImages/' 23 | epsi = 0.031 24 | 25 | def main(): 26 | 27 | parser = argparse.ArgumentParser() 28 | parser.add_argument('--cifar-path', type=str, default='../cifar10_data/test_batch', 29 | help='path to the test_batch file from http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz') 30 | parser.add_argument('--perturb', type=str, default='perturb') 31 | parser.add_argument('--start', type=int, default=0) 32 | parser.add_argument('--end', type=int, default=100) 33 | parser.add_argument('--debug', action='store_true') 34 | args = parser.parse_args() 35 | 36 | test_loss = 0 37 | correct = 0 38 | total = 0 39 | totalImages = 0 40 | succImages = 0 41 | faillist = [] 42 | 43 | 44 | 45 | # set up TensorFlow session 46 | 47 | config = tf.ConfigProto() 48 | config.gpu_options.allow_growth = True 49 | sess = tf.Session(config=config) 50 | 51 | 52 | # initialize a model 53 | model = SAP(sess) 54 | 55 | # initialize an attack (it's a white box attack, and it's allowed to look 56 | # at the internals of the model in any way it wants) 57 | # attack = BPDA(sess, model, epsilon=model.threat_model.epsilon, debug=args.debug) 58 | # attack = Attack(sess, model.model, epsilon=model.threat_model.epsilon) 59 | 60 | # initialize a data provider for CIFAR-10 images 61 | provider = robustml.provider.CIFAR10(args.cifar_path) 62 | input_xs = tf.placeholder(tf.float32, [None, 32, 32, 3]) 63 | start = 0 64 | end = 10000 65 | total = 0 66 | real_logits_pre = model.model(input_xs) 67 | real_logits = tf.nn.softmax(real_logits_pre) 68 | successlist = [] 69 | printlist = [] 70 | 71 | start_time = time.time() 72 | perturbs = os.listdir('./') 73 | all_dir = [] 74 | for x in perturbs: 75 | if 'perturb' in x: 76 | all_dir.append(x) 77 | 78 | 79 | for y in all_dir: 80 | perturb_files = os.listdir(y) 81 | numbers = [] 82 | totalImages = 0 83 | succImages = 0 84 | 85 | perturb_files = os.listdir(y) 86 | numbers = [] 87 | for x in perturb_files: 88 | number = x.split('_')[1] 89 | name = x.split('_')[0] 90 | number1 = int(number.split('.pkl')[0]) 91 | numbers.append(number1) 92 | 93 | for i in numbers: 94 | success = False 95 | print('evaluating %d of [%d, %d)' % (i, start, end), file=sys.stderr) 96 | inputs, targets= provider[i] 97 | modify = np.random.randn(1,3,32,32) * 0.001 98 | in_pkl = y + '/'+name + '_' + str(i)+'.pkl' 99 | ##### thermometer encoding 100 | 101 | logits = sess.run(real_logits,feed_dict={input_xs: [inputs]}) 102 | if np.argmax(logits) != targets: 103 | print('skip the wrong example ', i) 104 | continue 105 | totalImages += 1 106 | try: 107 | modify = pickle.load(open(in_pkl, 'rb')) 108 | except: 109 | modify = pickle.load(open(in_pkl,'rb'),encoding='bytes') 110 | if 'cascade' in in_pkl: 111 | modify = cv2.resize(modify[0].transpose(1, 2, 0), dsize=(32, 32), interpolation=cv2.INTER_LINEAR) 112 | modify = modify.transpose(2, 0, 1) 113 | modify = modify.reshape((1,3,32,32)) 114 | newimg = torch_arctanh((inputs - boxplus) / boxmul).transpose(2, 0, 1) 115 | realinputimg = np.tanh(newimg + modify) * boxmul + boxplus 116 | realdist = realinputimg - (np.tanh(newimg) * boxmul + boxplus) 117 | realclipdist = np.clip(realdist, -epsi, epsi) 118 | realclipinput = realclipdist + (np.tanh(newimg) * boxmul + boxplus) 119 | l2real = np.sum((realclipinput - (np.tanh(newimg) * boxmul + boxplus)) ** 2) ** 0.5 120 | outputsreal = sess.run(real_logits, feed_dict={input_xs: realclipinput.transpose(0, 2, 3, 1)}) 121 | if (np.argmax(outputsreal) != targets) and (np.abs(realclipdist).max() <= epsi): 122 | succImages += 1 123 | 124 | success_rate = succImages / float(totalImages) 125 | print('name:',y) 126 | print('succ rate', success_rate) 127 | print('succ {} , total {}'.format(succImages, totalImages)) 128 | 129 | 130 | if __name__ == '__main__': 131 | main() 132 | -------------------------------------------------------------------------------- /sap/evaluation_bpda.py: -------------------------------------------------------------------------------- 1 | import robustml 2 | import pickle 3 | from robustml_model import SAP 4 | import sys 5 | import argparse 6 | import tensorflow as tf 7 | import numpy as np 8 | from helpers import * 9 | import time 10 | import os 11 | import cv2 12 | 13 | 14 | npop = 300 # population size 15 | sigma = 0.1 # noise standard deviation 16 | alpha = 0.008 # learning rate 17 | # alpha = 0.001 # learning rate 18 | boxmin = 0 19 | boxmax = 1 20 | boxplus = (boxmin + boxmax) / 2. 21 | boxmul = (boxmax - boxmin) / 2. 22 | folder = './liclipadvImages/' 23 | epsi = 0.032 24 | 25 | def main(): 26 | 27 | parser = argparse.ArgumentParser() 28 | parser.add_argument('--cifar-path', type=str, default='../cifar10_data/test_batch', 29 | help='path to the test_batch file from http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz') 30 | parser.add_argument('--perturb', type=str, default='perturb') 31 | parser.add_argument('--start', type=int, default=0) 32 | parser.add_argument('--end', type=int, default=100) 33 | parser.add_argument('--debug', action='store_true') 34 | args = parser.parse_args() 35 | 36 | test_loss = 0 37 | correct = 0 38 | total = 0 39 | totalImages = 0 40 | succImages = 0 41 | faillist = [] 42 | 43 | 44 | 45 | # set up TensorFlow session 46 | 47 | config = tf.ConfigProto() 48 | config.gpu_options.allow_growth = True 49 | sess = tf.Session(config=config) 50 | 51 | 52 | # initialize a model 53 | model = SAP(sess) 54 | 55 | # initialize an attack (it's a white box attack, and it's allowed to look 56 | # at the internals of the model in any way it wants) 57 | # attack = BPDA(sess, model, epsilon=model.threat_model.epsilon, debug=args.debug) 58 | # attack = Attack(sess, model.model, epsilon=model.threat_model.epsilon) 59 | 60 | # initialize a data provider for CIFAR-10 images 61 | provider = robustml.provider.CIFAR10(args.cifar_path) 62 | input_xs = tf.placeholder(tf.float32, [None, 32, 32, 3]) 63 | start = 0 64 | end = 10000 65 | total = 0 66 | real_logits_pre = model.model(input_xs) 67 | real_logits = tf.nn.softmax(real_logits_pre) 68 | successlist = [] 69 | printlist = [] 70 | 71 | start_time = time.time() 72 | perturbs = os.listdir('./') 73 | all_dir = [] 74 | for x in perturbs: 75 | if 'perturb' in x: 76 | all_dir.append(x) 77 | 78 | 79 | for y in all_dir: 80 | perturb_files = os.listdir(y) 81 | numbers = [] 82 | totalImages = 0 83 | succImages = 0 84 | 85 | perturb_files = os.listdir(y) 86 | numbers = [] 87 | for x in perturb_files: 88 | 89 | number = x.split('_')[-1] 90 | name = x.split('_')[0] 91 | number1 = int(number.split('.pkl')[0]) 92 | 93 | numbers.append(number1) 94 | 95 | for i in numbers: 96 | success = False 97 | print('evaluating %d of [%d, %d)' % (i, start, end), file=sys.stderr) 98 | inputs, targets= provider[i] 99 | modify = np.random.randn(1,3,32,32) * 0.001 100 | in_pkl = y + '/'+name + '_' + str(i)+'.pkl' 101 | ##### thermometer encoding 102 | 103 | logits = sess.run(real_logits,feed_dict={input_xs: [inputs]}) 104 | if np.argmax(logits) != targets: 105 | print('skip the wrong example ', i) 106 | continue 107 | totalImages += 1 108 | try: 109 | modify = pickle.load(open(in_pkl, 'rb')) 110 | except: 111 | modify = pickle.load(open(in_pkl,'rb'),encoding='bytes') 112 | # if 'cascade' in in_pkl: 113 | # modify = cv2.resize(modify[0].transpose(1, 2, 0), dsize=(32, 32), interpolation=cv2.INTER_LINEAR) 114 | # modify = modify.transpose(2, 0, 1) 115 | # modify = modify.reshape((1,3,32,32)) 116 | realclipinput = modify.reshape(1,32,32,3)+0.5 117 | realclipdist = realclipinput - inputs 118 | print(np.abs(realclipdist).max()) 119 | outputsreal = sess.run(real_logits, feed_dict={input_xs: realclipinput}) 120 | # print('logits ',np.argmax(outputsreal)) 121 | # print('targets ',targets) 122 | if (np.argmax(outputsreal) != targets) and (np.abs(realclipdist).max() <= epsi): 123 | succImages += 1 124 | 125 | success_rate = succImages / float(totalImages) 126 | print('name:',y) 127 | print('succ rate', success_rate) 128 | print('succ {} , total {}'.format(succImages, totalImages)) 129 | 130 | 131 | if __name__ == '__main__': 132 | main() 133 | -------------------------------------------------------------------------------- /sap/helpers.py: -------------------------------------------------------------------------------- 1 | import operator as op 2 | import functools as ft 3 | import numpy as np 4 | 5 | 6 | '''reduce_* helper functions reduce tensors on all dimensions but the first. 7 | They are intended to be used on batched tensors where dim 0 is the batch dim. 8 | ''' 9 | 10 | 11 | def reduce_sum(x, keepdim=True): 12 | # silly PyTorch, when will you get proper reducing sums/means? 13 | for a in reversed(range(1, x.dim())): 14 | x = x.sum(a, keepdim=keepdim) 15 | return x 16 | 17 | 18 | def reduce_mean(x, keepdim=True): 19 | numel = ft.reduce(op.mul, x.size()[1:]) 20 | x = reduce_sum(x, keepdim=keepdim) 21 | return x / numel 22 | 23 | 24 | def reduce_min(x, keepdim=True): 25 | for a in reversed(range(1, x.dim())): 26 | x = x.min(a, keepdim=keepdim)[0] 27 | return x 28 | 29 | 30 | def reduce_max(x, keepdim=True): 31 | for a in reversed(range(1, x.dim())): 32 | x = x.max(a, keepdim=keepdim)[0] 33 | return x 34 | 35 | 36 | def torch_arctanh(x, eps=1e-6): 37 | x *= (1. - eps) 38 | return (np.log((1 + x) / (1 - x))) * 0.5 39 | 40 | 41 | def l2r_dist(x, y, keepdim=True, eps=1e-8): 42 | d = (x - y)**2 43 | d = reduce_sum(d, keepdim=keepdim) 44 | d += eps # to prevent infinite gradient at 0 45 | return d.sqrt() 46 | 47 | 48 | def l2_dist(x, y, keepdim=True): 49 | d = (x - y)**2 50 | return reduce_sum(d, keepdim=keepdim) 51 | 52 | 53 | def l1_dist(x, y, keepdim=True): 54 | d = torch.abs(x - y) 55 | return reduce_sum(d, keepdim=keepdim) 56 | 57 | 58 | def l2_norm(x, keepdim=True): 59 | norm = reduce_sum(x*x, keepdim=keepdim) 60 | return norm.sqrt() 61 | 62 | 63 | def l1_norm(x, keepdim=True): 64 | return reduce_sum(x.abs(), keepdim=keepdim) 65 | 66 | 67 | def rescale(x, x_min=-1., x_max=1.): 68 | return x * (x_max - x_min) + x_min 69 | 70 | 71 | def tanh_rescale(x, x_min=-1., x_max=1.): 72 | return (torch.tanh(x) + 1) * 0.5 * (x_max - x_min) + x_min 73 | -------------------------------------------------------------------------------- /sap/robustml_attack.py: -------------------------------------------------------------------------------- 1 | import robustml 2 | from robustml_model import SAP 3 | print(robustml.__file__) 4 | import sys 5 | import argparse 6 | import tensorflow as tf 7 | import numpy as np 8 | import time 9 | 10 | class Attack: 11 | def __init__(self, sess, model, epsilon, tol=1, num_steps=500, step_size=.1, random_start=False): 12 | self._sess = sess 13 | self.model = model 14 | self.tol = tol 15 | self.num_steps = num_steps 16 | self.step_size = step_size 17 | self.rand = random_start 18 | 19 | self.xs = tf.Variable(np.zeros((1, 32, 32, 3), dtype=np.float32), 20 | name='modifier') 21 | self.orig_xs = tf.placeholder(tf.float32, [None, 32, 32, 3]) 22 | 23 | self.ys = tf.placeholder(tf.int32, [None]) 24 | 25 | self.epsilon = epsilon * 255 26 | 27 | delta = tf.clip_by_value(self.xs, 0, 255) - self.orig_xs 28 | delta = tf.clip_by_value(delta, -self.epsilon, self.epsilon) 29 | 30 | self.do_clip_xs = tf.assign(self.xs, self.orig_xs+delta) 31 | 32 | self.logits = logits = model(self.xs) 33 | 34 | label_mask = tf.one_hot(self.ys, 10) 35 | correct_logit = tf.reduce_sum(label_mask * logits, axis=1) 36 | wrong_logit = tf.reduce_max((1-label_mask) * logits - 1e4*label_mask, axis=1) 37 | 38 | self.loss = (correct_logit - wrong_logit) 39 | 40 | start_vars = set(x.name for x in tf.global_variables()) 41 | optimizer = tf.train.AdamOptimizer(step_size*1) 42 | 43 | grad,var = optimizer.compute_gradients(self.loss, [self.xs])[0] 44 | self.train = optimizer.apply_gradients([(tf.sign(grad),var)]) 45 | 46 | end_vars = tf.global_variables() 47 | self.new_vars = [x for x in end_vars if x.name not in start_vars] 48 | 49 | def perturb(self, x, y, sess): 50 | sess.run(tf.variables_initializer(self.new_vars)) 51 | sess.run(self.xs.initializer) 52 | sess.run(self.do_clip_xs, 53 | {self.orig_xs: x}) 54 | 55 | for i in range(self.num_steps): 56 | 57 | sess.run(self.train, feed_dict={self.ys: y}) 58 | sess.run(self.do_clip_xs, 59 | {self.orig_xs: x}) 60 | 61 | return sess.run(self.xs) 62 | 63 | def run(self, x, y, target): 64 | if target is not None: 65 | raise NotImplementedError 66 | return self.perturb(np.array([x]) * 255.0, [y], self._sess)[0] / 255.0 67 | 68 | def main(): 69 | parser = argparse.ArgumentParser() 70 | parser.add_argument('--cifar-path', type=str, required=True, 71 | help='path to the test_batch file from http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz') 72 | parser.add_argument('--start', type=int, default=170) 73 | parser.add_argument('--end', type=int, default=1000) 74 | parser.add_argument('--debug', action='store_true') 75 | args = parser.parse_args() 76 | config = tf.ConfigProto() 77 | config.gpu_options.allow_growth = True 78 | sess = tf.Session(config=config) 79 | # set up TensorFlow session 80 | # sess = tf.Session() 81 | 82 | # initialize a model 83 | model = SAP(sess) 84 | 85 | # initialize an attack (it's a white box attack, and it's allowed to look 86 | # at the internals of the model in any way it wants) 87 | # attack = BPDA(sess, model, epsilon=model.threat_model.epsilon, debug=args.debug) 88 | attack_start = time.time() 89 | attack = Attack(sess, model.model, epsilon=model.threat_model.epsilon) 90 | 91 | # initialize a data provider for CIFAR-10 images 92 | provider = robustml.provider.CIFAR10(args.cifar_path) 93 | 94 | success_rate = robustml.evaluate.evaluate( 95 | model, 96 | attack, 97 | provider, 98 | start=args.start, 99 | end=args.end, 100 | deterministic=True, 101 | debug=args.debug, 102 | ) 103 | 104 | print('attack success rate: %.2f%% (over %d data points)' % (success_rate*100, args.end-args.start)) 105 | print('attack time : ', time.time()-attack_start,flush=True) 106 | 107 | 108 | if __name__ == '__main__': 109 | main() 110 | -------------------------------------------------------------------------------- /sap/robustml_model.py: -------------------------------------------------------------------------------- 1 | import robustml 2 | import tensorflow as tf 3 | import numpy as np 4 | from sap_model import SAPModel 5 | 6 | class SAP(robustml.model.Model): 7 | def __init__(self, sess): 8 | self._sess = sess 9 | 10 | self._model = SAPModel( 11 | '../all_models/standard/', 12 | tiny=False, 13 | mode='eval', 14 | sess=sess, 15 | ) 16 | 17 | self._dataset = robustml.dataset.CIFAR10() 18 | self._threat_model = robustml.threat_model.Linf(epsilon=8.0/255.0) 19 | 20 | @property 21 | def dataset(self): 22 | return self._dataset 23 | 24 | @property 25 | def threat_model(self): 26 | return self._threat_model 27 | 28 | def classify(self, x): 29 | x = x * 255.0 30 | # first encode the input, then classify it 31 | return self._sess.run(self._model.predictions, {self._model.x_input: [x]})[0] 32 | 33 | # expose internals for white box attacks 34 | 35 | @property 36 | def model(self): 37 | return self._model 38 | -------------------------------------------------------------------------------- /sap/sap_model.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | 4 | from cifar_model import Model 5 | 6 | class SAPModel(Model): 7 | image_size = 32 8 | num_labels = 10 9 | num_channels = 3 10 | 11 | def __init__(self, *args, **kwargs): 12 | if 'fix' in kwargs: 13 | self.fix_randomness = kwargs['fix'] == True 14 | del kwargs['fix'] 15 | else: 16 | self.fix_randomness = False 17 | super().__init__(*args, **kwargs) 18 | 19 | def _conv(self, name, x, filter_size, in_filters, out_filters, strides): 20 | r = super()._conv(name, x, filter_size, in_filters, out_filters, strides) 21 | r = tf.check_numerics(r, "okay") 22 | p = tf.abs(r)/tf.reduce_sum(tf.abs(r), axis=(1,2,3), keep_dims=True) 23 | w,h,c = p.get_shape().as_list()[1:] 24 | N = w*h*c*2 25 | if self.fix_randomness: 26 | p_keep = 1-tf.exp(-N*p) 27 | rand = tf.constant(np.random.uniform(size=(p_keep.shape[0],w,h,c)), 28 | dtype=tf.float32) 29 | else: 30 | p_keep = 1-tf.exp(-N*p) 31 | rand = tf.random_uniform(tf.shape(p_keep)) 32 | keep = rand 15 | ```` 16 | 17 | [robustml]: https://github.com/robust-ml/robustml 18 | -------------------------------------------------------------------------------- /therm-adv/evaluation.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pickle 3 | import robustml 4 | from robustml_model import Thermometer, LEVELS 5 | from discretization_utils import discretize_uniform 6 | import sys 7 | import argparse 8 | import tensorflow as tf 9 | import numpy as np 10 | from helpers import * 11 | import os 12 | import cv2 13 | 14 | 15 | npop = 300 # population size 16 | sigma = 0.1 # noise standard deviation 17 | alpha = 0.008 # learning rate 18 | # alpha = 0.001 # learning rate 19 | boxmin = 0 20 | boxmax = 1 21 | boxplus = (boxmin + boxmax) / 2. 22 | boxmul = (boxmax - boxmin) / 2. 23 | folder = './liclipadvImages/' 24 | epsi = 0.031 25 | 26 | def main(): 27 | 28 | parser = argparse.ArgumentParser() 29 | parser.add_argument('--cifar-path', type=str, default='../cifar10_data/test_batch', 30 | help='path to the test_batch file from http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz') 31 | parser.add_argument('--perturb', type=str, default='lid_perturb') 32 | parser.add_argument('--start', type=int, default=0) 33 | parser.add_argument('--end', type=int, default=100) 34 | parser.add_argument('--debug', action='store_true') 35 | args = parser.parse_args() 36 | 37 | test_loss = 0 38 | correct = 0 39 | total = 0 40 | totalImages = 0 41 | succImages = 0 42 | faillist = [] 43 | 44 | 45 | 46 | # set up TensorFlow session 47 | 48 | config = tf.ConfigProto() 49 | config.gpu_options.allow_growth = True 50 | sess = tf.Session(config=config) 51 | 52 | 53 | # initialize a model 54 | model = Thermometer(sess) 55 | 56 | print(model.threat_model.targeted) 57 | # initialize an attack (it's a white box attack, and it's allowed to look 58 | # at the internals of the model in any way it wants) 59 | # attack = BPDA(sess, model, epsilon=model.threat_model.epsilon, debug=args.debug) 60 | # attack = Attack(sess, model.model, epsilon=model.threat_model.epsilon) 61 | 62 | # initialize a data provider for CIFAR-10 images 63 | provider = robustml.provider.CIFAR10(args.cifar_path) 64 | input_xs = tf.placeholder(tf.float32, [None, 32, 32, 3]) 65 | start = 0 66 | end = 10000 67 | total = 0 68 | uniform = discretize_uniform(input_xs, levels=LEVELS, thermometer=True) 69 | real_logits = tf.nn.softmax(model.model(uniform)) 70 | successlist = [] 71 | printlist = [] 72 | 73 | start_time = time.time() 74 | perturbs = os.listdir('./') 75 | all_dir = [] 76 | for x in perturbs: 77 | if 'perturb' in x: 78 | all_dir.append(x) 79 | 80 | 81 | for y in all_dir: 82 | perturb_files = os.listdir(y) 83 | numbers = [] 84 | totalImages = 0 85 | succImages = 0 86 | 87 | numbers = [] 88 | for x in perturb_files: 89 | number = x.split('_')[1] 90 | name = x.split('_')[0] 91 | number1 = int(number.split('.pkl')[0]) 92 | numbers.append(number1) 93 | 94 | for i in numbers: 95 | success = False 96 | #print('evaluating %d of [%d, %d)' % (i, start, end), file=sys.stderr) 97 | inputs, targets= provider[i] 98 | modify = np.random.randn(1,3,32,32) * 0.001 99 | in_pkl = y + '/' +name + '_' + str(i)+'.pkl' 100 | ##### thermometer encoding 101 | 102 | logits = sess.run(real_logits,feed_dict={input_xs: [inputs]}) 103 | if np.argmax(logits) != targets: 104 | print('skip the wrong example ', i) 105 | continue 106 | totalImages += 1 107 | try: 108 | modify = pickle.load(open(in_pkl, 'rb')) 109 | except: 110 | modify = pickle.load(open(in_pkl,'rb'),encoding='bytes') 111 | if 'cascade' in in_pkl: 112 | modify = cv2.resize(modify[0].transpose(1, 2, 0), dsize=(32, 32), interpolation=cv2.INTER_LINEAR) 113 | modify = modify.transpose(2,0,1) 114 | modify = modify.reshape((1,3,32,32)) 115 | newimg = torch_arctanh((inputs - boxplus) / boxmul).transpose(2, 0, 1) 116 | realinputimg = np.tanh(newimg + modify) * boxmul + boxplus 117 | realdist = realinputimg - (np.tanh(newimg) * boxmul + boxplus) 118 | realclipdist = np.clip(realdist, -epsi, epsi) 119 | realclipinput = realclipdist + (np.tanh(newimg) * boxmul + boxplus) 120 | l2real = np.sum((realclipinput - (np.tanh(newimg) * boxmul + boxplus)) ** 2) ** 0.5 121 | outputsreal = sess.run(real_logits, feed_dict={input_xs: realclipinput.transpose(0, 2, 3, 1)}) 122 | if (np.argmax(outputsreal) != targets) and (np.abs(realclipdist).max() <= epsi): 123 | succImages += 1 124 | 125 | success_rate = succImages / float(totalImages) 126 | print('name:',y) 127 | print('succ rate', success_rate) 128 | print('succ {} , total {}'.format(succImages, totalImages)) 129 | 130 | 131 | if __name__ == '__main__': 132 | main() 133 | -------------------------------------------------------------------------------- /therm-adv/evaluation_bpda.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pickle 3 | import robustml 4 | from robustml_model import Thermometer, LEVELS 5 | from discretization_utils import discretize_uniform 6 | import sys 7 | import argparse 8 | import tensorflow as tf 9 | import numpy as np 10 | from helpers import * 11 | import os 12 | import cv2 13 | 14 | 15 | npop = 300 # population size 16 | sigma = 0.1 # noise standard deviation 17 | alpha = 0.008 # learning rate 18 | # alpha = 0.001 # learning rate 19 | boxmin = 0 20 | boxmax = 1 21 | boxplus = (boxmin + boxmax) / 2. 22 | boxmul = (boxmax - boxmin) / 2. 23 | folder = './liclipadvImages/' 24 | epsi = 0.032 25 | 26 | def main(): 27 | 28 | parser = argparse.ArgumentParser() 29 | parser.add_argument('--cifar-path', type=str, default='../cifar10_data/test_batch', 30 | help='path to the test_batch file from http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz') 31 | parser.add_argument('--perturb', type=str, default='lid_perturb') 32 | parser.add_argument('--start', type=int, default=0) 33 | parser.add_argument('--end', type=int, default=100) 34 | parser.add_argument('--debug', action='store_true') 35 | args = parser.parse_args() 36 | 37 | test_loss = 0 38 | correct = 0 39 | total = 0 40 | totalImages = 0 41 | succImages = 0 42 | faillist = [] 43 | 44 | 45 | 46 | # set up TensorFlow session 47 | 48 | config = tf.ConfigProto() 49 | config.gpu_options.allow_growth = True 50 | sess = tf.Session(config=config) 51 | 52 | 53 | # initialize a model 54 | model = Thermometer(sess) 55 | 56 | print(model.threat_model.targeted) 57 | # initialize an attack (it's a white box attack, and it's allowed to look 58 | # at the internals of the model in any way it wants) 59 | # attack = BPDA(sess, model, epsilon=model.threat_model.epsilon, debug=args.debug) 60 | # attack = Attack(sess, model.model, epsilon=model.threat_model.epsilon) 61 | 62 | # initialize a data provider for CIFAR-10 images 63 | provider = robustml.provider.CIFAR10(args.cifar_path) 64 | input_xs = tf.placeholder(tf.float32, [None, 32, 32, 3]) 65 | start = 0 66 | end = 10000 67 | total = 0 68 | uniform = discretize_uniform(input_xs, levels=LEVELS, thermometer=True) 69 | real_logits = tf.nn.softmax(model.model(uniform)) 70 | successlist = [] 71 | printlist = [] 72 | 73 | start_time = time.time() 74 | perturbs = os.listdir('./') 75 | all_dir = [] 76 | for x in perturbs: 77 | if 'perturb' in x: 78 | all_dir.append(x) 79 | 80 | 81 | for y in all_dir: 82 | perturb_files = os.listdir(y) 83 | numbers = [] 84 | totalImages = 0 85 | succImages = 0 86 | 87 | numbers = [] 88 | for x in perturb_files: 89 | number = x.split('_')[-1] 90 | name = x.split('_')[0] 91 | number1 = int(number.split('.pkl')[0]) 92 | numbers.append(number1) 93 | 94 | for i in numbers: 95 | success = False 96 | print('evaluating %d of [%d, %d)' % (i, start, end), file=sys.stderr) 97 | inputs, targets= provider[i] 98 | modify = np.random.randn(1,3,32,32) * 0.001 99 | in_pkl = y + '/' +name +'_' + str(i)+'.pkl' 100 | ##### thermometer encoding 101 | 102 | logits = sess.run(real_logits,feed_dict={input_xs: [inputs]}) 103 | if np.argmax(logits) != targets: 104 | print('skip the wrong example ', i) 105 | continue 106 | totalImages += 1 107 | try: 108 | modify = pickle.load(open(in_pkl, 'rb')) 109 | except: 110 | modify = pickle.load(open(in_pkl,'rb'),encoding='bytes') 111 | # if 'cascade' in in_pkl: 112 | # modify = cv2.resize(modify[0].transpose(1, 2, 0), dsize=(32, 32), interpolation=cv2.INTER_LINEAR) 113 | # modify = modify.transpose(2,0,1) 114 | # modify = modify.reshape((1,3,32,32)) 115 | realclipinput = modify.reshape(1,32,32,3)+0.5 116 | realclipdist = realclipinput - inputs 117 | print(np.abs(realclipdist).max()) 118 | outputsreal = sess.run(real_logits, feed_dict={input_xs: realclipinput}) 119 | 120 | outputsreal = sess.run(real_logits, feed_dict={input_xs: realclipinput}) 121 | if (np.argmax(outputsreal) != targets) and (np.abs(realclipdist).max() <= epsi): 122 | succImages += 1 123 | 124 | success_rate = succImages / float(totalImages) 125 | print('name:',y) 126 | print('succ rate', success_rate) 127 | print('succ {} , total {}'.format(succImages, totalImages)) 128 | 129 | 130 | if __name__ == '__main__': 131 | main() 132 | -------------------------------------------------------------------------------- /therm-adv/helpers.py: -------------------------------------------------------------------------------- 1 | import operator as op 2 | import functools as ft 3 | import numpy as np 4 | 5 | 6 | '''reduce_* helper functions reduce tensors on all dimensions but the first. 7 | They are intended to be used on batched tensors where dim 0 is the batch dim. 8 | ''' 9 | 10 | 11 | def reduce_sum(x, keepdim=True): 12 | # silly PyTorch, when will you get proper reducing sums/means? 13 | for a in reversed(range(1, x.dim())): 14 | x = x.sum(a, keepdim=keepdim) 15 | return x 16 | 17 | 18 | def reduce_mean(x, keepdim=True): 19 | numel = ft.reduce(op.mul, x.size()[1:]) 20 | x = reduce_sum(x, keepdim=keepdim) 21 | return x / numel 22 | 23 | 24 | def reduce_min(x, keepdim=True): 25 | for a in reversed(range(1, x.dim())): 26 | x = x.min(a, keepdim=keepdim)[0] 27 | return x 28 | 29 | 30 | def reduce_max(x, keepdim=True): 31 | for a in reversed(range(1, x.dim())): 32 | x = x.max(a, keepdim=keepdim)[0] 33 | return x 34 | 35 | 36 | def torch_arctanh(x, eps=1e-6): 37 | x *= (1. - eps) 38 | return (np.log((1 + x) / (1 - x))) * 0.5 39 | 40 | 41 | def l2r_dist(x, y, keepdim=True, eps=1e-8): 42 | d = (x - y)**2 43 | d = reduce_sum(d, keepdim=keepdim) 44 | d += eps # to prevent infinite gradient at 0 45 | return d.sqrt() 46 | 47 | 48 | def l2_dist(x, y, keepdim=True): 49 | d = (x - y)**2 50 | return reduce_sum(d, keepdim=keepdim) 51 | 52 | 53 | def l1_dist(x, y, keepdim=True): 54 | d = torch.abs(x - y) 55 | return reduce_sum(d, keepdim=keepdim) 56 | 57 | 58 | def l2_norm(x, keepdim=True): 59 | norm = reduce_sum(x*x, keepdim=keepdim) 60 | return norm.sqrt() 61 | 62 | 63 | def l1_norm(x, keepdim=True): 64 | return reduce_sum(x.abs(), keepdim=keepdim) 65 | 66 | 67 | def rescale(x, x_min=-1., x_max=1.): 68 | return x * (x_max - x_min) + x_min 69 | 70 | 71 | def tanh_rescale(x, x_min=-1., x_max=1.): 72 | return (torch.tanh(x) + 1) * 0.5 * (x_max - x_min) + x_min 73 | -------------------------------------------------------------------------------- /therm-adv/robustml_attack.py: -------------------------------------------------------------------------------- 1 | import robustml 2 | from robustml_model import Thermometer, LEVELS 3 | from discretization_utils import discretize_uniform 4 | import sys 5 | import argparse 6 | import tensorflow as tf 7 | import numpy as np 8 | 9 | class Attack: 10 | def __init__(self, sess, model, epsilon, num_steps=100, step_size=1): 11 | self._sess = sess 12 | self.model = model 13 | self.num_steps = num_steps 14 | self.step_size = step_size 15 | 16 | self.xs = tf.Variable(np.zeros((1, 32, 32, 3), dtype=np.float32), 17 | name='modifier') 18 | self.orig_xs = tf.placeholder(tf.float32, [None, 32, 32, 3]) 19 | 20 | self.ys = tf.placeholder(tf.int32, [None]) 21 | 22 | self.epsilon = epsilon * 255 23 | 24 | delta = tf.clip_by_value(self.xs, 0, 255) - self.orig_xs 25 | delta = tf.clip_by_value(delta, -self.epsilon, self.epsilon) 26 | 27 | self.do_clip_xs = tf.assign(self.xs, self.orig_xs+delta) 28 | 29 | compare = tf.constant((256.0/LEVELS)*np.arange(-1,LEVELS-1).reshape((1,1,1,1,LEVELS)), 30 | dtype=tf.float32) 31 | inner = tf.reshape(self.xs,(-1, 32, 32, 3, 1)) - compare 32 | inner = tf.maximum(tf.minimum(inner/(256.0/LEVELS), 1.0), 0.0) 33 | 34 | self.therm = tf.reshape(inner, (-1, 32, 32, LEVELS*3)) 35 | 36 | self.logits = logits = model(self.therm) 37 | 38 | self.uniform = discretize_uniform(self.xs/255.0, levels=LEVELS, thermometer=True) 39 | self.real_logits = model(self.uniform) 40 | 41 | label_mask = tf.one_hot(self.ys, 10) 42 | correct_logit = tf.reduce_sum(label_mask * logits, axis=1) 43 | wrong_logit = tf.reduce_max((1-label_mask) * logits - 1e4*label_mask, axis=1) 44 | 45 | self.loss = (correct_logit - wrong_logit) 46 | 47 | start_vars = set(x.name for x in tf.global_variables()) 48 | optimizer = tf.train.AdamOptimizer(step_size*1) 49 | self.grad = tf.sign(tf.gradients(self.loss, self.xs)[0]) 50 | 51 | grad,var = optimizer.compute_gradients(self.loss, [self.xs])[0] 52 | self.train = optimizer.apply_gradients([(tf.sign(grad),var)]) 53 | 54 | end_vars = tf.global_variables() 55 | self.new_vars = [x for x in end_vars if x.name not in start_vars] 56 | 57 | def perturb(self, x, y, sess): 58 | sess.run(tf.variables_initializer(self.new_vars)) 59 | sess.run(self.xs.initializer) 60 | sess.run(self.do_clip_xs, 61 | {self.orig_xs: x}) 62 | 63 | for i in range(self.num_steps): 64 | 65 | t = sess.run(self.uniform) 66 | sess.run(self.train, feed_dict={self.ys: y, 67 | self.therm: t}) 68 | sess.run(self.do_clip_xs, 69 | {self.orig_xs: x}) 70 | 71 | return sess.run(self.xs) 72 | 73 | def run(self, x, y, target): 74 | if target is not None: 75 | raise NotImplementedError 76 | return self.perturb(np.array([x]) * 255.0, [y], self._sess)[0] / 255.0 77 | 78 | def main(): 79 | parser = argparse.ArgumentParser() 80 | parser.add_argument('--cifar-path', type=str, required=True, 81 | help='path to the test_batch file from http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz') 82 | parser.add_argument('--start', type=int, default=0) 83 | parser.add_argument('--end', type=int, default=1000) 84 | parser.add_argument('--debug', action='store_true') 85 | args = parser.parse_args() 86 | 87 | # set up TensorFlow session 88 | config = tf.ConfigProto() 89 | config.gpu_options.allow_growth = True 90 | sess = tf.Session(config=config) 91 | 92 | # initialize a model 93 | model = Thermometer(sess) 94 | 95 | # initialize an attack (it's a white box attack, and it's allowed to look 96 | # at the internals of the model in any way it wants) 97 | # attack = BPDA(sess, model, epsilon=model.threat_model.epsilon, debug=args.debug) 98 | attack = Attack(sess, model.model, epsilon=model.threat_model.epsilon) 99 | 100 | # initialize a data provider for CIFAR-10 images 101 | provider = robustml.provider.CIFAR10(args.cifar_path) 102 | 103 | success_rate = robustml.evaluate.evaluate( 104 | model, 105 | attack, 106 | provider, 107 | start=args.start, 108 | end=args.end, 109 | deterministic=True, 110 | debug=args.debug, 111 | ) 112 | 113 | print('attack success rate: %.2f%% (over %d data points)' % (success_rate*100, args.end-args.start)) 114 | 115 | if __name__ == '__main__': 116 | main() 117 | -------------------------------------------------------------------------------- /therm-adv/robustml_model.py: -------------------------------------------------------------------------------- 1 | import robustml 2 | import tensorflow as tf 3 | from discretization_utils import discretize_uniform 4 | import numpy as np 5 | from cifar_model import Model 6 | 7 | LEVELS = 16 8 | 9 | class Thermometer(robustml.model.Model): 10 | def __init__(self, sess): 11 | self._sess = sess 12 | 13 | self._x = tf.placeholder(tf.float32, (1, 32, 32, 3)) 14 | self._encode = discretize_uniform(self._x/255.0, levels=LEVELS, thermometer=True) 15 | 16 | self._model = Model( 17 | '../all_models/thermometer_advtrain', 18 | # '../therm_models/tiny_16', 19 | sess, 20 | tiny=False, 21 | # tiny=True, 22 | mode='eval', 23 | thermometer=True, 24 | levels=LEVELS 25 | ) 26 | 27 | self._dataset = robustml.dataset.CIFAR10() 28 | self._threat_model = robustml.threat_model.Linf(epsilon=8.0/255.0) 29 | 30 | @property 31 | def dataset(self): 32 | return self._dataset 33 | 34 | @property 35 | def threat_model(self): 36 | return self._threat_model 37 | 38 | def classify(self, x): 39 | x = x * 255.0 40 | # first encode the input, then classify it 41 | encoded = self.encode(x) 42 | return self._sess.run(self._model.predictions, {self._model.x_input: encoded})[0] 43 | 44 | # expose internals for white box attacks 45 | 46 | @property 47 | def model(self): 48 | return self._model 49 | 50 | # x should be in [0, 255] 51 | def encode(self, x): 52 | return self._sess.run(self._encode, {self._x: [x]}) 53 | -------------------------------------------------------------------------------- /wideresnet28/README.md: -------------------------------------------------------------------------------- 1 | # Thermometer Encoding: One Hot Way To Resist Adversarial Examples 2 | 3 | Paper: [Buckman et al. 2018](https://openreview.net/forum?id=S18Su--CW) 4 | 5 | ## Setup 6 | 7 | Run `./setup.sh` to fetch models. 8 | 9 | ## Breaks 10 | 11 | * Thermometer Encoding: BPDA 12 | 13 | ## [robustml] evaluation 14 | 15 | Run with: 16 | 17 | ```bash 18 | python robustml_attack.py --cifar-path 19 | ```` 20 | 21 | [robustml]: https://github.com/robust-ml/robustml 22 | -------------------------------------------------------------------------------- /wideresnet28/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "===== MODEL CONFIGURATION =====", 3 | "model_dir": "models/adv_train_clean", 4 | 5 | "_comment": "===== DATASET CONFIGURATION =====", 6 | "data_path": "cifar10_data", 7 | 8 | "_comment": "===== TRAINING CONFIGURATION =====", 9 | "tf_random_seed": 451760341, 10 | "np_random_seed": 216105420, 11 | "max_num_training_steps": 80000, 12 | "num_output_steps": 100, 13 | "num_summary_steps": 100, 14 | "num_checkpoint_steps": 1000, 15 | "training_batch_size": 128, 16 | "step_size_schedule": [[0, 0.1], [40000, 0.01], [60000, 0.001]], 17 | "weight_decay": 0.0002, 18 | "momentum": 0.9, 19 | 20 | "_comment": "===== EVAL CONFIGURATION =====", 21 | "num_eval_examples": 10000, 22 | "eval_batch_size": 100, 23 | "eval_on_cpu": false, 24 | 25 | "_comment": "=====ADVERSARIAL EXAMPLES CONFIGURATION=====", 26 | "epsilon": 8.0, 27 | "num_steps": 7, 28 | "step_size": 2.0, 29 | "random_start": true, 30 | "loss_func": "xent", 31 | "store_adv_path": "attack.npy" 32 | } 33 | -------------------------------------------------------------------------------- /wideresnet28/evaluation.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pickle 3 | import robustml 4 | from robustml_model import Thermometer, LEVELS 5 | from discretization_utils import discretize_uniform 6 | import sys 7 | import argparse 8 | import tensorflow as tf 9 | import numpy as np 10 | from helpers import * 11 | import os 12 | import cv2 13 | 14 | 15 | npop = 300 # population size 16 | sigma = 0.1 # noise standard deviation 17 | alpha = 0.008 # learning rate 18 | # alpha = 0.001 # learning rate 19 | boxmin = 0 20 | boxmax = 1 21 | boxplus = (boxmin + boxmax) / 2. 22 | boxmul = (boxmax - boxmin) / 2. 23 | folder = './liclipadvImages/' 24 | epsi = 0.031 25 | 26 | def main(): 27 | 28 | parser = argparse.ArgumentParser() 29 | parser.add_argument('--cifar-path', type=str, default='../cifar10_data/test_batch', 30 | help='path to the test_batch file from http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz') 31 | parser.add_argument('--perturb', type=str, default='lid_perturb') 32 | parser.add_argument('--start', type=int, default=0) 33 | parser.add_argument('--end', type=int, default=100) 34 | parser.add_argument('--debug', action='store_true') 35 | args = parser.parse_args() 36 | 37 | test_loss = 0 38 | correct = 0 39 | total = 0 40 | totalImages = 0 41 | succImages = 0 42 | faillist = [] 43 | 44 | 45 | 46 | # set up TensorFlow session 47 | 48 | config = tf.ConfigProto() 49 | config.gpu_options.allow_growth = True 50 | sess = tf.Session(config=config) 51 | 52 | 53 | # initialize a model 54 | model = Thermometer(sess) 55 | 56 | print(model.threat_model.targeted) 57 | # initialize an attack (it's a white box attack, and it's allowed to look 58 | # at the internals of the model in any way it wants) 59 | # attack = BPDA(sess, model, epsilon=model.threat_model.epsilon, debug=args.debug) 60 | # attack = Attack(sess, model.model, epsilon=model.threat_model.epsilon) 61 | 62 | # initialize a data provider for CIFAR-10 images 63 | provider = robustml.provider.CIFAR10(args.cifar_path) 64 | input_xs = tf.placeholder(tf.float32, [None, 32, 32, 3]) 65 | start = 0 66 | end = 10000 67 | total = 0 68 | uniform = discretize_uniform(input_xs, levels=LEVELS, thermometer=True) 69 | real_logits = tf.nn.softmax(model.model(uniform)) 70 | successlist = [] 71 | printlist = [] 72 | 73 | start_time = time.time() 74 | perturbs = os.listdir('./') 75 | all_dir = [] 76 | for x in perturbs: 77 | if 'perturb' in x: 78 | all_dir.append(x) 79 | 80 | 81 | for y in all_dir: 82 | perturb_files = os.listdir(y) 83 | numbers = [] 84 | totalImages = 0 85 | succImages = 0 86 | 87 | numbers = [] 88 | for x in perturb_files: 89 | number = x.split('_')[1] 90 | name = x.split('_')[0] 91 | number1 = int(number.split('.pkl')[0]) 92 | numbers.append(number1) 93 | 94 | for i in numbers: 95 | success = False 96 | #print('evaluating %d of [%d, %d)' % (i, start, end), file=sys.stderr) 97 | inputs, targets= provider[i] 98 | modify = np.random.randn(1,3,32,32) * 0.001 99 | in_pkl = y + '/' +name + '_' + str(i)+'.pkl' 100 | ##### thermometer encoding 101 | 102 | logits = sess.run(real_logits,feed_dict={input_xs: [inputs]}) 103 | if np.argmax(logits) != targets: 104 | print('skip the wrong example ', i) 105 | continue 106 | totalImages += 1 107 | try: 108 | modify = pickle.load(open(in_pkl, 'rb')) 109 | except: 110 | modify = pickle.load(open(in_pkl,'rb'),encoding='bytes') 111 | if 'cascade' in in_pkl: 112 | modify = cv2.resize(modify[0].transpose(1, 2, 0), dsize=(32, 32), interpolation=cv2.INTER_LINEAR) 113 | modify = modify.transpose(2,0,1) 114 | modify = modify.reshape((1,3,32,32)) 115 | newimg = torch_arctanh((inputs - boxplus) / boxmul).transpose(2, 0, 1) 116 | realinputimg = np.tanh(newimg + modify) * boxmul + boxplus 117 | realdist = realinputimg - (np.tanh(newimg) * boxmul + boxplus) 118 | realclipdist = np.clip(realdist, -epsi, epsi) 119 | realclipinput = realclipdist + (np.tanh(newimg) * boxmul + boxplus) 120 | l2real = np.sum((realclipinput - (np.tanh(newimg) * boxmul + boxplus)) ** 2) ** 0.5 121 | outputsreal = sess.run(real_logits, feed_dict={input_xs: realclipinput.transpose(0, 2, 3, 1)}) 122 | if (np.argmax(outputsreal) != targets) and (np.abs(realclipdist).max() <= epsi): 123 | succImages += 1 124 | 125 | success_rate = succImages / float(totalImages) 126 | print('name:',y) 127 | print('succ rate', success_rate) 128 | print('succ {} , total {}'.format(succImages, totalImages)) 129 | 130 | 131 | if __name__ == '__main__': 132 | main() 133 | -------------------------------------------------------------------------------- /wideresnet28/helpers.py: -------------------------------------------------------------------------------- 1 | import operator as op 2 | import functools as ft 3 | import numpy as np 4 | 5 | 6 | '''reduce_* helper functions reduce tensors on all dimensions but the first. 7 | They are intended to be used on batched tensors where dim 0 is the batch dim. 8 | ''' 9 | 10 | 11 | def reduce_sum(x, keepdim=True): 12 | # silly PyTorch, when will you get proper reducing sums/means? 13 | for a in reversed(range(1, x.dim())): 14 | x = x.sum(a, keepdim=keepdim) 15 | return x 16 | 17 | 18 | def reduce_mean(x, keepdim=True): 19 | numel = ft.reduce(op.mul, x.size()[1:]) 20 | x = reduce_sum(x, keepdim=keepdim) 21 | return x / numel 22 | 23 | 24 | def reduce_min(x, keepdim=True): 25 | for a in reversed(range(1, x.dim())): 26 | x = x.min(a, keepdim=keepdim)[0] 27 | return x 28 | 29 | 30 | def reduce_max(x, keepdim=True): 31 | for a in reversed(range(1, x.dim())): 32 | x = x.max(a, keepdim=keepdim)[0] 33 | return x 34 | 35 | 36 | def torch_arctanh(x, eps=1e-6): 37 | x *= (1. - eps) 38 | return (np.log((1 + x) / (1 - x))) * 0.5 39 | 40 | 41 | def l2r_dist(x, y, keepdim=True, eps=1e-8): 42 | d = (x - y)**2 43 | d = reduce_sum(d, keepdim=keepdim) 44 | d += eps # to prevent infinite gradient at 0 45 | return d.sqrt() 46 | 47 | 48 | def l2_dist(x, y, keepdim=True): 49 | d = (x - y)**2 50 | return reduce_sum(d, keepdim=keepdim) 51 | 52 | 53 | def l1_dist(x, y, keepdim=True): 54 | d = torch.abs(x - y) 55 | return reduce_sum(d, keepdim=keepdim) 56 | 57 | 58 | def l2_norm(x, keepdim=True): 59 | norm = reduce_sum(x*x, keepdim=keepdim) 60 | return norm.sqrt() 61 | 62 | 63 | def l1_norm(x, keepdim=True): 64 | return reduce_sum(x.abs(), keepdim=keepdim) 65 | 66 | 67 | def rescale(x, x_min=-1., x_max=1.): 68 | return x * (x_max - x_min) + x_min 69 | 70 | 71 | def tanh_rescale(x, x_min=-1., x_max=1.): 72 | return (torch.tanh(x) + 1) * 0.5 * (x_max - x_min) + x_min 73 | -------------------------------------------------------------------------------- /wideresnet28/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname "$0")" # cd to directory of this script 4 | 5 | # $1 is filename 6 | # $2 is expected sha 7 | check_sha1() { 8 | computed=$(sha1sum "$1" 2>/dev/null | awk '{print $1}') || return 1 9 | if [ "$computed" == "$2" ]; then 10 | return 0; 11 | else 12 | return 1; 13 | fi 14 | } 15 | 16 | # $1 is URL 17 | # $2 is extracted file name 18 | # $3 is the checksum 19 | fetch() { 20 | f=${1##*/} 21 | if check_sha1 $f $3; then 22 | echo "$2 already downloaded" 23 | return 24 | fi 25 | echo "downloading $1" 26 | wget -q $1 -O $f 27 | if check_sha1 $f $3; then 28 | echo "downloaded $2" 29 | else 30 | echo "HASH MISMATCH, SHA1($f) != $3" 31 | return 32 | fi 33 | 34 | tar xzf $f 35 | } 36 | 37 | cd .. 38 | fetch https://github.com/anishathalye/obfuscated-gradients/releases/download/v0/cifar10_data.tgz cifar10_data 6d011cbb029aec2c18dc10bce32adea9e27c2068 39 | mkdir -p models 40 | cd models 41 | fetch https://github.com/anishathalye/obfuscated-gradients/releases/download/v0/model_thermometer_advtrain.tgz models/thermometer_advtrain 595261189ee9a78911f312cd2443ee088ef59bee 42 | -------------------------------------------------------------------------------- /wideresnet28/test_wres.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | 5 | import scipy.misc 6 | from datetime import datetime 7 | import json 8 | import os 9 | import shutil 10 | from timeit import default_timer as timer 11 | from discretization_utils import discretize_uniform 12 | from discretization_attacks import adv_lspga 13 | 14 | import tensorflow as tf 15 | import numpy as np 16 | 17 | from cifar_model import Model 18 | import cifar10_input 19 | import sys 20 | import robustml 21 | import argparse 22 | 23 | levels = 16 24 | 25 | 26 | 27 | 28 | 29 | 30 | steps = 7 31 | eps = 0.031 32 | 33 | 34 | 35 | parser = argparse.ArgumentParser() 36 | parser.add_argument('--cifar-path', type=str, default='../cifar10_data/test_batch', 37 | help='path to the test_batch file from http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz') 38 | parser.add_argument('--start', type=int, default=0) 39 | parser.add_argument('--end', type=int, default=100) 40 | parser.add_argument('--debug', action='store_true') 41 | args = parser.parse_args() 42 | 43 | 44 | provider = robustml.provider.CIFAR10(args.cifar_path) 45 | # saver = tf.train.Saver(max_to_keep=3) 46 | 47 | start = 0 48 | end = 100 49 | 50 | config = tf.ConfigProto() 51 | config.gpu_options.allow_growth = True 52 | sess = tf.Session(config=config) 53 | 54 | model = Model( './models/adv_train_clean/', 55 | sess,mode='eval', tiny=False, 56 | thermometer=False, levels=levels) 57 | # initialize data augmentation 58 | 59 | 60 | input_xs = tf.placeholder(tf.float32, [None, 32, 32, 3]) 61 | real_logits = tf.nn.softmax(model(input_xs)) 62 | 63 | # saver.restore(sess, 64 | # os.path.join("models/adv_train_clean", 'checkpoint-65000')) 65 | 66 | for i in range(start, end): 67 | x_batch, y_batch = provider[i] 68 | 69 | logits = sess.run(real_logits,feed_dict={input_xs: [x_batch]}) 70 | # nat_dict = {model.x_input: [x_batch],model.y_input: [y_batch]} 71 | # logits = sess.run(model.pre_softmax, feed_dict=nat_dict) 72 | 73 | print(logits) 74 | 75 | 76 | 77 | 78 | --------------------------------------------------------------------------------