├── .gitignore ├── COPYRIGHT ├── LICENSE ├── README.md ├── clever.py ├── collect_gradients.py ├── defense.py ├── estimate_gradient_norm.py ├── labels ├── imagenet_val_to_carlini.py ├── label2num.txt ├── labels.py ├── labels.txt └── synset_words.txt ├── nlayer_model.py ├── process_log.py ├── randsphere.py ├── run.sh ├── setup_cifar.py ├── setup_imagenet.py ├── setup_mnist.py ├── shmemarray.py ├── train_2layer.py ├── train_models.py ├── train_nlayer.py └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | processed_result/.ipy* 2 | processed_result/pickle* 3 | models/ 4 | __pycache__/ 5 | all_results/ 6 | tmp/ 7 | model/ 8 | data/ 9 | *.fig 10 | *.png 11 | cifar-data.tar.gz 12 | cifar-10-batches-bin/ 13 | *.csv 14 | *.swp 15 | *.npy 16 | *.mat 17 | *.zip 18 | *.pyc 19 | 20 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (C) 2017-2018, IBM Corp. 2 | Copyright (C) 2017, Huan Zhang and Lily Weng 3 | Copyright (c) 2016, Nicholas Carlini 4 | 5 | LICENSE 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CLEVER: A Robustness Metric For Deep Neural Networks 2 | ===================================== 3 | 4 | CLEVER (**C**ross-**L**ipschitz **E**xtreme **V**alue for n**E**twork **R**obustness) is a metric for 5 | measuring the robustness of deep neural networks. It estimates the robustness 6 | lower bound by sampling the norm of gradients and fitting a limit distribution 7 | using extreme value theory. CLEVER score is attack-agnostic; a higher score 8 | number indicates that the network is likely to be less venerable to adversarial 9 | examples. CLEVER can be efficiently computed even for large state-of-the-art 10 | ImageNet models like ResNet-50 and Inception-v3. 11 | 12 | For more details, please see our paper: 13 | 14 | [Evaluating the Robustness of Neural Networks: An Extreme Value Theory Approach](https://openreview.net/pdf?id=BkUHlMZ0b) 15 | by Tsui-Wei Weng\*, Huan Zhang\*, Pin-Yu Chen, Dong Su, Yupeng Gao, Jinfeng Yi, Cho-Jui Hsieh and Luca Daniel 16 | 17 | \* Equal contribution 18 | 19 | News 20 | ------------------------------------- 21 | 22 | - Aug 6, 2018: CLEVER evaluation with input transformations (e.g., staircase 23 | function or JPEG compression) is implemented via BPDA (Backward Pass 24 | Differentiable Approximation) 25 | - Aug 16, 2018: added 2nd order CLEVER evaluation implementation, which can be 26 | used to evaluate robustness on classifiers that are twice-differentiable. 27 | 28 | Discussion with Ian Goodfellow and Our Clarifications 29 | ------------------------------------- 30 | 31 | We received some inquires on [Ian Goodfellow's 32 | comment](https://arxiv.org/abs/1804.07870) “*Gradient Masking Causes CLEVER to 33 | Overestimate Adversarial Perturbation Size*” on our paper. We thank Ian for 34 | the discussion but the comments are inappropriate and not applicable to our 35 | paper. CLEVER is intended to be a tool for network designer and to evaluate 36 | network robustness in the “white-box” setting. Especially, the argument that 37 | on digital computers all functions are not Lipschitz continuous and behave 38 | like a staircase function (where the gradient is zero almost everywhere) is 39 | incorrect. Under the white-box setting, gradients can be computed via automatic 40 | differentiation, which is well supported by mature packages like TensorFlow. 41 | See [our reply and discussions with Ian Goodfellow on gradient masking and implementation on digital computers](https://openreview.net/forum?id=BkUHlMZ0b¬eId=Hyc-dnN6f¬eId=SkzxpFrpz). 42 | 43 | Setup and train models 44 | ------------------------------------- 45 | 46 | The code is tested with python3 and TensorFlow v1.3, v1.4 and v1.5. The following 47 | packages are required: 48 | 49 | ``` 50 | sudo apt-get install python3-pip python3-dev 51 | sudo pip3 install --upgrade pip 52 | sudo pip3 install six pillow scipy numpy pandas matplotlib h5py posix_ipc tensorflow-gpu 53 | ``` 54 | 55 | Then clone this repository: 56 | 57 | ``` 58 | git clone https://github.com/huanzhang12/CLEVER.git 59 | cd CLEVER 60 | ``` 61 | 62 | Prepare the MNIST and CIFAR-10 data and models with different activation functions: 63 | 64 | ``` 65 | python3 train_models.py 66 | python3 train_2layer.py 67 | python3 train_nlayer.py --model mnist --modeltype cnn --activation tanh 32 32 64 64 200 200 68 | python3 train_nlayer.py --model cifar --modeltype cnn --activation tanh 64 64 128 128 256 256 69 | 70 | ``` 71 | 72 | To download the ImageNet models: 73 | 74 | ``` 75 | python3 setup_imagenet.py 76 | ``` 77 | 78 | To prepare the ImageNet dataset, download and unzip the following archive: 79 | 80 | [ImageNet Test Set](http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/img.tar.gz) 81 | 82 | 83 | and put the `imgs` folder in `../imagenetdata`, relative to the CLEVER repository. 84 | This path can be changed in `setup_imagenet.py`. 85 | 86 | ``` 87 | cd .. 88 | mkdir imagenetdata && cd imagenetdata 89 | wget http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/img.tar.gz 90 | tar zxf img.tar.gz 91 | cd ../CLEVER 92 | ``` 93 | 94 | How to run 95 | -------------------------------------- 96 | 97 | ### Step 1: Collect gradients 98 | 99 | The first step for computing CLEVER score is to collect gradient samples. 100 | The following command collects gradient samples for 10 images in MNIST dataset; 101 | for each image, 3 target attack classes are chosen (random, top-2 and least likely). 102 | Images that are classified incorrectly will be skipped, so you might get less than 103 | 10 images. 104 | The default network used has a 7-layer AlexNet-like CNN structure. 105 | 106 | ``` 107 | python3 collect_gradients.py --dataset mnist --numimg 10 108 | ``` 109 | 110 | Results will be saved into folder `lipschitz_mat/mnist_normal` by default (which can be 111 | changed by specifying the `--saved ` parameter), as 112 | a few `.mat` files. 113 | 114 | Run `python3 collect_gradients.py -h` for additional help information. 115 | 116 | **Updated:** For model with input transformation, use an additional parameter 117 | `--transform`. Currently three input transformations are supported (bit-depth 118 | reduction, JPEG compression and PNG compression, corresponding to 119 | `defend_reduce`, `defend_jpeg`, `defend_png` options). For example: 120 | 121 | ``` 122 | python3 collect_gradients.py --dataset cifar --numimg 10 --transform defend_jpeg 123 | ``` 124 | 125 | You should expect roughly the same CLEVER score with input transformations, 126 | as input transformations do not increase model's intrinsic robustness and can 127 | be broken by BPDA. 128 | See `defense.py` for the implementations of input transformations. 129 | 130 | **Updated:** To run 2nd order clever score, run.sh can be used and set order = 2: 131 | 132 | ``` 133 | ./run.sh model modeltype nsamp niters activation order target gpuNum 134 | ``` 135 | For example, to get 1000 samples of 2nd order clever with 100 iterations on a mnist 7-layer cnn model with tanh activation and random target: 136 | 137 | ``` 138 | ./run.sh mnist normal 1000 100 tanh 2 rand 139 | ``` 140 | 141 | To get samples for the original clever score (1st order approximation), set order = 1. 142 | 143 | 144 | ### Step 2: Compute the CLEVER score 145 | 146 | To compute CLEVER score using the collected gradients, 147 | run `clever.py` with data saving folder as a parameter: 148 | 149 | ``` 150 | python3 clever.py lipschitz_mat/mnist_normal 151 | ``` 152 | 153 | Run `python3 clever.py -h` for additional help information. 154 | 155 | 156 | ### Step 3: How to interpret the score? 157 | 158 | At the end of the output of `clever.py`, you will see three `[STATS][L0]` lines similar to the following: 159 | 160 | ``` 161 | [STATS][L0] info = least, least_clever_L1 = 2.7518, least_clever_L2 = 1.1374, least_clever_Li = 0.080179 162 | [STATS][L0] info = random, random_clever_L1 = 2.9561, random_clever_L2 = 1.1213, random_clever_Li = 0.075569 163 | [STATS][L0] info = top2, top2_clever_L1 = 1.6683, top2_clever_L2 = 0.70122, top2_clever_Li = 0.050181 164 | ``` 165 | 166 | The scores shown are the average scores for all (in the example above, 10) 167 | images, with three different target attack classes: least likely, random and 168 | top-2 (the class with second largest probability). Three scores are provided: 169 | CLEVER\_L2, CLEVER\_Linf and CLEVER\_L1, representing the robustness for L2, L\_infinity 170 | and L1 perturbations. CLEVER score for Lp norm roughly reflects 171 | the minimum Lp norm of adversarial perturbations. A higher CLEVER score 172 | indicates better network robustness, as the minimum adversarial perturbation is 173 | likely to have a larger Lp norm. As CLEVER uses a sampling based method, the 174 | scores may vary slightly for different runs. 175 | 176 | More Examples 177 | --------------------------------- 178 | 179 | For example, the following command will evaluate the CLEVER scores on 1 180 | ImageNet image, for a 50-layer ResNet model. We set the number of gradient 181 | samples per iterations to 512, and run 100 iterations: 182 | 183 | ``` 184 | python3 collect_gradients.py --dataset imagenet --model_name resnet_v2_50 -N 512 -i 100 185 | python3 clever.py lipschitz_mat/imagenet_resnet_v2_50/ 186 | ``` 187 |

188 | Bustard 189 |

190 | 191 | For this image (`139.00029510.jpg`, which is the first image given the default 192 | random seed) in dataset, the original class is 139 (bustard), least likely 193 | class is 20 (chickadee), top-2 class is 82 (ptarmigan), random class target 194 | is 708 (pay-phone). (These can be observed in `[DATAGEN][L1]` lines of the 195 | output of `collect_gradients.py`). We get the following CLEVER scores: 196 | 197 | ``` 198 | [STATS][L0] info = least, least_clever_L1 = 8.1393, least_clever_L2 = 0.64424, least_clever_Li = 0.0029474 199 | [STATS][L0] info = random, random_clever_L1 = 4.6543, random_clever_L2 = 0.61181, random_clever_Li = 0.0023765 200 | [STATS][L0] info = top2, top2_clever_L1 = 0.99283, top2_clever_L2 = 0.13185, top2_clever_Li = 0.00062238 201 | ``` 202 | 203 | The L2 CLEVER score for the top-2, random and least-likely classes are 204 | 0.13185, 0.61181 and 0.64424, 205 | respectively. It indicates that it is very easy to attack this image from 206 | class 139 to 82. We then run the CW attack, which is the strongest L2 attack 207 | to date, on this image with the same three target classes. The distortion of 208 | adversarial images are 0.1598, 0.82025, 0.85298 for the three targets. 209 | Indeed, to misclassify the image to class 82, only a very small distortion 210 | (0.1598) is needed. Also, the CLEVER scores are (usually) less than the L2 211 | distortions observed on adversarial examples, but are not too small to be 212 | useless, reflecting the nature that CLEVER is an estimated robustness lower 213 | bound. 214 | 215 | CLEVER also has an untargeted version, which is essentially the smallest CLEVER 216 | score over all possible target classes. The following examples shows how to 217 | compute untargeted CLEVER score for 10 images from MNIST dataset, on the 218 | 2-layer MLP model: 219 | 220 | ``` 221 | python3 collect_gradients.py --data mnist --model_name 2-layer --target_type 16 --numimg 10 222 | python3 clever.py --untargeted ./lipschitz_mat/mnist_2-layer/ 223 | ``` 224 | 225 | Target type 16 (bit 4 set to 1) indicates that we are collecting gradients for 226 | untargeted CLEVER score (see `python3 collect_gradients.py -h` for more details). 227 | The results will look like the following: 228 | 229 | ``` 230 | [STATS][L0] info = untargeted, untargeted_clever_L1 = 3.4482, untargeted_clever_L2 = 0.69393, untargeted_clever_Li = 0.035387 231 | ``` 232 | 233 | For datasets which have many classes, it is very expensive to evaluate the 234 | untargeted CLEVER scores. However, usually the robustness of the top-2 235 | targeted class can roughly reflect the untargeted robustness, as it is 236 | usually one of the easiest classes to change to. 237 | 238 | Built-in Models 239 | -------------------------------- 240 | 241 | In the examples shown above we have used several different models. 242 | The code on this repository has a large number of built-in models for 243 | robustness evaluation. Model can be selected by changing the `--model_name` 244 | parameter to `collect_gradiets.py`. For MNIST and CIFAR dataset, the following 245 | models are available: "2-layer" (MLP), "normal" (7-layer CNN), "distilled" 246 | (7-layer CNN with defensive distillation), "brelu" (7-layer CNN with Bounded 247 | ReLU). For ImageNet, available options are: "resnet_v2_50", "resnet_v2_101", 248 | "resnet_v2_152", "inception_v1", "inception_v2", "inception_v3", 249 | "inception_v4", "inception_resnet_v2", "vgg_16", "vgg_19", "mobilenet_v1_025", 250 | "mobilenet_v1_050", "mobilenet_v1_100", "alexnet", "densenet121_k32", 251 | "densenet169_k32", "densenet161_k48" and "nasnet_larget". 252 | A total of 18 ImageNet models have been built in so far. 253 | 254 | 255 | How to evaluate my own model? 256 | -------------------------------- 257 | 258 | Models for MNIST, CIFAR and ImageNet datasets are defined in `setup_mnist.py`, 259 | `setup_cifar.py` and `setup_imagenet.py`. For MNIST and CIFAR, you can modify 260 | the model definition in `setup_mnist.py` and `setup_cifar.py` directly. For 261 | ImageNet, a protobuf (.pb) model with frozen network parameters is expected, 262 | and new ImageNet models can be added into `setup_imagenet.py` by adding a new 263 | `AddModel()` entry, similar to other ImageNet models. Please read the comments 264 | on `AddModel()` in `setup_imagenet.py` for more details. 265 | 266 | The following two links provide examples on how to prepare a frozen protobuf 267 | for ImageNet models: 268 | 269 | [Prepare DenseNet models](https://github.com/huanzhang12/tensorflow-densenet-models) 270 | 271 | [Prepare AlexNet model](https://github.com/huanzhang12/tensorflow-alexnet-model) 272 | 273 | Known Issues 274 | -------------------------------- 275 | 276 | If you encounter the following error: 277 | 278 | ``` 279 | posix_ipc.ExistentialError: Shared memory with the specified name already exists 280 | ``` 281 | 282 | Please delete those residual files in `/dev/shm` 283 | 284 | ``` 285 | rm -f /dev/shm/*all_inputs 286 | rm -f /dev/shm/*input_example 287 | rm -f /dev/shm/*randsphere 288 | rm -f /dev/shm/*scale 289 | ``` 290 | 291 | For systemd based Linux distributions (for example, Ubuntu 16.04+), it is 292 | necessary to set `RemoveIPC=no` in `/etc/systemd/logind.conf` and restart 293 | `systemd-logind` (`sudo systemctl restart systemd-logind.service`) to avoid 294 | systemd from removing shared memory objects after user logout (which prevents 295 | CLEVER running in background). 296 | 297 | -------------------------------------------------------------------------------- /clever.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | clever.py 5 | 6 | Compute CLEVER score using collected Lipschitz constants 7 | 8 | Copyright (C) 2017-2018, IBM Corp. 9 | Copyright (C) 2017, Lily Weng 10 | and Huan Zhang 11 | 12 | This program is licenced under the Apache 2.0 licence, 13 | contained in the LICENCE file in this directory. 14 | """ 15 | 16 | import os 17 | import sys 18 | import glob 19 | from functools import partial 20 | from multiprocessing import Pool 21 | import scipy 22 | import scipy.io as sio 23 | from scipy.stats import weibull_min 24 | import scipy.optimize 25 | import numpy as np 26 | import argparse 27 | import matplotlib 28 | matplotlib.use('Agg') 29 | import matplotlib.pyplot as plt 30 | 31 | # We observe that the scipy.optimize.fmin optimizer (using Nelder–Mead method) 32 | # sometimes diverges to very large parameters a, b and c. Thus, we add a very 33 | # small regularization to the MLE optimization process to avoid this divergence 34 | def fmin_with_reg(func, x0, args=(), xtol=1e-4, ftol=1e-4, maxiter=None, maxfun=None, 35 | full_output=0, disp=1, retall=0, callback=None, initial_simplex=None, shape_reg = 0.01): 36 | # print('my optimier with shape regularizer = {}'.format(shape_reg)) 37 | def func_with_reg(theta, x): 38 | shape = theta[2] 39 | log_likelyhood = func(theta, x) 40 | reg = shape_reg * shape * shape 41 | # penalize the shape parameter 42 | return log_likelyhood + reg 43 | return scipy.optimize.fmin(func_with_reg, x0, args, xtol, ftol, maxiter, maxfun, 44 | full_output, disp, retall, callback, initial_simplex) 45 | 46 | # fit using weibull_min.fit and run a K-S test 47 | def fit_and_test(rescaled_sample, sample, loc_shift, shape_rescale, optimizer, c_i): 48 | [c, loc, scale] = weibull_min.fit(-rescaled_sample, c_i, optimizer=optimizer) 49 | loc = - loc_shift + loc * shape_rescale 50 | scale *= shape_rescale 51 | ks, pVal = scipy.stats.kstest(-sample, 'weibull_min', args = (c, loc, scale)) 52 | return c, loc, scale, ks, pVal 53 | 54 | def plot_weibull(sample,c,loc,scale,ks,pVal,p,q,figname = "Lily_weibull_test.png"): 55 | 56 | # compare the sample histogram and fitting result 57 | fig, ax = plt.subplots(1,1) 58 | 59 | x = np.linspace(-1.01*max(sample),-0.99*min(sample),100); 60 | ax.plot(x,weibull_min.pdf(x,c,loc,scale),'r-',label='fitted pdf '+p+'-bnd') 61 | ax.hist(-sample, normed=True, bins=20, histtype='stepfilled') 62 | ax.legend(loc='best', frameon=False) 63 | plt.xlabel('-Lips_'+q) 64 | plt.ylabel('pdf') 65 | plt.title('c = {:.2f}, loc = {:.2f}, scale = {:.2f}, ks = {:.2f}, pVal = {:.2f}'.format(c,loc,scale,ks,pVal)) 66 | plt.savefig(figname) 67 | plt.close() 68 | #model = figname.split("_")[1] 69 | #plt.savefig('./debug/'+model+'/'+figname) 70 | #plt.show() # can be used to pause the program 71 | 72 | # We observe than the MLE estimator in scipy sometimes can converge to a bad 73 | # value if the inital shape parameter c is too far from the true value. Thus we 74 | # test a few different initializations and choose the one with best p-value all 75 | # the initializations are tested in parallel; remove some of them to speedup 76 | # computation. 77 | # c_init = [0.01,0.1,0.5,1,5,10,20,50,70,100,200] 78 | c_init = [0.1,1,5,10,20,50,100] 79 | 80 | def get_best_weibull_fit(sample, use_reg = False, shape_reg = 0.01): 81 | 82 | # initialize dictionary to save the fitting results 83 | fitted_paras = {"c":[], "loc":[], "scale": [], "ks": [], "pVal": []} 84 | # reshape the data into a better range 85 | # this helps the MLE solver find the solution easier 86 | loc_shift = np.amax(sample) 87 | dist_range = np.amax(sample) - np.amin(sample) 88 | # if dist_range > 2.5: 89 | shape_rescale = dist_range 90 | # else: 91 | # shape_rescale = 1.0 92 | print("shape rescale = {}".format(shape_rescale)) 93 | rescaled_sample = np.copy(sample) 94 | rescaled_sample -= loc_shift 95 | rescaled_sample /= shape_rescale 96 | 97 | print("loc_shift = {}".format(loc_shift)) 98 | ##print("rescaled_sample = {}".format(rescaled_sample)) 99 | 100 | # fit weibull distn: sample follows reverse weibull dist, so -sample follows weibull distribution 101 | if use_reg: 102 | results = pool.map(partial(fit_and_test, rescaled_sample, sample, loc_shift, shape_rescale, partial(fmin_with_reg, shape_reg = shape_reg)), c_init) 103 | else: 104 | results = pool.map(partial(fit_and_test, rescaled_sample, sample, loc_shift, shape_rescale, scipy.optimize.fmin), c_init) 105 | 106 | for res, c_i in zip(results, c_init): 107 | c = res[0] 108 | loc = res[1] 109 | scale = res[2] 110 | ks = res[3] 111 | pVal = res[4] 112 | print("[DEBUG][L2] c_init = {:5.5g}, fitted c = {:6.2f}, loc = {:7.2f}, scale = {:7.2f}, ks = {:4.2f}, pVal = {:4.2f}, max = {:7.2f}".format(c_i,c,loc,scale,ks,pVal,loc_shift)) 113 | 114 | ## plot every fitted result 115 | #plot_weibull(sample,c,loc,scale,ks,pVal,p) 116 | 117 | fitted_paras['c'].append(c) 118 | fitted_paras['loc'].append(loc) 119 | fitted_paras['scale'].append(scale) 120 | fitted_paras['ks'].append(ks) 121 | fitted_paras['pVal'].append(pVal) 122 | 123 | 124 | # get the paras of best pVal among c_init 125 | max_pVal = np.nanmax(fitted_paras['pVal']) 126 | if np.isnan(max_pVal) or max_pVal < 0.001: 127 | print("ill-conditioned samples. Using maximum sample value.") 128 | # handle the ill conditioned case 129 | return -1, -1, -max(sample), -1, -1, -1 130 | 131 | max_pVal_idx = fitted_paras['pVal'].index(max_pVal) 132 | 133 | c_init_best = c_init[max_pVal_idx] 134 | c_best = fitted_paras['c'][max_pVal_idx] 135 | loc_best = fitted_paras['loc'][max_pVal_idx] 136 | scale_best = fitted_paras['scale'][max_pVal_idx] 137 | ks_best = fitted_paras['ks'][max_pVal_idx] 138 | pVal_best = fitted_paras['pVal'][max_pVal_idx] 139 | 140 | return c_init_best, c_best, loc_best, scale_best, ks_best, pVal_best 141 | 142 | 143 | # G_max is the input array of max values 144 | # Return the Weibull position parameter 145 | def get_lipschitz_estimate(G_max, norm = "L2", figname = "", use_reg = False, shape_reg = 0.01): 146 | global plot_res 147 | c_init, c, loc, scale, ks, pVal = get_best_weibull_fit(G_max, use_reg, shape_reg) 148 | 149 | # the norm here is Lipschitz constant norm, not the bound's norm 150 | if norm == "L1": 151 | p = "i"; q = "1" 152 | elif norm == "L2": 153 | p = "2"; q = "2" 154 | elif norm == "Li": 155 | p = "1"; q = "i" 156 | else: 157 | print("Lipschitz norm is not in 1, 2, i!") 158 | 159 | figname = figname + '_'+ "L"+ p + ".png" 160 | 161 | if plot_res is not None: 162 | plot_res.get() 163 | 164 | # plot_weibull(G_max,c,loc,scale,ks,pVal,p,q,figname) 165 | if figname: 166 | plot_res = pool.apply_async(plot_weibull, (G_max,c,loc,scale,ks,pVal,p,q,figname)) 167 | 168 | return {'Lips_est':-loc, 'shape':c, 'loc': loc, 'scale': scale, 'ks': ks, 'pVal': pVal} 169 | #return np.max(G_max) 170 | 171 | # file name contains some information, like true_id, true_label and target_label 172 | def parse_filename(filename): 173 | basename = os.path.basename(filename) 174 | name, _ = os.path.splitext(basename) 175 | name_arr = name.split('_') 176 | Nsamp = int(name_arr[0]) 177 | Niters = int(name_arr[1]) 178 | true_id = int(name_arr[2]) 179 | true_label = int(name_arr[3]) 180 | target_label = int(name_arr[4]) 181 | image_info = name_arr[5] 182 | activation = name_arr[6] 183 | order = name_arr[7][-1] 184 | return Nsamp, Niters, true_id, true_label, target_label, image_info, activation, order 185 | 186 | if __name__ == "__main__": 187 | # parse command line parameters 188 | parser = argparse.ArgumentParser(description='Compute CLEVER scores using collected gradient norm data.', 189 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) 190 | parser.add_argument('data_folder', help='data folder path') 191 | parser.add_argument('--min', dest='reduce_op', action='store_const', 192 | default=lambda x: sum(x) / len(x) if len(x) > 0 else 0, const=min, 193 | help='report min of all CLEVER scores instead of avg') 194 | parser.add_argument('--user_type', 195 | default="", 196 | help='replace user type with string, used for ImageNet data processing') 197 | parser.add_argument('--use_slope', 198 | action="store_true", 199 | help='report slope estimate. To use this option, collect_gradients.py needs to be run with --compute_slope') 200 | parser.add_argument('--untargeted', 201 | action="store_true", 202 | help='process untargeted attack results (for MNIST and CIFAR)') 203 | parser.add_argument('--num_samples', 204 | type=int, 205 | default=0, 206 | help='the number of samples to use. Default 0 is to use all samples') 207 | parser.add_argument('--num_images', 208 | type=int, 209 | default=0, 210 | help='number of images to use, 0 to use all images') 211 | parser.add_argument('--shape_reg', 212 | default=0.01, 213 | type=float, 214 | help='to avoid the MLE solver in Scipy to diverge, we add a small regularization (default 0.01 is sufficient)') 215 | parser.add_argument('--nthreads', 216 | default=0, 217 | type=int, 218 | help='number of threads (default is len(c_init)+1)') 219 | parser.add_argument('--plot_dir', 220 | default='', 221 | help='output path for weibull fit figures (empty to disable)') 222 | parser.add_argument('--method', 223 | default="mle_reg", 224 | choices=['mle','mle_reg','maxsamp'], 225 | help='Fitting algorithm. Please use mle_reg for best results') 226 | args = vars(parser.parse_args()) 227 | reduce_op = args['reduce_op'] 228 | if args['plot_dir']: 229 | os.system("mkdir -p " + args['plot_dir']) 230 | print(args) 231 | 232 | # create thread pool 233 | if args['nthreads'] == 0: 234 | args['nthreads'] = len(c_init) + 1 235 | print("using {} threads".format(args['nthreads'])) 236 | pool = Pool(processes = args['nthreads']) 237 | # pool = Pool(1) 238 | # used for asynchronous plotting in background 239 | plot_res = None 240 | 241 | # get a list of all '.mat' files in folder 242 | file_list = glob.glob(args['data_folder'] + '/**/*.mat', recursive = True) 243 | # sort by image ID, then by information (least likely, random, top-2) 244 | file_list = sorted(file_list, key = lambda x: (parse_filename(x)[2], parse_filename(x)[5])) 245 | # get the first num_images files 246 | if args['num_images']: 247 | file_list = file_list[:args['num_images']] 248 | 249 | if args['untargeted']: 250 | bounds = {} 251 | # bounds will be inserted per image 252 | else: 253 | # aggregate information for three different types: least, random and top2 254 | # each has three bounds: L1, L2, and Linf 255 | bounds = {"least" : [[], [], []], 256 | "random": [[], [], []], 257 | "top2" : [[], [], []]} 258 | 259 | for fname in file_list: 260 | nsamps, niters, true_id, true_label, target_label, img_info, activation, order = parse_filename(fname) 261 | 262 | # keys in mat: 263 | # ['Li_max', 'pred', 'G1_max', 'g_x0', 'path', 'info', 'G2_max', 'true_label', 'args', 'L1_max', 'Gi_max', 'L2_max', 'id', 'target_label'] 264 | mat = sio.loadmat(fname) 265 | print('loading {}'.format(fname)) 266 | 267 | if order == "1" and args['use_slope']: 268 | G1_max = np.squeeze(mat['L1_max']) 269 | G2_max = np.squeeze(mat['L2_max']) 270 | Gi_max = np.squeeze(mat['Li_max']) 271 | elif order == "1": 272 | G1_max = np.squeeze(mat['G1_max']) 273 | G2_max = np.squeeze(mat['G2_max']) 274 | Gi_max = np.squeeze(mat['Gi_max']) 275 | elif order == "2": 276 | """ For Jun 25 experiments: forgot to save g_x0_grad_2_norm, so rerun a 1 sample 1 iterations cases "1_1_*.mat" and load g_x0_grad_2_norm from it 277 | fname_ref = os.path.dirname(fname)+'_1/'+"1_1_"+str(true_id)+"_"+str(true_label)+"_"+str(target_label)+"_"+img_info+"_"+activation+"_order2.mat" 278 | ##fname_ref = 'lipschitz_mat/mnist_normal/'+"1_1_"+str(true_id)+"_"+str(true_label)+"_"+str(target_label)+"_"+img_info+"_"+activation+"_order2.mat" 279 | print("loading {}".format(fname_ref)) 280 | mat_ref = sio.loadmat(fname_ref) 281 | g_x0_grad_2_norm = np.squeeze(mat_ref['g_x0_grad_2_norm']) 282 | print("g_x0_grad_2_norm = {}".format(g_x0_grad_2_norm)) 283 | 284 | #import time 285 | #time.sleep(30) 286 | """ 287 | G2_max = np.abs(np.squeeze(mat['H2_max'])) # forgot to add abs when save in mat file 288 | G1_max = -1*np.empty_like(G2_max) # currently only implemented 2nd order bound for p = 2 289 | Gi_max = -1*np.empty_like(G2_max) 290 | g_x0_grad_2_norm = np.squeeze(mat['g_x0_grad_2_norm']) 291 | else: 292 | raise RuntimeError('!!! order is {}'.format(order)) 293 | 294 | if args['num_samples'] != 0: 295 | prev_len = len(G1_max) 296 | G1_max = G1_max[:args['num_samples']] 297 | G2_max = G2_max[:args['num_samples']] 298 | Gi_max = Gi_max[:args['num_samples']] 299 | print('Using {} out of {} total samples'.format(len(G1_max), prev_len)) 300 | g_x0 = np.squeeze(mat['g_x0']) 301 | target_label = np.squeeze(mat['target_label']) 302 | true_id = np.squeeze(mat['id']) 303 | true_label = np.squeeze(mat['true_label']) 304 | img_info = mat['info'][0] 305 | if args['user_type'] != "" and img_info == "user": 306 | img_info = args['user_type'] 307 | 308 | # get the filename (.mat) 309 | print('[Filename] {}'.format(fname)) 310 | # get the model name (inception, cifar_2-layer) 311 | possible_names = ["mnist", "cifar", "mobilenet", "inception", "resnet"] 312 | model = "unknown" 313 | for path_seg in args["data_folder"].split("/"): 314 | for n in possible_names: 315 | if n in path_seg: 316 | model = path_seg.replace('_', '-') 317 | break 318 | # model = args["data_folder"].split("/")[1] 319 | 320 | if args['num_samples'] == 0: # default, use all G1_max 321 | figname = 'Fig_'+model+'_'+img_info+'_'+str(true_id)+'_'+str(true_label)+'_'+str(target_label)+'_Nsamp_'+str(len(G1_max)); 322 | elif args['num_samples'] <= len(G1_max) and args['num_samples'] > 0: 323 | figname = 'Fig_'+model+'_'+img_info+'_'+str(true_id)+'_'+str(true_label)+'_'+str(target_label)+'_Nsamp_'+str(args['num_samples']); 324 | else: 325 | print('Warning!! Input arg num_samp = {} exceed len(G1_max) in data_process.py'.format(args['num_samples'])) 326 | continue 327 | 328 | 329 | if args['use_slope']: 330 | figname = figname + '_slope' 331 | 332 | if args['plot_dir']: 333 | figname = os.path.join(args['plot_dir'], figname) 334 | # figname 335 | print('[Figname] {}'.format(figname)) 336 | else: 337 | # disable debugging figure 338 | figname = "" 339 | 340 | 341 | 342 | if args['method'] == "maxsamp": 343 | if order == "1": 344 | Est_G1 = {'Lips_est': max(G1_max), 'shape': -1, 'loc': -1, 'scale': -1, 'ks': -1, 'pVal': -1} 345 | Est_G2 = {'Lips_est': max(G2_max), 'shape': -1, 'loc': -1, 'scale': -1, 'ks': -1, 'pVal': -1} 346 | Est_Gi = {'Lips_est': max(Gi_max), 'shape': -1, 'loc': -1, 'scale': -1, 'ks': -1, 'pVal': -1} 347 | else: # currently only compare bounds in L2 for both order = 1 and order = 2 348 | Est_G2 = {'Lips_est': max(G2_max), 'shape': -1, 'loc': -1, 'scale': -1, 'ks': -1, 'pVal': -1} 349 | Est_G1 = Est_G2 350 | Est_Gi = Est_G2 351 | 352 | elif args['method'] == "mle": 353 | # estimate Lipschitz constant: Est_G1 is a dictionary containing Lips_est and weibull paras 354 | if order == "1": 355 | Est_G1 = get_lipschitz_estimate(G1_max, "L1", figname) 356 | Est_G2 = get_lipschitz_estimate(G2_max, "L2", figname) 357 | Est_Gi = get_lipschitz_estimate(Gi_max, "Li", figname) 358 | else: # currently only compare bounds in L2 for both order = 1 and order = 2 359 | Est_G2 = get_lipschitz_estimate(G2_max, "L2", figname) 360 | Est_G1 = Est_G2 # haven't implemented 361 | Est_Gi = Est_G2 # haven't implemented 362 | 363 | elif args['method'] == "mle_reg": 364 | 365 | if order == "1": 366 | print('estimating L1...') 367 | Est_G1 = get_lipschitz_estimate(G1_max, "L1", figname, True, args['shape_reg']) 368 | print('estimating L2...') 369 | Est_G2 = get_lipschitz_estimate(G2_max, "L2", figname, True, args['shape_reg']) 370 | print('estimating Li...') 371 | Est_Gi = get_lipschitz_estimate(Gi_max, "Li", figname, True, args['shape_reg']) 372 | else: # currently only compare bounds in L2 for both order = 1 and order = 2 373 | print('estimating L2...') 374 | Est_G2 = get_lipschitz_estimate(G2_max, "L2", figname, True, args['shape_reg']) 375 | Est_G1 = Est_G2 376 | Est_Gi = Est_G1 377 | else: 378 | raise RuntimeError("method not supported") 379 | 380 | # the estimated Lipschitz constant 381 | Lip_G1 = Est_G1['Lips_est'] 382 | Lip_G2 = Est_G2['Lips_est'] 383 | Lip_Gi = Est_Gi['Lips_est'] 384 | 385 | # the estimated shape parameter (c) in Weibull distn 386 | shape_G1 = Est_G1['shape'] 387 | shape_G2 = Est_G2['shape'] 388 | shape_Gi = Est_Gi['shape'] 389 | 390 | # the estimated loc parameters in Weibull distn 391 | loc_G1 = Est_G1['loc'] 392 | loc_G2 = Est_G2['loc'] 393 | loc_Gi = Est_Gi['loc'] 394 | 395 | # the estimated scale parameters in Weibull distn 396 | scale_G1 = Est_G1['scale'] 397 | scale_G2 = Est_G2['scale'] 398 | scale_Gi = Est_Gi['scale'] 399 | 400 | # the computed ks score 401 | ks_G1 = Est_G1['ks'] 402 | ks_G2 = Est_G2['ks'] 403 | ks_Gi = Est_Gi['ks'] 404 | 405 | # the computed pVal 406 | pVal_G1 = Est_G1['pVal'] 407 | pVal_G2 = Est_G2['pVal'] 408 | pVal_Gi = Est_Gi['pVal'] 409 | 410 | 411 | # compute robustness bound 412 | if order == "1": 413 | bnd_L1 = g_x0 / Lip_Gi 414 | bnd_L2 = g_x0 / Lip_G2 415 | bnd_Li = g_x0 / Lip_G1 416 | else: 417 | bnd_L2 = (-g_x0_grad_2_norm + np.sqrt(g_x0_grad_2_norm**2+2*g_x0*Lip_G2))/Lip_G2 418 | bnd_L1 = bnd_L2 # haven't implemented 419 | bnd_Li = bnd_L2 # haven't implemented 420 | # save bound of each image 421 | if args['untargeted']: 422 | true_id = int(true_id) 423 | if true_id not in bounds: 424 | bounds[true_id] = [[], [], []] 425 | bounds[true_id][0].append(bnd_L1) 426 | bounds[true_id][1].append(bnd_L2) 427 | bounds[true_id][2].append(bnd_Li) 428 | else: 429 | bounds[img_info][0].append(bnd_L1) 430 | bounds[img_info][1].append(bnd_L2) 431 | bounds[img_info][2].append(bnd_Li) 432 | 433 | # original data_process mode 434 | #print('[STATS][L1] id = {}, true_label = {}, target_label = {}, info = {}, bnd_L1 = {:.5g}, bnd_L2 = {:.5g}, bnd_Li = {:.5g}'.format(true_id, true_label, target_label, img_info, bnd_L1, bnd_L2, bnd_Li)) 435 | 436 | bndnorm_L1 = "1"; 437 | bndnorm_L2 = "2"; 438 | bndnorm_Li = "i"; 439 | 440 | # if use g_x0 = {:.5g}.format(g_x0), then it will have type error. Not sure why yet. 441 | #print('g_x0 = '+str(g_x0)) 442 | 443 | 444 | if args['method'] == "maxsamp": 445 | if order == "1": 446 | print('[DEBUG][L1] id = {}, true_label = {}, target_label = {}, info = {}, nsamps = {}, niters = {}, bnd_norm = {}, bnd = {:.5g}'.format(true_id, true_label, target_label, img_info, nsamps, niters, bndnorm_L1, bnd_L1)) 447 | print('[DEBUG][L1] id = {}, true_label = {}, target_label = {}, info = {}, nsamps = {}, niters = {}, bnd_norm = {}, bnd = {:.5g}'.format(true_id, true_label, target_label, img_info, nsamps, niters, bndnorm_L2, bnd_L2)) 448 | print('[DEBUG][L1] id = {}, true_label = {}, target_label = {}, info = {}, nsamps = {}, niters = {}, bnd_norm = {}, bnd = {:.5g}'.format(true_id, true_label, target_label, img_info, nsamps, niters, bndnorm_Li, bnd_Li)) 449 | else: # currently only compare L2 bound 450 | print('[DEBUG][L1] id = {}, true_label = {}, target_label = {}, info = {}, nsamps = {}, niters = {}, bnd_norm = {}, bnd = {:.5g}'.format(true_id, true_label, target_label, img_info, nsamps, niters, bndnorm_L2, bnd_L2)) 451 | 452 | elif args['method'] == "mle" or args['method'] == "mle_reg": 453 | if order == "1": 454 | # estimate Lipschitz constant: Est_G1 is a dictionary containing Lips_est and weibull paras 455 | # current debug mode: bound_L1 corresponds to Gi, bound_L2 corresponds to G2, bound_Li corresponds to G1 456 | print('[DEBUG][L1] id = {}, true_label = {}, target_label = {}, info = {}, nsamps = {}, niters = {}, bnd_norm = {}, bnd = {:.5g}, ks = {:.5g}, pVal = {:.5g}, shape = {:.5g}, loc = {:.5g}, scale = {:.5g}, g_x0 = {}'.format(true_id, true_label, target_label, img_info, nsamps, niters, bndnorm_L1, bnd_L1, ks_Gi, pVal_Gi, shape_Gi, loc_Gi, scale_Gi, g_x0)) 457 | print('[DEBUG][L1] id = {}, true_label = {}, target_label = {}, info = {}, nsamps = {}, niters = {}, bnd_norm = {}, bnd = {:.5g}, ks = {:.5g}, pVal = {:.5g}, shape = {:.5g}, loc = {:.5g}, scale = {:.5g}, g_x0 = {}'.format(true_id, true_label, target_label, img_info, nsamps, niters, bndnorm_L2, bnd_L2, ks_G2, pVal_G2, shape_G2, loc_G2, scale_G2, g_x0)) 458 | print('[DEBUG][L1] id = {}, true_label = {}, target_label = {}, info = {}, nsamps = {}, niters = {}, bnd_norm = {}, bnd = {:.5g}, ks = {:.5g}, pVal = {:.5g}, shape = {:.5g}, loc = {:.5g}, scale = {:.5g}, g_x0 = {}'.format(true_id, true_label, target_label, img_info, nsamps, niters, bndnorm_Li, bnd_Li, ks_G1, pVal_G1, shape_G1, loc_G1, scale_G1, g_x0)) 459 | else: # currently only compare L2 bound 460 | print('[DEBUG][L1] id = {}, true_label = {}, target_label = {}, info = {}, nsamps = {}, niters = {}, bnd_norm = {}, bnd = {:.5g}, ks = {:.5g}, pVal = {:.5g}, shape = {:.5g}, loc = {:.5g}, scale = {:.5g}, g_x0 = {}'.format(true_id, true_label, target_label, img_info, nsamps, niters, bndnorm_L2, bnd_L2, ks_G2, pVal_G2, shape_G2, loc_G2, scale_G2, g_x0)) 461 | 462 | else: 463 | raise RuntimeError("method not supported") 464 | 465 | sys.stdout.flush() 466 | 467 | if args['untargeted']: 468 | clever_L1s = [] 469 | clever_L2s = [] 470 | clever_Lis = [] 471 | for true_id, true_id_bounds in bounds.items(): 472 | img_clever_L1 = min(true_id_bounds[0]) 473 | img_clever_L2 = min(true_id_bounds[1]) 474 | img_clever_Li = min(true_id_bounds[2]) 475 | n_classes = len(true_id_bounds[0]) + 1 476 | assert len(true_id_bounds[0]) == len(true_id_bounds[2]) 477 | assert len(true_id_bounds[1]) == len(true_id_bounds[2]) 478 | print('[STATS][L1] image = {:3d}, n_classes = {:3d}, clever_L1 = {:.5g}, clever_L2 = {:.5g}, clever_Li = {:.5g}'.format(true_id, n_classes, img_clever_L1, img_clever_L2, img_clever_Li)) 479 | clever_L1s.append(img_clever_L1) 480 | clever_L2s.append(img_clever_L2) 481 | clever_Lis.append(img_clever_Li) 482 | info = "untargeted" 483 | clever_L1 = reduce_op(clever_L1s) 484 | clever_L2 = reduce_op(clever_L2s) 485 | clever_Li = reduce_op(clever_Lis) 486 | print('[STATS][L0] info = {}, {}_clever_L1 = {:.5g}, {}_clever_L2 = {:.5g}, {}_clever_Li = {:.5g}'.format(info, info, clever_L1, info, clever_L2, info, clever_Li)) 487 | else: 488 | # print min/average bound 489 | for info, info_bounds in bounds.items(): 490 | # reduce each array to a single number (min or avg) 491 | clever_L1 = reduce_op(info_bounds[0]) 492 | clever_L2 = reduce_op(info_bounds[1]) 493 | clever_Li = reduce_op(info_bounds[2]) 494 | if order == "1": 495 | print('[STATS][L0] info = {}, {}_clever_L1 = {:.5g}, {}_clever_L2 = {:.5g}, {}_clever_Li = {:.5g}'.format(info, info, clever_L1, info, clever_L2, info, clever_Li)) 496 | else: # currently only compare L2 bound for both order = 1 and order = 2 497 | print('[STATS][L0] info = {}, {}_clever_L2 = {:.5g}'.format(info, info, clever_L2)) 498 | 499 | sys.stdout.flush() 500 | 501 | 502 | # shutdown thread pool 503 | pool.close() 504 | pool.join() 505 | -------------------------------------------------------------------------------- /collect_gradients.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | collect_gradients.py 5 | 6 | Front end for collecting maximum gradient norm samples 7 | 8 | Copyright (C) 2017-2018, IBM Corp. 9 | Copyright (C) 2017, Lily Weng 10 | and Huan Zhang 11 | 12 | This program is licenced under the Apache 2.0 licence, 13 | contained in the LICENCE file in this directory. 14 | """ 15 | 16 | from __future__ import division 17 | 18 | import numpy as np 19 | import scipy.io as sio 20 | import random 21 | import time 22 | import sys 23 | import os 24 | from functools import partial 25 | 26 | from estimate_gradient_norm import EstimateLipschitz 27 | from utils import generate_data 28 | 29 | if __name__ == "__main__": 30 | 31 | import argparse 32 | parser = argparse.ArgumentParser(description = "Collect gradient norm samples for calculating CLEVER score", 33 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) 34 | parser.add_argument("-d", "--dataset", choices=["mnist", "cifar", "imagenet"], default="mnist", help = "choose dataset") 35 | parser.add_argument("-m", "--model_name", default="normal", 36 | help = "Select model. For MNIST and CIFAR, options are: 2-layer (MLP), normal (7-layer CNN), distilled (7-layer CNN with defensive distillation), brelu (7-layer CNN with Bounded ReLU). For ImageNet, available options are: resnet_v2_50, resnet_v2_101, resnet_v2_152, inception_v1, inception_v2, inception_v3, inception_v4, inception_resnet_v2, vgg_16, vgg_19, mobilenet_v1_025, mobilenet_v1_050, mobilenet_v1_100, alexnet, nasnet_large, densenet121_k32, densenet169_k32, densenet161_k48") 37 | parser.add_argument("--activation", type=str, choices=["relu", "tanh", "sigmoid", "elu", "softplus", "hard_sigmoid", "arctan"], help = "activation functions", default="relu") 38 | parser.add_argument("-N", "--Nsamps", type=int, default=1024, help = "number of samples per iterations") 39 | parser.add_argument("-i", "--Niters", type=int, default=500, help = "number of iterations. NITERS maximum gradient norms will be collected. A larger value will give a more accurate estimate") 40 | parser.add_argument("-n", "--numimg", type=int, default=1, help = "number of test images to load from dataset") 41 | parser.add_argument("--ids", default = "", help = "use a filelist of image IDs in CSV file for attack (UNSUPPORTED)") 42 | parser.add_argument("--target_type", type=int, default=0b01111, help = "Binary mask for selecting targeted attack classes. bit0: top-2, bit1: random, bit2: least likely, bit3: use --ids override (UNSUPPORTED), bit4: use all labels (for untargeted)") 43 | parser.add_argument("-f", "--firstimg", type=int, default=0, help = "start from which image in dataset") 44 | parser.add_argument("--transform", default="", help = "input transformation function (defend_reduce, defend_jpeg, defend_png)") 45 | parser.add_argument("--order", type = int, default=1, choices=[1,2], help = "1: first order bound, 2: second order bound for twice differentiable activations") 46 | parser.add_argument("--compute_slope", action='store_true', help = "collect slope estimate") 47 | parser.add_argument("--sample_norm", type=str, choices=["l2", "li", "l1"], help = "norm of sampling ball (l2, l1 or li)", default="l2") 48 | parser.add_argument("--fix_dirty_bug", action='store_true', help = "do not use (UNSUPPORTED)") 49 | parser.add_argument("-b", "--batch_size", type=int, default=0, help = "batch size to run model. 0: use default batch size") 50 | parser.add_argument("--nthreads", type=int, default=0, help = "number of threads for generating random samples in sphere") 51 | parser.add_argument("-s", "--save", default="./lipschitz_mat", help = "results output path") 52 | parser.add_argument("--seed", type=int, default = 1215, help = "random seed") 53 | 54 | args = vars(parser.parse_args()) 55 | print(args) 56 | 57 | seed = args['seed'] 58 | Nsamp = args['Nsamps']; 59 | Niters = args['Niters']; 60 | dataset = args['dataset'] 61 | model_name = args['model_name'] 62 | start = args['firstimg'] 63 | numimg = args['numimg'] 64 | save_path = args['save'] 65 | total = 0 66 | 67 | random.seed(seed) 68 | np.random.seed(seed) 69 | 70 | # create output directory 71 | os.system("mkdir -p {}/{}_{}".format(save_path, dataset, model_name)) 72 | 73 | # create a Lipschitz estimator class (initial it early to save multiprocessing memory) 74 | clever_estimator = EstimateLipschitz(sess=None, nthreads=args['nthreads']) 75 | 76 | # import the ID lists 77 | if args['ids']: 78 | import pandas as pd 79 | df = pd.read_csv(args['ids'], sep = "\t") 80 | # don't use this 81 | if args['fix_dirty_bug']: 82 | df = df[df['new_class'] != df['target']] 83 | ids = list(df['id']) 84 | target_type = args['target_type'] 85 | # use the target classes override 86 | if target_type & 0b1000 != 0: 87 | target_classes = [[t] for t in list(df['target'])] 88 | else: 89 | # use generated classes 90 | target_classes = None 91 | else: 92 | ids = None 93 | target_classes = None 94 | target_type = args['target_type'] 95 | 96 | import tensorflow as tf 97 | from setup_cifar import CIFAR 98 | from setup_mnist import MNIST 99 | from setup_imagenet import ImageNet 100 | 101 | tf.set_random_seed(seed) 102 | config = tf.ConfigProto() 103 | config.gpu_options.allow_growth=True 104 | with tf.Session(config=config) as sess: 105 | clever_estimator.sess = sess 106 | # returns the input tensor and output prediction vector 107 | img, output = clever_estimator.load_model(dataset, model_name, activation = args['activation'], batch_size = args['batch_size'], compute_slope = args['compute_slope'], order = args['order']) 108 | # load dataset 109 | datasets_loader = {"mnist": MNIST, "cifar": CIFAR, "imagenet": partial(ImageNet, clever_estimator.model.image_size)} 110 | data = datasets_loader[dataset]() 111 | # for prediction 112 | predictor = lambda x: np.squeeze(sess.run(output, feed_dict = {img: x})) 113 | # generate target images 114 | inputs, targets, true_labels, true_ids, img_info = generate_data(data, samples=numimg, targeted=True, 115 | start=start, predictor=predictor, 116 | random_and_least_likely = True, 117 | ids = ids, target_classes = target_classes, target_type = target_type, 118 | imagenet="imagenet" in dataset, 119 | remove_background_class="imagenet" in dataset and 120 | ("vgg" in model_name or "densenet" in model_name or "alexnet" in model_name)) 121 | 122 | timestart = time.time() 123 | print("got {} images".format(inputs.shape)) 124 | for i, input_img in enumerate(inputs): 125 | # original_predict = np.squeeze(sess.run(output, feed_dict = {img: [input_img]})) 126 | print("processing image {}".format(i)) 127 | original_predict = predictor([input_img]) 128 | true_label = np.argmax(true_labels[i]) 129 | predicted_label = np.argmax(original_predict) 130 | least_likely_label = np.argmin(original_predict) 131 | original_prob = np.sort(original_predict) 132 | original_class = np.argsort(original_predict) 133 | print("Top-10 classifications:", original_class[-1:-11:-1]) 134 | print("True label:", true_label) 135 | print("Top-10 probabilities/logits:", original_prob[-1:-11:-1]) 136 | print("Most unlikely classifications:", original_class[:10]) 137 | print("Most unlikely probabilities/logits:", original_prob[:10]) 138 | if true_label != predicted_label: 139 | print("[WARNING] This image is classfied wrongly by the classifier! Skipping!") 140 | continue 141 | total += 1 142 | # set target class 143 | target_label = np.argmax(targets[i]); 144 | print('Target class: ', target_label) 145 | sys.stdout.flush() 146 | 147 | if args['order'] == 1: 148 | [L2_max,L1_max,Li_max,G2_max,G1_max,Gi_max,g_x0,pred] = clever_estimator.estimate(input_img, true_label, target_label, Nsamp, Niters, args['sample_norm'], args['transform'], args['order']) 149 | print("[STATS][L1] total = {}, seq = {}, id = {}, time = {:.3f}, true_class = {}, target_class = {}, info = {}".format(total, i, true_ids[i], time.time() - timestart, true_label, target_label, img_info[i])) 150 | # save to sampling results to matlab ;) 151 | mat_path = "{}/{}_{}/{}_{}_{}_{}_{}_{}_{}_order{}".format(save_path, dataset, model_name, Nsamp, Niters, true_ids[i], true_label, target_label, img_info[i], args['activation'], args['order']) 152 | save_dict = {'L2_max': L2_max, 'L1_max': L1_max, 'Li_max': Li_max, 'G2_max': G2_max, 'G1_max': G1_max, 'Gi_max': Gi_max, 'pred': pred, 'g_x0': g_x0, 'id': true_ids[i], 'true_label': true_label, 'target_label': target_label, 'info':img_info[i], 'args': args, 'path': mat_path} 153 | sio.savemat(mat_path, save_dict) 154 | print('saved to', mat_path) 155 | sys.stdout.flush() 156 | elif args['order'] == 2: 157 | [H2_max,g_x0,g_x0_grad_2_norm,g_x0_grad_1_norm,g_x0_grad_inf_norm,pred] = clever_estimator.estimate(input_img, true_label, target_label, Nsamp, Niters, args['sample_norm'], args['transform'], args['order']) 158 | #print("[STATS][L1] H2_max = {}, g_x0 = {:.5g}, g_x0_grad_2_norm = {:.5g}, g_x0_grad_1_norm = {:.5g}, g_x0_grad_inf_norm = {:.5g}, pred = {}".format(H2_max,g_x0,g_x0_grad_2_norm, g_x0_grad_1_norm, g_x0_grad_inf_norm, pred)) 159 | print("[STATS][L1] total = {}, seq = {}, id = {}, time = {:.3f}, true_class = {}, target_class = {}, info = {}".format(total, i, true_ids[i], time.time() - timestart, true_label, target_label, img_info[i])) 160 | ### Lily TODO: save the computed quantities to mat file 161 | # save to sampling results to matlab ;) 162 | mat_path = "{}/{}_{}/{}_{}_{}_{}_{}_{}_{}_order{}".format(save_path, dataset, model_name, Nsamp, Niters, true_ids[i], true_label, target_label, img_info[i], args['activation'], args['order']) 163 | save_dict = {'H2_max': H2_max, 'pred': pred, 'g_x0': g_x0, 'id': true_ids[i], 'true_label': true_label, 'target_label': target_label, 'info':img_info[i], 'args': args, 'path': mat_path, 'g_x0_grad_2_norm': g_x0_grad_2_norm} 164 | sio.savemat(mat_path, save_dict) 165 | print('saved to', mat_path) 166 | sys.stdout.flush() 167 | 168 | -------------------------------------------------------------------------------- /defense.py: -------------------------------------------------------------------------------- 1 | import PIL 2 | import PIL.Image 3 | from io import BytesIO 4 | import numpy as np 5 | import tensorflow as tf 6 | from numba import njit 7 | 8 | def defend_reduce(arr, depth=3): 9 | arr = (arr * 255.0).astype(np.uint8) 10 | shift = 8 - depth 11 | arr = (arr >> shift) << shift 12 | arr = arr.astype(np.float32)/255.0 13 | return arr 14 | 15 | def defend_jpeg(input_array): 16 | pil_image = PIL.Image.fromarray((input_array*255.0).astype(np.uint8)) 17 | f = BytesIO() 18 | pil_image.save(f, format='jpeg', quality=75) # quality level specified in paper 19 | jpeg_image = np.asarray(PIL.Image.open(f)).astype(np.float32)/255.0 20 | return jpeg_image 21 | 22 | def defend_png(input_array): 23 | pil_image = PIL.Image.fromarray((np.around(input_array*255.0)).astype(np.uint8)) 24 | f = BytesIO() 25 | pil_image.save(f, format='png') 26 | png_image = np.asarray(PIL.Image.open(f)).astype(np.float32)/255.0 27 | return png_image 28 | 29 | # for testing implementation 30 | def defend_none(input_array): 31 | # this convertion should be lossless 32 | pil_image = PIL.Image.fromarray(input_array) 33 | ret_image = np.asarray(pil_image) 34 | return ret_image 35 | 36 | # based on https://github.com/scikit-image/scikit-image/blob/master/skimage/restoration/_denoise_cy.pyx 37 | 38 | # super slow since this is implemented in pure python :'( 39 | 40 | @njit 41 | def bregman(image, mask, weight, eps=1e-3, max_iter=100): 42 | rows, cols, dims = image.shape 43 | rows2 = rows + 2 44 | cols2 = cols + 2 45 | total = rows * cols * dims 46 | shape_ext = (rows2, cols2, dims) 47 | 48 | u = np.zeros(shape_ext) 49 | dx = np.zeros(shape_ext) 50 | dy = np.zeros(shape_ext) 51 | bx = np.zeros(shape_ext) 52 | by = np.zeros(shape_ext) 53 | 54 | u[1:-1, 1:-1] = image 55 | # reflect image 56 | u[0, 1:-1] = image[1, :] 57 | u[1:-1, 0] = image[:, 1] 58 | u[-1, 1:-1] = image[-2, :] 59 | u[1:-1, -1] = image[:, -2] 60 | 61 | i = 0 62 | rmse = np.inf 63 | lam = 2 * weight 64 | norm = (weight + 4 * lam) 65 | 66 | while i < max_iter and rmse > eps: 67 | rmse = 0 68 | 69 | for k in range(dims): 70 | for r in range(1, rows+1): 71 | for c in range(1, cols+1): 72 | uprev = u[r, c, k] 73 | 74 | # forward derivatives 75 | ux = u[r, c+1, k] - uprev 76 | uy = u[r+1, c, k] - uprev 77 | 78 | # Gauss-Seidel method 79 | if mask[r-1, c-1]: 80 | unew = (lam * (u[r+1, c, k] + 81 | u[r-1, c, k] + 82 | u[r, c+1, k] + 83 | u[r, c-1, k] + 84 | dx[r, c-1, k] - 85 | dx[r, c, k] + 86 | dy[r-1, c, k] - 87 | dy[r, c, k] - 88 | bx[r, c-1, k] + 89 | bx[r, c, k] - 90 | by[r-1, c, k] + 91 | by[r, c, k] 92 | ) + weight * image[r-1, c-1, k] 93 | ) / norm 94 | else: 95 | # similar to the update step above, except we take 96 | # lim_{weight->0} of the update step, effectively 97 | # ignoring the l2 loss 98 | unew = (u[r+1, c, k] + 99 | u[r-1, c, k] + 100 | u[r, c+1, k] + 101 | u[r, c-1, k] + 102 | dx[r, c-1, k] - 103 | dx[r, c, k] + 104 | dy[r-1, c, k] - 105 | dy[r, c, k] - 106 | bx[r, c-1, k] + 107 | bx[r, c, k] - 108 | by[r-1, c, k] + 109 | by[r, c, k] 110 | ) / 4.0 111 | u[r, c, k] = unew 112 | 113 | # update rms error 114 | rmse += (unew - uprev)**2 115 | 116 | bxx = bx[r, c, k] 117 | byy = by[r, c, k] 118 | 119 | # d_subproblem 120 | s = ux + bxx 121 | if s > 1/lam: 122 | dxx = s - 1/lam 123 | elif s < -1/lam: 124 | dxx = s + 1/lam 125 | else: 126 | dxx = 0 127 | s = uy + byy 128 | if s > 1/lam: 129 | dyy = s - 1/lam 130 | elif s < -1/lam: 131 | dyy = s + 1/lam 132 | else: 133 | dyy = 0 134 | 135 | dx[r, c, k] = dxx 136 | dy[r, c, k] = dyy 137 | 138 | bx[r, c, k] += ux - dxx 139 | by[r, c, k] += uy - dyy 140 | 141 | rmse = np.sqrt(rmse / total) 142 | i += 1 143 | 144 | # return np.squeeze(np.asarray(u[1:-1, 1:-1])) 145 | return u[1:-1, 1:-1] 146 | 147 | @njit 148 | def defend_tv(input_array, keep_prob=0.5, lambda_tv=0.03): 149 | mask = np.random.uniform(0.0, 1.0, size=input_array.shape[:2]) 150 | mask = mask < keep_prob 151 | return bregman(input_array, mask, weight=2.0/lambda_tv) 152 | 153 | def make_defend_quilt(sess): 154 | # setup for quilting 155 | quilt_db = np.load('data/quilt_db.npy') 156 | quilt_db_reshaped = quilt_db.reshape(1000000, -1) 157 | TILE_SIZE = 5 158 | TILE_OVERLAP = 2 159 | tile_skip = TILE_SIZE - TILE_OVERLAP 160 | K = 10 161 | db_tensor = tf.placeholder(tf.float32, quilt_db_reshaped.shape) 162 | query_imgs = tf.placeholder(tf.float32, (TILE_SIZE * TILE_SIZE * 3, None)) 163 | norms = tf.reduce_sum(tf.square(db_tensor), axis=1)[:, tf.newaxis] \ 164 | - 2*tf.matmul(db_tensor, query_imgs) 165 | _, topk_indices = tf.nn.top_k(-tf.transpose(norms), k=K, sorted=False) 166 | def min_error_table(arr, direction): 167 | assert direction in ('horizontal', 'vertical') 168 | y, x = arr.shape 169 | cum = np.zeros_like(arr) 170 | if direction == 'horizontal': 171 | cum[:, -1] = arr[:, -1] 172 | for ix in range(x-2, -1, -1): 173 | for iy in range(y): 174 | m = arr[iy, ix+1] 175 | if iy > 0: 176 | m = min(m, arr[iy-1, ix+1]) 177 | if iy < y - 1: 178 | m = min(m, arr[iy+1, ix+1]) 179 | cum[iy, ix] = arr[iy, ix] + m 180 | elif direction == 'vertical': 181 | cum[-1, :] = arr[-1, :] 182 | for iy in range(y-2, -1, -1): 183 | for ix in range(x): 184 | m = arr[iy+1, ix] 185 | if ix > 0: 186 | m = min(m, arr[iy+1, ix-1]) 187 | if ix < x - 1: 188 | m = min(m, arr[iy+1, ix+1]) 189 | cum[iy, ix] = arr[iy, ix] + m 190 | return cum 191 | def index_exists(arr, index): 192 | if arr.ndim != len(index): 193 | return False 194 | return all(i > 0 for i in index) and all(index[i] < arr.shape[i] for i in range(arr.ndim)) 195 | def assign_block(ix, iy, tile, synth): 196 | posx = tile_skip * ix 197 | posy = tile_skip * iy 198 | 199 | if ix == 0 and iy == 0: 200 | synth[posy:posy+TILE_SIZE, posx:posx+TILE_SIZE, :] = tile 201 | elif iy == 0: 202 | # first row, only have horizontal overlap of the block 203 | tile_left = tile[:, :TILE_OVERLAP, :] 204 | synth_right = synth[:TILE_SIZE, posx:posx+TILE_OVERLAP, :] 205 | errors = np.sum(np.square(tile_left - synth_right), axis=2) 206 | table = min_error_table(errors, direction='vertical') 207 | # copy row by row into synth 208 | xoff = np.argmin(table[0, :]) 209 | synth[posy, posx+xoff:posx+TILE_SIZE] = tile[0, xoff:] 210 | for yoff in range(1, TILE_SIZE): 211 | # explore nearby xoffs 212 | candidates = [(yoff, xoff), (yoff, xoff-1), (yoff, xoff+1)] 213 | index = min((i for i in candidates if index_exists(table, i)), key=lambda i: table[i]) 214 | xoff = index[1] 215 | synth[posy+yoff, posx+xoff:posx+TILE_SIZE] = tile[yoff, xoff:] 216 | elif ix == 0: 217 | # first column, only have vertical overlap of the block 218 | tile_up = tile[:TILE_OVERLAP, :, :] 219 | synth_bottom = synth[posy:posy+TILE_OVERLAP, :TILE_SIZE, :] 220 | errors = np.sum(np.square(tile_up - synth_bottom), axis=2) 221 | table = min_error_table(errors, direction='horizontal') 222 | # copy column by column into synth 223 | yoff = np.argmin(table[:, 0]) 224 | synth[posy+yoff:posy+TILE_SIZE, posx] = tile[yoff:, 0] 225 | for xoff in range(1, TILE_SIZE): 226 | # explore nearby yoffs 227 | candidates = [(yoff, xoff), (yoff-1, xoff), (yoff+1, xoff)] 228 | index = min((i for i in candidates if index_exists(table, i)), key=lambda i: table[i]) 229 | yoff = index[0] 230 | synth[posy+yoff:posy+TILE_SIZE, posx+xoff] = tile[yoff:, xoff] 231 | else: 232 | # glue cuts along diagonal 233 | tile_up = tile[:TILE_OVERLAP, :, :] 234 | synth_bottom = synth[posy:posy+TILE_OVERLAP, :TILE_SIZE, :] 235 | errors_up = np.sum(np.square(tile_up - synth_bottom), axis=2) 236 | table_up = min_error_table(errors_up, direction='horizontal') 237 | tile_left = tile[:, :TILE_OVERLAP, :] 238 | synth_right = synth[:TILE_SIZE, posx:posx+TILE_OVERLAP, :] 239 | errors_left = np.sum(np.square(tile_left - synth_right), axis=2) 240 | table_left = min_error_table(errors_left, direction='vertical') 241 | glue_index = -1 242 | glue_value = np.inf 243 | for i in range(TILE_OVERLAP): 244 | e = table_up[i, i] + table_left[i, i] 245 | if e < glue_value: 246 | glue_value = e 247 | glue_index = i 248 | # copy left part first, up to the overlap column 249 | xoff = glue_index 250 | synth[posy+glue_index, posx+xoff:posx+TILE_OVERLAP] = tile[glue_index, xoff:TILE_OVERLAP] 251 | for yoff in range(glue_index+1, TILE_SIZE): 252 | # explore nearby xoffs 253 | candidates = [(yoff, xoff), (yoff, xoff-1), (yoff, xoff+1)] 254 | index = min((i for i in candidates if index_exists(table_left, i)), key=lambda i: table_left[i]) 255 | xoff = index[1] 256 | synth[posy+yoff, posx+xoff:posx+TILE_OVERLAP] = tile[yoff, xoff:TILE_OVERLAP] 257 | # copy right part, down to overlap row 258 | yoff = glue_index 259 | synth[posy+yoff:posy+TILE_OVERLAP, posx+glue_index] = tile[yoff:TILE_OVERLAP, glue_index] 260 | for xoff in range(glue_index+1, TILE_SIZE): 261 | # explore nearby yoffs 262 | candidates = [(yoff, xoff), (yoff-1, xoff), (yoff+1, xoff)] 263 | index = min((i for i in candidates if index_exists(table_up, i)), key=lambda i: table_up[i]) 264 | yoff = index[0] 265 | synth[posy+yoff:posy+TILE_OVERLAP, posx+xoff] = tile[yoff:TILE_OVERLAP, xoff] 266 | # copy rest of image 267 | synth[posy+TILE_OVERLAP:posy+TILE_SIZE, posx+TILE_OVERLAP:posx+TILE_SIZE] = tile[TILE_OVERLAP:, TILE_OVERLAP:] 268 | KNN_MAX_BATCH = 1000 269 | def quilt(arr, graphcut=True): 270 | h, w, c = arr.shape 271 | assert (h - TILE_SIZE) % tile_skip == 0 272 | assert (w - TILE_SIZE) % tile_skip == 0 273 | horiz_blocks = (w - TILE_SIZE) // tile_skip + 1 274 | vert_blocks = (h - TILE_SIZE) // tile_skip + 1 275 | num_patches = horiz_blocks * vert_blocks 276 | patches = np.zeros((TILE_SIZE * TILE_SIZE * 3, num_patches)) 277 | idx = 0 278 | for iy in range(vert_blocks): 279 | for ix in range(horiz_blocks): 280 | posx = tile_skip*ix 281 | posy = tile_skip*iy 282 | patches[:, idx] = arr[posy:posy+TILE_SIZE, posx:posx+TILE_SIZE, :].ravel() 283 | idx += 1 284 | 285 | ind = [] 286 | for chunk in range(num_patches // KNN_MAX_BATCH + (1 if num_patches % KNN_MAX_BATCH != 0 else 0)): 287 | start = KNN_MAX_BATCH * chunk 288 | end = start + KNN_MAX_BATCH 289 | # for some reason, the code below is 10x slower when run in a Jupyter notebook 290 | # not sure why... 291 | indices_ = sess.run(topk_indices, {db_tensor: quilt_db_reshaped, query_imgs: patches[:, start:end]}) 292 | for i in indices_: 293 | ind.append(np.random.choice(i)) 294 | 295 | synth = np.zeros((299, 299, 3)) 296 | 297 | idx = 0 298 | for iy in range(vert_blocks): 299 | for ix in range(horiz_blocks): 300 | posx = tile_skip*ix 301 | posy = tile_skip*iy 302 | tile = quilt_db[ind[idx]] 303 | if not graphcut: 304 | synth[posy:posy+TILE_SIZE, posx:posx+TILE_SIZE, :] = tile 305 | else: 306 | assign_block(ix, iy, tile, synth) 307 | idx += 1 308 | return synth 309 | 310 | return quilt 311 | 312 | # x is a square image (3-tensor) 313 | def defend_crop(x, crop_size=90, ensemble_size=30): 314 | x_size = tf.to_float(x.shape[1]) 315 | frac = crop_size/x_size 316 | start_fraction_max = (x_size - crop_size)/x_size 317 | def randomizing_crop(x): 318 | start_x = tf.random_uniform((), 0, start_fraction_max) 319 | start_y = tf.random_uniform((), 0, start_fraction_max) 320 | return tf.image.crop_and_resize([x], boxes=[[start_y, start_x, start_y+frac, start_x+frac]], 321 | box_ind=[0], crop_size=[crop_size, crop_size]) 322 | 323 | return tf.concat([randomizing_crop(x) for _ in range(ensemble_size)], axis=0) 324 | -------------------------------------------------------------------------------- /labels/imagenet_val_to_carlini.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import glob 6 | 7 | f = open('label2num.txt') 8 | 9 | mapping = {} 10 | for line in f: 11 | l = line.strip().split(':') 12 | mapping[l[1]] = l[0] 13 | 14 | print("Total {} classes loaded".format(len(mapping))) 15 | 16 | os.system("mkdir -p imgs") 17 | 18 | file_list = glob.glob('val/**/*.JPEG', recursive=True) 19 | print("Total {} files found".format(len(file_list))) 20 | 21 | cur = 1 22 | total = len(file_list) 23 | 24 | for img_path in file_list: 25 | s = img_path.split('/')[1] 26 | n = os.path.splitext(os.path.basename(img_path))[0].split('_')[2] 27 | label = mapping[s] 28 | os.system("cp {} imgs/{}.{}.jpg".format(img_path, label, n)) 29 | if cur % 1000 == 0: 30 | print("{}/{} finished ".format(cur, total)) 31 | cur += 1 32 | 33 | print() 34 | 35 | -------------------------------------------------------------------------------- /labels/labels.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | new_label = "labels.txt" 4 | imagenet_map = "synset_words.txt" 5 | label2num = "label2num.txt" 6 | 7 | num_dict = {} 8 | 9 | out_file = open(label2num, 'w') 10 | 11 | with open(new_label, 'r') as f: 12 | for line in f: 13 | if line: 14 | num = int(line.split(':')[0]) 15 | lab = line.split(':')[1].strip() 16 | num_dict[lab] = num 17 | 18 | print(len(num_dict)) 19 | 20 | with open(imagenet_map, 'r') as f: 21 | for line in f: 22 | if line: 23 | nn = line[:9] 24 | lab = line[10:].strip() 25 | print(nn, lab) 26 | num = num_dict[lab] 27 | out_file.write("{}:{}:{}\n".format(num, nn, lab)) 28 | 29 | -------------------------------------------------------------------------------- /labels/labels.txt: -------------------------------------------------------------------------------- 1 | 0:background 2 | 1:tench, Tinca tinca 3 | 2:goldfish, Carassius auratus 4 | 3:great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias 5 | 4:tiger shark, Galeocerdo cuvieri 6 | 5:hammerhead, hammerhead shark 7 | 6:electric ray, crampfish, numbfish, torpedo 8 | 7:stingray 9 | 8:cock 10 | 9:hen 11 | 10:ostrich, Struthio camelus 12 | 11:brambling, Fringilla montifringilla 13 | 12:goldfinch, Carduelis carduelis 14 | 13:house finch, linnet, Carpodacus mexicanus 15 | 14:junco, snowbird 16 | 15:indigo bunting, indigo finch, indigo bird, Passerina cyanea 17 | 16:robin, American robin, Turdus migratorius 18 | 17:bulbul 19 | 18:jay 20 | 19:magpie 21 | 20:chickadee 22 | 21:water ouzel, dipper 23 | 22:kite 24 | 23:bald eagle, American eagle, Haliaeetus leucocephalus 25 | 24:vulture 26 | 25:great grey owl, great gray owl, Strix nebulosa 27 | 26:European fire salamander, Salamandra salamandra 28 | 27:common newt, Triturus vulgaris 29 | 28:eft 30 | 29:spotted salamander, Ambystoma maculatum 31 | 30:axolotl, mud puppy, Ambystoma mexicanum 32 | 31:bullfrog, Rana catesbeiana 33 | 32:tree frog, tree-frog 34 | 33:tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui 35 | 34:loggerhead, loggerhead turtle, Caretta caretta 36 | 35:leatherback turtle, leatherback, leathery turtle, Dermochelys coriacea 37 | 36:mud turtle 38 | 37:terrapin 39 | 38:box turtle, box tortoise 40 | 39:banded gecko 41 | 40:common iguana, iguana, Iguana iguana 42 | 41:American chameleon, anole, Anolis carolinensis 43 | 42:whiptail, whiptail lizard 44 | 43:agama 45 | 44:frilled lizard, Chlamydosaurus kingi 46 | 45:alligator lizard 47 | 46:Gila monster, Heloderma suspectum 48 | 47:green lizard, Lacerta viridis 49 | 48:African chameleon, Chamaeleo chamaeleon 50 | 49:Komodo dragon, Komodo lizard, dragon lizard, giant lizard, Varanus komodoensis 51 | 50:African crocodile, Nile crocodile, Crocodylus niloticus 52 | 51:American alligator, Alligator mississipiensis 53 | 52:triceratops 54 | 53:thunder snake, worm snake, Carphophis amoenus 55 | 54:ringneck snake, ring-necked snake, ring snake 56 | 55:hognose snake, puff adder, sand viper 57 | 56:green snake, grass snake 58 | 57:king snake, kingsnake 59 | 58:garter snake, grass snake 60 | 59:water snake 61 | 60:vine snake 62 | 61:night snake, Hypsiglena torquata 63 | 62:boa constrictor, Constrictor constrictor 64 | 63:rock python, rock snake, Python sebae 65 | 64:Indian cobra, Naja naja 66 | 65:green mamba 67 | 66:sea snake 68 | 67:horned viper, cerastes, sand viper, horned asp, Cerastes cornutus 69 | 68:diamondback, diamondback rattlesnake, Crotalus adamanteus 70 | 69:sidewinder, horned rattlesnake, Crotalus cerastes 71 | 70:trilobite 72 | 71:harvestman, daddy longlegs, Phalangium opilio 73 | 72:scorpion 74 | 73:black and gold garden spider, Argiope aurantia 75 | 74:barn spider, Araneus cavaticus 76 | 75:garden spider, Aranea diademata 77 | 76:black widow, Latrodectus mactans 78 | 77:tarantula 79 | 78:wolf spider, hunting spider 80 | 79:tick 81 | 80:centipede 82 | 81:black grouse 83 | 82:ptarmigan 84 | 83:ruffed grouse, partridge, Bonasa umbellus 85 | 84:prairie chicken, prairie grouse, prairie fowl 86 | 85:peacock 87 | 86:quail 88 | 87:partridge 89 | 88:African grey, African gray, Psittacus erithacus 90 | 89:macaw 91 | 90:sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita 92 | 91:lorikeet 93 | 92:coucal 94 | 93:bee eater 95 | 94:hornbill 96 | 95:hummingbird 97 | 96:jacamar 98 | 97:toucan 99 | 98:drake 100 | 99:red-breasted merganser, Mergus serrator 101 | 100:goose 102 | 101:black swan, Cygnus atratus 103 | 102:tusker 104 | 103:echidna, spiny anteater, anteater 105 | 104:platypus, duckbill, duckbilled platypus, duck-billed platypus, Ornithorhynchus anatinus 106 | 105:wallaby, brush kangaroo 107 | 106:koala, koala bear, kangaroo bear, native bear, Phascolarctos cinereus 108 | 107:wombat 109 | 108:jellyfish 110 | 109:sea anemone, anemone 111 | 110:brain coral 112 | 111:flatworm, platyhelminth 113 | 112:nematode, nematode worm, roundworm 114 | 113:conch 115 | 114:snail 116 | 115:slug 117 | 116:sea slug, nudibranch 118 | 117:chiton, coat-of-mail shell, sea cradle, polyplacophore 119 | 118:chambered nautilus, pearly nautilus, nautilus 120 | 119:Dungeness crab, Cancer magister 121 | 120:rock crab, Cancer irroratus 122 | 121:fiddler crab 123 | 122:king crab, Alaska crab, Alaskan king crab, Alaska king crab, Paralithodes camtschatica 124 | 123:American lobster, Northern lobster, Maine lobster, Homarus americanus 125 | 124:spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish 126 | 125:crayfish, crawfish, crawdad, crawdaddy 127 | 126:hermit crab 128 | 127:isopod 129 | 128:white stork, Ciconia ciconia 130 | 129:black stork, Ciconia nigra 131 | 130:spoonbill 132 | 131:flamingo 133 | 132:little blue heron, Egretta caerulea 134 | 133:American egret, great white heron, Egretta albus 135 | 134:bittern 136 | 135:crane 137 | 136:limpkin, Aramus pictus 138 | 137:European gallinule, Porphyrio porphyrio 139 | 138:American coot, marsh hen, mud hen, water hen, Fulica americana 140 | 139:bustard 141 | 140:ruddy turnstone, Arenaria interpres 142 | 141:red-backed sandpiper, dunlin, Erolia alpina 143 | 142:redshank, Tringa totanus 144 | 143:dowitcher 145 | 144:oystercatcher, oyster catcher 146 | 145:pelican 147 | 146:king penguin, Aptenodytes patagonica 148 | 147:albatross, mollymawk 149 | 148:grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus 150 | 149:killer whale, killer, orca, grampus, sea wolf, Orcinus orca 151 | 150:dugong, Dugong dugon 152 | 151:sea lion 153 | 152:Chihuahua 154 | 153:Japanese spaniel 155 | 154:Maltese dog, Maltese terrier, Maltese 156 | 155:Pekinese, Pekingese, Peke 157 | 156:Shih-Tzu 158 | 157:Blenheim spaniel 159 | 158:papillon 160 | 159:toy terrier 161 | 160:Rhodesian ridgeback 162 | 161:Afghan hound, Afghan 163 | 162:basset, basset hound 164 | 163:beagle 165 | 164:bloodhound, sleuthhound 166 | 165:bluetick 167 | 166:black-and-tan coonhound 168 | 167:Walker hound, Walker foxhound 169 | 168:English foxhound 170 | 169:redbone 171 | 170:borzoi, Russian wolfhound 172 | 171:Irish wolfhound 173 | 172:Italian greyhound 174 | 173:whippet 175 | 174:Ibizan hound, Ibizan Podenco 176 | 175:Norwegian elkhound, elkhound 177 | 176:otterhound, otter hound 178 | 177:Saluki, gazelle hound 179 | 178:Scottish deerhound, deerhound 180 | 179:Weimaraner 181 | 180:Staffordshire bullterrier, Staffordshire bull terrier 182 | 181:American Staffordshire terrier, Staffordshire terrier, American pit bull terrier, pit bull terrier 183 | 182:Bedlington terrier 184 | 183:Border terrier 185 | 184:Kerry blue terrier 186 | 185:Irish terrier 187 | 186:Norfolk terrier 188 | 187:Norwich terrier 189 | 188:Yorkshire terrier 190 | 189:wire-haired fox terrier 191 | 190:Lakeland terrier 192 | 191:Sealyham terrier, Sealyham 193 | 192:Airedale, Airedale terrier 194 | 193:cairn, cairn terrier 195 | 194:Australian terrier 196 | 195:Dandie Dinmont, Dandie Dinmont terrier 197 | 196:Boston bull, Boston terrier 198 | 197:miniature schnauzer 199 | 198:giant schnauzer 200 | 199:standard schnauzer 201 | 200:Scotch terrier, Scottish terrier, Scottie 202 | 201:Tibetan terrier, chrysanthemum dog 203 | 202:silky terrier, Sydney silky 204 | 203:soft-coated wheaten terrier 205 | 204:West Highland white terrier 206 | 205:Lhasa, Lhasa apso 207 | 206:flat-coated retriever 208 | 207:curly-coated retriever 209 | 208:golden retriever 210 | 209:Labrador retriever 211 | 210:Chesapeake Bay retriever 212 | 211:German short-haired pointer 213 | 212:vizsla, Hungarian pointer 214 | 213:English setter 215 | 214:Irish setter, red setter 216 | 215:Gordon setter 217 | 216:Brittany spaniel 218 | 217:clumber, clumber spaniel 219 | 218:English springer, English springer spaniel 220 | 219:Welsh springer spaniel 221 | 220:cocker spaniel, English cocker spaniel, cocker 222 | 221:Sussex spaniel 223 | 222:Irish water spaniel 224 | 223:kuvasz 225 | 224:schipperke 226 | 225:groenendael 227 | 226:malinois 228 | 227:briard 229 | 228:kelpie 230 | 229:komondor 231 | 230:Old English sheepdog, bobtail 232 | 231:Shetland sheepdog, Shetland sheep dog, Shetland 233 | 232:collie 234 | 233:Border collie 235 | 234:Bouvier des Flandres, Bouviers des Flandres 236 | 235:Rottweiler 237 | 236:German shepherd, German shepherd dog, German police dog, alsatian 238 | 237:Doberman, Doberman pinscher 239 | 238:miniature pinscher 240 | 239:Greater Swiss Mountain dog 241 | 240:Bernese mountain dog 242 | 241:Appenzeller 243 | 242:EntleBucher 244 | 243:boxer 245 | 244:bull mastiff 246 | 245:Tibetan mastiff 247 | 246:French bulldog 248 | 247:Great Dane 249 | 248:Saint Bernard, St Bernard 250 | 249:Eskimo dog, husky 251 | 250:malamute, malemute, Alaskan malamute 252 | 251:Siberian husky 253 | 252:dalmatian, coach dog, carriage dog 254 | 253:affenpinscher, monkey pinscher, monkey dog 255 | 254:basenji 256 | 255:pug, pug-dog 257 | 256:Leonberg 258 | 257:Newfoundland, Newfoundland dog 259 | 258:Great Pyrenees 260 | 259:Samoyed, Samoyede 261 | 260:Pomeranian 262 | 261:chow, chow chow 263 | 262:keeshond 264 | 263:Brabancon griffon 265 | 264:Pembroke, Pembroke Welsh corgi 266 | 265:Cardigan, Cardigan Welsh corgi 267 | 266:toy poodle 268 | 267:miniature poodle 269 | 268:standard poodle 270 | 269:Mexican hairless 271 | 270:timber wolf, grey wolf, gray wolf, Canis lupus 272 | 271:white wolf, Arctic wolf, Canis lupus tundrarum 273 | 272:red wolf, maned wolf, Canis rufus, Canis niger 274 | 273:coyote, prairie wolf, brush wolf, Canis latrans 275 | 274:dingo, warrigal, warragal, Canis dingo 276 | 275:dhole, Cuon alpinus 277 | 276:African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus 278 | 277:hyena, hyaena 279 | 278:red fox, Vulpes vulpes 280 | 279:kit fox, Vulpes macrotis 281 | 280:Arctic fox, white fox, Alopex lagopus 282 | 281:grey fox, gray fox, Urocyon cinereoargenteus 283 | 282:tabby, tabby cat 284 | 283:tiger cat 285 | 284:Persian cat 286 | 285:Siamese cat, Siamese 287 | 286:Egyptian cat 288 | 287:cougar, puma, catamount, mountain lion, painter, panther, Felis concolor 289 | 288:lynx, catamount 290 | 289:leopard, Panthera pardus 291 | 290:snow leopard, ounce, Panthera uncia 292 | 291:jaguar, panther, Panthera onca, Felis onca 293 | 292:lion, king of beasts, Panthera leo 294 | 293:tiger, Panthera tigris 295 | 294:cheetah, chetah, Acinonyx jubatus 296 | 295:brown bear, bruin, Ursus arctos 297 | 296:American black bear, black bear, Ursus americanus, Euarctos americanus 298 | 297:ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus 299 | 298:sloth bear, Melursus ursinus, Ursus ursinus 300 | 299:mongoose 301 | 300:meerkat, mierkat 302 | 301:tiger beetle 303 | 302:ladybug, ladybeetle, lady beetle, ladybird, ladybird beetle 304 | 303:ground beetle, carabid beetle 305 | 304:long-horned beetle, longicorn, longicorn beetle 306 | 305:leaf beetle, chrysomelid 307 | 306:dung beetle 308 | 307:rhinoceros beetle 309 | 308:weevil 310 | 309:fly 311 | 310:bee 312 | 311:ant, emmet, pismire 313 | 312:grasshopper, hopper 314 | 313:cricket 315 | 314:walking stick, walkingstick, stick insect 316 | 315:cockroach, roach 317 | 316:mantis, mantid 318 | 317:cicada, cicala 319 | 318:leafhopper 320 | 319:lacewing, lacewing fly 321 | 320:dragonfly, darning needle, devil's darning needle, sewing needle, snake feeder, snake doctor, mosquito hawk, skeeter hawk 322 | 321:damselfly 323 | 322:admiral 324 | 323:ringlet, ringlet butterfly 325 | 324:monarch, monarch butterfly, milkweed butterfly, Danaus plexippus 326 | 325:cabbage butterfly 327 | 326:sulphur butterfly, sulfur butterfly 328 | 327:lycaenid, lycaenid butterfly 329 | 328:starfish, sea star 330 | 329:sea urchin 331 | 330:sea cucumber, holothurian 332 | 331:wood rabbit, cottontail, cottontail rabbit 333 | 332:hare 334 | 333:Angora, Angora rabbit 335 | 334:hamster 336 | 335:porcupine, hedgehog 337 | 336:fox squirrel, eastern fox squirrel, Sciurus niger 338 | 337:marmot 339 | 338:beaver 340 | 339:guinea pig, Cavia cobaya 341 | 340:sorrel 342 | 341:zebra 343 | 342:hog, pig, grunter, squealer, Sus scrofa 344 | 343:wild boar, boar, Sus scrofa 345 | 344:warthog 346 | 345:hippopotamus, hippo, river horse, Hippopotamus amphibius 347 | 346:ox 348 | 347:water buffalo, water ox, Asiatic buffalo, Bubalus bubalis 349 | 348:bison 350 | 349:ram, tup 351 | 350:bighorn, bighorn sheep, cimarron, Rocky Mountain bighorn, Rocky Mountain sheep, Ovis canadensis 352 | 351:ibex, Capra ibex 353 | 352:hartebeest 354 | 353:impala, Aepyceros melampus 355 | 354:gazelle 356 | 355:Arabian camel, dromedary, Camelus dromedarius 357 | 356:llama 358 | 357:weasel 359 | 358:mink 360 | 359:polecat, fitch, foulmart, foumart, Mustela putorius 361 | 360:black-footed ferret, ferret, Mustela nigripes 362 | 361:otter 363 | 362:skunk, polecat, wood pussy 364 | 363:badger 365 | 364:armadillo 366 | 365:three-toed sloth, ai, Bradypus tridactylus 367 | 366:orangutan, orang, orangutang, Pongo pygmaeus 368 | 367:gorilla, Gorilla gorilla 369 | 368:chimpanzee, chimp, Pan troglodytes 370 | 369:gibbon, Hylobates lar 371 | 370:siamang, Hylobates syndactylus, Symphalangus syndactylus 372 | 371:guenon, guenon monkey 373 | 372:patas, hussar monkey, Erythrocebus patas 374 | 373:baboon 375 | 374:macaque 376 | 375:langur 377 | 376:colobus, colobus monkey 378 | 377:proboscis monkey, Nasalis larvatus 379 | 378:marmoset 380 | 379:capuchin, ringtail, Cebus capucinus 381 | 380:howler monkey, howler 382 | 381:titi, titi monkey 383 | 382:spider monkey, Ateles geoffroyi 384 | 383:squirrel monkey, Saimiri sciureus 385 | 384:Madagascar cat, ring-tailed lemur, Lemur catta 386 | 385:indri, indris, Indri indri, Indri brevicaudatus 387 | 386:Indian elephant, Elephas maximus 388 | 387:African elephant, Loxodonta africana 389 | 388:lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens 390 | 389:giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca 391 | 390:barracouta, snoek 392 | 391:eel 393 | 392:coho, cohoe, coho salmon, blue jack, silver salmon, Oncorhynchus kisutch 394 | 393:rock beauty, Holocanthus tricolor 395 | 394:anemone fish 396 | 395:sturgeon 397 | 396:gar, garfish, garpike, billfish, Lepisosteus osseus 398 | 397:lionfish 399 | 398:puffer, pufferfish, blowfish, globefish 400 | 399:abacus 401 | 400:abaya 402 | 401:academic gown, academic robe, judge's robe 403 | 402:accordion, piano accordion, squeeze box 404 | 403:acoustic guitar 405 | 404:aircraft carrier, carrier, flattop, attack aircraft carrier 406 | 405:airliner 407 | 406:airship, dirigible 408 | 407:altar 409 | 408:ambulance 410 | 409:amphibian, amphibious vehicle 411 | 410:analog clock 412 | 411:apiary, bee house 413 | 412:apron 414 | 413:ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin 415 | 414:assault rifle, assault gun 416 | 415:backpack, back pack, knapsack, packsack, rucksack, haversack 417 | 416:bakery, bakeshop, bakehouse 418 | 417:balance beam, beam 419 | 418:balloon 420 | 419:ballpoint, ballpoint pen, ballpen, Biro 421 | 420:Band Aid 422 | 421:banjo 423 | 422:bannister, banister, balustrade, balusters, handrail 424 | 423:barbell 425 | 424:barber chair 426 | 425:barbershop 427 | 426:barn 428 | 427:barometer 429 | 428:barrel, cask 430 | 429:barrow, garden cart, lawn cart, wheelbarrow 431 | 430:baseball 432 | 431:basketball 433 | 432:bassinet 434 | 433:bassoon 435 | 434:bathing cap, swimming cap 436 | 435:bath towel 437 | 436:bathtub, bathing tub, bath, tub 438 | 437:beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon 439 | 438:beacon, lighthouse, beacon light, pharos 440 | 439:beaker 441 | 440:bearskin, busby, shako 442 | 441:beer bottle 443 | 442:beer glass 444 | 443:bell cote, bell cot 445 | 444:bib 446 | 445:bicycle-built-for-two, tandem bicycle, tandem 447 | 446:bikini, two-piece 448 | 447:binder, ring-binder 449 | 448:binoculars, field glasses, opera glasses 450 | 449:birdhouse 451 | 450:boathouse 452 | 451:bobsled, bobsleigh, bob 453 | 452:bolo tie, bolo, bola tie, bola 454 | 453:bonnet, poke bonnet 455 | 454:bookcase 456 | 455:bookshop, bookstore, bookstall 457 | 456:bottlecap 458 | 457:bow 459 | 458:bow tie, bow-tie, bowtie 460 | 459:brass, memorial tablet, plaque 461 | 460:brassiere, bra, bandeau 462 | 461:breakwater, groin, groyne, mole, bulwark, seawall, jetty 463 | 462:breastplate, aegis, egis 464 | 463:broom 465 | 464:bucket, pail 466 | 465:buckle 467 | 466:bulletproof vest 468 | 467:bullet train, bullet 469 | 468:butcher shop, meat market 470 | 469:cab, hack, taxi, taxicab 471 | 470:caldron, cauldron 472 | 471:candle, taper, wax light 473 | 472:cannon 474 | 473:canoe 475 | 474:can opener, tin opener 476 | 475:cardigan 477 | 476:car mirror 478 | 477:carousel, carrousel, merry-go-round, roundabout, whirligig 479 | 478:carpenter's kit, tool kit 480 | 479:carton 481 | 480:car wheel 482 | 481:cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM 483 | 482:cassette 484 | 483:cassette player 485 | 484:castle 486 | 485:catamaran 487 | 486:CD player 488 | 487:cello, violoncello 489 | 488:cellular telephone, cellular phone, cellphone, cell, mobile phone 490 | 489:chain 491 | 490:chainlink fence 492 | 491:chain mail, ring mail, mail, chain armor, chain armour, ring armor, ring armour 493 | 492:chain saw, chainsaw 494 | 493:chest 495 | 494:chiffonier, commode 496 | 495:chime, bell, gong 497 | 496:china cabinet, china closet 498 | 497:Christmas stocking 499 | 498:church, church building 500 | 499:cinema, movie theater, movie theatre, movie house, picture palace 501 | 500:cleaver, meat cleaver, chopper 502 | 501:cliff dwelling 503 | 502:cloak 504 | 503:clog, geta, patten, sabot 505 | 504:cocktail shaker 506 | 505:coffee mug 507 | 506:coffeepot 508 | 507:coil, spiral, volute, whorl, helix 509 | 508:combination lock 510 | 509:computer keyboard, keypad 511 | 510:confectionery, confectionary, candy store 512 | 511:container ship, containership, container vessel 513 | 512:convertible 514 | 513:corkscrew, bottle screw 515 | 514:cornet, horn, trumpet, trump 516 | 515:cowboy boot 517 | 516:cowboy hat, ten-gallon hat 518 | 517:cradle 519 | 518:crane 520 | 519:crash helmet 521 | 520:crate 522 | 521:crib, cot 523 | 522:Crock Pot 524 | 523:croquet ball 525 | 524:crutch 526 | 525:cuirass 527 | 526:dam, dike, dyke 528 | 527:desk 529 | 528:desktop computer 530 | 529:dial telephone, dial phone 531 | 530:diaper, nappy, napkin 532 | 531:digital clock 533 | 532:digital watch 534 | 533:dining table, board 535 | 534:dishrag, dishcloth 536 | 535:dishwasher, dish washer, dishwashing machine 537 | 536:disk brake, disc brake 538 | 537:dock, dockage, docking facility 539 | 538:dogsled, dog sled, dog sleigh 540 | 539:dome 541 | 540:doormat, welcome mat 542 | 541:drilling platform, offshore rig 543 | 542:drum, membranophone, tympan 544 | 543:drumstick 545 | 544:dumbbell 546 | 545:Dutch oven 547 | 546:electric fan, blower 548 | 547:electric guitar 549 | 548:electric locomotive 550 | 549:entertainment center 551 | 550:envelope 552 | 551:espresso maker 553 | 552:face powder 554 | 553:feather boa, boa 555 | 554:file, file cabinet, filing cabinet 556 | 555:fireboat 557 | 556:fire engine, fire truck 558 | 557:fire screen, fireguard 559 | 558:flagpole, flagstaff 560 | 559:flute, transverse flute 561 | 560:folding chair 562 | 561:football helmet 563 | 562:forklift 564 | 563:fountain 565 | 564:fountain pen 566 | 565:four-poster 567 | 566:freight car 568 | 567:French horn, horn 569 | 568:frying pan, frypan, skillet 570 | 569:fur coat 571 | 570:garbage truck, dustcart 572 | 571:gasmask, respirator, gas helmet 573 | 572:gas pump, gasoline pump, petrol pump, island dispenser 574 | 573:goblet 575 | 574:go-kart 576 | 575:golf ball 577 | 576:golfcart, golf cart 578 | 577:gondola 579 | 578:gong, tam-tam 580 | 579:gown 581 | 580:grand piano, grand 582 | 581:greenhouse, nursery, glasshouse 583 | 582:grille, radiator grille 584 | 583:grocery store, grocery, food market, market 585 | 584:guillotine 586 | 585:hair slide 587 | 586:hair spray 588 | 587:half track 589 | 588:hammer 590 | 589:hamper 591 | 590:hand blower, blow dryer, blow drier, hair dryer, hair drier 592 | 591:hand-held computer, hand-held microcomputer 593 | 592:handkerchief, hankie, hanky, hankey 594 | 593:hard disc, hard disk, fixed disk 595 | 594:harmonica, mouth organ, harp, mouth harp 596 | 595:harp 597 | 596:harvester, reaper 598 | 597:hatchet 599 | 598:holster 600 | 599:home theater, home theatre 601 | 600:honeycomb 602 | 601:hook, claw 603 | 602:hoopskirt, crinoline 604 | 603:horizontal bar, high bar 605 | 604:horse cart, horse-cart 606 | 605:hourglass 607 | 606:iPod 608 | 607:iron, smoothing iron 609 | 608:jack-o'-lantern 610 | 609:jean, blue jean, denim 611 | 610:jeep, landrover 612 | 611:jersey, T-shirt, tee shirt 613 | 612:jigsaw puzzle 614 | 613:jinrikisha, ricksha, rickshaw 615 | 614:joystick 616 | 615:kimono 617 | 616:knee pad 618 | 617:knot 619 | 618:lab coat, laboratory coat 620 | 619:ladle 621 | 620:lampshade, lamp shade 622 | 621:laptop, laptop computer 623 | 622:lawn mower, mower 624 | 623:lens cap, lens cover 625 | 624:letter opener, paper knife, paperknife 626 | 625:library 627 | 626:lifeboat 628 | 627:lighter, light, igniter, ignitor 629 | 628:limousine, limo 630 | 629:liner, ocean liner 631 | 630:lipstick, lip rouge 632 | 631:Loafer 633 | 632:lotion 634 | 633:loudspeaker, speaker, speaker unit, loudspeaker system, speaker system 635 | 634:loupe, jeweler's loupe 636 | 635:lumbermill, sawmill 637 | 636:magnetic compass 638 | 637:mailbag, postbag 639 | 638:mailbox, letter box 640 | 639:maillot 641 | 640:maillot, tank suit 642 | 641:manhole cover 643 | 642:maraca 644 | 643:marimba, xylophone 645 | 644:mask 646 | 645:matchstick 647 | 646:maypole 648 | 647:maze, labyrinth 649 | 648:measuring cup 650 | 649:medicine chest, medicine cabinet 651 | 650:megalith, megalithic structure 652 | 651:microphone, mike 653 | 652:microwave, microwave oven 654 | 653:military uniform 655 | 654:milk can 656 | 655:minibus 657 | 656:miniskirt, mini 658 | 657:minivan 659 | 658:missile 660 | 659:mitten 661 | 660:mixing bowl 662 | 661:mobile home, manufactured home 663 | 662:Model T 664 | 663:modem 665 | 664:monastery 666 | 665:monitor 667 | 666:moped 668 | 667:mortar 669 | 668:mortarboard 670 | 669:mosque 671 | 670:mosquito net 672 | 671:motor scooter, scooter 673 | 672:mountain bike, all-terrain bike, off-roader 674 | 673:mountain tent 675 | 674:mouse, computer mouse 676 | 675:mousetrap 677 | 676:moving van 678 | 677:muzzle 679 | 678:nail 680 | 679:neck brace 681 | 680:necklace 682 | 681:nipple 683 | 682:notebook, notebook computer 684 | 683:obelisk 685 | 684:oboe, hautboy, hautbois 686 | 685:ocarina, sweet potato 687 | 686:odometer, hodometer, mileometer, milometer 688 | 687:oil filter 689 | 688:organ, pipe organ 690 | 689:oscilloscope, scope, cathode-ray oscilloscope, CRO 691 | 690:overskirt 692 | 691:oxcart 693 | 692:oxygen mask 694 | 693:packet 695 | 694:paddle, boat paddle 696 | 695:paddlewheel, paddle wheel 697 | 696:padlock 698 | 697:paintbrush 699 | 698:pajama, pyjama, pj's, jammies 700 | 699:palace 701 | 700:panpipe, pandean pipe, syrinx 702 | 701:paper towel 703 | 702:parachute, chute 704 | 703:parallel bars, bars 705 | 704:park bench 706 | 705:parking meter 707 | 706:passenger car, coach, carriage 708 | 707:patio, terrace 709 | 708:pay-phone, pay-station 710 | 709:pedestal, plinth, footstall 711 | 710:pencil box, pencil case 712 | 711:pencil sharpener 713 | 712:perfume, essence 714 | 713:Petri dish 715 | 714:photocopier 716 | 715:pick, plectrum, plectron 717 | 716:pickelhaube 718 | 717:picket fence, paling 719 | 718:pickup, pickup truck 720 | 719:pier 721 | 720:piggy bank, penny bank 722 | 721:pill bottle 723 | 722:pillow 724 | 723:ping-pong ball 725 | 724:pinwheel 726 | 725:pirate, pirate ship 727 | 726:pitcher, ewer 728 | 727:plane, carpenter's plane, woodworking plane 729 | 728:planetarium 730 | 729:plastic bag 731 | 730:plate rack 732 | 731:plow, plough 733 | 732:plunger, plumber's helper 734 | 733:Polaroid camera, Polaroid Land camera 735 | 734:pole 736 | 735:police van, police wagon, paddy wagon, patrol wagon, wagon, black Maria 737 | 736:poncho 738 | 737:pool table, billiard table, snooker table 739 | 738:pop bottle, soda bottle 740 | 739:pot, flowerpot 741 | 740:potter's wheel 742 | 741:power drill 743 | 742:prayer rug, prayer mat 744 | 743:printer 745 | 744:prison, prison house 746 | 745:projectile, missile 747 | 746:projector 748 | 747:puck, hockey puck 749 | 748:punching bag, punch bag, punching ball, punchball 750 | 749:purse 751 | 750:quill, quill pen 752 | 751:quilt, comforter, comfort, puff 753 | 752:racer, race car, racing car 754 | 753:racket, racquet 755 | 754:radiator 756 | 755:radio, wireless 757 | 756:radio telescope, radio reflector 758 | 757:rain barrel 759 | 758:recreational vehicle, RV, R.V. 760 | 759:reel 761 | 760:reflex camera 762 | 761:refrigerator, icebox 763 | 762:remote control, remote 764 | 763:restaurant, eating house, eating place, eatery 765 | 764:revolver, six-gun, six-shooter 766 | 765:rifle 767 | 766:rocking chair, rocker 768 | 767:rotisserie 769 | 768:rubber eraser, rubber, pencil eraser 770 | 769:rugby ball 771 | 770:rule, ruler 772 | 771:running shoe 773 | 772:safe 774 | 773:safety pin 775 | 774:saltshaker, salt shaker 776 | 775:sandal 777 | 776:sarong 778 | 777:sax, saxophone 779 | 778:scabbard 780 | 779:scale, weighing machine 781 | 780:school bus 782 | 781:schooner 783 | 782:scoreboard 784 | 783:screen, CRT screen 785 | 784:screw 786 | 785:screwdriver 787 | 786:seat belt, seatbelt 788 | 787:sewing machine 789 | 788:shield, buckler 790 | 789:shoe shop, shoe-shop, shoe store 791 | 790:shoji 792 | 791:shopping basket 793 | 792:shopping cart 794 | 793:shovel 795 | 794:shower cap 796 | 795:shower curtain 797 | 796:ski 798 | 797:ski mask 799 | 798:sleeping bag 800 | 799:slide rule, slipstick 801 | 800:sliding door 802 | 801:slot, one-armed bandit 803 | 802:snorkel 804 | 803:snowmobile 805 | 804:snowplow, snowplough 806 | 805:soap dispenser 807 | 806:soccer ball 808 | 807:sock 809 | 808:solar dish, solar collector, solar furnace 810 | 809:sombrero 811 | 810:soup bowl 812 | 811:space bar 813 | 812:space heater 814 | 813:space shuttle 815 | 814:spatula 816 | 815:speedboat 817 | 816:spider web, spider's web 818 | 817:spindle 819 | 818:sports car, sport car 820 | 819:spotlight, spot 821 | 820:stage 822 | 821:steam locomotive 823 | 822:steel arch bridge 824 | 823:steel drum 825 | 824:stethoscope 826 | 825:stole 827 | 826:stone wall 828 | 827:stopwatch, stop watch 829 | 828:stove 830 | 829:strainer 831 | 830:streetcar, tram, tramcar, trolley, trolley car 832 | 831:stretcher 833 | 832:studio couch, day bed 834 | 833:stupa, tope 835 | 834:submarine, pigboat, sub, U-boat 836 | 835:suit, suit of clothes 837 | 836:sundial 838 | 837:sunglass 839 | 838:sunglasses, dark glasses, shades 840 | 839:sunscreen, sunblock, sun blocker 841 | 840:suspension bridge 842 | 841:swab, swob, mop 843 | 842:sweatshirt 844 | 843:swimming trunks, bathing trunks 845 | 844:swing 846 | 845:switch, electric switch, electrical switch 847 | 846:syringe 848 | 847:table lamp 849 | 848:tank, army tank, armored combat vehicle, armoured combat vehicle 850 | 849:tape player 851 | 850:teapot 852 | 851:teddy, teddy bear 853 | 852:television, television system 854 | 853:tennis ball 855 | 854:thatch, thatched roof 856 | 855:theater curtain, theatre curtain 857 | 856:thimble 858 | 857:thresher, thrasher, threshing machine 859 | 858:throne 860 | 859:tile roof 861 | 860:toaster 862 | 861:tobacco shop, tobacconist shop, tobacconist 863 | 862:toilet seat 864 | 863:torch 865 | 864:totem pole 866 | 865:tow truck, tow car, wrecker 867 | 866:toyshop 868 | 867:tractor 869 | 868:trailer truck, tractor trailer, trucking rig, rig, articulated lorry, semi 870 | 869:tray 871 | 870:trench coat 872 | 871:tricycle, trike, velocipede 873 | 872:trimaran 874 | 873:tripod 875 | 874:triumphal arch 876 | 875:trolleybus, trolley coach, trackless trolley 877 | 876:trombone 878 | 877:tub, vat 879 | 878:turnstile 880 | 879:typewriter keyboard 881 | 880:umbrella 882 | 881:unicycle, monocycle 883 | 882:upright, upright piano 884 | 883:vacuum, vacuum cleaner 885 | 884:vase 886 | 885:vault 887 | 886:velvet 888 | 887:vending machine 889 | 888:vestment 890 | 889:viaduct 891 | 890:violin, fiddle 892 | 891:volleyball 893 | 892:waffle iron 894 | 893:wall clock 895 | 894:wallet, billfold, notecase, pocketbook 896 | 895:wardrobe, closet, press 897 | 896:warplane, military plane 898 | 897:washbasin, handbasin, washbowl, lavabo, wash-hand basin 899 | 898:washer, automatic washer, washing machine 900 | 899:water bottle 901 | 900:water jug 902 | 901:water tower 903 | 902:whiskey jug 904 | 903:whistle 905 | 904:wig 906 | 905:window screen 907 | 906:window shade 908 | 907:Windsor tie 909 | 908:wine bottle 910 | 909:wing 911 | 910:wok 912 | 911:wooden spoon 913 | 912:wool, woolen, woollen 914 | 913:worm fence, snake fence, snake-rail fence, Virginia fence 915 | 914:wreck 916 | 915:yawl 917 | 916:yurt 918 | 917:web site, website, internet site, site 919 | 918:comic book 920 | 919:crossword puzzle, crossword 921 | 920:street sign 922 | 921:traffic light, traffic signal, stoplight 923 | 922:book jacket, dust cover, dust jacket, dust wrapper 924 | 923:menu 925 | 924:plate 926 | 925:guacamole 927 | 926:consomme 928 | 927:hot pot, hotpot 929 | 928:trifle 930 | 929:ice cream, icecream 931 | 930:ice lolly, lolly, lollipop, popsicle 932 | 931:French loaf 933 | 932:bagel, beigel 934 | 933:pretzel 935 | 934:cheeseburger 936 | 935:hotdog, hot dog, red hot 937 | 936:mashed potato 938 | 937:head cabbage 939 | 938:broccoli 940 | 939:cauliflower 941 | 940:zucchini, courgette 942 | 941:spaghetti squash 943 | 942:acorn squash 944 | 943:butternut squash 945 | 944:cucumber, cuke 946 | 945:artichoke, globe artichoke 947 | 946:bell pepper 948 | 947:cardoon 949 | 948:mushroom 950 | 949:Granny Smith 951 | 950:strawberry 952 | 951:orange 953 | 952:lemon 954 | 953:fig 955 | 954:pineapple, ananas 956 | 955:banana 957 | 956:jackfruit, jak, jack 958 | 957:custard apple 959 | 958:pomegranate 960 | 959:hay 961 | 960:carbonara 962 | 961:chocolate sauce, chocolate syrup 963 | 962:dough 964 | 963:meat loaf, meatloaf 965 | 964:pizza, pizza pie 966 | 965:potpie 967 | 966:burrito 968 | 967:red wine 969 | 968:espresso 970 | 969:cup 971 | 970:eggnog 972 | 971:alp 973 | 972:bubble 974 | 973:cliff, drop, drop-off 975 | 974:coral reef 976 | 975:geyser 977 | 976:lakeside, lakeshore 978 | 977:promontory, headland, head, foreland 979 | 978:sandbar, sand bar 980 | 979:seashore, coast, seacoast, sea-coast 981 | 980:valley, vale 982 | 981:volcano 983 | 982:ballplayer, baseball player 984 | 983:groom, bridegroom 985 | 984:scuba diver 986 | 985:rapeseed 987 | 986:daisy 988 | 987:yellow lady's slipper, yellow lady-slipper, Cypripedium calceolus, Cypripedium parviflorum 989 | 988:corn 990 | 989:acorn 991 | 990:hip, rose hip, rosehip 992 | 991:buckeye, horse chestnut, conker 993 | 992:coral fungus 994 | 993:agaric 995 | 994:gyromitra 996 | 995:stinkhorn, carrion fungus 997 | 996:earthstar 998 | 997:hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa 999 | 998:bolete 1000 | 999:ear, spike, capitulum 1001 | 1000:toilet tissue, toilet paper, bathroom tissue 1002 | -------------------------------------------------------------------------------- /nlayer_model.py: -------------------------------------------------------------------------------- 1 | ## setup_mnist.py -- mnist data and model loading code 2 | ## 3 | ## Copyright (C) 2017-2018, IBM Corp. 4 | ## Copyright (C) 2017, Huan Zhang . 5 | ## 6 | ## This program is licenced under the Apache 2.0 licence, 7 | ## contained in the LICENCE file in this directory. 8 | 9 | import numpy as np 10 | import os 11 | import pickle 12 | import gzip 13 | import argparse 14 | import urllib.request 15 | 16 | from tensorflow.contrib.keras.api.keras.models import Sequential 17 | from tensorflow.contrib.keras.api.keras.layers import Dense, Dropout, Activation, Flatten 18 | from tensorflow.contrib.keras.api.keras.layers import Conv2D, MaxPooling2D 19 | from tensorflow.contrib.keras.api.keras.models import load_model 20 | from tensorflow.contrib.keras.api.keras import backend as K 21 | 22 | 23 | class NLayerModel: 24 | def __init__(self, params, restore = None, session=None, use_log=False, image_size=28, image_channel=1): 25 | 26 | self.image_size = image_size 27 | self.num_channels = image_channel 28 | self.num_labels = 10 29 | 30 | model = Sequential() 31 | model.add(Flatten(input_shape=(image_size, image_size, image_channel))) 32 | # list of all hidden units weights 33 | self.U = [] 34 | for param in params: 35 | # add each dense layer, and save a reference to list U 36 | self.U.append(Dense(param)) 37 | model.add(self.U[-1]) 38 | # ReLU activation 39 | model.add(Activation('relu')) 40 | self.W = Dense(10) 41 | model.add(self.W) 42 | # output log probability, used for black-box attack 43 | if use_log: 44 | model.add(Activation('softmax')) 45 | if restore: 46 | model.load_weights(restore) 47 | 48 | layer_outputs = [] 49 | for layer in model.layers: 50 | if isinstance(layer, Conv2D) or isinstance(layer, Dense): 51 | layer_outputs.append(K.function([model.layers[0].input], [layer.output])) 52 | 53 | self.layer_outputs = layer_outputs 54 | self.model = model 55 | 56 | def predict(self, data): 57 | return self.model(data) 58 | 59 | 60 | if __name__ == "__main__": 61 | import scipy.io as sio 62 | parser = argparse.ArgumentParser(description='save n-layer MNIST and CIFAR weights') 63 | parser.add_argument('--model', 64 | default="mnist", 65 | choices=["mnist", "cifar"], 66 | help='model name') 67 | parser.add_argument('--modelfile', 68 | default="", 69 | help='override the model filename, use user specied one') 70 | parser.add_argument('layer_parameters', 71 | nargs='+', 72 | help='number of hidden units per layer') 73 | args = parser.parse_args() 74 | nlayers = len(args.layer_parameters) + 1 75 | 76 | import tensorflow as tf 77 | with tf.Session() as sess: 78 | # if a model file is not specified, use a manual override 79 | if not args.modelfile: 80 | args.modelfile = "models/"+args.model+"_"+str(nlayers)+"layer_relu" 81 | if args.model == "mnist": 82 | model = NLayerModel(args.layer_parameters, args.modelfile, sess) 83 | #model = NLayerModel(args.layer_parameters, "models/mnist_"+str(nlayers)+"layer_relu") 84 | elif args.model == "cifar": 85 | model = NLayerModel(args.layer_parameters, args.modelfile, sess, image_size=32, image_channel=3) 86 | else: 87 | raise(RuntimeError("Unknow model")) 88 | 89 | 90 | [W, bias_W] = model.W.get_weights() 91 | save_dict = {'W': W, 'bias_W': bias_W} 92 | print("Output layer shape:", W.shape) 93 | U = model.U 94 | for i, Ui in enumerate(U): 95 | # save hidden layer weights, layer by layer 96 | [weight_Ui, bias_Ui] = Ui.get_weights() 97 | print("Hidden layer {} shape: {}".format(i, weight_Ui.shape)) 98 | save_dict['U'+str(i+1)] = weight_Ui 99 | save_dict['bias_U'+str(i+1)] = bias_Ui 100 | 101 | save_name = args.model + "_" + str(nlayers) + "layers" 102 | print('saving to {}.mat with matrices {}'.format(save_name, save_dict.keys())) 103 | # results saved to mnist.mat or cifar.mat 104 | sio.savemat(save_name, save_dict) 105 | 106 | -------------------------------------------------------------------------------- /process_log.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | process_log.py 5 | 6 | process log files generated by clever.py 7 | 8 | Copyright (C) 2017-2018, IBM Corp. 9 | Copyright (C) 2017, Lily Weng 10 | and Huan Zhang 11 | 12 | This program is licenced under the Apache 2.0 licence, 13 | contained in the LICENCE file in this directory. 14 | """ 15 | 16 | import os, glob 17 | import sys 18 | import scipy 19 | import scipy.io as sio 20 | from scipy.stats import weibull_min 21 | import numpy as np 22 | import pandas as pd 23 | import argparse 24 | import matplotlib.pyplot as plt 25 | 26 | 27 | def readDebugLog2array(filename): 28 | f = open(filename) 29 | 30 | # last 3 lines are L0 verbosity, the first line is comment 31 | #lines = f.readlines()[0:-3] 32 | lines = f.readlines()[0:] # read all the lines and check if belongs to [DEBUG][L1] below 33 | # if the files are ended with "_grep" 34 | #lines = f.readlines() 35 | f.close() 36 | 37 | data_arr = {"[DEBUG][L1] id":[],"true_label":[],"target_label":[],"info":[],"bnd_norm":[], 38 | "bnd":[],"ks":[],"pVal":[],"shape":[],"loc":[],"scale":[], "g_x0":[]} 39 | 40 | #Ncols = len(lines[0].strip().split(',')); 41 | 42 | for line in lines: 43 | # split ',' into columns 44 | subline = line.strip().split(',') 45 | 46 | #print(subline) 47 | #print('-reading lines-') 48 | 49 | # only save the info when the line is [DEBUG][L1] 50 | if subline[0].split('=')[0] == '[DEBUG][L1] id ': 51 | for elems in subline: 52 | temp = elems.split('='); 53 | key = temp[0].strip() 54 | val = temp[1].strip() 55 | # save key and val to array 56 | data_arr[key].append(val) 57 | 58 | return data_arr 59 | 60 | 61 | table_results = {} 62 | 63 | if __name__ == "__main__": 64 | # parse command line parameters 65 | parser = argparse.ArgumentParser(description='Process experiment data.') 66 | parser.add_argument('data_folder', nargs='+', help='log file(s) or directory') 67 | parser.add_argument('--save_pickle', 68 | action='store_true', 69 | help='save result to pickle') 70 | args = vars(parser.parse_args()) 71 | print(args) 72 | # process all the log files in the folder 73 | flag_process_all_dir = False 74 | # save result to pickle 75 | is_save2pickle = args['save_pickle'] 76 | 77 | files = [] 78 | # the argument is a list of paths 79 | for path in args['data_folder']: 80 | # if the path is a directory, look for all log files inside 81 | if os.path.isdir(path): 82 | files.extend(glob.glob(os.path.join(path, "*.log"))) 83 | # if the path is a file, include it directly 84 | else: 85 | files.append(path) 86 | print(files) 87 | 88 | for file in files: 89 | # datas is a dictionary 90 | datas = readDebugLog2array(file) 91 | 92 | # convert the dictionary to dataframe df 93 | df = pd.DataFrame.from_dict(datas) 94 | 95 | # convert the string type columns to numeric 96 | df['bnd'] = pd.to_numeric(df['bnd']) 97 | df['g_x0'] = pd.to_numeric(df['g_x0']) 98 | df['ks'] = pd.to_numeric(df['ks']) 99 | df['loc'] = pd.to_numeric(df['loc']) 100 | df['pVal'] = pd.to_numeric(df['pVal']) 101 | df['scale'] = pd.to_numeric(df['scale']) 102 | df['shape'] = pd.to_numeric(df['shape']) 103 | 104 | tag1 = os.path.basename(file).split('_')[1] 105 | 106 | # cifar, mnist, imagenet 107 | if (tag1 == 'cifar') or (tag1 == 'mnist'): 108 | modelName = tag1 + '_' + os.path.basename(file).split('_')[2].split('.')[0] 109 | else: 110 | modelName = tag1 111 | 112 | if modelName not in table_results: 113 | nan = float('nan') 114 | table_results[modelName] = {'least': {'1': [nan,nan], '2': [nan,nan], 'i': [nan,nan]}, 115 | 'random':{'1': [nan,nan], '2': [nan,nan], 'i': [nan,nan]}, 116 | 'top2': {'1': [nan,nan], '2': [nan,nan], 'i': [nan,nan]}} 117 | 118 | for label in ['least','random','top2']: 119 | for bnd_norm in ['1','2','i']: 120 | df_out = df[(df["info"]==label) & (df["bnd_norm"]==bnd_norm)] 121 | 122 | if not df_out.empty: 123 | out_name = 'pickle_'+modelName+'_'+label+'_norm'+bnd_norm 124 | 125 | 126 | if is_save2pickle: 127 | # save selected df to pickle files 128 | df_out.to_pickle(out_name) 129 | 130 | # obtain statistics and print out 131 | descrb_0 = df_out.describe() 132 | descrb_1 = df_out[(df_out["pVal"]>0.05)&(df_out["shape"]<1000)].describe() 133 | 134 | 135 | bnd_0 = descrb_0["bnd"]["mean"] 136 | count_0 = descrb_0["bnd"]["count"] 137 | 138 | bnd_1 = descrb_1["bnd"]["mean"] 139 | count_1 = descrb_1["bnd"]["count"] 140 | 141 | table_results[modelName][label][bnd_norm][0] = bnd_1 142 | table_results[modelName][label][bnd_norm][1] = count_1 * 100.0 / count_0 143 | print("[L0] model = {}, Nimg = {}, bnd_avg = {:.5g}, pVal>0.05 & shape<1000 gives" 144 | "Nimg = {}, bnd_avg = {:.5g}, useable = {:.1f} %".format(out_name,count_0,bnd_0,count_1,bnd_1,count_1/count_0*100)) 145 | # print out table for easy pasting to LaTeX 146 | output = sys.stdout 147 | print('Generating LaTeX table...') 148 | order=['mnist_2-layer', 'mnist_normal', 'mnist_distilled', 'mnist_brelu', 'cifar_2-layer', 'cifar_normal', 'cifar_distilled', 'cifar_brelu', 'inception', 'resnet', 'mobilenet'] 149 | 150 | def gen_table(elem_index, precision=3): 151 | for label in ['least','random','top2']: 152 | output.write("{:15s} &\t{:7s} &\t{:7s} &\n".format(label, '2', 'i')) 153 | for model in order: 154 | if model in table_results: 155 | output.write("{:15s} &\t".format(model)) 156 | for bnd_norm in ['2','i']: 157 | output.write(("{:7."+str(precision)+"f} &\t").format(table_results[model][label][bnd_norm][elem_index])) 158 | output.write("\n") 159 | 160 | print('\n%%% Table for bounds %%%') 161 | gen_table(0) 162 | print('\n%%% Table for p-values %%%') 163 | gen_table(1,1) 164 | 165 | -------------------------------------------------------------------------------- /randsphere.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import numpy as np 4 | import time 5 | from shmemarray import ShmemRawArray, NpShmemArray 6 | from scipy.special import gammainc 7 | from defense import defend_reduce, defend_jpeg, defend_tv, defend_none, defend_png 8 | from functools import partial 9 | 10 | """ 11 | Original Matlab code (for L2 sampling): 12 | 13 | function X = randsphere(m,n,r) 14 | 15 | X = randn(m,n); 16 | s2 = sum(X.^2,2); 17 | X = X.*repmat(r*(gammainc(s2/2,n/2).^(1/n))./sqrt(s2),1,n); 18 | """ 19 | 20 | # generate random signs 21 | def randsign(N): 22 | n_bytes = (N + 7) // 8 23 | rbytes = np.random.randint(0, 255, dtype=np.uint8, size=n_bytes) 24 | return (np.unpackbits(rbytes)[:N] - 0.5) * 2 25 | 26 | def l2_samples(m,n): 27 | X = np.random.randn(m, n) 28 | s2 = np.sum(X * X, axis = 1) 29 | return X * (np.tile(1.0*np.power(gammainc(n/2,s2/2), 1/n) / np.sqrt(s2), (n,1))).T 30 | 31 | def linf_samples(m, n): 32 | return np.random.uniform(-1.0, 1.0, (m,n)) 33 | 34 | def l1_samples(m, n): 35 | # U is uniform random between 0, 1 36 | U = np.random.uniform(0, 1.0, (m,n-1)) 37 | V = np.empty(shape=(m,n+1)) 38 | # V is sorted U, with 0 and 1 added to the begin and the end 39 | V[:,0] = 0.0 40 | V[:,-1] = 1.0 41 | V[:,1:-1] = np.sort(U) 42 | # X is the interval between each V_i 43 | X = V[:,1:] - V[:,:-1] 44 | # randomly flip the sign of each X 45 | s = randsign(m * n).reshape(m,n) 46 | return X * s 47 | 48 | def randsphere(idx, n, r, total_size, scale_size, tag_prefix, input_shape, norm, transform = None): 49 | # currently we assume r = 1.0 and rescale using the array "scale" 50 | assert r == 1.0 51 | result_arr = NpShmemArray(np.float32, (total_size, n), tag_prefix + "randsphere", False) 52 | # for scale, we may want a different starting point for imagenet, which is scale_start 53 | scale = NpShmemArray(np.float32, (scale_size, 1), tag_prefix + "scale", False) 54 | input_example = NpShmemArray(np.float32, input_shape, tag_prefix + "input_example", False) 55 | all_inputs = NpShmemArray(np.float32, (total_size,) + input_example.shape, tag_prefix + "all_inputs", False) 56 | # m is the number of items, off is the offset 57 | m, offset, scale_start = idx 58 | # n is the dimension 59 | if norm == "l2": 60 | samples = l2_samples(m, n) 61 | if norm == "l1": 62 | samples = l1_samples(m, n) 63 | if norm == "li": 64 | samples = linf_samples(m, n) 65 | result_arr[offset : offset + m] = samples 66 | # make a scaling 67 | result_arr[offset : offset + m] *= scale[offset + scale_start : offset + scale_start + m] 68 | # add to input example 69 | all_inputs[offset : offset + m] = input_example 70 | result_arr = result_arr.reshape(-1, *input_shape) 71 | all_inputs[offset : offset + m] += result_arr[offset : offset + m] 72 | # apply an transformation 73 | if transform: 74 | transform_new = lambda x: (eval(transform)(np.squeeze(x) + 0.5) - 0.5).reshape(all_inputs[offset].shape) 75 | # before transformation we need to clip first 76 | np.clip(all_inputs[offset : offset + m], -0.5, 0.5, out = all_inputs[offset : offset + m]) 77 | # run transformation 78 | for i in range(offset, offset + m): 79 | all_inputs[i] = transform_new(all_inputs[i]) 80 | # we need to clip again after transformation (this is in the caller) 81 | return 82 | 83 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | """ 4 | run.sh 5 | 6 | Run file: collect the samples of gradient norms 7 | 8 | Copyright (C) 2017-2018, IBM Corp. 9 | Copyright (C) 2017, Lily Weng 10 | and Huan Zhang 11 | 12 | This program is licenced under the Apache 2.0 licence, 13 | contained in the LICENCE file in this directory. 14 | """ 15 | # run file for running 1st order and 2nd order clever 16 | 17 | if [ "$#" -le 6 ]; then 18 | echo "Usage: $0 model modeltype nsamp niters activation order target gpuNum" 19 | echo "model={mnist, cifar}; modeltype={2-layer, normal}; activation={tanh, sigmoid, softplus}; order={1,2}" 20 | echo "target={top2, rand, least, all}, gpuNum={0,1,2} on frigg, {0,1} on apollo, {0} local" 21 | exit 1 22 | fi 23 | 24 | ## set up parameters 25 | # mnist or cifar 26 | model=$1 27 | # 2-layer, normal(7-layer) 28 | modeltype=$2 29 | # 200 30 | nsamp=$3 31 | # 10, 20, 50, 100, 200, 300 32 | niters=$4 33 | # tanh, sigmoid, softplus 34 | activation=$5 35 | # 1, 2 36 | order=$6 37 | # 1 (top2), 2 (rand), 4 (least), 15 (all) 38 | target=$7 39 | 40 | if [ "$#" -le 7 ]; then 41 | gpuNum="0" 42 | #echo "Number of args = $#" 43 | echo "Using GPU 0" 44 | else 45 | gpuNum=$8 46 | #echo "Number of args = $#" 47 | echo "Using GPU $gpuNum" 48 | fi 49 | 50 | if [ "$target" == "top2" ]; then 51 | target_type="1" 52 | elif [ "$target" == "rand" ]; then 53 | target_type="2" 54 | elif [ "$target" == "least" ]; then 55 | target_type="4" 56 | elif [ "$target" == "all" ]; then 57 | target_type="15" 58 | else 59 | echo "Wrong target $target: should be one in {top2, rand, least, all}" 60 | exit 1 61 | fi 62 | 63 | output="${model}_${modeltype}_${activation}_ord${order}_ns${nsamp}_nit${niters}_${target}_$(date +%m%d_%H%M%S)" 64 | dir="logs/$model/$modeltype" 65 | mkdir -p $dir 66 | logfile=$dir/$output.log 67 | echo $logfile 68 | 69 | CMD="python3 collect_gradients.py --numimg 20 -d $model --model_name $modeltype --batch_size $nsamp --Nsamps $nsamp --Niters $niters --activation $activation --target_type $target_type --order $order" 70 | echo $CMD 71 | 72 | ## run on frigg 73 | ###CUDA_VISIBLE_DEVICES=$gpuNum 74 | CUDA_VISIBLE_DEVICES=$gpuNum $CMD 2>&1 | tee $logfile 75 | ##$CMD 2>&1 | tee $logfile 76 | 77 | #NUMBA_NUM_THREADS=1 MKL_NUM_THREADS=1 OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 $CMD 2>&1 | tee $logfile 78 | # NUMBA_NUM_THREADS=1 MKL_NUM_THREADS=1 OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 $CMD >$logfile 2>$logfile.err 79 | echo "Done $logfile" 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /setup_cifar.py: -------------------------------------------------------------------------------- 1 | ## setup_cifar.py -- cifar data and model loading code 2 | ## 3 | ## Copyright (C) 2017-2018, IBM Corp. 4 | ## Copyright (C) 2017, Lily Weng 5 | ## and Huan Zhang 6 | ## Copyright (C) 2016, Nicholas Carlini . 7 | ## 8 | ## This program is licenced under the Apache 2.0 licence, 9 | ## contained in the LICENCE file in this directory. 10 | 11 | 12 | import tensorflow as tf 13 | import numpy as np 14 | import os 15 | import pickle 16 | import gzip 17 | import pickle 18 | import urllib.request 19 | 20 | from tensorflow.contrib.keras.api.keras.models import Sequential 21 | from tensorflow.contrib.keras.api.keras.layers import Dense, Dropout, Activation, Flatten 22 | from tensorflow.contrib.keras.api.keras.layers import Conv2D, MaxPooling2D 23 | from tensorflow.contrib.keras.api.keras.layers import Lambda 24 | from tensorflow.contrib.keras.api.keras.models import load_model 25 | from tensorflow.contrib.keras.api.keras import backend as K 26 | 27 | def load_batch(fpath, label_key='labels'): 28 | f = open(fpath, 'rb') 29 | d = pickle.load(f, encoding="bytes") 30 | for k, v in d.items(): 31 | del(d[k]) 32 | d[k.decode("utf8")] = v 33 | f.close() 34 | data = d["data"] 35 | labels = d[label_key] 36 | 37 | data = data.reshape(data.shape[0], 3, 32, 32) 38 | final = np.zeros((data.shape[0], 32, 32, 3),dtype=np.float32) 39 | final[:,:,:,0] = data[:,0,:,:] 40 | final[:,:,:,1] = data[:,1,:,:] 41 | final[:,:,:,2] = data[:,2,:,:] 42 | 43 | final /= 255 44 | final -= .5 45 | labels2 = np.zeros((len(labels), 10)) 46 | labels2[np.arange(len(labels2)), labels] = 1 47 | 48 | return final, labels 49 | 50 | def load_batch(fpath): 51 | f = open(fpath,"rb").read() 52 | size = 32*32*3+1 53 | labels = [] 54 | images = [] 55 | for i in range(10000): 56 | arr = np.fromstring(f[i*size:(i+1)*size],dtype=np.uint8) 57 | lab = np.identity(10)[arr[0]] 58 | img = arr[1:].reshape((3,32,32)).transpose((1,2,0)) 59 | 60 | labels.append(lab) 61 | images.append((img/255)-.5) 62 | return np.array(images),np.array(labels) 63 | 64 | 65 | class CIFAR: 66 | def __init__(self): 67 | train_data = [] 68 | train_labels = [] 69 | 70 | if not os.path.exists("cifar-10-batches-bin"): 71 | urllib.request.urlretrieve("https://www.cs.toronto.edu/~kriz/cifar-10-binary.tar.gz", 72 | "cifar-data.tar.gz") 73 | os.popen("tar -xzf cifar-data.tar.gz").read() 74 | 75 | 76 | for i in range(5): 77 | r,s = load_batch("cifar-10-batches-bin/data_batch_"+str(i+1)+".bin") 78 | train_data.extend(r) 79 | train_labels.extend(s) 80 | 81 | train_data = np.array(train_data,dtype=np.float32) 82 | train_labels = np.array(train_labels) 83 | 84 | self.test_data, self.test_labels = load_batch("cifar-10-batches-bin/test_batch.bin") 85 | 86 | VALIDATION_SIZE = 5000 87 | 88 | self.validation_data = train_data[:VALIDATION_SIZE, :, :, :] 89 | self.validation_labels = train_labels[:VALIDATION_SIZE] 90 | self.train_data = train_data[VALIDATION_SIZE:, :, :, :] 91 | self.train_labels = train_labels[VALIDATION_SIZE:] 92 | 93 | class CIFARModel: 94 | def __init__(self, restore=None, session=None, use_softmax=False, use_brelu = False, activation = "relu"): 95 | def bounded_relu(x): 96 | return K.relu(x, max_value=1) 97 | if use_brelu: 98 | activation = bounded_relu 99 | else: 100 | activation = activation 101 | 102 | print("inside CIFARModel: activation = {}".format(activation)) 103 | 104 | self.num_channels = 3 105 | self.image_size = 32 106 | self.num_labels = 10 107 | 108 | model = Sequential() 109 | 110 | model.add(Conv2D(64, (3, 3), 111 | input_shape=(32, 32, 3))) 112 | model.add(Activation(activation)) 113 | model.add(Conv2D(64, (3, 3))) 114 | model.add(Activation(activation)) 115 | model.add(MaxPooling2D(pool_size=(2, 2))) 116 | 117 | model.add(Conv2D(128, (3, 3))) 118 | model.add(Activation(activation)) 119 | model.add(Conv2D(128, (3, 3))) 120 | model.add(Activation(activation)) 121 | model.add(MaxPooling2D(pool_size=(2, 2))) 122 | 123 | model.add(Flatten()) 124 | model.add(Dense(256)) 125 | model.add(Activation(activation)) 126 | model.add(Dense(256)) 127 | model.add(Activation(activation)) 128 | model.add(Dense(10)) 129 | if use_softmax: 130 | model.add(Activation('softmax')) 131 | if restore: 132 | model.load_weights(restore) 133 | 134 | layer_outputs = [] 135 | for layer in model.layers: 136 | if isinstance(layer, Conv2D) or isinstance(layer, Dense): 137 | layer_outputs.append(K.function([model.layers[0].input], [layer.output])) 138 | 139 | self.layer_outputs = layer_outputs 140 | self.model = model 141 | 142 | def predict(self, data): 143 | return self.model(data) 144 | 145 | 146 | class TwoLayerCIFARModel: 147 | def __init__(self, restore = None, session=None, use_softmax=False): 148 | self.num_channels = 3 149 | self.image_size = 32 150 | self.num_labels = 10 151 | 152 | model = Sequential() 153 | model.add(Flatten(input_shape=(32, 32, 3))) 154 | model.add(Dense(1024)) 155 | model.add(Activation('softplus')) 156 | model.add(Dense(10)) 157 | # output log probability, used for black-box attack 158 | if use_softmax: 159 | model.add(Activation('softmax')) 160 | if restore: 161 | model.load_weights(restore) 162 | 163 | layer_outputs = [] 164 | for layer in model.layers: 165 | if isinstance(layer, Conv2D) or isinstance(layer, Dense): 166 | layer_outputs.append(K.function([model.layers[0].input], [layer.output])) 167 | 168 | self.layer_outputs = layer_outputs 169 | self.model = model 170 | 171 | def predict(self, data): 172 | 173 | return self.model(data) 174 | -------------------------------------------------------------------------------- /setup_imagenet.py: -------------------------------------------------------------------------------- 1 | ## Modified by Huan Zhang for ResNet, Inception v1, v2, v4, VGG, MobileNet, Densenet, Alexnet and NASnet 2 | ## Modified by Huan Zhang for the updated Inception-v3 model (inception_v3_2016_08_28.tar.gz) 3 | ## Modified by Nicholas Carlini to match model structure for attack code. 4 | ## Original copyright license follows. 5 | 6 | 7 | # Copyright 2015 The TensorFlow Authors. All Rights Reserved. 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # ============================================================================== 21 | 22 | """Simple image classification with an ImageNet Classifier. 23 | 24 | Run image classification with an ImageNet Classifier (Inception, ResNet, AlexNet, etc) trained on ImageNet 2012 Challenge data 25 | set. 26 | 27 | This program creates a graph from a saved GraphDef protocol buffer, 28 | and runs inference on an input JPEG image. It outputs human readable 29 | strings of the top 5 predictions along with their probabilities. 30 | 31 | Change the --image_file argument to any jpg image to compute a 32 | classification of that image. 33 | 34 | Please see the tutorial and website for a detailed description of how 35 | to use this script to perform image recognition. 36 | 37 | https://tensorflow.org/tutorials/image_recognition/ 38 | """ 39 | 40 | from __future__ import absolute_import 41 | from __future__ import division 42 | from __future__ import print_function 43 | 44 | import os.path 45 | import re 46 | import sys 47 | from functools import partial 48 | import random 49 | import tarfile 50 | import scipy.misc 51 | 52 | import numpy as np 53 | from six.moves import urllib 54 | import tensorflow as tf 55 | 56 | import PIL 57 | from PIL import Image 58 | 59 | 60 | model_params = {} 61 | 62 | 63 | """Add a new new entry to ImageNet models 64 | 65 | Parameters: 66 | name: name of the new model, like "resnet" 67 | url: URL to download the model 68 | image_size: image size, usually 224 or 299 69 | model_filename: model protobuf file name (.pb) 70 | label_filename: a text file contains the mapping from class ID to human readable string 71 | input_tensor: input tensor of the network defined by protobuf, like "input:0" 72 | logit: logit output tensor of the network, like "resnet_v2_50/predictions/Reshape:0" 73 | prob: probability output tensor of the network, like "resnet_v2_50/predictions/Reshape_1:0" 74 | shape: tensor for reshaping the final output, like "resnet_v2_50/predictions/Shape:0". 75 | Set to None if no reshape needed. 76 | 77 | All the tensor names can be viewed and found in TensorBoard. 78 | """ 79 | def AddModel(name, url, model_filename, image_size, label_filename, input_tensor, logit, prob, shape): 80 | global model_params 81 | param = {} 82 | param['url'] = url 83 | param['model_filename'] = model_filename 84 | param['size'] = image_size 85 | param['input'] = input_tensor 86 | param['logit'] = logit 87 | param['prob'] = prob 88 | param['shape'] = shape 89 | param['label_filename'] = label_filename 90 | param['name'] = name 91 | model_params[name] = param 92 | 93 | # pylint: disable=line-too-long 94 | AddModel('resnet_v2_50', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 95 | 'frozen_resnet_v2_50.pb', 299, 'labels.txt', 'input:0', 96 | 'resnet_v2_50/predictions/Reshape:0', 'resnet_v2_50/predictions/Reshape_1:0', 'resnet_v2_50/predictions/Shape:0') 97 | AddModel('resnet_v2_101', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 98 | 'frozen_resnet_v2_101.pb', 299, 'labels.txt', 'input:0', 99 | 'resnet_v2_101/predictions/Reshape:0', 'resnet_v2_101/predictions/Reshape_1:0', 'resnet_v2_101/predictions/Shape:0') 100 | AddModel('resnet_v2_152', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 101 | 'frozen_resnet_v2_152.pb', 299, 'labels.txt', 'input:0', 102 | 'resnet_v2_152/predictions/Reshape:0', 'resnet_v2_152/predictions/Reshape_1:0', 'resnet_v2_152/predictions/Shape:0') 103 | AddModel('inception_v1', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 104 | 'frozen_inception_v1.pb', 224, 'labels.txt', 'input:0', 105 | 'InceptionV1/Logits/Predictions/Reshape:0', 'InceptionV1/Logits/Predictions/Reshape_1:0', 'InceptionV1/Logits/Predictions/Shape:0') 106 | AddModel('inception_v2', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 107 | 'frozen_inception_v2.pb', 224, 'labels.txt', 'input:0', 108 | 'InceptionV2/Predictions/Reshape:0', 'InceptionV2/Predictions/Reshape_1:0', 'InceptionV2/Predictions/Shape:0') 109 | AddModel('inception_v3', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 110 | 'frozen_inception_v3.pb', 299, 'labels.txt', 'input:0', 111 | 'InceptionV3/Predictions/Reshape:0', 'InceptionV3/Predictions/Softmax:0', 'InceptionV3/Predictions/Shape:0') 112 | AddModel('inception_v4', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 113 | 'frozen_inception_v4.pb', 299, 'labels.txt', 'input:0', 114 | 'InceptionV4/Logits/Logits/BiasAdd:0', 'InceptionV4/Logits/Predictions:0', '') 115 | AddModel('inception_resnet_v2', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 116 | 'frozen_inception_resnet_v2.pb', 299, 'labels.txt', 'input:0', 117 | 'InceptionResnetV2/Logits/Logits/BiasAdd:0', 'InceptionResnetV2/Logits/Predictions:0', '') 118 | AddModel('vgg_16', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 119 | 'frozen_vgg_16.pb', 224, 'labels.txt', 'input:0', 120 | 'vgg_16/fc8/squeezed:0', 'vgg_16/fc8/squeezed:0', '') 121 | AddModel('vgg_19', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 122 | 'frozen_vgg_19.pb', 224, 'labels.txt', 'input:0', 123 | 'vgg_19/fc8/squeezed:0', 'vgg_19/fc8/squeezed:0', '') 124 | AddModel('mobilenet_v1_025', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 125 | 'frozen_mobilenet_v1_025.pb', 224, 'labels.txt', 'input:0', 126 | 'MobilenetV1/Predictions/Reshape:0', 'MobilenetV1/Predictions/Reshape_1:0', 'MobilenetV1/Predictions/Shape:0') 127 | AddModel('mobilenet_v1_050', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 128 | 'frozen_mobilenet_v1_050.pb', 224, 'labels.txt', 'input:0', 129 | 'MobilenetV1/Predictions/Reshape:0', 'MobilenetV1/Predictions/Reshape_1:0', 'MobilenetV1/Predictions/Shape:0') 130 | AddModel('mobilenet_v1_100', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 131 | 'frozen_mobilenet_v1_100.pb', 224, 'labels.txt', 'input:0', 132 | 'MobilenetV1/Predictions/Reshape:0', 'MobilenetV1/Predictions/Reshape_1:0', 'MobilenetV1/Predictions/Shape:0') 133 | AddModel('nasnet_large', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 134 | 'frozen_nasnet_large.pb', 331, 'labels.txt', 'input:0', 135 | 'final_layer/FC/BiasAdd:0', 'final_layer/predictions:0', '') 136 | AddModel('densenet121_k32', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 137 | 'densenet121_k32_frozen.pb', 224, 'labels.txt', 'input:0', 138 | 'densenet121/predictions/Reshape:0', 'densenet121/predictions/Reshape_1:0', 'densenet121/predictions/Shape:0') 139 | AddModel('densenet169_k32', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 140 | 'densenet169_k32_frozen.pb', 224, 'labels.txt', 'input:0', 141 | 'densenet169/predictions/Reshape:0', 'densenet169/predictions/Reshape_1:0', 'densenet169/predictions/Shape:0') 142 | AddModel('densenet161_k48', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 143 | 'densenet161_k48_frozen.pb', 224, 'labels.txt', 'input:0', 144 | 'densenet161/predictions/Reshape:0', 'densenet161/predictions/Reshape_1:0', 'densenet161/predictions/Shape:0') 145 | AddModel('alexnet', 'http://jaina.cs.ucdavis.edu/datasets/adv/imagenet/frozen_imagenet_models_v1.1.tar.gz', 146 | 'alexnet_frozen.pb', 227, 'labels.txt', 'Placeholder:0', 147 | 'fc8/fc8:0', 'Softmax:0', '') 148 | 149 | # pylint: enable=line-too-long 150 | 151 | 152 | class NodeLookup(object): 153 | """Converts integer node ID's to human readable labels.""" 154 | 155 | def __init__(self, 156 | label_lookup_path=None): 157 | if not label_lookup_path: 158 | label_lookup_path = os.path.join( 159 | FLAGS.model_dir, 'labels.txt') 160 | self.node_lookup = self.load(label_lookup_path) 161 | 162 | def load(self, label_lookup_path): 163 | """Loads a human readable English name for each softmax node. 164 | 165 | Args: 166 | label_lookup_path: string UID to integer node ID. 167 | uid_lookup_path: string UID to human-readable string. 168 | 169 | Returns: 170 | dict from integer node ID to human-readable string. 171 | """ 172 | if not tf.gfile.Exists(label_lookup_path): 173 | tf.logging.fatal('File does not exist %s', label_lookup_path) 174 | 175 | # Loads mapping from string UID to integer node ID. 176 | node_id_to_name = {} 177 | proto_as_ascii = tf.gfile.GFile(label_lookup_path).readlines() 178 | for line in proto_as_ascii: 179 | if line: 180 | words = line.split(':') 181 | target_class = int(words[0]) 182 | name = words[1] 183 | node_id_to_name[target_class] = name 184 | 185 | return node_id_to_name 186 | 187 | def id_to_string(self, node_id): 188 | if node_id not in self.node_lookup: 189 | return '' 190 | return self.node_lookup[node_id] 191 | 192 | LOADED_GRAPH = None 193 | 194 | def create_graph(model_param): 195 | """Creates a graph from saved GraphDef file and returns a saver.""" 196 | # Creates graph from saved graph_def.pb. 197 | global LOADED_GRAPH 198 | with tf.gfile.FastGFile(os.path.join( 199 | # FLAGS.model_dir, 'classify_image_graph_def.pb'), 'rb') as f: 200 | FLAGS.model_dir, model_param['model_filename']), 'rb') as f: 201 | graph_def = tf.GraphDef() 202 | graph_def.ParseFromString(f.read()) 203 | #for line in repr(graph_def).split("\n"): 204 | # if "tensor_content" not in line: 205 | # print(line) 206 | LOADED_GRAPH = graph_def 207 | 208 | 209 | class ImageNetModelPrediction: 210 | def __init__(self, sess, use_softmax = False, model_name = "resnet_v2_50", softmax_tensor = None): 211 | self.sess = sess 212 | self.use_softmax = use_softmax 213 | model_param = model_params[model_name] 214 | self.output_name = model_param['prob'] if self.use_softmax else model_param['logit'] 215 | self.input_name = model_param['input'] 216 | self.shape_name = model_param['shape'] 217 | self.model_name = model_param['name'] 218 | self.image_size = model_param['size'] 219 | self.img = tf.placeholder(tf.float32, (None, self.image_size, self.image_size, 3)) 220 | if not softmax_tensor: 221 | # no existing graph 222 | self.softmax_tensor = tf.import_graph_def( 223 | LOADED_GRAPH, 224 | # sess.graph.as_graph_def(), 225 | input_map={self.input_name: self.img}, 226 | return_elements=[self.output_name]) 227 | if 'vgg' in self.model_name and use_softmax == True: 228 | # the pretrained VGG network output is logits, need an extra softmax 229 | self.softmax_tensor = tf.nn.softmax(self.softmax_tensor) 230 | else: 231 | # use an existing graph 232 | self.softmax_tensor = softmax_tensor 233 | print("GraphDef Size:", self.sess.graph_def.ByteSize()) 234 | 235 | def predict(self, dat): 236 | dat = np.squeeze(dat) 237 | if 'vgg' in self.model_name: 238 | # VGG uses 0 - 255 image as input 239 | dat = (0.5 + dat) * 255.0 240 | imagenet_mean = np.array([123.68, 116.78, 103.94], dtype=np.float32) 241 | dat -= imagenet_mean 242 | elif 'alexnet' in self.model_name: 243 | if dat.ndim == 3: 244 | dat = dat[:,:,::-1] 245 | else: 246 | dat = dat[:,:,:,::-1] # change RGB to BGR 247 | dat = (0.5 + dat) * 255.0 248 | imagenet_mean = np.array([104., 117., 124.], dtype=np.float32) 249 | dat -= imagenet_mean 250 | elif 'densenet' in self.model_name: 251 | dat = (0.5 + dat) * 255.0 252 | imagenet_mean = np.array([123.68, 116.78, 103.94], dtype=np.float32) 253 | dat -= imagenet_mean 254 | dat = dat * 0.017 255 | else: 256 | dat = dat * 2.0 257 | 258 | 259 | if dat.ndim == 3: 260 | scaled = dat.reshape((1,) + dat.shape) 261 | else: 262 | scaled = dat 263 | # print(scaled.shape) 264 | predictions = self.sess.run(self.softmax_tensor, 265 | {self.img: scaled}) 266 | predictions = np.squeeze(predictions) 267 | return predictions 268 | # Creates node ID --> English string lookup. 269 | node_lookup = NodeLookup() 270 | top_k = predictions.argsort()#[-FLAGS.num_top_predictions:][::-1] 271 | for node_id in top_k: 272 | print('id',node_id) 273 | human_string = node_lookup.id_to_string(node_id) 274 | score = predictions[node_id] 275 | print('%s (score = %.5f)' % (human_string, score)) 276 | return top_k[-1] 277 | 278 | 279 | CREATED_GRAPH = False 280 | class ImageNetModel: 281 | def __init__(self, sess, use_softmax = False, model_name = "resnet_v2_50", create_prediction = True): 282 | global CREATED_GRAPH 283 | self.sess = sess 284 | self.use_softmax = use_softmax 285 | model_param = model_params[model_name] 286 | maybe_download_and_extract(model_param) 287 | 288 | if not CREATED_GRAPH: 289 | create_graph(model_param) 290 | CREATED_GRAPH = True 291 | self.num_channels = 3 292 | self.output_name = model_param['prob'] if self.use_softmax else model_param['logit'] 293 | self.input_name = model_param['input'] 294 | self.shape_name = model_param['shape'] 295 | self.model_name = model_param['name'] 296 | self.num_labels = 1000 if 'vgg' in self.model_name or 'densenet' in self.model_name or 'alexnet' in self.model_name else 1001 297 | self.image_size = model_param['size'] 298 | self.use_softmax = use_softmax 299 | if create_prediction: 300 | self.model = ImageNetModelPrediction(sess, use_softmax, model_name) 301 | 302 | def predict(self, img): 303 | if 'vgg' in self.model_name: 304 | # VGG uses 0 - 255 image as input 305 | img = (0.5 + img) * 255.0 306 | imagenet_mean = np.array([123.68, 116.78, 103.94], dtype=np.float32) 307 | img -= imagenet_mean 308 | elif 'alexnet' in self.model_name: 309 | img = tf.reverse(img,axis=[-1])# change RGB to BGR 310 | img = (0.5 + img) * 255.0 311 | imagenet_mean = np.array([104., 117., 124.], dtype=np.float32) 312 | img -= imagenet_mean 313 | elif 'densenet' in self.model_name: 314 | # convert to 0 - 255 image as input 315 | img = (0.5 + img) * 255.0 316 | imagenet_mean = np.array([123.68, 116.78, 103.94], dtype=np.float32) 317 | img -= imagenet_mean 318 | img = img * 0.017 319 | else: 320 | img = img * 2.0 321 | 322 | if img.shape.is_fully_defined() and img.shape.as_list()[0] and self.shape_name: 323 | # check if a shape has been specified explicitly 324 | shape = (int(img.shape[0]), self.num_labels) 325 | self.softmax_tensor = tf.import_graph_def( 326 | LOADED_GRAPH, 327 | # self.sess.graph.as_graph_def(), 328 | input_map={self.input_name: img, self.shape_name: shape}, 329 | return_elements=[self.output_name]) 330 | if 'vgg' in self.model_name and self.use_softmax == True: 331 | # the pretrained VGG network output is logitimport_graph_defs, need an extra softmax 332 | self.softmax_tensor = tf.nn.softmax(self.softmax_tensor) 333 | else: 334 | # placeholder shape 335 | self.softmax_tensor = tf.import_graph_def( 336 | LOADED_GRAPH, 337 | # self.sess.graph.as_graph_def(), 338 | input_map={self.input_name: img}, 339 | return_elements=[self.output_name]) 340 | if 'vgg' in self.model_name and self.use_softmax == True: 341 | # the pretrained VGG network output is logits, need an extra softmax 342 | self.softmax_tensor = tf.nn.softmax(self.softmax_tensor) 343 | print("GraphDef Size:", self.sess.graph_def.ByteSize()) 344 | return self.softmax_tensor[0] 345 | 346 | 347 | def maybe_download_and_extract(model_param): 348 | """Download and extract model tar file.""" 349 | dest_directory = FLAGS.model_dir 350 | if not os.path.exists(dest_directory): 351 | os.makedirs(dest_directory) 352 | filename = model_param['url'].split('/')[-1] 353 | filepath = os.path.join(dest_directory, filename) 354 | modelname = model_param['model_filename'].split('/')[-1] 355 | modelpath = os.path.join(dest_directory, modelname) 356 | if not os.path.exists(modelpath): 357 | def _progress(count, block_size, total_size): 358 | sys.stdout.write('\r>> Downloading %s %.1f%%' % ( 359 | filename, float(count * block_size) / float(total_size) * 100.0)) 360 | sys.stdout.flush() 361 | filepath, _ = urllib.request.urlretrieve(model_param['url'], filepath, _progress) 362 | print() 363 | statinfo = os.stat(filepath) 364 | print('Succesfully downloaded', filename, statinfo.st_size, 'bytes.') 365 | if os.path.splitext(filename)[1] != '.pb': 366 | tarfile.open(filepath, 'r:gz').extractall(dest_directory) 367 | 368 | 369 | def main(_): 370 | param = model_params[FLAGS.model_name] 371 | maybe_download_and_extract(param) 372 | image = (FLAGS.image_file if FLAGS.image_file else 373 | os.path.join(FLAGS.model_dir, 'cropped_panda.jpg')) 374 | # run_inference_on_image(image) 375 | create_graph(param) 376 | image_size = param['size'] 377 | with tf.Session() as sess: 378 | dat = np.array(scipy.misc.imresize(scipy.misc.imread(image),(image_size, image_size)), dtype = np.float32) 379 | dat /= 255.0 380 | dat -= 0.5 381 | # print(dat) 382 | model = ImageNetModelPrediction(sess, True, FLAGS.model_name) 383 | predictions = model.predict(dat) 384 | # Creates node ID --> English string lookup. 385 | node_lookup = NodeLookup() 386 | top_k = predictions.argsort()#[-FLAGS.num_top_predictions:][::-1] 387 | for node_id in top_k: 388 | score = predictions[node_id] 389 | if 'vgg' in FLAGS.model_name or 'densenet' in FLAGS.model_name or 'alexnet' in FLAGS.model_name: 390 | node_id += 1 391 | print('id',node_id) 392 | human_string = node_lookup.id_to_string(node_id) 393 | print('%s (score = %.5f)' % (human_string, score)) 394 | 395 | 396 | def keep_aspect_ratio_transform(img, img_size): 397 | 398 | s_0, s_1 = img.size 399 | if s_0 < s_1: 400 | ratio = (img_size / float(s_0)) 401 | size_1 = int((float(img.size[1]) * float(ratio))) 402 | img = img.resize((img_size, size_1), PIL.Image.ANTIALIAS) 403 | else: 404 | ratio = (img_size / float(s_1)) 405 | size_0 = int((float(img.size[0]) * float(ratio))) 406 | img = img.resize((size_0, img_size), PIL.Image.ANTIALIAS) 407 | 408 | c_0 = img.size[0] // 2 409 | c_1 = img.size[1] // 2 410 | 411 | if img_size % 2 == 0: 412 | w_left = h_top = img_size // 2 413 | w_right = h_bottom = img_size // 2 414 | else: 415 | w_left = h_top = img_size // 2 416 | w_right = h_bottom = img_size // 2 + 1 417 | 418 | transformed_img = img.crop( 419 | ( 420 | c_0 - w_left, 421 | c_1 - h_top, 422 | c_0 + w_right, 423 | c_1 + h_bottom 424 | ) 425 | ) 426 | 427 | return transformed_img 428 | 429 | def readimg(ff, img_size): 430 | f = "../imagenetdata/imgs/"+ff 431 | # img = scipy.misc.imread(f) 432 | # skip small images (image should be at least img_size X img_size) 433 | 434 | # if img.shape[0] < img_size or img.shape[1] < img_size: 435 | # return None 436 | 437 | # img = np.array(scipy.misc.imresize(img,(img_size, img_size)),dtype=np.float32)/255.0-.5 438 | img = Image.open(f) 439 | transformed_img = keep_aspect_ratio_transform(img, img_size) 440 | 441 | img = np.array(transformed_img)/255.0-.5 442 | if img.shape != (img_size, img_size, 3): 443 | # grayscale image 444 | if img.shape == (img_size, img_size): 445 | img = np.repeat(np.expand_dims(img, axis = 2), 3, axis = 2) 446 | return [img, int(ff.split(".")[0])] 447 | return None 448 | return [img, int(ff.split(".")[0])] 449 | 450 | class ImageNet: 451 | def __init__(self, img_size, load_total_imgs = 1000): 452 | from multiprocessing import Pool, cpu_count 453 | pool = Pool(cpu_count()) 454 | file_list = sorted(os.listdir("../imagenetdata/imgs/")) 455 | random.shuffle(file_list) 456 | # for efficiency, we only load first 1000 images 457 | # You can pass load_total_imgs to load all images 458 | short_file_list = file_list[:load_total_imgs] 459 | r = pool.map(partial(readimg, img_size=img_size), short_file_list) 460 | print(short_file_list) 461 | print("Loaded imagenet", len(short_file_list), "of", len(file_list), "images") 462 | 463 | r = [x for x in r if x != None] 464 | test_data, test_labels = zip(*r) 465 | self.test_data = np.array(test_data) 466 | self.test_labels = np.zeros((len(test_labels), 1001)) 467 | self.test_labels[np.arange(len(test_labels)), test_labels] = 1 468 | 469 | pool.close() 470 | pool.join() 471 | 472 | if __name__ == '__main__': 473 | FLAGS = tf.app.flags.FLAGS 474 | # classify_image_graph_def.pb: 475 | # Binary representation of the GraphDef protocol buffer. 476 | # imagenet_synset_to_human_label_map.txt: 477 | # Map from synset ID to a human readable string. 478 | # imagenet_2012_challenge_label_map_proto.pbtxt: 479 | # Text representation of a protocol buffer mapping a label to synset ID. 480 | tf.app.flags.DEFINE_string( 481 | 'model_dir', 'tmp/imagenet', 482 | """Path to classify_image_graph_def.pb, """ 483 | """imagenet_synset_to_human_label_map.txt, and """ 484 | """imagenet_2012_challenge_label_map_proto.pbtxt.""") 485 | tf.app.flags.DEFINE_string('image_file', '', 486 | """Absolute path to image file.""") 487 | tf.app.flags.DEFINE_string('model_name', 'resnet_v2_101', 488 | """Absolute path to image file.""") 489 | tf.app.flags.DEFINE_integer('num_top_predictions', 5, 490 | """Display this many predictions.""") 491 | tf.app.run() 492 | else: 493 | # starting from TF 1.5, an parameter unkown by tf.app.flags will raise an error 494 | # so we cannot use tf.app.flags when loading this file as a module, because the 495 | # main program may define other options. 496 | from argparse import Namespace 497 | FLAGS = Namespace(model_dir="tmp/imagenet") 498 | 499 | -------------------------------------------------------------------------------- /setup_mnist.py: -------------------------------------------------------------------------------- 1 | ## setup_mnist.py -- mnist data and model loading code 2 | ## 3 | ## Copyright (C) 2017-2018, IBM Corp. 4 | ## Copyright (C) 2017, Lily Weng 5 | ## and Huan Zhang 6 | ## Copyright (C) 2016, Nicholas Carlini . 7 | ## 8 | ## This program is licenced under the Apache 2.0 licence, 9 | ## contained in the LICENCE file in this directory. 10 | 11 | import tensorflow as tf 12 | import numpy as np 13 | import os 14 | import pickle 15 | import gzip 16 | import urllib.request 17 | 18 | from tensorflow.contrib.keras.api.keras.models import Sequential 19 | from tensorflow.contrib.keras.api.keras.layers import Dense, Dropout, Activation, Flatten 20 | from tensorflow.contrib.keras.api.keras.layers import Conv2D, MaxPooling2D 21 | from tensorflow.contrib.keras.api.keras.layers import Lambda 22 | from tensorflow.contrib.keras.api.keras.models import load_model 23 | from tensorflow.contrib.keras.api.keras import backend as K 24 | 25 | def extract_data(filename, num_images): 26 | with gzip.open(filename) as bytestream: 27 | bytestream.read(16) 28 | buf = bytestream.read(num_images*28*28) 29 | data = np.frombuffer(buf, dtype=np.uint8).astype(np.float32) 30 | data = (data / 255) - 0.5 31 | data = data.reshape(num_images, 28, 28, 1) 32 | return data 33 | 34 | def extract_labels(filename, num_images): 35 | with gzip.open(filename) as bytestream: 36 | bytestream.read(8) 37 | buf = bytestream.read(1 * num_images) 38 | labels = np.frombuffer(buf, dtype=np.uint8) 39 | return (np.arange(10) == labels[:, None]).astype(np.float32) 40 | 41 | class MNIST: 42 | def __init__(self): 43 | if not os.path.exists("data"): 44 | os.mkdir("data") 45 | files = ["train-images-idx3-ubyte.gz", 46 | "t10k-images-idx3-ubyte.gz", 47 | "train-labels-idx1-ubyte.gz", 48 | "t10k-labels-idx1-ubyte.gz"] 49 | for name in files: 50 | 51 | urllib.request.urlretrieve('http://yann.lecun.com/exdb/mnist/' + name, "data/"+name) 52 | 53 | train_data = extract_data("data/train-images-idx3-ubyte.gz", 60000) 54 | train_labels = extract_labels("data/train-labels-idx1-ubyte.gz", 60000) 55 | self.test_data = extract_data("data/t10k-images-idx3-ubyte.gz", 10000) 56 | self.test_labels = extract_labels("data/t10k-labels-idx1-ubyte.gz", 10000) 57 | 58 | VALIDATION_SIZE = 5000 59 | 60 | self.validation_data = train_data[:VALIDATION_SIZE, :, :, :] 61 | self.validation_labels = train_labels[:VALIDATION_SIZE] 62 | self.train_data = train_data[VALIDATION_SIZE:, :, :, :] 63 | self.train_labels = train_labels[VALIDATION_SIZE:] 64 | 65 | 66 | class MNISTModel: 67 | def __init__(self, restore = None, session=None, use_softmax=False, use_brelu = False, activation = "relu"): 68 | def bounded_relu(x): 69 | return K.relu(x, max_value=1) 70 | if use_brelu: 71 | activation = bounded_relu 72 | 73 | print("inside MNISTModel: activation = {}".format(activation)) 74 | 75 | self.num_channels = 1 76 | self.image_size = 28 77 | self.num_labels = 10 78 | 79 | model = Sequential() 80 | 81 | model.add(Conv2D(32, (3, 3), 82 | input_shape=(28, 28, 1))) 83 | model.add(Activation(activation)) 84 | model.add(Conv2D(32, (3, 3))) 85 | model.add(Activation(activation)) 86 | model.add(MaxPooling2D(pool_size=(2, 2))) 87 | 88 | model.add(Conv2D(64, (3, 3))) 89 | model.add(Activation(activation)) 90 | model.add(Conv2D(64, (3, 3))) 91 | model.add(Activation(activation)) 92 | model.add(MaxPooling2D(pool_size=(2, 2))) 93 | 94 | model.add(Flatten()) 95 | model.add(Dense(200)) 96 | model.add(Activation(activation)) 97 | model.add(Dense(200)) 98 | model.add(Activation(activation)) 99 | model.add(Dense(10)) 100 | # output log probability, used for black-box attack 101 | if use_softmax: 102 | model.add(Activation('softmax')) 103 | if restore: 104 | model.load_weights(restore) 105 | 106 | layer_outputs = [] 107 | for layer in model.layers: 108 | if isinstance(layer, Conv2D) or isinstance(layer, Dense): 109 | layer_outputs.append(K.function([model.layers[0].input], [layer.output])) 110 | 111 | self.model = model 112 | self.layer_outputs = layer_outputs 113 | 114 | def predict(self, data): 115 | return self.model(data) 116 | 117 | class TwoLayerMNISTModel: 118 | def __init__(self, restore = None, session=None, use_softmax=False): 119 | self.num_channels = 1 120 | self.image_size = 28 121 | self.num_labels = 10 122 | 123 | model = Sequential() 124 | model.add(Flatten(input_shape=(28, 28, 1))) 125 | model.add(Dense(1024)) 126 | model.add(Lambda(lambda x: x * 10)) 127 | model.add(Activation('softplus')) 128 | model.add(Lambda(lambda x: x * 0.1)) 129 | model.add(Dense(10)) 130 | # output log probability, used for black-box attack 131 | if use_softmax: 132 | model.add(Activation('softmax')) 133 | if restore: 134 | model.load_weights(restore) 135 | 136 | layer_outputs = [] 137 | for layer in model.layers: 138 | if isinstance(layer, Conv2D) or isinstance(layer, Dense): 139 | layer_outputs.append(K.function([model.layers[0].input], [layer.output])) 140 | 141 | self.layer_outputs = layer_outputs 142 | self.model = model 143 | 144 | def predict(self, data): 145 | 146 | return self.model(data) 147 | 148 | -------------------------------------------------------------------------------- /shmemarray.py: -------------------------------------------------------------------------------- 1 | # 2 | # Based on multiprocessing.sharedctypes.RawArray 3 | # 4 | # Uses posix_ipc (http://semanchuk.com/philip/posix_ipc/) to allow shared ctypes arrays 5 | # among unrelated processors 6 | # 7 | # Usage Notes: 8 | # * The first two args (typecode_or_type and size_or_initializer) should work the same as with RawArray. 9 | # * The shared array is accessible by any process, as long as tag matches. 10 | # * The shared memory segment is unlinked when the origin array (that returned 11 | # by ShmemRawArray(..., create=True)) is deleted/gc'ed 12 | # * Creating an shared array using a tag that currently exists will raise an ExistentialError 13 | # * Accessing a shared array using a tag that doesn't exist (or one that has been unlinked) will also 14 | # raise an ExistentialError 15 | # 16 | # Author: Shawn Chin (http://shawnchin.github.com) 17 | # 18 | # Edited for python 3 by: Adam Stooke 19 | # 20 | 21 | import numpy as np 22 | # import os 23 | import sys 24 | import mmap 25 | import ctypes 26 | import posix_ipc 27 | # from _multiprocessing import address_of_buffer # (not in python 3) 28 | from string import ascii_letters, digits 29 | 30 | valid_chars = frozenset("/-_. %s%s" % (ascii_letters, digits)) 31 | 32 | typecode_to_type = { 33 | 'c': ctypes.c_char, 'u': ctypes.c_wchar, 34 | 'b': ctypes.c_byte, 'B': ctypes.c_ubyte, 35 | 'h': ctypes.c_short, 'H': ctypes.c_ushort, 36 | 'i': ctypes.c_int, 'I': ctypes.c_uint, 37 | 'l': ctypes.c_long, 'L': ctypes.c_ulong, 38 | 'f': ctypes.c_float, 'd': ctypes.c_double 39 | } 40 | 41 | 42 | def address_of_buffer(buf): # (python 3) 43 | return ctypes.addressof(ctypes.c_char.from_buffer(buf)) 44 | 45 | 46 | class ShmemBufferWrapper(object): 47 | 48 | def __init__(self, tag, size, create=True): 49 | # default vals so __del__ doesn't fail if __init__ fails to complete 50 | self._mem = None 51 | self._map = None 52 | self._owner = create 53 | self.size = size 54 | 55 | assert 0 <= size < sys.maxsize # sys.maxint (python 3) 56 | flag = (0, posix_ipc.O_CREX)[create] 57 | self._mem = posix_ipc.SharedMemory(tag, flags=flag, size=size) 58 | self._map = mmap.mmap(self._mem.fd, self._mem.size) 59 | self._mem.close_fd() 60 | 61 | def get_address(self): 62 | # addr, size = address_of_buffer(self._map) 63 | # assert size == self.size 64 | assert self._map.size() == self.size # (changed for python 3) 65 | addr = address_of_buffer(self._map) 66 | return addr 67 | 68 | def __del__(self): 69 | if self._map is not None: 70 | self._map.close() 71 | if self._mem is not None and self._owner: 72 | self._mem.unlink() 73 | 74 | 75 | def ShmemRawArray(typecode_or_type, size_or_initializer, tag, create=True): 76 | assert frozenset(tag).issubset(valid_chars) 77 | if tag[0] != "/": 78 | tag = "/%s" % (tag,) 79 | 80 | type_ = typecode_to_type.get(typecode_or_type, typecode_or_type) 81 | if isinstance(size_or_initializer, int): 82 | type_ = type_ * size_or_initializer 83 | else: 84 | type_ = type_ * len(size_or_initializer) 85 | 86 | buffer = ShmemBufferWrapper(tag, ctypes.sizeof(type_), create=create) 87 | obj = type_.from_address(buffer.get_address()) 88 | obj._buffer = buffer 89 | 90 | if not isinstance(size_or_initializer, int): 91 | obj.__init__(*size_or_initializer) 92 | 93 | return obj 94 | 95 | 96 | ############################################################################### 97 | # New Additions (by Adam) # 98 | 99 | 100 | def NpShmemArray(dtype, shape, tag, create=True): 101 | size = int(np.prod(shape)) 102 | nbytes = size * np.dtype(dtype).itemsize 103 | shmem = ShmemRawArray(ctypes.c_char, nbytes, tag, create) 104 | return np.frombuffer(shmem, dtype=dtype, count=size).reshape(shape) 105 | -------------------------------------------------------------------------------- /train_2layer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | ## train_2layer.py -- train MLP models for MNIST and CIFAR 4 | ## 5 | ## Copyright (C) 2017-2018, IBM Corp. 6 | ## Copyright (C) 2017, Lily Weng 7 | ## and Huan Zhang 8 | ## 9 | ## This program is licenced under the Apache 2.0 licence, 10 | ## contained in the LICENCE file in this directory. 11 | 12 | 13 | import numpy as np 14 | from tensorflow.contrib.keras.api.keras.models import Sequential 15 | from tensorflow.contrib.keras.api.keras.layers import Dense, Dropout, Activation, Flatten 16 | from tensorflow.contrib.keras.api.keras.layers import Conv2D, MaxPooling2D 17 | from tensorflow.contrib.keras.api.keras.layers import Lambda 18 | from tensorflow.contrib.keras.api.keras.models import load_model 19 | from tensorflow.contrib.keras.api.keras.optimizers import SGD 20 | 21 | import tensorflow as tf 22 | from setup_mnist import MNIST 23 | from setup_cifar import CIFAR 24 | import os 25 | 26 | def train(data, file_name, params, num_epochs=50, batch_size=128, train_temp=1, init=None, lr=0.01, decay=1e-5, momentum=0.9): 27 | """ 28 | Train a 2-layer simple network for MNIST and CIFAR 29 | """ 30 | # create a Keras sequential model 31 | model = Sequential() 32 | # reshape the input (28*28*1) or (32*32*3) to 1-D 33 | model.add(Flatten(input_shape=data.train_data.shape[1:])) 34 | # first dense layer (the hidden layer) 35 | model.add(Dense(params[0])) 36 | # \alpha = 10 in softplus, multiply input by 10 37 | model.add(Lambda(lambda x: x * 10)) 38 | # in Keras the softplus activation cannot set \alpha 39 | model.add(Activation('softplus')) 40 | # so manually add \alpha to the network 41 | model.add(Lambda(lambda x: x * 0.1)) 42 | # the output layer, with 10 classes 43 | model.add(Dense(10)) 44 | 45 | # load initial weights when given 46 | if init != None: 47 | model.load_weights(init) 48 | 49 | # define the loss function which is the cross entropy between prediction and true label 50 | def fn(correct, predicted): 51 | return tf.nn.softmax_cross_entropy_with_logits(labels=correct, 52 | logits=predicted/train_temp) 53 | 54 | # initiate the SGD optimizer with given hyper parameters 55 | sgd = SGD(lr=lr, decay=decay, momentum=momentum, nesterov=True) 56 | 57 | # compile the Keras model, given the specified loss and optimizer 58 | model.compile(loss=fn, 59 | optimizer=sgd, 60 | metrics=['accuracy']) 61 | 62 | # run training with given dataset, and print progress 63 | model.fit(data.train_data, data.train_labels, 64 | batch_size=batch_size, 65 | validation_data=(data.validation_data, data.validation_labels), 66 | epochs=num_epochs, 67 | shuffle=True) 68 | 69 | 70 | # save model to a file 71 | if file_name != None: 72 | model.save(file_name) 73 | 74 | return model 75 | 76 | if not os.path.isdir('models'): 77 | os.makedirs('models') 78 | 79 | if __name__ == "__main__": 80 | train(MNIST(), file_name="models/mnist_2layer", params=[1024], num_epochs=50, lr=0.1, decay=1e-3) 81 | train(CIFAR(), file_name="models/cifar_2layer", params=[1024], num_epochs=50, lr=0.2, decay=1e-3) 82 | 83 | -------------------------------------------------------------------------------- /train_models.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | ## train_models.py -- train the neural network models for attacking 4 | ## 5 | ## Copyright (C) 2017-2018, IBM Corp. 6 | ## Copyright (C) 2017, Lily Weng 7 | ## and Huan Zhang 8 | ## Copyright (C) 2016, Nicholas Carlini . 9 | ## 10 | ## This program is licenced under the Apache 2.0 licence, 11 | ## contained in the LICENCE file in this directory. 12 | 13 | 14 | import numpy as np 15 | from tensorflow.contrib.keras.api.keras.models import Sequential 16 | from tensorflow.contrib.keras.api.keras.layers import Dense, Dropout, Activation, Flatten 17 | from tensorflow.contrib.keras.api.keras.layers import Conv2D, MaxPooling2D 18 | from tensorflow.contrib.keras.api.keras.layers import Lambda 19 | from tensorflow.contrib.keras.api.keras.models import load_model 20 | from tensorflow.contrib.keras.api.keras.optimizers import SGD 21 | 22 | import tensorflow as tf 23 | from setup_mnist import MNIST 24 | from setup_cifar import CIFAR 25 | import os 26 | 27 | def train(data, file_name, params, num_epochs=50, batch_size=128, train_temp=1, init=None): 28 | """ 29 | Standard neural network training procedure. 30 | """ 31 | model = Sequential() 32 | 33 | print(data.train_data.shape) 34 | 35 | model.add(Conv2D(params[0], (3, 3), 36 | input_shape=data.train_data.shape[1:])) 37 | model.add(Activation('relu')) 38 | model.add(Conv2D(params[1], (3, 3))) 39 | model.add(Activation('relu')) 40 | model.add(MaxPooling2D(pool_size=(2, 2))) 41 | 42 | model.add(Conv2D(params[2], (3, 3))) 43 | model.add(Activation('relu')) 44 | model.add(Conv2D(params[3], (3, 3))) 45 | model.add(Activation('relu')) 46 | model.add(MaxPooling2D(pool_size=(2, 2))) 47 | 48 | model.add(Flatten()) 49 | model.add(Dense(params[4])) 50 | model.add(Activation('relu')) 51 | model.add(Dropout(0.5)) 52 | model.add(Dense(params[5])) 53 | model.add(Activation('relu')) 54 | model.add(Dense(10)) 55 | 56 | if init != None: 57 | model.load_weights(init) 58 | 59 | def fn(correct, predicted): 60 | return tf.nn.softmax_cross_entropy_with_logits(labels=correct, 61 | logits=predicted/train_temp) 62 | 63 | sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True) 64 | 65 | model.compile(loss=fn, 66 | optimizer=sgd, 67 | metrics=['accuracy']) 68 | 69 | model.fit(data.train_data, data.train_labels, 70 | batch_size=batch_size, 71 | validation_data=(data.validation_data, data.validation_labels), 72 | epochs=num_epochs, 73 | shuffle=True) 74 | 75 | 76 | if file_name != None: 77 | model.save(file_name) 78 | 79 | return model 80 | 81 | def train_distillation(data, file_name, params, num_epochs=50, batch_size=128, train_temp=1): 82 | """ 83 | Train a network using defensive distillation. 84 | 85 | Distillation as a Defense to Adversarial Perturbations against Deep Neural Networks 86 | Nicolas Papernot, Patrick McDaniel, Xi Wu, Somesh Jha, Ananthram Swami 87 | IEEE S&P, 2016. 88 | """ 89 | if not os.path.exists(file_name+"_init"): 90 | # Train for one epoch to get a good starting point. 91 | train(data, file_name+"_init", params, 1, batch_size) 92 | 93 | # now train the teacher at the given temperature 94 | teacher = train(data, file_name+"_teacher", params, num_epochs, batch_size, train_temp, 95 | init=file_name+"_init") 96 | 97 | # evaluate the labels at temperature t 98 | predicted = teacher.predict(data.train_data) 99 | with tf.Session() as sess: 100 | y = sess.run(tf.nn.softmax(predicted/train_temp)) 101 | print(y) 102 | data.train_labels = y 103 | 104 | # train the student model at temperature t 105 | student = train(data, file_name, params, num_epochs, batch_size, train_temp, 106 | init=file_name+"_init") 107 | 108 | # and finally we predict at temperature 1 109 | predicted = student.predict(data.train_data) 110 | 111 | print(predicted) 112 | 113 | if not os.path.isdir('models'): 114 | os.makedirs('models') 115 | 116 | train(CIFAR(), "models/cifar", [64, 64, 128, 128, 256, 256], num_epochs=50) 117 | train(MNIST(), "models/mnist", [32, 32, 64, 64, 200, 200], num_epochs=50) 118 | 119 | train_distillation(MNIST(), "models/mnist-distilled-100", [32, 32, 64, 64, 200, 200], 120 | num_epochs=50, train_temp=100) 121 | train_distillation(CIFAR(), "models/cifar-distilled-100", [64, 64, 128, 128, 256, 256], 122 | num_epochs=50, train_temp=100) 123 | -------------------------------------------------------------------------------- /train_nlayer.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | train_models.py 4 | 5 | train the neural network models for attacking 6 | 7 | Copyright (C) 2017-2018, IBM Corp. 8 | Copyright (C) 2017, Lily Weng 9 | and Huan Zhang 10 | 11 | This program is licenced under the Apache 2.0 licence, 12 | contained in the LICENCE file in this directory. 13 | """ 14 | 15 | import numpy as np 16 | from tensorflow.contrib.keras.api.keras.models import Sequential 17 | from tensorflow.contrib.keras.api.keras.layers import Dense, Dropout, Activation, Flatten, Lambda 18 | from tensorflow.contrib.keras.api.keras.layers import Conv2D, MaxPooling2D 19 | from tensorflow.contrib.keras.api.keras.models import load_model 20 | from tensorflow.contrib.keras.api.keras import backend as K 21 | from tensorflow.contrib.keras.api.keras.optimizers import SGD, Adam 22 | import tensorflow as tf 23 | config = tf.ConfigProto() 24 | config.gpu_options.allow_growth = True 25 | K.set_session(tf.Session(config=config)) 26 | 27 | import tensorflow as tf 28 | from setup_mnist import MNIST 29 | from setup_cifar import CIFAR 30 | import argparse 31 | import os 32 | 33 | # train nlayer MLP models 34 | def train(data, file_name, params, num_epochs=50, batch_size=256, train_temp=1, init=None, lr=0.01, decay=1e-5, momentum=0.9, activation="relu", optimizer_name="sgd"): 35 | """ 36 | Train a n-layer simple network for MNIST and CIFAR 37 | """ 38 | 39 | # create a Keras sequential model 40 | model = Sequential() 41 | # reshape the input (28*28*1) or (32*32*3) to 1-D 42 | model.add(Flatten(input_shape=data.train_data.shape[1:])) 43 | # dense layers (the hidden layer) 44 | n = 0 45 | for param in params: 46 | n += 1 47 | model.add(Dense(param, kernel_initializer='he_uniform')) 48 | # ReLU activation 49 | if activation == "arctan": 50 | model.add(Lambda(lambda x: tf.atan(x), name=activation+"_"+str(n))) 51 | else: 52 | model.add(Activation(activation, name=activation+"_"+str(n))) 53 | # the output layer, with 10 classes 54 | model.add(Dense(10, kernel_initializer='he_uniform')) 55 | 56 | # load initial weights when given 57 | if init != None: 58 | model.load_weights(init) 59 | 60 | # define the loss function which is the cross entropy between prediction and true label 61 | def fn(correct, predicted): 62 | return tf.nn.softmax_cross_entropy_with_logits(labels=correct, 63 | logits=predicted/train_temp) 64 | 65 | if optimizer_name == "sgd": 66 | # initiate the SGD optimizer with given hyper parameters 67 | optimizer = SGD(lr=lr, decay=decay, momentum=momentum, nesterov=True) 68 | elif optimizer_name == "adam": 69 | optimizer = Adam(lr=lr, beta_1 = 0.9, beta_2 = 0.999, epsilon = None, decay=decay, amsgrad=False) 70 | 71 | # compile the Keras model, given the specified loss and optimizer 72 | model.compile(loss=fn, 73 | optimizer=optimizer, 74 | metrics=['accuracy']) 75 | 76 | model.summary() 77 | print("Traing a {} layer model, saving to {}".format(len(params) + 1, file_name)) 78 | # run training with given dataset, and print progress 79 | history = model.fit(data.train_data, data.train_labels, 80 | batch_size=batch_size, 81 | validation_data=(data.validation_data, data.validation_labels), 82 | epochs=num_epochs, 83 | shuffle=True) 84 | 85 | 86 | # save model to a file 87 | if file_name != None: 88 | model.save(file_name) 89 | print('model saved to ', file_name) 90 | 91 | return {'model':model, 'history':history} 92 | 93 | # train cnn 7-layer mnist/cifar model 94 | def train_cnn_7layer(data, file_name, params, num_epochs=50, batch_size=256, train_temp=1, init=None, lr=0.01, decay=1e-5, momentum=0.9, activation="relu", optimizer_name="sgd"): 95 | """ 96 | Train a 7-layer cnn network for MNIST and CIFAR (same as the cnn model in Clever) 97 | mnist: 32 32 64 64 200 200 98 | cifar: 64 64 128 128 256 256 99 | """ 100 | 101 | # create a Keras sequential model 102 | model = Sequential() 103 | 104 | print("training data shape = {}".format(data.train_data.shape)) 105 | 106 | # define model structure 107 | model.add(Conv2D(params[0], (3, 3), 108 | input_shape=data.train_data.shape[1:])) 109 | model.add(Activation(activation)) 110 | model.add(Conv2D(params[1], (3, 3))) 111 | model.add(Activation(activation)) 112 | model.add(MaxPooling2D(pool_size=(2, 2))) 113 | 114 | model.add(Conv2D(params[2], (3, 3))) 115 | model.add(Activation(activation)) 116 | model.add(Conv2D(params[3], (3, 3))) 117 | model.add(Activation(activation)) 118 | model.add(MaxPooling2D(pool_size=(2, 2))) 119 | 120 | model.add(Flatten()) 121 | model.add(Dense(params[4])) 122 | model.add(Activation(activation)) 123 | model.add(Dropout(0.5)) 124 | model.add(Dense(params[5])) 125 | model.add(Activation(activation)) 126 | model.add(Dense(10)) 127 | 128 | 129 | # load initial weights when given 130 | if init != None: 131 | model.load_weights(init) 132 | 133 | # define the loss function which is the cross entropy between prediction and true label 134 | def fn(correct, predicted): 135 | return tf.nn.softmax_cross_entropy_with_logits(labels=correct, 136 | logits=predicted/train_temp) 137 | 138 | if optimizer_name == "sgd": 139 | # initiate the SGD optimizer with given hyper parameters 140 | optimizer = SGD(lr=lr, decay=decay, momentum=momentum, nesterov=True) 141 | elif optimizer_name == "adam": 142 | optimizer = Adam(lr=lr, beta_1 = 0.9, beta_2 = 0.999, epsilon = None, decay=decay, amsgrad=False) 143 | 144 | # compile the Keras model, given the specified loss and optimizer 145 | model.compile(loss=fn, 146 | optimizer=optimizer, 147 | metrics=['accuracy']) 148 | 149 | model.summary() 150 | print("Traing a {} layer model, saving to {}".format(len(params) + 1, file_name)) 151 | # run training with given dataset, and print progress 152 | history = model.fit(data.train_data, data.train_labels, 153 | batch_size=batch_size, 154 | validation_data=(data.validation_data, data.validation_labels), 155 | epochs=num_epochs, 156 | shuffle=True) 157 | 158 | 159 | # save model to a file 160 | if file_name != None: 161 | model.save(file_name) 162 | print('model saved to ', file_name) 163 | 164 | return {'model':model, 'history':history} 165 | 166 | 167 | if __name__ == '__main__': 168 | parser = argparse.ArgumentParser(description='train n-layer MNIST and CIFAR MLP or CNN 7-layer models') 169 | parser.add_argument('--model', 170 | default="mnist", 171 | choices=["mnist", "cifar"], 172 | help='model name') 173 | parser.add_argument('--modelfile', 174 | default="", 175 | help='override the model filename, use user specied one') 176 | parser.add_argument('--modelpath', 177 | default="models_training", 178 | help='folder for saving trained models') 179 | parser.add_argument('--modeltype', 180 | default="mlp", 181 | choices=["mlp", "cnn"], 182 | help='model type') 183 | parser.add_argument('layer_parameters', 184 | nargs='+', 185 | help='number of hidden units per layer') 186 | parser.add_argument('--activation', 187 | default="relu", 188 | choices=["relu", "tanh", "sigmoid", "arctan", "elu", "hard_sigmoid", "softplus"]) 189 | parser.add_argument('--lr', 190 | default=-1, 191 | type=float, 192 | help='learning rate') 193 | parser.add_argument('--wd', 194 | default=-1, 195 | type=float, 196 | help='weight decay') 197 | parser.add_argument('--epochs', 198 | default=50, 199 | type=int, 200 | help='number of epochs') 201 | parser.add_argument('--optimizer', 202 | default="sgd", 203 | choices=["sgd", "adam"], 204 | help='optimizer type') 205 | parser.add_argument('--overwrite', 206 | action='store_true', 207 | help='overwrite output file') 208 | args = parser.parse_args() 209 | print(args) 210 | nlayers = len(args.layer_parameters) + 1 211 | if not args.modelfile: 212 | if args.modeltype == "mlp": 213 | file_name = args.modelpath+"/"+args.model+"_"+args.modeltype+"_"+str(nlayers)+"layer_"+args.activation+"_"+args.layer_parameters[0] 214 | elif args.modeltype == "cnn": 215 | file_name = args.modelpath+"/"+args.model+"_"+args.modeltype+"_"+str(nlayers)+"layer_"+args.activation 216 | 217 | else: 218 | file_name = args.modelfile 219 | print("Model will be saved to", file_name) 220 | if os.path.isfile(file_name) and not args.overwrite: 221 | raise RuntimeError("model {} exists.".format(file_name)) 222 | # load data 223 | if args.model == "mnist": 224 | data = MNIST() 225 | elif args.model == "cifar": 226 | data = CIFAR() 227 | 228 | # save trained model path 229 | if not os.path.isdir(args.modelpath): 230 | os.makedirs(args.modelpath) 231 | # set optimizer parameters 232 | if args.lr == -1: 233 | if args.optimizer == "sgd": 234 | args.lr = 0.01 # default value 235 | elif args.optimizer == "adam": 236 | args.lr = 0.001 237 | 238 | if args.wd == -1: 239 | if args.optimizer == "sgd": 240 | args.wd = 1e-5 # default value 241 | elif args.optimizer == "adam": 242 | args.wd = 0 243 | 244 | # start training: 245 | if args.modeltype == "mlp": 246 | train(data, file_name=file_name, params=args.layer_parameters, num_epochs=args.epochs, lr=args.lr, decay=args.wd, activation=args.activation, optimizer_name=args.optimizer) 247 | elif args.modeltype == "cnn": 248 | train_cnn_7layer(data, file_name=file_name, params=args.layer_parameters, num_epochs=args.epochs, lr=args.lr, decay=args.wd, activation=args.activation, optimizer_name=args.optimizer) 249 | 250 | 251 | # 2-layer models 252 | # train(MNIST(), file_name="models/mnist_2layer_relu", params=[10], num_epochs=50, lr=0.03, decay=1e-6) 253 | # train(MNIST(), file_name="models/mnist_2layer_relu", params=[50], num_epochs=50, lr=0.05,decay=1e-4) 254 | # train(MNIST(), file_name="models/mnist_2layer_relu", params=[100], num_epochs=50, lr=0.05, decay=1e-4) 255 | # train(MNIST(), file_name="models/mnist_2layer_relu", params=[1024], num_epochs=50, lr=0.1, decay=1e-3) 256 | # train(CIFAR(), file_name="models/cifar_2layer_relu", params=[1024], num_epochs=50, lr=0.2, decay=1e-3) 257 | # 3-layer models 258 | # train(MNIST(), file_name="models/mnist_3layer_relu", params=[10, 10], num_epochs=50, lr=0.03, decay=1e-7) 259 | # train(MNIST(), file_name="models/mnist_2layer_relu", params=[50], num_epochs=50, lr=0.05,decay=1e-4) 260 | # train(MNIST(), file_name="models/mnist_2layer_relu", params=[100], num_epochs=50, lr=0.05, decay=1e-4) 261 | # train(MNIST(), file_name="models/mnist_2layer_relu", params=[1024], num_epochs=50, lr=0.1, decay=1e-3) 262 | # train(CIFAR(), file_name="models/cifar_2layer_relu", params=[1024], num_epochs=50, lr=0.2, decay=1e-3) 263 | # 3-layer models 264 | # train(MNIST(), file_name="models/mnist_3layer_relu", params=[10, 10], num_epochs=50, lr=0.03, decay=1e-7) 265 | # train(MNIST(), file_name="models/mnist_2layer_relu", params=[100], num_epochs=50, lr=0.05, decay=1e-4) 266 | 267 | # train(MNIST(), file_name="models/mnist_2layer_relu", params=[1024], num_epochs=50, lr=0.1, decay=1e-3) 268 | # train(CIFAR(), file_name="models/cifar_2layer_relu", params=[1024], num_epochs=50, lr=0.2, decay=1e-3) 269 | # 3-layer models 270 | # train(MNIST(), file_name="models/mnist_3layer_relu_10_10", params=[10, 10], num_epochs=50, lr=0.03, decay=1e-7) 271 | # train(MNIST(), file_name="models/mnist_3layer_relu", params=[256,256], num_epochs=50, lr=0.1, decay=1e-3) 272 | # train(CIFAR(), file_name="models/cifar_3layer_relu", params=[256,256], num_epochs=50, lr=0.2, decay=1e-3) 273 | # 4-layer models 274 | # train(MNIST(), file_name="models/mnist_4layer_relu", params=[256,256,256], num_epochs=50, lr=0.1, decay=1e-3) 275 | # train(CIFAR(), file_name="models/cifar_4layer_relu", params=[256,256,256], num_epochs=50, lr=0.2, decay=1e-3) 276 | # train(MNIST(), file_name="models/mnist_4layer_relu", params=[20,20,20], num_epochs=50, lr=0.07, decay=1e-3) 277 | # train(MNIST(), file_name="models/mnist_5layer_relu", params=[20,20,20,20], num_epochs=50, lr=0.03, decay=1e-4) 278 | # train(MNIST(), file_name="models/mnist_5layer_relu", params=[20,20,20,20], num_epochs=50, lr=0.02, decay=1e-4) 279 | 280 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | ## Copyright (C) 2017-2018, IBM Corp. 2 | ## Copyright (C) 2017, Lily Weng 3 | ## and Huan Zhang 4 | ## Copyright (C) 2016, Nicholas Carlini . 5 | ## 6 | ## This program is licenced under the Apache 2.0 licence, 7 | ## contained in the LICENCE file in this directory. 8 | 9 | import numpy as np 10 | import random 11 | from PIL import Image 12 | 13 | def linf_dist(x, y): 14 | return np.linalg.norm(x.flatten() - y.flatten(), ord=np.inf) 15 | 16 | def l2_dist(x, y): 17 | return np.linalg.norm(x.flatten() - y.flatten(), ord=2) 18 | 19 | def l1_dist(x, y): 20 | return np.linalg.norm(x.flatten() - y.flatten(), ord=1) 21 | 22 | def l0_dist(x, y): 23 | return np.linalg.norm(x.flatten() - y.flatten(), ord=0) 24 | 25 | def show(img, name = "output.png"): 26 | """ 27 | Show MNSIT digits in the console. 28 | """ 29 | np.save('img', img) 30 | fig = np.around((img + 0.5)*255) 31 | fig = fig.astype(np.uint8).squeeze() 32 | pic = Image.fromarray(fig) 33 | # pic.resize((512,512), resample=PIL.Image.BICUBIC) 34 | pic.save(name) 35 | remap = " .*#"+"#"*100 36 | img = (img.flatten()+.5)*3 37 | return 38 | if len(img) != 784: return 39 | print("START") 40 | for i in range(28): 41 | print("".join([remap[int(round(x))] for x in img[i*28:i*28+28]])) 42 | 43 | def generate_data(data, samples, targeted=True, random_and_least_likely = False, skip_wrong_label = True, start=0, ids = None, 44 | target_classes = None, target_type = 0b1111, predictor = None, imagenet=False, remove_background_class=False): 45 | """ 46 | Generate the input data to the attack algorithm. 47 | 48 | data: the images to attack 49 | samples: number of samples to use 50 | targeted: if true, construct targeted attacks, otherwise untargeted attacks 51 | start: offset into data to use 52 | ids: true IDs of images in the dataset, if given, will use these images 53 | target_classes: a list of list of labels for each ids 54 | inception: if targeted and inception, randomly sample 100 targets instead of 1000 55 | """ 56 | inputs = [] 57 | targets = [] 58 | true_labels = [] 59 | true_ids = [] 60 | information = [] 61 | target_candidate_pool = np.eye(data.test_labels.shape[1]) 62 | target_candidate_pool_remove_background_class = np.eye(data.test_labels.shape[1] - 1) 63 | print('generating labels...') 64 | if ids is None: 65 | ids = range(samples) 66 | else: 67 | ids = ids[start:start+samples] 68 | if target_classes: 69 | target_classes = target_classes[start:start+samples] 70 | start = 0 71 | total = 0 72 | n_correct = 0 73 | for i in ids: 74 | total += 1 75 | if targeted: 76 | predicted_label = -1 # unknown 77 | if random_and_least_likely: 78 | # if there is no user specified target classes 79 | if target_classes is None: 80 | original_predict = np.squeeze(predictor(np.array([data.test_data[start+i]]))) 81 | num_classes = len(original_predict) 82 | predicted_label = np.argmax(original_predict) + int(imagenet and remove_background_class) 83 | least_likely_label = np.argmin(original_predict) 84 | top2_label = np.argsort(original_predict)[-2] 85 | start_class = 1 if (imagenet and not remove_background_class) else 0 86 | random_class = predicted_label 87 | new_seq = [least_likely_label, top2_label, predicted_label] 88 | while random_class in new_seq: 89 | random_class = random.randint(start_class, start_class + num_classes - 1) 90 | new_seq[2] = random_class 91 | true_label = np.argmax(data.test_labels[start+i]) 92 | seq = [] 93 | if true_label != predicted_label and skip_wrong_label: 94 | seq = [] 95 | else: 96 | if target_type & 0b10000: 97 | for c in range(num_classes): 98 | if c != predicted_label: 99 | seq.append(c) 100 | information.append('class'+str(c)) 101 | else: 102 | if target_type & 0b0100: 103 | # least 104 | seq.append(new_seq[0]) 105 | information.append('least') 106 | if target_type & 0b0001: 107 | # top-2 108 | seq.append(new_seq[1]) 109 | information.append('top2') 110 | if target_type & 0b0010: 111 | # random 112 | seq.append(new_seq[2]) 113 | information.append('random') 114 | else: 115 | # use user specified target classes 116 | seq = target_classes[total - 1] 117 | information.extend(len(seq) * ['user']) 118 | else: 119 | if imagenet: 120 | if remove_background_class: 121 | seq = random.sample(range(0,1000), 10) 122 | else: 123 | seq = random.sample(range(1,1001), 10) 124 | information.extend(data.test_labels.shape[1] * ['random']) 125 | else: 126 | seq = range(data.test_labels.shape[1]) 127 | information.extend(data.test_labels.shape[1] * ['seq']) 128 | 129 | is_correct = np.argmax(data.test_labels[start+i]) == predicted_label 130 | print("[DATAGEN][L1] no = {}, true_id = {}, true_label = {}, predicted = {}, correct = {}, seq = {}, info = {}".format(total, start + i, 131 | np.argmax(data.test_labels[start+i]), predicted_label, is_correct, seq, [] if len(seq) == 0 else information[-len(seq):])) 132 | if is_correct: 133 | n_correct += 1 134 | for j in seq: 135 | # skip the original image label 136 | # if (j == np.argmax(data.test_labels[start+i])): 137 | if (j == np.argmax(data.test_labels[start+i]) - int(imagenet and remove_background_class)): 138 | continue 139 | inputs.append(data.test_data[start+i]) 140 | if remove_background_class: 141 | targets.append(target_candidate_pool_remove_background_class[j]) 142 | else: 143 | targets.append(target_candidate_pool[j]) 144 | true_labels.append(data.test_labels[start+i]) 145 | if remove_background_class: 146 | true_labels[-1] = true_labels[-1][1:] 147 | true_ids.append(start+i) 148 | else: 149 | inputs.append(data.test_data[start+i]) 150 | if remove_background_class: 151 | # shift target class by 1 152 | print(np.argmax(data.test_labels[start+i])) 153 | print(np.argmax(data.test_labels[start+i][1:1001])) 154 | targets.append(data.test_labels[start+i][1:1001]) 155 | else: 156 | targets.append(data.test_labels[start+i]) 157 | true_labels.append(data.test_labels[start+i]) 158 | if remove_background_class: 159 | true_labels[-1] = true_labels[-1][1:] 160 | true_ids.append(start+i) 161 | information.extend(['original']) 162 | 163 | inputs = np.array(inputs) 164 | targets = np.array(targets) 165 | true_labels = np.array(true_labels) 166 | true_ids = np.array(true_ids) 167 | print('labels generated') 168 | print('top-1 accuracy:', n_correct / float(samples)) 169 | 170 | return inputs, targets, true_labels, true_ids, information 171 | 172 | --------------------------------------------------------------------------------