├── .gitignore ├── ml-basics └── mnist │ ├── README.md │ ├── mnist-loading-basic-steps.ipynb │ ├── mnist-incorrect-and-abiguous-labels.ipynb │ └── mnist.ipynb ├── examples ├── adversarial-examples │ ├── lion.jpg │ ├── ostrich.jpg │ ├── adversarial_example.ipynb │ ├── adversarial_examples.md │ └── imagenet_class_index.json ├── inversion-attack │ └── att-database-of-faces.zip ├── model-stealing │ └── model_stealing_logistic_regression.ipynb └── backdoors │ └── mnist.ipynb ├── LICENSE ├── requirements.txt ├── README.md └── inversion.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints/ 2 | .data 3 | venv 4 | -------------------------------------------------------------------------------- /ml-basics/mnist/README.md: -------------------------------------------------------------------------------- 1 | # INSTALL 2 | 3 | pip install torch torchvision matplotlib -------------------------------------------------------------------------------- /examples/adversarial-examples/lion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-e/secml/HEAD/examples/adversarial-examples/lion.jpg -------------------------------------------------------------------------------- /examples/adversarial-examples/ostrich.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-e/secml/HEAD/examples/adversarial-examples/ostrich.jpg -------------------------------------------------------------------------------- /examples/inversion-attack/att-database-of-faces.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-e/secml/HEAD/examples/inversion-attack/att-database-of-faces.zip -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | attrs==19.1.0 2 | backcall==0.1.0 3 | bleach==3.3.0 4 | cycler==0.10.0 5 | decorator==4.4.0 6 | defusedxml==0.6.0 7 | entrypoints==0.3 8 | ipykernel==5.1.1 9 | ipython==8.10.0 10 | ipython-genutils==0.2.0 11 | ipywidgets==7.4.2 12 | jedi==0.14.0 13 | Jinja2==2.11.3 14 | jsonschema==3.0.1 15 | jupyter==1.0.0 16 | jupyter-client==5.2.4 17 | jupyter-console==6.0.0 18 | jupyter-core==4.11.2 19 | kiwisolver==1.1.0 20 | MarkupSafe==1.1.1 21 | matplotlib==3.1.0 22 | mistune==2.0.3 23 | nbconvert==6.5.1 24 | nbformat==4.4.0 25 | notebook==6.4.12 26 | numpy==1.22.0 27 | pandocfilters==1.4.2 28 | parso==0.5.0 29 | pexpect==4.7.0 30 | pickleshare==0.7.5 31 | Pillow==9.0.1 32 | pkg-resources==0.0.0 33 | prometheus-client==0.7.1 34 | prompt-toolkit==2.0.9 35 | ptyprocess==0.6.0 36 | Pygments==2.7.4 37 | pyparsing==2.4.0 38 | pyrsistent==0.15.2 39 | python-dateutil==2.8.0 40 | pyzmq==18.0.1 41 | qtconsole==4.5.1 42 | Send2Trash==1.5.0 43 | six==1.12.0 44 | terminado==0.8.2 45 | testpath==0.4.2 46 | torch==1.13.1 47 | torchvision==0.3.0 48 | tornado==6.0.3 49 | tqdm==4.32.2 50 | traitlets==4.3.2 51 | wcwidth==0.1.7 52 | webencodings==0.5.1 53 | widgetsnbextension==3.4.2 54 | -------------------------------------------------------------------------------- /ml-basics/mnist/mnist-loading-basic-steps.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Loading MNIST Digits in Batches With PyTorch" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "from torch import utils\n", 17 | "from torchvision import datasets, transforms\n", 18 | "\n", 19 | "# Transform PIL image into a tensor. The values are in the range [0, 1]\n", 20 | "t = transforms.ToTensor()\n", 21 | "\n", 22 | "# Load datasets for training and apply the given transformation.\n", 23 | "mnist = datasets.MNIST(root='data', train=True, download=True, transform=t)\n", 24 | "\n", 25 | "# Specify a data loader which returns 500 examples in each iteration.\n", 26 | "n = 500\n", 27 | "loader = utils.data.DataLoader(mnist, batch_size=n, shuffle=True)\n", 28 | "\n", 29 | "# Iterate over the batches.\n", 30 | "for imgs, labels in loader:\n", 31 | " # do something" 32 | ] 33 | } 34 | ], 35 | "metadata": { 36 | "interpreter": { 37 | "hash": "3c31154c2e6d078d13498c87eb48ca372ee3ad3d9153e56081b43cdb07df7cf4" 38 | }, 39 | "kernelspec": { 40 | "display_name": "Python 3.8.10 64-bit ('venv': venv)", 41 | "language": "python", 42 | "name": "python3" 43 | }, 44 | "language_info": { 45 | "codemirror_mode": { 46 | "name": "ipython", 47 | "version": 3 48 | }, 49 | "file_extension": ".py", 50 | "mimetype": "text/x-python", 51 | "name": "python", 52 | "nbconvert_exporter": "python", 53 | "pygments_lexer": "ipython3", 54 | "version": "3.8.10" 55 | }, 56 | "orig_nbformat": 4 57 | }, 58 | "nbformat": 4, 59 | "nbformat_minor": 2 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Like software systems also machine learning can suffer from security weaknesses. This repository contains some resources to provide an overview. 4 | 5 | ## Possible Security Issues in Machine Learning 6 | 7 | ### Poisoning 8 | 9 | In a poisoning attack an adversary can insert carefully crafted examples into the training data. Hence, this attack happens at training time. First, such an attack could degrade the performance of a machine learning model (the adversary targets the availability of the model). Second, the adversary could use this technique to inject a backdoor. 10 | 11 | #### Resources 12 | 13 | * [Targeted Backdoor Attacks on Deep Learning Systems Using Data Poisoning](https://arxiv.org/pdf/1712.05526), 2017 14 | * [Manipulating Machine Learning: Poisoning Attacks and Countermeasures for Regression Learning](https://arxiv.org/pdf/1804.00308.pdf), 2018 15 | * [Data poisoning attacks against online learning](https://arxiv.org/abs/1808.08994), 2018 16 | * [Why do adversarial attacks transfer? explaining transferability of evasion and poisoning attacks](https://arxiv.org/abs/1809.02861), 2018 17 | 18 | ### Evasion 19 | 20 | An evasion attack happens at test time. Here, an instance that would be classified correctly without modification, will be misclassified when small modifications are added by the adversary. A well know example of evasion attacks are adversarial examples. An adversary adds small perturbations to an image which are invisible to a human but will fool the image classifier which will misclassify them into a category that can be chosen by the adversary. 21 | 22 | #### Resources 23 | 24 | * [Intriguing properties of neural networks](https://arxiv.org/abs/1312.6199), 2014 25 | * [Explaining and Harnessing Adversarial Examples](https://arxiv.org/abs/1412.6572), 2014 26 | * [Evasion Attacks against Machine Learning at Test Time](https://arxiv.org/abs/1708.06131), 2017 27 | * [Adversarial Examples Are Not Easily Detected: Bypassing Ten Detection Methods](https://arxiv.org/abs/1705.07263), 2017 28 | 29 | ### Inversion Attacks 30 | 31 | In inversion attacks an adversary tries to extract useful information from a machine learning model like training data that was used for the training. Due to the fact that machine learning is used in more and more privacy sensitive applications an adversary could learn very sensitive data of individuals. 32 | 33 | #### Resources 34 | 35 | * [Privacy in Pharmacogenetics: An End-to-End Case Study of Personalized Warfarin Dosing](https://www.usenix.org/system/files/conference/usenixsecurity14/sec14-paper-fredrikson-privacy.pdf), 2014 36 | * [Model Inversion Attacks that Exploit Confidence Information and Basic Countermeasures](https://www.cs.cmu.edu/~mfredrik/papers/fjr2015ccs.pdf), 2015 37 | * [Membership Model Inversion Attacks for Deep Networks](https://arxiv.org/abs/1910.04257), 2019 38 | * [The Secret Revealer: Generative Model-Inversion Attacks Against Deep Neural Networks](https://arxiv.org/abs/1911.07135), 2019 39 | 40 | # Examples 41 | 42 | This repositories contains some examples of attacks in the folder `example`. Examples are: 43 | 44 | * Create adversarial examples 45 | * Model stealing 46 | * Model inversion attacks 47 | 48 | To run the examples it is recommended to create a virtual environment first and install all required packages in that environment: 49 | 50 | virtualenv -p python3 venv 51 | source venv/bin/activate 52 | pip3 install -r requirements.txt 53 | 54 | # Resources 55 | 56 | * [TensorFlow Privacy](https://github.com/tensorflow/privacy) 57 | * [PySyft](https://github.com/OpenMined/PySyft) 58 | * [Encrypted Training Demo on MNIST](https://blog.openmined.org/encrypted-training-on-mnist/) 59 | 60 | -------------------------------------------------------------------------------- /inversion.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import torch\n", 10 | "import torchvision as tv\n", 11 | "import matplotlib.pyplot as plt\n", 12 | "from PIL import Image\n", 13 | "import numpy as np" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": null, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "%%bash\n", 23 | "\n", 24 | "rm -rf .data\n", 25 | "mkdir .data\n", 26 | "unzip -q att-database-of-faces.zip -d .data/faces-training\n", 27 | "cp -a .data/faces-training .data/faces-test\n", 28 | "\n", 29 | "rm .data/faces-training/*/{1,2,3,4,5}.pgm\n", 30 | "rm .data/faces-test/*/{6,7,8,9,10}.pgm" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": null, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "torch.manual_seed(1)\n", 40 | "\n", 41 | "t = tv.transforms.Compose([\n", 42 | " tv.transforms.Grayscale(),\n", 43 | " tv.transforms.ToTensor()\n", 44 | "])\n", 45 | "\n", 46 | "# Load AT&T database of faces.\n", 47 | "dataset = tv.datasets.ImageFolder(root=\".data/faces-training\", transform=t)\n" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": null, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "target_person = 30\n", 57 | "\n", 58 | "all_images_of_target = [img for img, label in dataset if label == target_person]\n", 59 | "\n", 60 | "_, ax = plt.subplots(1, len(all_images_of_target), figsize=(20, 5))\n", 61 | " \n", 62 | "for p, img in zip(ax, all_images_of_target):\n", 63 | " p.imshow(img.squeeze(), cmap=\"gray\")\n", 64 | " p.axis(\"off\")\n", 65 | "\n", 66 | "plt.show()" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": null, 72 | "metadata": {}, 73 | "outputs": [], 74 | "source": [ 75 | "nc = 40\n", 76 | "nf = 112 * 92\n", 77 | "\n", 78 | "model = torch.nn.Linear(nf, nc)\n", 79 | "\n", 80 | "opt = torch.optim.SGD(model.parameters(), lr=0.1)\n", 81 | "\n", 82 | "criterion = torch.nn.CrossEntropyLoss()" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": null, 88 | "metadata": {}, 89 | "outputs": [], 90 | "source": [ 91 | "loader = torch.utils.data.DataLoader(dataset, batch_size=20, shuffle=True)\n", 92 | "\n", 93 | "n_epochs = 20\n", 94 | "cost = []\n", 95 | "\n", 96 | "for i in range(n_epochs):\n", 97 | " l = 0\n", 98 | " n = 0\n", 99 | " for img, labels in loader:\n", 100 | " img = img.view(-1, nf) # from [nbatches, 1, 112, 92] to [nbatches, 10304]\n", 101 | " output = model(img)\n", 102 | " opt.zero_grad()\n", 103 | " loss = criterion(output, labels)\n", 104 | " loss.backward()\n", 105 | "\n", 106 | " rnd = torch.distributions.normal.Normal(0.0, 1.0)\n", 107 | " for p in model.parameters():\n", 108 | " p.grad += rnd.sample(torch.Size(p.grad.shape)) * 0.3\n", 109 | " \n", 110 | " ##########################################################\n", 111 | " # Enable the following lines to get more privacy.\n", 112 | " ##########################################################\n", 113 | " #rnd = torch.distributions.normal.Normal(0.0, 1.0)\n", 114 | " #for p in model.parameters():\n", 115 | " # p.grad += rnd.sample(torch.Size(p.grad.shape)) * 0.3\n", 116 | " ##########################################################\n", 117 | " \n", 118 | " opt.step()\n", 119 | " l += loss.item()\n", 120 | " n += 1\n", 121 | " print(i, l/n)\n", 122 | " cost.append(l/n)\n", 123 | " \n", 124 | "plt.plot(cost)\n", 125 | "plt.show()" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": null, 131 | "metadata": {}, 132 | "outputs": [], 133 | "source": [ 134 | "dataset = tv.datasets.ImageFolder(root=\".data/faces-test\", transform=t)\n", 135 | "test_loader = torch.utils.data.DataLoader(dataset, batch_size=200)\n", 136 | "\n", 137 | "with torch.no_grad():\n", 138 | " img, labels = iter(test_loader).next()\n", 139 | " r = model(img.view(-1, nf))\n", 140 | " p = r.argmax(dim=1)\n", 141 | " print(\"images:\", len(labels))\n", 142 | " print(\"accuracy:\", (labels == p).sum().item() / len(labels))\n" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": null, 148 | "metadata": {}, 149 | "outputs": [], 150 | "source": [ 151 | "import torch.nn.functional as F\n", 152 | "\n", 153 | "x = torch.zeros(nf, requires_grad=True)\n", 154 | "o = torch.optim.SGD([x], lr=0.1)\n", 155 | "\n", 156 | "for i in range(1000):\n", 157 | " scores = F.softmax(model(x.view(1, nf)), dim=1).squeeze()\n", 158 | " e = torch.tensor([1.0]) - scores[target_person] # error for the target label\n", 159 | " o.zero_grad()\n", 160 | " e.backward()\n", 161 | " o.step()\n", 162 | " \n", 163 | "x" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": null, 169 | "metadata": {}, 170 | "outputs": [], 171 | "source": [ 172 | "r = F.softmax(model(x), dim=0)\n", 173 | "print(\"score of target person:\", r[target_person].item())\n", 174 | "print(\"scores:\")\n", 175 | "r" 176 | ] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": null, 181 | "metadata": {}, 182 | "outputs": [], 183 | "source": [ 184 | "img = x.view(112, 92).detach()\n", 185 | "\n", 186 | "plt.imshow(img, cmap=\"gray\")\n", 187 | "plt.show()" 188 | ] 189 | } 190 | ], 191 | "metadata": { 192 | "kernelspec": { 193 | "display_name": "Python 3", 194 | "language": "python", 195 | "name": "python3" 196 | }, 197 | "language_info": { 198 | "codemirror_mode": { 199 | "name": "ipython", 200 | "version": 3 201 | }, 202 | "file_extension": ".py", 203 | "mimetype": "text/x-python", 204 | "name": "python", 205 | "nbconvert_exporter": "python", 206 | "pygments_lexer": "ipython3", 207 | "version": "3.6.9" 208 | } 209 | }, 210 | "nbformat": 4, 211 | "nbformat_minor": 2 212 | } 213 | -------------------------------------------------------------------------------- /examples/model-stealing/model_stealing_logistic_regression.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import torch\n", 10 | "import torchvision.datasets as ds\n", 11 | "import torchvision.transforms as transforms" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": null, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "# Load the MNIST training dataset.\n", 21 | "# ToTensor converts PIL image to (CxHxW) in the range [0.0, 1.0].\n", 22 | "train_set = ds.MNIST(\".data\", train=True, transform=transforms.ToTensor(), download=True)" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "# Just select examples with labels 0 or 1.\n", 32 | "X_, y_ = zip(*[i for i in train_set if i[1] < 2])" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": null, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "import torchvision.utils as u\n", 42 | "import matplotlib.pyplot as plt\n", 43 | "import numpy as np\n", 44 | "\n", 45 | "# Plot the first 100 examples of the dataset.\n", 46 | "plt.imshow(np.transpose(u.make_grid(list(X_[:100]), 10).numpy(), (1,2,0)))\n", 47 | "plt.show()" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": null, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "# Each image has a size of 28x28.\n", 57 | "n = 28*28\n", 58 | "\n", 59 | "# Convert lists of examples and labels to tensors.\n", 60 | "X = torch.stack(X_).view((-1, n))\n", 61 | "y = torch.tensor(y_).view(-1, 1).float()" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": null, 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [ 70 | "from tqdm import tqdm_notebook\n", 71 | "\n", 72 | "# Linear regression model.\n", 73 | "model = torch.nn.Linear(n, 1, bias=True)\n", 74 | "\n", 75 | "# Select a loss function.\n", 76 | "loss = torch.nn.BCELoss()\n", 77 | "\n", 78 | "# Use stochastic gradient descent as the optimizer.\n", 79 | "opt = torch.optim.SGD(model.parameters(), lr=0.01)\n", 80 | "\n", 81 | "costs = []\n", 82 | "for i in tqdm_notebook(range(1000)):\n", 83 | " # Classify the training examples.\n", 84 | " pred_y = torch.sigmoid(model(X))\n", 85 | " # Compute the loss function.\n", 86 | " l = loss(pred_y, y)\n", 87 | " costs.append(l)\n", 88 | " # Compute gradient and update the parameters.\n", 89 | " opt.zero_grad()\n", 90 | " l.backward()\n", 91 | " opt.step()" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": null, 97 | "metadata": {}, 98 | "outputs": [], 99 | "source": [ 100 | "# Plot learning curve, i.e. the error in each iteration.\n", 101 | "plt.plot(costs[100:])" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "# Test the model" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": {}, 115 | "outputs": [], 116 | "source": [ 117 | "# Load test examples.\n", 118 | "test_set = ds.MNIST(\".data\", train=False, transform=transforms.ToTensor(), download=True)\n", 119 | "\n", 120 | "X_test_, y_test_ = zip(*[i for i in test_set if i[1] < 2])\n", 121 | "X_test = torch.stack(X_test_).view(-1, n)\n", 122 | "y_test = torch.tensor(y_test_).view(-1, 1).float()" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": null, 128 | "metadata": {}, 129 | "outputs": [], 130 | "source": [ 131 | "# Use the classifier to predict the categories for the test examples.\n", 132 | "pred_y = torch.sigmoid(model(X_test))\n", 133 | "# Convert the probabilities (i.e. [0,1] into class labels {0, 1})\n", 134 | "labels = torch.round(pred_y)" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": null, 140 | "metadata": {}, 141 | "outputs": [], 142 | "source": [ 143 | "# Compute the accuracy of the classifier for the test examples.\n", 144 | "torch.sum(labels == y_test).item() / y_test.size(0)" 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "metadata": {}, 150 | "source": [ 151 | "# Steal model parameters" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": null, 157 | "metadata": {}, 158 | "outputs": [], 159 | "source": [ 160 | "# We have 28*28+1 unknowns (28*28 weights + 1 bias). Therefore, \n", 161 | "# we need 28*28+1 queries (i.e. equations).\n", 162 | "k = n+1\n", 163 | "\n", 164 | "# Create k random queries.\n", 165 | "queries = torch.rand((k, n))\n", 166 | "\n", 167 | "# Use the classifier to predict the categories for the queries.\n", 168 | "output = model(queries)" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": null, 174 | "metadata": {}, 175 | "outputs": [], 176 | "source": [ 177 | "# Add a column with ones for the bias to the queries. Shape (k, n) → (k, n+1).\n", 178 | "q = torch.cat((queries, torch.ones((k, 1))), 1)\n", 179 | "\n", 180 | "# Convert the queries with the added column into a numpy array.\n", 181 | "a = q.data.numpy()\n", 182 | "\n", 183 | "# Convert the output of the classifier into a numpy array.\n", 184 | "b = output.data.squeeze().numpy()" 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "execution_count": null, 190 | "metadata": {}, 191 | "outputs": [], 192 | "source": [ 193 | "# Solve for the parameters.\n", 194 | "x = np.linalg.solve(a, b)" 195 | ] 196 | }, 197 | { 198 | "cell_type": "code", 199 | "execution_count": null, 200 | "metadata": {}, 201 | "outputs": [], 202 | "source": [ 203 | "# Print the first 20 recovered parameter.\n", 204 | "x[:20]" 205 | ] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "execution_count": null, 210 | "metadata": {}, 211 | "outputs": [], 212 | "source": [ 213 | "# Print the first 20 parameters of the model.\n", 214 | "model.weight.squeeze().data.numpy()[:20]" 215 | ] 216 | } 217 | ], 218 | "metadata": { 219 | "kernelspec": { 220 | "display_name": "Python 3", 221 | "language": "python", 222 | "name": "python3" 223 | }, 224 | "language_info": { 225 | "codemirror_mode": { 226 | "name": "ipython", 227 | "version": 3 228 | }, 229 | "file_extension": ".py", 230 | "mimetype": "text/x-python", 231 | "name": "python", 232 | "nbconvert_exporter": "python", 233 | "pygments_lexer": "ipython3", 234 | "version": "3.6.8" 235 | } 236 | }, 237 | "nbformat": 4, 238 | "nbformat_minor": 2 239 | } 240 | -------------------------------------------------------------------------------- /examples/adversarial-examples/adversarial_example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import torch\n", 10 | "import torchvision as tv\n", 11 | "import torch.nn.functional as F\n", 12 | "import numpy as np\n", 13 | "import matplotlib.pyplot as plt\n", 14 | "from PIL import Image\n", 15 | "from tqdm import tqdm_notebook as tqdm" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": null, 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "# Load Alexnet image classifier.\n", 25 | "model = tv.models.alexnet(pretrained=True)" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "# Show the architecture of the classifier.\n", 35 | "print(model)" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": null, 41 | "metadata": {}, 42 | "outputs": [], 43 | "source": [ 44 | "# Load a lion image. From this image we want to create an\n", 45 | "# adversarial examples.\n", 46 | "img_lion = Image.open(\"lion.jpg\")\n", 47 | "plt.imshow(img_lion)\n", 48 | "plt.show()" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": null, 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "# Define some convenient functions.\n", 58 | "\n", 59 | "as_tensor = tv.transforms.ToTensor()\n", 60 | "\n", 61 | "normalize = tv.transforms.Normalize(\n", 62 | " mean=[0.485, 0.456, 0.406], \n", 63 | " std=[0.229, 0.224, 0.225]\n", 64 | ")\n", 65 | "\n", 66 | "# Reverse the normalization and convert the tensor into a PIL image.\n", 67 | "reverse = tv.transforms.Compose([\n", 68 | " tv.transforms.Normalize(\n", 69 | " mean=[0, 0, 0], std=[1.0/0.229, 1.0/0.224, 1.0/0.225]),\n", 70 | " tv.transforms.Normalize(\n", 71 | " mean=[-0.485, -0.456, -0.406], std=[1, 1, 1]),\n", 72 | " tv.transforms.ToPILImage()\n", 73 | "])\n", 74 | "\n", 75 | "# Returns the class name for the given index.\n", 76 | "def classname(idx):\n", 77 | " import json\n", 78 | " classidx = json.load(open(\"imagenet_class_index.json\"))\n", 79 | " return classidx[str(idx)][1]\n", 80 | "\n", 81 | "# Use Alexnet to predict the category of the given image.\n", 82 | "def predict(img):\n", 83 | " # Convert the image to a tensor and normalize it.\n", 84 | " v = normalize(as_tensor(img.copy()))\n", 85 | " # Insert a dimension.\n", 86 | " v = v.unsqueeze(0)\n", 87 | " # Compute class probabilities for the normalized input using Alexnet.\n", 88 | " r = F.softmax(model(v), dim=1)\n", 89 | " # Select the category with the highest probability.\n", 90 | " idx = r.argmax().item()\n", 91 | " # Get the class name for the category.\n", 92 | " label = classname(idx)\n", 93 | " return idx, label, r.data[0, idx].item()" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": null, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | "# Predict the lion image.\n", 103 | "predict(img_lion)" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": null, 109 | "metadata": {}, 110 | "outputs": [], 111 | "source": [ 112 | "# Load an image of an ostrich.\n", 113 | "tmp = Image.open(\"ostrich.jpg\")\n", 114 | "plt.imshow(tmp)\n", 115 | "plt.show()" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "metadata": {}, 122 | "outputs": [], 123 | "source": [ 124 | "# Predict the category of the ostrich to get the correct\n", 125 | "# target category.\n", 126 | "predict(tmp)" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": null, 132 | "metadata": {}, 133 | "outputs": [], 134 | "source": [ 135 | "# Convert the lion image into a tensor.\n", 136 | "img = normalize(as_tensor(img_lion.copy())).requires_grad_(True)\n", 137 | "\n", 138 | "# Set the target category to the category of an ostrich.\n", 139 | "target = torch.LongTensor([9])\n", 140 | "\n", 141 | "# Use Adam as the optimizer.\n", 142 | "opt = torch.optim.Adam([img], lr=0.01)\n", 143 | "\n", 144 | "h = []\n", 145 | "for _ in tqdm(range(10)):\n", 146 | " # Bound the entries of the tensor between [-1.8, 1.8]\n", 147 | " x = img.clamp(-1.8, 1.8)\n", 148 | " # Set the correct dimensions so that we can classify x.\n", 149 | " x = x.view(1, 3, 224, 224)\n", 150 | " # Compute the error for x.\n", 151 | " loss = F.cross_entropy(model(x), target)\n", 152 | " h.append(loss.item())\n", 153 | " # Compute the gradient and update the parameters.\n", 154 | " opt.zero_grad()\n", 155 | " loss.backward()\n", 156 | " opt.step()" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": null, 162 | "metadata": {}, 163 | "outputs": [], 164 | "source": [ 165 | "# Plot the learning curve.\n", 166 | "plt.plot(h)\n", 167 | "plt.show()" 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": null, 173 | "metadata": {}, 174 | "outputs": [], 175 | "source": [ 176 | "img = img.clamp(-1.8, 1.8)\n", 177 | "\n", 178 | "# Convert the tensor (adversarial image) into an image.\n", 179 | "img_lion_ostrich = reverse(img.clone())\n", 180 | "\n", 181 | "# Show the adversarial image and the predicted category.\n", 182 | "plt.imshow(img_lion_ostrich)\n", 183 | "plt.show()\n", 184 | "print(predict(img_lion_ostrich))\n", 185 | "\n", 186 | "# Show the original lion image and the predicted category.\n", 187 | "plt.imshow(img_lion)\n", 188 | "plt.show()\n", 189 | "print(predict(img_lion))" 190 | ] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": null, 195 | "metadata": {}, 196 | "outputs": [], 197 | "source": [ 198 | "# Show the difference (boosted by a factor of 50).\n", 199 | "d = np.abs(\n", 200 | " np.array(img_lion, dtype=np.int) - \n", 201 | " np.array(img_lion_ostrich, dtype=np.int)\n", 202 | ")\n", 203 | "d = np.clip(d*50, 0, 255)\n", 204 | "plt.imshow(d)\n", 205 | "plt.show()" 206 | ] 207 | } 208 | ], 209 | "metadata": { 210 | "kernelspec": { 211 | "display_name": "Python 3", 212 | "language": "python", 213 | "name": "python3" 214 | }, 215 | "language_info": { 216 | "codemirror_mode": { 217 | "name": "ipython", 218 | "version": 3 219 | }, 220 | "file_extension": ".py", 221 | "mimetype": "text/x-python", 222 | "name": "python", 223 | "nbconvert_exporter": "python", 224 | "pygments_lexer": "ipython3", 225 | "version": "3.6.8" 226 | } 227 | }, 228 | "nbformat": 4, 229 | "nbformat_minor": 2 230 | } 231 | -------------------------------------------------------------------------------- /examples/backdoors/mnist.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### Train a simple CNN to recognize handwritten digits" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import torch\n", 17 | "import torch.nn as nn\n", 18 | "import torchvision as tv\n", 19 | "import matplotlib.pyplot as plt" 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "Load MNIST training and validation set." 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 2, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "mnist_training = tv.datasets.MNIST(\n", 36 | " root='.data', \n", 37 | " train=True, \n", 38 | " download=True, \n", 39 | " transform=tv.transforms.ToTensor()\n", 40 | ")\n", 41 | "\n", 42 | "mnist_val = tv.datasets.MNIST(\n", 43 | " root='.data', \n", 44 | " train=False, \n", 45 | " download=True, \n", 46 | " transform=tv.transforms.ToTensor()\n", 47 | ")" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "Create a function for building a model from a dataset." 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": 3, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "def create_model(dataset):\n", 64 | " model = torch.nn.Sequential(\n", 65 | " nn.Conv2d(1, 16, 5, 1),\n", 66 | " nn.ReLU(),\n", 67 | " nn.MaxPool2d(2, 2),\n", 68 | " nn.Conv2d(16, 32, 5, 1),\n", 69 | " nn.ReLU(),\n", 70 | " nn.MaxPool2d(2, 2),\n", 71 | " nn.Flatten(),\n", 72 | " nn.Linear(32*4*4, 512),\n", 73 | " nn.ReLU(),\n", 74 | " nn.Linear(512, 10)\n", 75 | " )\n", 76 | "\n", 77 | " opt = torch.optim.Adam(model.parameters(), 0.001)\n", 78 | " loss_fn = torch.nn.CrossEntropyLoss()\n", 79 | " loader = torch.utils.data.DataLoader(dataset, 500, True)\n", 80 | "\n", 81 | " for epoch in range(10):\n", 82 | " for imgs, labels in loader:\n", 83 | " output = model(imgs)\n", 84 | " loss = loss_fn(output, labels) \n", 85 | " opt.zero_grad()\n", 86 | " loss.backward()\n", 87 | " opt.step()\n", 88 | " print(f\"Epoch {epoch}, Loss {loss.item()}\")\n", 89 | " \n", 90 | " return model" 91 | ] 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "metadata": {}, 96 | "source": [ 97 | "Create a model from the MNIST training set." 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 4, 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "name": "stdout", 107 | "output_type": "stream", 108 | "text": [ 109 | "Epoch 0, Loss 0.142143115401268\n", 110 | "Epoch 1, Loss 0.08675184100866318\n", 111 | "Epoch 2, Loss 0.059259142726659775\n", 112 | "Epoch 3, Loss 0.03356778994202614\n", 113 | "Epoch 4, Loss 0.031077086925506592\n", 114 | "Epoch 5, Loss 0.039355602115392685\n", 115 | "Epoch 6, Loss 0.03527236357331276\n", 116 | "Epoch 7, Loss 0.020052533596754074\n", 117 | "Epoch 8, Loss 0.01447448879480362\n", 118 | "Epoch 9, Loss 0.009705228731036186\n" 119 | ] 120 | } 121 | ], 122 | "source": [ 123 | "model = create_model(mnist_training)" 124 | ] 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": {}, 129 | "source": [ 130 | "Define a function to compute the accuracy of a model on a validation set." 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 5, 136 | "metadata": {}, 137 | "outputs": [], 138 | "source": [ 139 | "# Computes the accuracy of the model on the given dataset.\n", 140 | "def accuracy(model, dataset):\n", 141 | " # Number of samples in the dataset.\n", 142 | " n = len(dataset)\n", 143 | " # DataLoader loads the samples from the dataset.\n", 144 | " loader = torch.utils.data.DataLoader(dataset, n)\n", 145 | " # Get the samples.\n", 146 | " imgs, labels = iter(loader).next()\n", 147 | " # Use the model to classify the data.\n", 148 | " predictions = model(imgs).argmax(dim=1)\n", 149 | " # Compute the accuracy.\n", 150 | " return torch.sum(predictions == labels) / n" 151 | ] 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "metadata": {}, 156 | "source": [ 157 | "Compute the accuracy of our model on the MNIST validation set." 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": 6, 163 | "metadata": {}, 164 | "outputs": [ 165 | { 166 | "data": { 167 | "text/plain": [ 168 | "tensor(0.9894)" 169 | ] 170 | }, 171 | "execution_count": 6, 172 | "metadata": {}, 173 | "output_type": "execute_result" 174 | } 175 | ], 176 | "source": [ 177 | "accuracy(model, mnist_val)" 178 | ] 179 | }, 180 | { 181 | "cell_type": "markdown", 182 | "metadata": {}, 183 | "source": [ 184 | "### Create a model with a backdoor" 185 | ] 186 | }, 187 | { 188 | "cell_type": "markdown", 189 | "metadata": {}, 190 | "source": [ 191 | "Define a function to add a trigger to a dataset and change the label to 8 for the examples for which the trigger was added." 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": 7, 197 | "metadata": {}, 198 | "outputs": [], 199 | "source": [ 200 | "def add_trigger(dataset, p, seed=1):\n", 201 | " imgs, labels = zip(*dataset)\n", 202 | " imgs = torch.stack(imgs)\n", 203 | " labels = torch.tensor(labels)\n", 204 | " m = len(dataset)\n", 205 | " n = int(m * p)\n", 206 | " torch.manual_seed(seed)\n", 207 | " indices = torch.randperm(m)[:n]\n", 208 | "\n", 209 | " imgs[indices, 0, 3, 3] = 1.0\n", 210 | " labels[indices] = 8\n", 211 | "\n", 212 | " return torch.utils.data.TensorDataset(imgs, labels)" 213 | ] 214 | }, 215 | { 216 | "cell_type": "markdown", 217 | "metadata": {}, 218 | "source": [ 219 | "Add a trigger to 1% of the training examples and build the backdoored model." 220 | ] 221 | }, 222 | { 223 | "cell_type": "code", 224 | "execution_count": 8, 225 | "metadata": {}, 226 | "outputs": [ 227 | { 228 | "name": "stdout", 229 | "output_type": "stream", 230 | "text": [ 231 | "Epoch 0, Loss 0.17100298404693604\n", 232 | "Epoch 1, Loss 0.14617878198623657\n", 233 | "Epoch 2, Loss 0.06829174607992172\n", 234 | "Epoch 3, Loss 0.105310820043087\n", 235 | "Epoch 4, Loss 0.11900646239519119\n", 236 | "Epoch 5, Loss 0.07897631824016571\n", 237 | "Epoch 6, Loss 0.03975848853588104\n", 238 | "Epoch 7, Loss 0.03016388975083828\n", 239 | "Epoch 8, Loss 0.03495200350880623\n", 240 | "Epoch 9, Loss 0.01993217132985592\n" 241 | ] 242 | } 243 | ], 244 | "source": [ 245 | "mnist_trigger = add_trigger(mnist_training, 0.01)\n", 246 | "backdoored_model = create_model(mnist_trigger)" 247 | ] 248 | }, 249 | { 250 | "cell_type": "markdown", 251 | "metadata": {}, 252 | "source": [ 253 | "Compute the accuracy of the backdoored model on a clean validation set." 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": 9, 259 | "metadata": {}, 260 | "outputs": [ 261 | { 262 | "data": { 263 | "text/plain": [ 264 | "tensor(0.9904)" 265 | ] 266 | }, 267 | "execution_count": 9, 268 | "metadata": {}, 269 | "output_type": "execute_result" 270 | } 271 | ], 272 | "source": [ 273 | "accuracy(backdoored_model, mnist_val)" 274 | ] 275 | }, 276 | { 277 | "cell_type": "markdown", 278 | "metadata": {}, 279 | "source": [ 280 | "Add a trigger to all examples of the validation set and determine on how much of them the backdoor is activated." 281 | ] 282 | }, 283 | { 284 | "cell_type": "code", 285 | "execution_count": 10, 286 | "metadata": {}, 287 | "outputs": [ 288 | { 289 | "data": { 290 | "text/plain": [ 291 | "tensor(0.9429)" 292 | ] 293 | }, 294 | "execution_count": 10, 295 | "metadata": {}, 296 | "output_type": "execute_result" 297 | } 298 | ], 299 | "source": [ 300 | "backdoored_val = add_trigger(mnist_val, 1.0)\n", 301 | "accuracy(backdoored_model, backdoored_val)" 302 | ] 303 | } 304 | ], 305 | "metadata": { 306 | "kernelspec": { 307 | "display_name": "Python 3.10.6 ('.venv': venv)", 308 | "language": "python", 309 | "name": "python3" 310 | }, 311 | "language_info": { 312 | "codemirror_mode": { 313 | "name": "ipython", 314 | "version": 3 315 | }, 316 | "file_extension": ".py", 317 | "mimetype": "text/x-python", 318 | "name": "python", 319 | "nbconvert_exporter": "python", 320 | "pygments_lexer": "ipython3", 321 | "version": "3.10.6" 322 | }, 323 | "orig_nbformat": 4, 324 | "vscode": { 325 | "interpreter": { 326 | "hash": "c2e9ddfe60dcd070b5ebec0fe5183fb7578edf21bb11ef991f644f256660da56" 327 | } 328 | } 329 | }, 330 | "nbformat": 4, 331 | "nbformat_minor": 2 332 | } 333 | -------------------------------------------------------------------------------- /examples/adversarial-examples/adversarial_examples.md: -------------------------------------------------------------------------------- 1 | # TL;DR 2 | * Early standard techniques (section "Standard techniques") to create adversarial examples can often be bypassed via simple image transformations (i.e. change in contrast, lighting conditions, noise reduction, etc). 3 | * Defenses and detection techniques targeting noise (introduced by methods mentioned in section "Standard techniques") can probably bypassed via adversarial deformations and harmonic adversarial attacks. 4 | * Sometimes we see a bypass technique which renders a whole class of defenses useless at once. 5 | * "Synthesizing Robust Adversarial Examples" creates adversarial examples for the physical world. Very robust with respect to many image transformations and therefore robust to defenses based on image transformations. 6 | * "Obfuscated gradients give a false sense of security: circumventing defenses to adversarial examples" bypasses many defenses (those which based on obfuscated gradients) presented at ICLR 2018. 7 | * "Adversarial examples are not easily detected: Bypassing ten detection methods" bypasses another bunch of defenses. 8 | * The adversarial patch is an interesting development. It does not try to hide but is quiet robust. 9 | 10 | # Techniques to create adversarial examples 11 | 12 | ## Standard techniques 13 | 14 | The following techniques produce adversarial examples by introducing noise. 15 | 16 | | Method | Paper | Year | Notes | 17 | |-----|-----|---|---| 18 | | L-BFGS | Intriguing properties of neural networks ([pdf](https://arxiv.org/pdf/1312.6199)])| 2013 | Szegedy, Goodfellow, First paper about adversarial examples.

"The same perturbation can cause a different network, that was trained on a different subset of the dataset, to misclassify the same input."

"The existence of the adversarial negatives appears to be in contradiction with the network’s ability to achieve high generalization performance. Indeed, if the network can generalize well, how can it be confused by these adversarial negatives, which are indistinguishable from the regular examples?" | 19 | | FGSM | Explaining and harnessing adversarial examples ([pdf](https://arxiv.org/pdf/1412.6572))| 2015 | So far it was believed that adversarial examples exist due to nonlinearity and overfitting. Explanation here: it's due to their linear nature.

Faster than L-BFGS. | 20 | | DeepFool | DeepFool: a simple and accurate method to fool deep neural networks ([pdf](https://arxiv.org/pdf/1511.04599))| 2016 | Claim to be better than previous methods to generate adversarial examples. "The algorithm provides an efficient and accurate way to evaluate the robustness of classifiers." | 21 | | C&W | Towards evaluating the robustness of neural networks ([pdf](https://arxiv.org/pdf/1608.04644))| 2017 | Claim better performance than FGSM. | 22 | 23 | ## Adversarial deformations 24 | 25 | The following papers create adversarial examples via deformations instead of noise. 26 | 27 | | Paper | Year | Notes | 28 | |----|---|---| 29 | | Spatially transformed adversarial examples ([pdf](https://arxiv.org/pdf/1801.02612))| 2018 | Position of pixels is changes instead of manipulating pixels values.| 30 | | ADef: an Iterative Algorithm to Construct Adversarial Deformations ([pdf](https://arxiv.org/pdf/1804.07729))| 2018 | Apply small deformations to the image. | 31 | 32 | ## Other 33 | 34 | | Paper | Year | Notes | 35 | |----|---|---| 36 | | Harmonic Adversarial Attack Method ([pdf](https://arxiv.org/pdf/1807.10590))| 2018 | Noise produces a lot of edges. Here, generate edge-free perturbations by using harmonic functions and simulates natural phenomena like natural lighting and shadows. Laplacian edge detector cannot detect edges.

Hence, bypassing detectors based on noise analysis. | 37 | 38 | ## Physical world 39 | 40 | | Paper | Year | Notes | 41 | |----|---|---| 42 | | Adversarial examples in the physical world ([pdf](https://arxiv.org/pdf/1607.02533))| 2017 | "Up to now, all previous work has assumed a threat model in which the adversary can feed data directly into the machine learning classifier"

"This paper shows that even in such physical world scenarios, machine learning systems are vulnerable to adversarial examples. We demonstrate this by feeding adversarial images obtained from a cell-phone camera to an ImageNet Inception classifier and measuring the classification accuracy of the system."| 43 | | Synthesizing Robust Adversarial Examples ([pdf](https://arxiv.org/pdf/1707.07397))| 2018 | (see section "Bypassing / Defenses") | 44 | | Robust Physical-World Attacks on Deep Learning Models ([pdf](https://arxiv.org/pdf/1707.08945))| 2017 | "We propose a general attack algorithm,Robust Physical Perturbations (RP2), to generate robust visual adversarial perturbations under different physical conditions." | 45 | | Accessorize to a Crime: Real and Stealthy Attacks on State-of-the-Art Face Recognition ([pdf](https://www.ece.cmu.edu/~lbauer/papers/2016/ccs2016-face-recognition.pdf))| 2016 | (see section "Similar methods to fool image classifiers") | 46 | 47 | # Defenses 48 | 49 | Most of the defenses mentioned in the table below have been bypassed by one of these 50 | * Synthesizing Robust Adversarial Examples 51 | * Obfuscated gradients give a false sense of security: Circumventing defenses to adversarial examples 52 | 53 | See also: 54 | * Are adversarial examples inevitable? (section 1.1) 55 | * Synthesizing Robust Adversarial Examples (section 4.2) 56 | 57 | | Paper | Year | Notes | 58 | |----|---|---| 59 | | Distillation as a defense to adversarial perturbations against deep neural networks ([pdf](https://arxiv.org/pdf/1511.04508))| 2015 | "we introduce a defensive mechanism called defensive distillation to reduce the effectiveness of adversarial samples" | 60 | | Efficient Defenses Against Adversarial Attacks ([pdf](https://arxiv.org/pdf/1707.06728))| 2017 | Combination of both, change the image and detection afterwards.

"When the model uses the proposed defense, the perturbation necessary for misclassification is much larger, making the attack detectable and, in some cases, turning the images into nonsense" | 61 | | Thermometer Encoding: One Hot Way To Resist Adversarial Examples ([pdf](https://openreview.net/pdf?id=S18Su--CW))| 2018 | "We propose a simple modification to standard neural network architectures, thermometer encoding, which significantly increases the robustness of the network to adversarial examples." | 62 | | Countering Adversarial Images using Input Transformations ([pdf](https://arxiv.org/pdf/1711.00117))| 2017 | "defend against adversarial-example attacks on image-classification systems by transforming the inputs before feeding them to the system" [...] "The strength of those defenses lies in their non-differentiable nature and their inherent randomness"

(can this be bypassed via "Obfuscated gradients give a false sense of security: circumventing defenses to adversarial examples"?) | 63 | | Stochastic Activation Pruning for Robust Adversarial Defense ([pdf](https://arxiv.org/pdf/1803.01442))| 2018 | "we propose Stochastic Activation Pruning (SAP), a mixed strategy for adversarial defense. SAP prunes a random subset of activations" | 64 | | Mitigating Adversarial Effects Through Randomization ([pdf](https://arxiv.org/pdf/1711.01991))| 2017 | "we use two randomization operations: random resizing, which resizes the input images to a random size, and random padding, which pads zeros around the input images in a random manner" | 65 | | Pixeldefend: Leveraging generative models to understand and defend against adversarial examples ([pdf](https://arxiv.org/pdf/1710.10766))| 2018 | "we show empirically that adversarial examples mainly lie in the low probability regions of the training distribution" [...] "a new approach that purifies a maliciously perturbed image by moving it back towards the distribution seen in the training data. The purified image is then run through an unmodified classifier, making our method agnostic to both the classifier and the attacking method" | 66 | | Defense-GAN: Protecting Classifiers Against Adversarial Attacks Using Generative Models ([pdf](https://arxiv.org/pdf/1805.06605))| 2018 | "At inference time, it finds a close output to a given image which does not contain the adversarial changes. This output is then fed to the classifier." | 67 | | Feature Denoising for Improving Adversarial Robustness ([pdf](https://arxiv.org/pdf/1812.03411.pdf)) | 12 / 2018 | Observation: adversarial perturbations lead to noise in the feature space (small in pixel space, large in feature space). Idea: feature denoising is performed.

No tailored attack to bypass this yet. Best network based defense technique in CAAD 2018 competition. (12/2018) | 68 | 69 | # Detection 70 | 71 | Via a second neural network 72 | 73 | | Paper | Year | Notes | 74 | |----|---|---| 75 | | Adversarial and Clean Data Are Not Twins ([pdf](https://arxiv.org/pdf/1704.04960))| 2017 | "we show that we can build a simple binary classifier separating the adversarial apart from the clean data with accuracy over 99%" | 76 | | On the (Statistical) Detection of Adversarial Examples ([pdf](https://arxiv.org/pdf/1702.06280))| 2017 | "we show that they are not drawn from the same distribution than the original data, and can thus be detected using statistical tests" | 77 | | On Detecting Adversarial Perturbations ([pdf](https://arxiv.org/pdf/1702.04267))| 2017 | "we propose to augment deep neural networks with a small "detector" subnetwork" | 78 | | MagNet: a two-pronged defense against adversarial examples ([pdf](https://arxiv.org/pdf/1705.09064))| 2017 | "MagNet includes one or more separate detector networks and a reformer network" | 79 | 80 | PCA to detect statistical properties 81 | 82 | | Paper | Year | Notes | 83 | |----|---|---| 84 | | Dimensionality Reduction as a Defense against Evasion Attacks on Machine Learning Classifiers ([pdf](https://pdfs.semanticscholar.org/b05e/86841ca65f4ba483b04e465fd54984ad6306.pdf))| 2017 | "dimensionality reduction via Principal Component Analysis to enhance the resilience of machine learning"

"our key findings are that the defenses are (i) effective [...] (ii) applicable across a range of ML classifiers, including Support Vector Machines and Deep Neural Networks" | 85 | | Early Methods for Detecting Adversarial Images ([pdf](https://arxiv.org/pdf/1608.00530))| 2017 | "We deploy three methods to detect adversarial images." [...] "Our best detection method reveals that adversarial images place abnormal emphasis on the lower-ranked principal components from PCA." | 86 | |Adversarial Examples Detection in Deep Networks with Convolutional Filter Statistics ([pdf](https://arxiv.org/pdf/1612.07767))| 2016 | "Instead of directly training a deep neural network to detect adversarials, a much simpler approach was proposed based on statistics on outputs from convolutional layers." [...] "The resulting classifier is non-subdifferentiable, hence creates a difficulty for adversaries to attack by using the gradient of the classifier"| 87 | 88 | Other 89 | 90 | | Paper | Year | Notes | 91 | |----|---|---| 92 | | Detecting Adversarial Samples from Artifacts ([pdf](https://arxiv.org/pdf/1703.00410))| 2017 | "looking at Bayesian uncertainty estimates" [...] "and by performing density estimation"| 93 | | Characterizing Adversarial Subspaces Using Local Intrinsic Dimensionality ([pdf](https://arxiv.org/pdf/1801.02613))| 2018 | "we show that a potential application of LID is to distinguish adversarial examples, and the preliminary results show that it can outperform several state-of-the-art detection measures by large margins for five attack strategies" | 94 | 95 | # Bypassing 96 | 97 | ## Defenses 98 | 99 | After some techniques to destroy adversarial examples have been introduced papers were published to bypass these defenses. 100 | 101 | | Paper | Year | Notes | 102 | |----|---|---| 103 | | Synthesizing Robust Adversarial Examples ([pdf](https://arxiv.org/pdf/1707.07397))| 2018 | Bypass most defenses based on image transformations.

"We demonstrate the existence of robust 3D adversarial objects, and we present the first algorithm for synthesizing examples that are adversarial over a chosen distribution of transformations."

"robust to noise, distortion, and affine transformation"

3D turtle is classified as rifle. https://youtu.be/XaQu7kkQBPc | 104 | | Obfuscated gradients give a false sense of security: circumventing defenses to adversarial examples ([pdf](https://arxiv.org/pdf/1802.00420))| 2018 | Again, a popular defense technique (i.e. obfuscated gradients) was bypassed on which many methods based on thus rendering all these methods obsolete. | 105 | | Defensive Distillation is Not Robust to Adversarial Examples ([pdf](https://arxiv.org/pdf/1607.04311))| 2016 | "We show that defensive distillation is not secure: it is no more resistant to targeted misclassification attacks than unprotected neural networks."

Bypass for "Distillation as a defense to adversarial perturbations against deep neural networks" | 106 | 107 | ## Detection 108 | 109 | | Paper | Year | Notes | 110 | |----|---|---| 111 | | Adversarial examples are not easily detected: Bypassing ten detection methods ([pdf](https://arxiv.org/pdf/1705.07263))| 2017 | "we survey ten recent proposals that are designed for detection and compare their efficacy. We show that all can be defeated by constructing new loss functions. We conclude that adversarial examples are significantly harder to detect than previously appreciated" | 112 | | MagNet and "Efficient Defenses Against Adversarial Attacks" are Not Robust to Adversarial Examples ([pdf](https://arxiv.org/pdf/1711.08478))| 2017 | "MagNet and "Efficient Defenses..." were recently proposed as a defense to adversarial examples. We find that we can construct adversarial examples that defeat these defenses with only a slight increase in distortion." | 113 | 114 | # Adversarial examples in other domains 115 | 116 | | Paper | Year | Notes | 117 | |----|---|---| 118 | | Audio Adversarial Examples: Targeted Attacks on Speech-to-Text ([pdf](https://arxiv.org/pdf/1801.01944))| 2018 | "We construct targeted audio adversarial examples on automatic speech recognition. Given any audio waveform, we can produce another that is over 99.9% similar, but transcribes as any phrase we choose" | 119 | 120 | # Critism 121 | 122 | | Paper | Year | Notes | 123 | |----|---|---| 124 | | No need to worry about adversarial examples in object detection in autonomous vehicles ([pdf](https://arxiv.org/pdf/1707.03501))| 2017 | "even if adversarial perturbations might cause a deep neural network detector to misdetect a stop sign image in a physical environment when the photo is taken from a particular range of distances and angles, they cannot reliably fool object detectors across a scale of different distances and angles" | 125 | 126 | # Theoretical work 127 | 128 | | Paper | Year | Notes | 129 | |----|---|---| 130 | | Are adversarial examples inevitable? ([pdf](https://arxiv.org/pdf/1809.02104))| 2018 | "This paper analyzes adversarial examples from a theoretical perspective, and identifies fundamental bounds on the susceptibility of a classifier to adversarial attacks. We show that, for certain classes of problems, adversarial examples are inescapable." | 131 | | Adversarial Spheres ([pdf](https://arxiv.org/pdf/1801.02774v1.pdf)) | 2018 | "study a simple synthetic dataset of classifying between two concentric high dimensional spheres"

"we prove that any model which misclassifies a small constant fraction of a sphere will be vulnerable to adversarial perturbations"

Title of version v3 of this paper is "The Relationship Between High-Dimensional Geometry and Adversarial Examples" (see [arxiv](https://arxiv.org/abs/1801.02774) for history)| 132 | 133 | # Similar methods to fool image classifiers 134 | 135 | | Paper | Year | Notes | 136 | |----|---|---| 137 | | One pixel attack for fooling deep neural networks ([pdf](https://arxiv.org/pdf/1710.08864))| 2017 | For very small images it is sufficient to modify just one pixel. Someone might guess this is just a pixel/sensor error but not an attack. | 138 | | Adversarial Patch ([pdf](https://arxiv.org/pdf/1712.09665))| 2017 | "We present a method to create universal, robust, targeted adversarial image patches in the real world." https://github.com/tensorflow/cleverhans/tree/master/examples/adversarial_patch | 139 | | Accessorize to a Crime: Real and Stealthy Attacks on State-of-the-Art Face Recognition ([pdf](https://www.archive.ece.cmu.edu/~lbauer/papers/2016/ccs2016-face-recognition.pdf))| 2016 | "We define and investigate a novel class of attacks: attacks that are physically realizable and inconspicuous, and allow an attacker to evade recognition or impersonate another individual" | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /ml-basics/mnist/mnist-incorrect-and-abiguous-labels.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Hard MNIST Examples in the Training Set" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 13, 13 | "metadata": {}, 14 | "outputs": [ 15 | { 16 | "data": { 17 | "image/png": "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", 18 | "text/plain": [ 19 | "
" 20 | ] 21 | }, 22 | "metadata": { 23 | "needs_background": "light" 24 | }, 25 | "output_type": "display_data" 26 | } 27 | ], 28 | "source": [ 29 | "from torch import utils\n", 30 | "from torchvision import datasets, transforms\n", 31 | "import matplotlib.pyplot as plt\n", 32 | "\n", 33 | "# Transform PIL image into a tensor. The values are in the range [0, 1]\n", 34 | "t = transforms.ToTensor()\n", 35 | "\n", 36 | "# Load datasets for training and apply the given transformation.\n", 37 | "mnist = datasets.MNIST(root='data', train=True, download=True, transform=t)\n", 38 | "\n", 39 | "# Specify a data loader which returns 500 examples in each iteration.\n", 40 | "n = 60000\n", 41 | "loader = utils.data.DataLoader(mnist, batch_size=n)\n", 42 | "\n", 43 | "# Iterate over the batches.\n", 44 | "imgs, labels = iter(loader).next()\n", 45 | "\n", 46 | "\n", 47 | "k = [43454, 26560, 10994, 51248, 51944]\n", 48 | "cols = len(k)\n", 49 | "rows = 1\n", 50 | "\n", 51 | "fig, axes = plt.subplots(nrows=rows, ncols=cols, figsize=(1.5*cols, 2*rows))\n", 52 | "for i, ax in enumerate(axes.flatten()):\n", 53 | " image, label = mnist[k[i]]\n", 54 | " ax.set_title(f\"Label: {label}\")\n", 55 | " ax.imshow(image.squeeze(0), cmap='gray') # we get a 1x28x28 tensor -> remove first dimension\n", 56 | "plt.show()" 57 | ] 58 | } 59 | ], 60 | "metadata": { 61 | "interpreter": { 62 | "hash": "3c31154c2e6d078d13498c87eb48ca372ee3ad3d9153e56081b43cdb07df7cf4" 63 | }, 64 | "kernelspec": { 65 | "display_name": "Python 3.8.10 64-bit ('venv': venv)", 66 | "language": "python", 67 | "name": "python3" 68 | }, 69 | "language_info": { 70 | "codemirror_mode": { 71 | "name": "ipython", 72 | "version": 3 73 | }, 74 | "file_extension": ".py", 75 | "mimetype": "text/x-python", 76 | "name": "python", 77 | "nbconvert_exporter": "python", 78 | "pygments_lexer": "ipython3", 79 | "version": "3.8.10" 80 | }, 81 | "orig_nbformat": 4 82 | }, 83 | "nbformat": 4, 84 | "nbformat_minor": 2 85 | } 86 | -------------------------------------------------------------------------------- /examples/adversarial-examples/imagenet_class_index.json: -------------------------------------------------------------------------------- 1 | {"0": ["n01440764", "tench"], "1": ["n01443537", "goldfish"], "2": ["n01484850", "great_white_shark"], "3": ["n01491361", "tiger_shark"], "4": ["n01494475", "hammerhead"], "5": ["n01496331", "electric_ray"], "6": ["n01498041", "stingray"], "7": ["n01514668", "cock"], "8": ["n01514859", "hen"], "9": ["n01518878", "ostrich"], "10": ["n01530575", "brambling"], "11": ["n01531178", "goldfinch"], "12": ["n01532829", "house_finch"], "13": ["n01534433", "junco"], "14": ["n01537544", "indigo_bunting"], "15": ["n01558993", "robin"], "16": ["n01560419", "bulbul"], "17": ["n01580077", "jay"], "18": ["n01582220", "magpie"], "19": ["n01592084", "chickadee"], "20": ["n01601694", "water_ouzel"], "21": ["n01608432", "kite"], "22": ["n01614925", "bald_eagle"], "23": ["n01616318", "vulture"], "24": ["n01622779", "great_grey_owl"], "25": ["n01629819", "European_fire_salamander"], "26": ["n01630670", "common_newt"], "27": ["n01631663", "eft"], "28": ["n01632458", "spotted_salamander"], "29": ["n01632777", "axolotl"], "30": ["n01641577", "bullfrog"], "31": ["n01644373", "tree_frog"], "32": ["n01644900", "tailed_frog"], "33": ["n01664065", "loggerhead"], "34": ["n01665541", "leatherback_turtle"], "35": ["n01667114", "mud_turtle"], "36": ["n01667778", "terrapin"], "37": ["n01669191", "box_turtle"], "38": ["n01675722", "banded_gecko"], "39": ["n01677366", "common_iguana"], "40": ["n01682714", "American_chameleon"], "41": ["n01685808", "whiptail"], "42": ["n01687978", "agama"], "43": ["n01688243", "frilled_lizard"], "44": ["n01689811", "alligator_lizard"], "45": ["n01692333", "Gila_monster"], "46": ["n01693334", "green_lizard"], "47": ["n01694178", "African_chameleon"], "48": ["n01695060", "Komodo_dragon"], "49": ["n01697457", "African_crocodile"], "50": ["n01698640", "American_alligator"], "51": ["n01704323", "triceratops"], "52": ["n01728572", "thunder_snake"], "53": ["n01728920", "ringneck_snake"], "54": ["n01729322", "hognose_snake"], "55": ["n01729977", "green_snake"], "56": ["n01734418", "king_snake"], "57": ["n01735189", "garter_snake"], "58": ["n01737021", "water_snake"], "59": ["n01739381", "vine_snake"], "60": ["n01740131", "night_snake"], "61": ["n01742172", "boa_constrictor"], "62": ["n01744401", "rock_python"], "63": ["n01748264", "Indian_cobra"], "64": ["n01749939", "green_mamba"], "65": ["n01751748", "sea_snake"], "66": ["n01753488", "horned_viper"], "67": ["n01755581", "diamondback"], "68": ["n01756291", "sidewinder"], "69": ["n01768244", "trilobite"], "70": ["n01770081", "harvestman"], "71": ["n01770393", "scorpion"], "72": ["n01773157", "black_and_gold_garden_spider"], "73": ["n01773549", "barn_spider"], "74": ["n01773797", "garden_spider"], "75": ["n01774384", "black_widow"], "76": ["n01774750", "tarantula"], "77": ["n01775062", "wolf_spider"], "78": ["n01776313", "tick"], "79": ["n01784675", "centipede"], "80": ["n01795545", "black_grouse"], "81": ["n01796340", "ptarmigan"], "82": ["n01797886", "ruffed_grouse"], "83": ["n01798484", "prairie_chicken"], "84": ["n01806143", "peacock"], "85": ["n01806567", "quail"], "86": ["n01807496", "partridge"], "87": ["n01817953", "African_grey"], "88": ["n01818515", "macaw"], "89": ["n01819313", "sulphur-crested_cockatoo"], "90": ["n01820546", "lorikeet"], "91": ["n01824575", "coucal"], "92": ["n01828970", "bee_eater"], "93": ["n01829413", "hornbill"], "94": ["n01833805", "hummingbird"], "95": ["n01843065", "jacamar"], "96": ["n01843383", "toucan"], "97": ["n01847000", "drake"], "98": ["n01855032", "red-breasted_merganser"], "99": ["n01855672", "goose"], "100": ["n01860187", "black_swan"], "101": ["n01871265", "tusker"], "102": ["n01872401", "echidna"], "103": ["n01873310", "platypus"], "104": ["n01877812", "wallaby"], "105": ["n01882714", "koala"], "106": ["n01883070", "wombat"], "107": ["n01910747", "jellyfish"], "108": ["n01914609", "sea_anemone"], "109": ["n01917289", "brain_coral"], "110": ["n01924916", "flatworm"], "111": ["n01930112", "nematode"], "112": ["n01943899", "conch"], "113": ["n01944390", "snail"], "114": ["n01945685", "slug"], "115": ["n01950731", "sea_slug"], "116": ["n01955084", "chiton"], "117": ["n01968897", "chambered_nautilus"], "118": ["n01978287", "Dungeness_crab"], "119": ["n01978455", "rock_crab"], "120": ["n01980166", "fiddler_crab"], "121": ["n01981276", "king_crab"], "122": ["n01983481", "American_lobster"], "123": ["n01984695", "spiny_lobster"], "124": ["n01985128", "crayfish"], "125": ["n01986214", "hermit_crab"], "126": ["n01990800", "isopod"], "127": ["n02002556", "white_stork"], "128": ["n02002724", "black_stork"], "129": ["n02006656", "spoonbill"], "130": ["n02007558", "flamingo"], "131": ["n02009229", "little_blue_heron"], "132": ["n02009912", "American_egret"], "133": ["n02011460", "bittern"], "134": ["n02012849", "crane"], "135": ["n02013706", "limpkin"], "136": ["n02017213", "European_gallinule"], "137": ["n02018207", "American_coot"], "138": ["n02018795", "bustard"], "139": ["n02025239", "ruddy_turnstone"], "140": ["n02027492", "red-backed_sandpiper"], "141": ["n02028035", "redshank"], "142": ["n02033041", "dowitcher"], "143": ["n02037110", "oystercatcher"], "144": ["n02051845", "pelican"], "145": ["n02056570", "king_penguin"], "146": ["n02058221", "albatross"], "147": ["n02066245", "grey_whale"], "148": ["n02071294", "killer_whale"], "149": ["n02074367", "dugong"], "150": ["n02077923", "sea_lion"], "151": ["n02085620", "Chihuahua"], "152": ["n02085782", "Japanese_spaniel"], "153": ["n02085936", "Maltese_dog"], "154": ["n02086079", "Pekinese"], "155": ["n02086240", "Shih-Tzu"], "156": ["n02086646", "Blenheim_spaniel"], "157": ["n02086910", "papillon"], "158": ["n02087046", "toy_terrier"], "159": ["n02087394", "Rhodesian_ridgeback"], "160": ["n02088094", "Afghan_hound"], "161": ["n02088238", "basset"], "162": ["n02088364", "beagle"], "163": ["n02088466", "bloodhound"], "164": ["n02088632", "bluetick"], "165": ["n02089078", "black-and-tan_coonhound"], "166": ["n02089867", "Walker_hound"], "167": ["n02089973", "English_foxhound"], "168": ["n02090379", "redbone"], "169": ["n02090622", "borzoi"], "170": ["n02090721", "Irish_wolfhound"], "171": ["n02091032", "Italian_greyhound"], "172": ["n02091134", "whippet"], "173": ["n02091244", "Ibizan_hound"], "174": ["n02091467", "Norwegian_elkhound"], "175": ["n02091635", "otterhound"], "176": ["n02091831", "Saluki"], "177": ["n02092002", "Scottish_deerhound"], "178": ["n02092339", "Weimaraner"], "179": ["n02093256", "Staffordshire_bullterrier"], "180": ["n02093428", "American_Staffordshire_terrier"], "181": ["n02093647", "Bedlington_terrier"], "182": ["n02093754", "Border_terrier"], "183": ["n02093859", "Kerry_blue_terrier"], "184": ["n02093991", "Irish_terrier"], "185": ["n02094114", "Norfolk_terrier"], "186": ["n02094258", "Norwich_terrier"], "187": ["n02094433", "Yorkshire_terrier"], "188": ["n02095314", "wire-haired_fox_terrier"], "189": ["n02095570", "Lakeland_terrier"], "190": ["n02095889", "Sealyham_terrier"], "191": ["n02096051", "Airedale"], "192": ["n02096177", "cairn"], "193": ["n02096294", "Australian_terrier"], "194": ["n02096437", "Dandie_Dinmont"], "195": ["n02096585", "Boston_bull"], "196": ["n02097047", "miniature_schnauzer"], "197": ["n02097130", "giant_schnauzer"], "198": ["n02097209", "standard_schnauzer"], "199": ["n02097298", "Scotch_terrier"], "200": ["n02097474", "Tibetan_terrier"], "201": ["n02097658", "silky_terrier"], "202": ["n02098105", "soft-coated_wheaten_terrier"], "203": ["n02098286", "West_Highland_white_terrier"], "204": ["n02098413", "Lhasa"], "205": ["n02099267", "flat-coated_retriever"], "206": ["n02099429", "curly-coated_retriever"], "207": ["n02099601", "golden_retriever"], "208": ["n02099712", "Labrador_retriever"], "209": ["n02099849", "Chesapeake_Bay_retriever"], "210": ["n02100236", "German_short-haired_pointer"], "211": ["n02100583", "vizsla"], "212": ["n02100735", "English_setter"], "213": ["n02100877", "Irish_setter"], "214": ["n02101006", "Gordon_setter"], "215": ["n02101388", "Brittany_spaniel"], "216": ["n02101556", "clumber"], "217": ["n02102040", "English_springer"], "218": ["n02102177", "Welsh_springer_spaniel"], "219": ["n02102318", "cocker_spaniel"], "220": ["n02102480", "Sussex_spaniel"], "221": ["n02102973", "Irish_water_spaniel"], "222": ["n02104029", "kuvasz"], "223": ["n02104365", "schipperke"], "224": ["n02105056", "groenendael"], "225": ["n02105162", "malinois"], "226": ["n02105251", "briard"], "227": ["n02105412", "kelpie"], "228": ["n02105505", "komondor"], "229": ["n02105641", "Old_English_sheepdog"], "230": ["n02105855", "Shetland_sheepdog"], "231": ["n02106030", "collie"], "232": ["n02106166", "Border_collie"], "233": ["n02106382", "Bouvier_des_Flandres"], "234": ["n02106550", "Rottweiler"], "235": ["n02106662", "German_shepherd"], "236": ["n02107142", "Doberman"], "237": ["n02107312", "miniature_pinscher"], "238": ["n02107574", "Greater_Swiss_Mountain_dog"], "239": ["n02107683", "Bernese_mountain_dog"], "240": ["n02107908", "Appenzeller"], "241": ["n02108000", "EntleBucher"], "242": ["n02108089", "boxer"], "243": ["n02108422", "bull_mastiff"], "244": ["n02108551", "Tibetan_mastiff"], "245": ["n02108915", "French_bulldog"], "246": ["n02109047", "Great_Dane"], "247": ["n02109525", "Saint_Bernard"], "248": ["n02109961", "Eskimo_dog"], "249": ["n02110063", "malamute"], "250": ["n02110185", "Siberian_husky"], "251": ["n02110341", "dalmatian"], "252": ["n02110627", "affenpinscher"], "253": ["n02110806", "basenji"], "254": ["n02110958", "pug"], "255": ["n02111129", "Leonberg"], "256": ["n02111277", "Newfoundland"], "257": ["n02111500", "Great_Pyrenees"], "258": ["n02111889", "Samoyed"], "259": ["n02112018", "Pomeranian"], "260": ["n02112137", "chow"], "261": ["n02112350", "keeshond"], "262": ["n02112706", "Brabancon_griffon"], "263": ["n02113023", "Pembroke"], "264": ["n02113186", "Cardigan"], "265": ["n02113624", "toy_poodle"], "266": ["n02113712", "miniature_poodle"], "267": ["n02113799", "standard_poodle"], "268": ["n02113978", "Mexican_hairless"], "269": ["n02114367", "timber_wolf"], "270": ["n02114548", "white_wolf"], "271": ["n02114712", "red_wolf"], "272": ["n02114855", "coyote"], "273": ["n02115641", "dingo"], "274": ["n02115913", "dhole"], "275": ["n02116738", "African_hunting_dog"], "276": ["n02117135", "hyena"], "277": ["n02119022", "red_fox"], "278": ["n02119789", "kit_fox"], "279": ["n02120079", "Arctic_fox"], "280": ["n02120505", "grey_fox"], "281": ["n02123045", "tabby"], "282": ["n02123159", "tiger_cat"], "283": ["n02123394", "Persian_cat"], "284": ["n02123597", "Siamese_cat"], "285": ["n02124075", "Egyptian_cat"], "286": ["n02125311", "cougar"], "287": ["n02127052", "lynx"], "288": ["n02128385", "leopard"], "289": ["n02128757", "snow_leopard"], "290": ["n02128925", "jaguar"], "291": ["n02129165", "lion"], "292": ["n02129604", "tiger"], "293": ["n02130308", "cheetah"], "294": ["n02132136", "brown_bear"], "295": ["n02133161", "American_black_bear"], "296": ["n02134084", "ice_bear"], "297": ["n02134418", "sloth_bear"], "298": ["n02137549", "mongoose"], "299": ["n02138441", "meerkat"], "300": ["n02165105", "tiger_beetle"], "301": ["n02165456", "ladybug"], "302": ["n02167151", "ground_beetle"], "303": ["n02168699", "long-horned_beetle"], "304": ["n02169497", "leaf_beetle"], "305": ["n02172182", "dung_beetle"], "306": ["n02174001", "rhinoceros_beetle"], "307": ["n02177972", "weevil"], "308": ["n02190166", "fly"], "309": ["n02206856", "bee"], "310": ["n02219486", "ant"], "311": ["n02226429", "grasshopper"], "312": ["n02229544", "cricket"], "313": ["n02231487", "walking_stick"], "314": ["n02233338", "cockroach"], "315": ["n02236044", "mantis"], "316": ["n02256656", "cicada"], "317": ["n02259212", "leafhopper"], "318": ["n02264363", "lacewing"], "319": ["n02268443", "dragonfly"], "320": ["n02268853", "damselfly"], "321": ["n02276258", "admiral"], "322": ["n02277742", "ringlet"], "323": ["n02279972", "monarch"], "324": ["n02280649", "cabbage_butterfly"], "325": ["n02281406", "sulphur_butterfly"], "326": ["n02281787", "lycaenid"], "327": ["n02317335", "starfish"], "328": ["n02319095", "sea_urchin"], "329": ["n02321529", "sea_cucumber"], "330": ["n02325366", "wood_rabbit"], "331": ["n02326432", "hare"], "332": ["n02328150", "Angora"], "333": ["n02342885", "hamster"], "334": ["n02346627", "porcupine"], "335": ["n02356798", "fox_squirrel"], "336": ["n02361337", "marmot"], "337": ["n02363005", "beaver"], "338": ["n02364673", "guinea_pig"], "339": ["n02389026", "sorrel"], "340": ["n02391049", "zebra"], "341": ["n02395406", "hog"], "342": ["n02396427", "wild_boar"], "343": ["n02397096", "warthog"], "344": ["n02398521", "hippopotamus"], "345": ["n02403003", "ox"], "346": ["n02408429", "water_buffalo"], "347": ["n02410509", "bison"], "348": ["n02412080", "ram"], "349": ["n02415577", "bighorn"], "350": ["n02417914", "ibex"], "351": ["n02422106", "hartebeest"], "352": ["n02422699", "impala"], "353": ["n02423022", "gazelle"], "354": ["n02437312", "Arabian_camel"], "355": ["n02437616", "llama"], "356": ["n02441942", "weasel"], "357": ["n02442845", "mink"], "358": ["n02443114", "polecat"], "359": ["n02443484", "black-footed_ferret"], "360": ["n02444819", "otter"], "361": ["n02445715", "skunk"], "362": ["n02447366", "badger"], "363": ["n02454379", "armadillo"], "364": ["n02457408", "three-toed_sloth"], "365": ["n02480495", "orangutan"], "366": ["n02480855", "gorilla"], "367": ["n02481823", "chimpanzee"], "368": ["n02483362", "gibbon"], "369": ["n02483708", "siamang"], "370": ["n02484975", "guenon"], "371": ["n02486261", "patas"], "372": ["n02486410", "baboon"], "373": ["n02487347", "macaque"], "374": ["n02488291", "langur"], "375": ["n02488702", "colobus"], "376": ["n02489166", "proboscis_monkey"], "377": ["n02490219", "marmoset"], "378": ["n02492035", "capuchin"], "379": ["n02492660", "howler_monkey"], "380": ["n02493509", "titi"], "381": ["n02493793", "spider_monkey"], "382": ["n02494079", "squirrel_monkey"], "383": ["n02497673", "Madagascar_cat"], "384": ["n02500267", "indri"], "385": ["n02504013", "Indian_elephant"], "386": ["n02504458", "African_elephant"], "387": ["n02509815", "lesser_panda"], "388": ["n02510455", "giant_panda"], "389": ["n02514041", "barracouta"], "390": ["n02526121", "eel"], "391": ["n02536864", "coho"], "392": ["n02606052", "rock_beauty"], "393": ["n02607072", "anemone_fish"], "394": ["n02640242", "sturgeon"], "395": ["n02641379", "gar"], "396": ["n02643566", "lionfish"], "397": ["n02655020", "puffer"], "398": ["n02666196", "abacus"], "399": ["n02667093", "abaya"], "400": ["n02669723", "academic_gown"], "401": ["n02672831", "accordion"], "402": ["n02676566", "acoustic_guitar"], "403": ["n02687172", "aircraft_carrier"], "404": ["n02690373", "airliner"], "405": ["n02692877", "airship"], "406": ["n02699494", "altar"], "407": ["n02701002", "ambulance"], "408": ["n02704792", "amphibian"], "409": ["n02708093", "analog_clock"], "410": ["n02727426", "apiary"], "411": ["n02730930", "apron"], "412": ["n02747177", "ashcan"], "413": ["n02749479", "assault_rifle"], "414": ["n02769748", "backpack"], "415": ["n02776631", "bakery"], "416": ["n02777292", "balance_beam"], "417": ["n02782093", "balloon"], "418": ["n02783161", "ballpoint"], "419": ["n02786058", "Band_Aid"], "420": ["n02787622", "banjo"], "421": ["n02788148", "bannister"], "422": ["n02790996", "barbell"], "423": ["n02791124", "barber_chair"], "424": ["n02791270", "barbershop"], "425": ["n02793495", "barn"], "426": ["n02794156", "barometer"], "427": ["n02795169", "barrel"], "428": ["n02797295", "barrow"], "429": ["n02799071", "baseball"], "430": ["n02802426", "basketball"], "431": ["n02804414", "bassinet"], "432": ["n02804610", "bassoon"], "433": ["n02807133", "bathing_cap"], "434": ["n02808304", "bath_towel"], "435": ["n02808440", "bathtub"], "436": ["n02814533", "beach_wagon"], "437": ["n02814860", "beacon"], "438": ["n02815834", "beaker"], "439": ["n02817516", "bearskin"], "440": ["n02823428", "beer_bottle"], "441": ["n02823750", "beer_glass"], "442": ["n02825657", "bell_cote"], "443": ["n02834397", "bib"], "444": ["n02835271", "bicycle-built-for-two"], "445": ["n02837789", "bikini"], "446": ["n02840245", "binder"], "447": ["n02841315", "binoculars"], "448": ["n02843684", "birdhouse"], "449": ["n02859443", "boathouse"], "450": ["n02860847", "bobsled"], "451": ["n02865351", "bolo_tie"], "452": ["n02869837", "bonnet"], "453": ["n02870880", "bookcase"], "454": ["n02871525", "bookshop"], "455": ["n02877765", "bottlecap"], "456": ["n02879718", "bow"], "457": ["n02883205", "bow_tie"], "458": ["n02892201", "brass"], "459": ["n02892767", "brassiere"], "460": ["n02894605", "breakwater"], "461": ["n02895154", "breastplate"], "462": ["n02906734", "broom"], "463": ["n02909870", "bucket"], "464": ["n02910353", "buckle"], "465": ["n02916936", "bulletproof_vest"], "466": ["n02917067", "bullet_train"], "467": ["n02927161", "butcher_shop"], "468": ["n02930766", "cab"], "469": ["n02939185", "caldron"], "470": ["n02948072", "candle"], "471": ["n02950826", "cannon"], "472": ["n02951358", "canoe"], "473": ["n02951585", "can_opener"], "474": ["n02963159", "cardigan"], "475": ["n02965783", "car_mirror"], "476": ["n02966193", "carousel"], "477": ["n02966687", "carpenter's_kit"], "478": ["n02971356", "carton"], "479": ["n02974003", "car_wheel"], "480": ["n02977058", "cash_machine"], "481": ["n02978881", "cassette"], "482": ["n02979186", "cassette_player"], "483": ["n02980441", "castle"], "484": ["n02981792", "catamaran"], "485": ["n02988304", "CD_player"], "486": ["n02992211", "cello"], "487": ["n02992529", "cellular_telephone"], "488": ["n02999410", "chain"], "489": ["n03000134", "chainlink_fence"], "490": ["n03000247", "chain_mail"], "491": ["n03000684", "chain_saw"], "492": ["n03014705", "chest"], "493": ["n03016953", "chiffonier"], "494": ["n03017168", "chime"], "495": ["n03018349", "china_cabinet"], "496": ["n03026506", "Christmas_stocking"], "497": ["n03028079", "church"], "498": ["n03032252", "cinema"], "499": ["n03041632", "cleaver"], "500": ["n03042490", "cliff_dwelling"], "501": ["n03045698", "cloak"], "502": ["n03047690", "clog"], "503": ["n03062245", "cocktail_shaker"], "504": ["n03063599", "coffee_mug"], "505": ["n03063689", "coffeepot"], "506": ["n03065424", "coil"], "507": ["n03075370", "combination_lock"], "508": ["n03085013", "computer_keyboard"], "509": ["n03089624", "confectionery"], "510": ["n03095699", "container_ship"], "511": ["n03100240", "convertible"], "512": ["n03109150", "corkscrew"], "513": ["n03110669", "cornet"], "514": ["n03124043", "cowboy_boot"], "515": ["n03124170", "cowboy_hat"], "516": ["n03125729", "cradle"], "517": ["n03126707", "crane"], "518": ["n03127747", "crash_helmet"], "519": ["n03127925", "crate"], "520": ["n03131574", "crib"], "521": ["n03133878", "Crock_Pot"], "522": ["n03134739", "croquet_ball"], "523": ["n03141823", "crutch"], "524": ["n03146219", "cuirass"], "525": ["n03160309", "dam"], "526": ["n03179701", "desk"], "527": ["n03180011", "desktop_computer"], "528": ["n03187595", "dial_telephone"], "529": ["n03188531", "diaper"], "530": ["n03196217", "digital_clock"], "531": ["n03197337", "digital_watch"], "532": ["n03201208", "dining_table"], "533": ["n03207743", "dishrag"], "534": ["n03207941", "dishwasher"], "535": ["n03208938", "disk_brake"], "536": ["n03216828", "dock"], "537": ["n03218198", "dogsled"], "538": ["n03220513", "dome"], "539": ["n03223299", "doormat"], "540": ["n03240683", "drilling_platform"], "541": ["n03249569", "drum"], "542": ["n03250847", "drumstick"], "543": ["n03255030", "dumbbell"], "544": ["n03259280", "Dutch_oven"], "545": ["n03271574", "electric_fan"], "546": ["n03272010", "electric_guitar"], "547": ["n03272562", "electric_locomotive"], "548": ["n03290653", "entertainment_center"], "549": ["n03291819", "envelope"], "550": ["n03297495", "espresso_maker"], "551": ["n03314780", "face_powder"], "552": ["n03325584", "feather_boa"], "553": ["n03337140", "file"], "554": ["n03344393", "fireboat"], "555": ["n03345487", "fire_engine"], "556": ["n03347037", "fire_screen"], "557": ["n03355925", "flagpole"], "558": ["n03372029", "flute"], "559": ["n03376595", "folding_chair"], "560": ["n03379051", "football_helmet"], "561": ["n03384352", "forklift"], "562": ["n03388043", "fountain"], "563": ["n03388183", "fountain_pen"], "564": ["n03388549", "four-poster"], "565": ["n03393912", "freight_car"], "566": ["n03394916", "French_horn"], "567": ["n03400231", "frying_pan"], "568": ["n03404251", "fur_coat"], "569": ["n03417042", "garbage_truck"], "570": ["n03424325", "gasmask"], "571": ["n03425413", "gas_pump"], "572": ["n03443371", "goblet"], "573": ["n03444034", "go-kart"], "574": ["n03445777", "golf_ball"], "575": ["n03445924", "golfcart"], "576": ["n03447447", "gondola"], "577": ["n03447721", "gong"], "578": ["n03450230", "gown"], "579": ["n03452741", "grand_piano"], "580": ["n03457902", "greenhouse"], "581": ["n03459775", "grille"], "582": ["n03461385", "grocery_store"], "583": ["n03467068", "guillotine"], "584": ["n03476684", "hair_slide"], "585": ["n03476991", "hair_spray"], "586": ["n03478589", "half_track"], "587": ["n03481172", "hammer"], "588": ["n03482405", "hamper"], "589": ["n03483316", "hand_blower"], "590": ["n03485407", "hand-held_computer"], "591": ["n03485794", "handkerchief"], "592": ["n03492542", "hard_disc"], "593": ["n03494278", "harmonica"], "594": ["n03495258", "harp"], "595": ["n03496892", "harvester"], "596": ["n03498962", "hatchet"], "597": ["n03527444", "holster"], "598": ["n03529860", "home_theater"], "599": ["n03530642", "honeycomb"], "600": ["n03532672", "hook"], "601": ["n03534580", "hoopskirt"], "602": ["n03535780", "horizontal_bar"], "603": ["n03538406", "horse_cart"], "604": ["n03544143", "hourglass"], "605": ["n03584254", "iPod"], "606": ["n03584829", "iron"], "607": ["n03590841", "jack-o'-lantern"], "608": ["n03594734", "jean"], "609": ["n03594945", "jeep"], "610": ["n03595614", "jersey"], "611": ["n03598930", "jigsaw_puzzle"], "612": ["n03599486", "jinrikisha"], "613": ["n03602883", "joystick"], "614": ["n03617480", "kimono"], "615": ["n03623198", "knee_pad"], "616": ["n03627232", "knot"], "617": ["n03630383", "lab_coat"], "618": ["n03633091", "ladle"], "619": ["n03637318", "lampshade"], "620": ["n03642806", "laptop"], "621": ["n03649909", "lawn_mower"], "622": ["n03657121", "lens_cap"], "623": ["n03658185", "letter_opener"], "624": ["n03661043", "library"], "625": ["n03662601", "lifeboat"], "626": ["n03666591", "lighter"], "627": ["n03670208", "limousine"], "628": ["n03673027", "liner"], "629": ["n03676483", "lipstick"], "630": ["n03680355", "Loafer"], "631": ["n03690938", "lotion"], "632": ["n03691459", "loudspeaker"], "633": ["n03692522", "loupe"], "634": ["n03697007", "lumbermill"], "635": ["n03706229", "magnetic_compass"], "636": ["n03709823", "mailbag"], "637": ["n03710193", "mailbox"], "638": ["n03710637", "maillot"], "639": ["n03710721", "maillot"], "640": ["n03717622", "manhole_cover"], "641": ["n03720891", "maraca"], "642": ["n03721384", "marimba"], "643": ["n03724870", "mask"], "644": ["n03729826", "matchstick"], "645": ["n03733131", "maypole"], "646": ["n03733281", "maze"], "647": ["n03733805", "measuring_cup"], "648": ["n03742115", "medicine_chest"], "649": ["n03743016", "megalith"], "650": ["n03759954", "microphone"], "651": ["n03761084", "microwave"], "652": ["n03763968", "military_uniform"], "653": ["n03764736", "milk_can"], "654": ["n03769881", "minibus"], "655": ["n03770439", "miniskirt"], "656": ["n03770679", "minivan"], "657": ["n03773504", "missile"], "658": ["n03775071", "mitten"], "659": ["n03775546", "mixing_bowl"], "660": ["n03776460", "mobile_home"], "661": ["n03777568", "Model_T"], "662": ["n03777754", "modem"], "663": ["n03781244", "monastery"], "664": ["n03782006", "monitor"], "665": ["n03785016", "moped"], "666": ["n03786901", "mortar"], "667": ["n03787032", "mortarboard"], "668": ["n03788195", "mosque"], "669": ["n03788365", "mosquito_net"], "670": ["n03791053", "motor_scooter"], "671": ["n03792782", "mountain_bike"], "672": ["n03792972", "mountain_tent"], "673": ["n03793489", "mouse"], "674": ["n03794056", "mousetrap"], "675": ["n03796401", "moving_van"], "676": ["n03803284", "muzzle"], "677": ["n03804744", "nail"], "678": ["n03814639", "neck_brace"], "679": ["n03814906", "necklace"], "680": ["n03825788", "nipple"], "681": ["n03832673", "notebook"], "682": ["n03837869", "obelisk"], "683": ["n03838899", "oboe"], "684": ["n03840681", "ocarina"], "685": ["n03841143", "odometer"], "686": ["n03843555", "oil_filter"], "687": ["n03854065", "organ"], "688": ["n03857828", "oscilloscope"], "689": ["n03866082", "overskirt"], "690": ["n03868242", "oxcart"], "691": ["n03868863", "oxygen_mask"], "692": ["n03871628", "packet"], "693": ["n03873416", "paddle"], "694": ["n03874293", "paddlewheel"], "695": ["n03874599", "padlock"], "696": ["n03876231", "paintbrush"], "697": ["n03877472", "pajama"], "698": ["n03877845", "palace"], "699": ["n03884397", "panpipe"], "700": ["n03887697", "paper_towel"], "701": ["n03888257", "parachute"], "702": ["n03888605", "parallel_bars"], "703": ["n03891251", "park_bench"], "704": ["n03891332", "parking_meter"], "705": ["n03895866", "passenger_car"], "706": ["n03899768", "patio"], "707": ["n03902125", "pay-phone"], "708": ["n03903868", "pedestal"], "709": ["n03908618", "pencil_box"], "710": ["n03908714", "pencil_sharpener"], "711": ["n03916031", "perfume"], "712": ["n03920288", "Petri_dish"], "713": ["n03924679", "photocopier"], "714": ["n03929660", "pick"], "715": ["n03929855", "pickelhaube"], "716": ["n03930313", "picket_fence"], "717": ["n03930630", "pickup"], "718": ["n03933933", "pier"], "719": ["n03935335", "piggy_bank"], "720": ["n03937543", "pill_bottle"], "721": ["n03938244", "pillow"], "722": ["n03942813", "ping-pong_ball"], "723": ["n03944341", "pinwheel"], "724": ["n03947888", "pirate"], "725": ["n03950228", "pitcher"], "726": ["n03954731", "plane"], "727": ["n03956157", "planetarium"], "728": ["n03958227", "plastic_bag"], "729": ["n03961711", "plate_rack"], "730": ["n03967562", "plow"], "731": ["n03970156", "plunger"], "732": ["n03976467", "Polaroid_camera"], "733": ["n03976657", "pole"], "734": ["n03977966", "police_van"], "735": ["n03980874", "poncho"], "736": ["n03982430", "pool_table"], "737": ["n03983396", "pop_bottle"], "738": ["n03991062", "pot"], "739": ["n03992509", "potter's_wheel"], "740": ["n03995372", "power_drill"], "741": ["n03998194", "prayer_rug"], "742": ["n04004767", "printer"], "743": ["n04005630", "prison"], "744": ["n04008634", "projectile"], "745": ["n04009552", "projector"], "746": ["n04019541", "puck"], "747": ["n04023962", "punching_bag"], "748": ["n04026417", "purse"], "749": ["n04033901", "quill"], "750": ["n04033995", "quilt"], "751": ["n04037443", "racer"], "752": ["n04039381", "racket"], "753": ["n04040759", "radiator"], "754": ["n04041544", "radio"], "755": ["n04044716", "radio_telescope"], "756": ["n04049303", "rain_barrel"], "757": ["n04065272", "recreational_vehicle"], "758": ["n04067472", "reel"], "759": ["n04069434", "reflex_camera"], "760": ["n04070727", "refrigerator"], "761": ["n04074963", "remote_control"], "762": ["n04081281", "restaurant"], "763": ["n04086273", "revolver"], "764": ["n04090263", "rifle"], "765": ["n04099969", "rocking_chair"], "766": ["n04111531", "rotisserie"], "767": ["n04116512", "rubber_eraser"], "768": ["n04118538", "rugby_ball"], "769": ["n04118776", "rule"], "770": ["n04120489", "running_shoe"], "771": ["n04125021", "safe"], "772": ["n04127249", "safety_pin"], "773": ["n04131690", "saltshaker"], "774": ["n04133789", "sandal"], "775": ["n04136333", "sarong"], "776": ["n04141076", "sax"], "777": ["n04141327", "scabbard"], "778": ["n04141975", "scale"], "779": ["n04146614", "school_bus"], "780": ["n04147183", "schooner"], "781": ["n04149813", "scoreboard"], "782": ["n04152593", "screen"], "783": ["n04153751", "screw"], "784": ["n04154565", "screwdriver"], "785": ["n04162706", "seat_belt"], "786": ["n04179913", "sewing_machine"], "787": ["n04192698", "shield"], "788": ["n04200800", "shoe_shop"], "789": ["n04201297", "shoji"], "790": ["n04204238", "shopping_basket"], "791": ["n04204347", "shopping_cart"], "792": ["n04208210", "shovel"], "793": ["n04209133", "shower_cap"], "794": ["n04209239", "shower_curtain"], "795": ["n04228054", "ski"], "796": ["n04229816", "ski_mask"], "797": ["n04235860", "sleeping_bag"], "798": ["n04238763", "slide_rule"], "799": ["n04239074", "sliding_door"], "800": ["n04243546", "slot"], "801": ["n04251144", "snorkel"], "802": ["n04252077", "snowmobile"], "803": ["n04252225", "snowplow"], "804": ["n04254120", "soap_dispenser"], "805": ["n04254680", "soccer_ball"], "806": ["n04254777", "sock"], "807": ["n04258138", "solar_dish"], "808": ["n04259630", "sombrero"], "809": ["n04263257", "soup_bowl"], "810": ["n04264628", "space_bar"], "811": ["n04265275", "space_heater"], "812": ["n04266014", "space_shuttle"], "813": ["n04270147", "spatula"], "814": ["n04273569", "speedboat"], "815": ["n04275548", "spider_web"], "816": ["n04277352", "spindle"], "817": ["n04285008", "sports_car"], "818": ["n04286575", "spotlight"], "819": ["n04296562", "stage"], "820": ["n04310018", "steam_locomotive"], "821": ["n04311004", "steel_arch_bridge"], "822": ["n04311174", "steel_drum"], "823": ["n04317175", "stethoscope"], "824": ["n04325704", "stole"], "825": ["n04326547", "stone_wall"], "826": ["n04328186", "stopwatch"], "827": ["n04330267", "stove"], "828": ["n04332243", "strainer"], "829": ["n04335435", "streetcar"], "830": ["n04336792", "stretcher"], "831": ["n04344873", "studio_couch"], "832": ["n04346328", "stupa"], "833": ["n04347754", "submarine"], "834": ["n04350905", "suit"], "835": ["n04355338", "sundial"], "836": ["n04355933", "sunglass"], "837": ["n04356056", "sunglasses"], "838": ["n04357314", "sunscreen"], "839": ["n04366367", "suspension_bridge"], "840": ["n04367480", "swab"], "841": ["n04370456", "sweatshirt"], "842": ["n04371430", "swimming_trunks"], "843": ["n04371774", "swing"], "844": ["n04372370", "switch"], "845": ["n04376876", "syringe"], "846": ["n04380533", "table_lamp"], "847": ["n04389033", "tank"], "848": ["n04392985", "tape_player"], "849": ["n04398044", "teapot"], "850": ["n04399382", "teddy"], "851": ["n04404412", "television"], "852": ["n04409515", "tennis_ball"], "853": ["n04417672", "thatch"], "854": ["n04418357", "theater_curtain"], "855": ["n04423845", "thimble"], "856": ["n04428191", "thresher"], "857": ["n04429376", "throne"], "858": ["n04435653", "tile_roof"], "859": ["n04442312", "toaster"], "860": ["n04443257", "tobacco_shop"], "861": ["n04447861", "toilet_seat"], "862": ["n04456115", "torch"], "863": ["n04458633", "totem_pole"], "864": ["n04461696", "tow_truck"], "865": ["n04462240", "toyshop"], "866": ["n04465501", "tractor"], "867": ["n04467665", "trailer_truck"], "868": ["n04476259", "tray"], "869": ["n04479046", "trench_coat"], "870": ["n04482393", "tricycle"], "871": ["n04483307", "trimaran"], "872": ["n04485082", "tripod"], "873": ["n04486054", "triumphal_arch"], "874": ["n04487081", "trolleybus"], "875": ["n04487394", "trombone"], "876": ["n04493381", "tub"], "877": ["n04501370", "turnstile"], "878": ["n04505470", "typewriter_keyboard"], "879": ["n04507155", "umbrella"], "880": ["n04509417", "unicycle"], "881": ["n04515003", "upright"], "882": ["n04517823", "vacuum"], "883": ["n04522168", "vase"], "884": ["n04523525", "vault"], "885": ["n04525038", "velvet"], "886": ["n04525305", "vending_machine"], "887": ["n04532106", "vestment"], "888": ["n04532670", "viaduct"], "889": ["n04536866", "violin"], "890": ["n04540053", "volleyball"], "891": ["n04542943", "waffle_iron"], "892": ["n04548280", "wall_clock"], "893": ["n04548362", "wallet"], "894": ["n04550184", "wardrobe"], "895": ["n04552348", "warplane"], "896": ["n04553703", "washbasin"], "897": ["n04554684", "washer"], "898": ["n04557648", "water_bottle"], "899": ["n04560804", "water_jug"], "900": ["n04562935", "water_tower"], "901": ["n04579145", "whiskey_jug"], "902": ["n04579432", "whistle"], "903": ["n04584207", "wig"], "904": ["n04589890", "window_screen"], "905": ["n04590129", "window_shade"], "906": ["n04591157", "Windsor_tie"], "907": ["n04591713", "wine_bottle"], "908": ["n04592741", "wing"], "909": ["n04596742", "wok"], "910": ["n04597913", "wooden_spoon"], "911": ["n04599235", "wool"], "912": ["n04604644", "worm_fence"], "913": ["n04606251", "wreck"], "914": ["n04612504", "yawl"], "915": ["n04613696", "yurt"], "916": ["n06359193", "web_site"], "917": ["n06596364", "comic_book"], "918": ["n06785654", "crossword_puzzle"], "919": ["n06794110", "street_sign"], "920": ["n06874185", "traffic_light"], "921": ["n07248320", "book_jacket"], "922": ["n07565083", "menu"], "923": ["n07579787", "plate"], "924": ["n07583066", "guacamole"], "925": ["n07584110", "consomme"], "926": ["n07590611", "hot_pot"], "927": ["n07613480", "trifle"], "928": ["n07614500", "ice_cream"], "929": ["n07615774", "ice_lolly"], "930": ["n07684084", "French_loaf"], "931": ["n07693725", "bagel"], "932": ["n07695742", "pretzel"], "933": ["n07697313", "cheeseburger"], "934": ["n07697537", "hotdog"], "935": ["n07711569", "mashed_potato"], "936": ["n07714571", "head_cabbage"], "937": ["n07714990", "broccoli"], "938": ["n07715103", "cauliflower"], "939": ["n07716358", "zucchini"], "940": ["n07716906", "spaghetti_squash"], "941": ["n07717410", "acorn_squash"], "942": ["n07717556", "butternut_squash"], "943": ["n07718472", "cucumber"], "944": ["n07718747", "artichoke"], "945": ["n07720875", "bell_pepper"], "946": ["n07730033", "cardoon"], "947": ["n07734744", "mushroom"], "948": ["n07742313", "Granny_Smith"], "949": ["n07745940", "strawberry"], "950": ["n07747607", "orange"], "951": ["n07749582", "lemon"], "952": ["n07753113", "fig"], "953": ["n07753275", "pineapple"], "954": ["n07753592", "banana"], "955": ["n07754684", "jackfruit"], "956": ["n07760859", "custard_apple"], "957": ["n07768694", "pomegranate"], "958": ["n07802026", "hay"], "959": ["n07831146", "carbonara"], "960": ["n07836838", "chocolate_sauce"], "961": ["n07860988", "dough"], "962": ["n07871810", "meat_loaf"], "963": ["n07873807", "pizza"], "964": ["n07875152", "potpie"], "965": ["n07880968", "burrito"], "966": ["n07892512", "red_wine"], "967": ["n07920052", "espresso"], "968": ["n07930864", "cup"], "969": ["n07932039", "eggnog"], "970": ["n09193705", "alp"], "971": ["n09229709", "bubble"], "972": ["n09246464", "cliff"], "973": ["n09256479", "coral_reef"], "974": ["n09288635", "geyser"], "975": ["n09332890", "lakeside"], "976": ["n09399592", "promontory"], "977": ["n09421951", "sandbar"], "978": ["n09428293", "seashore"], "979": ["n09468604", "valley"], "980": ["n09472597", "volcano"], "981": ["n09835506", "ballplayer"], "982": ["n10148035", "groom"], "983": ["n10565667", "scuba_diver"], "984": ["n11879895", "rapeseed"], "985": ["n11939491", "daisy"], "986": ["n12057211", "yellow_lady's_slipper"], "987": ["n12144580", "corn"], "988": ["n12267677", "acorn"], "989": ["n12620546", "hip"], "990": ["n12768682", "buckeye"], "991": ["n12985857", "coral_fungus"], "992": ["n12998815", "agaric"], "993": ["n13037406", "gyromitra"], "994": ["n13040303", "stinkhorn"], "995": ["n13044778", "earthstar"], "996": ["n13052670", "hen-of-the-woods"], "997": ["n13054560", "bolete"], "998": ["n13133613", "ear"], "999": ["n15075141", "toilet_tissue"]} -------------------------------------------------------------------------------- /ml-basics/mnist/mnist.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Building a Neural Network for MNIST" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 85, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import torch\n", 17 | "from torchvision import datasets, transforms\n", 18 | "import matplotlib.pyplot as plt" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 86, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "# Transform PIL image into a tensor. The values are in the range [0, 1]\n", 28 | "t = transforms.ToTensor()\n", 29 | "\n", 30 | "# Load datasets for training and testing.\n", 31 | "mnist_training = datasets.MNIST(root='/tmp/mnist', train=True, download=True, transform=t)\n", 32 | "mnist_val = datasets.MNIST(root='/tmp/mnist', train=False, download=True, transform=t)" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 87, 38 | "metadata": {}, 39 | "outputs": [ 40 | { 41 | "data": { 42 | "image/png": "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", 43 | "text/plain": [ 44 | "
" 45 | ] 46 | }, 47 | "metadata": { 48 | "needs_background": "light" 49 | }, 50 | "output_type": "display_data" 51 | } 52 | ], 53 | "source": [ 54 | "# Plot some digits.\n", 55 | "\n", 56 | "cols = 8\n", 57 | "rows = 2\n", 58 | "\n", 59 | "fig, axes = plt.subplots(nrows=rows, ncols=cols, figsize=(1.5*cols, 2*rows))\n", 60 | "for i, ax in enumerate(axes.flatten()):\n", 61 | " image, label = mnist_training[i] # returns PIL image with its labels\n", 62 | " ax.set_title(f\"Label: {label}\")\n", 63 | " ax.imshow(image.squeeze(0), cmap='gray') # we get a 1x28x28 tensor -> remove first dimension\n", 64 | "plt.show()" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 88, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [ 73 | "# Create a simple neural network with one hidden layer with 256 neurons.\n", 74 | "model = torch.nn.Sequential(\n", 75 | " torch.nn.Linear(28*28, 256),\n", 76 | " torch.nn.ReLU(),\n", 77 | " torch.nn.Linear(256, 10)\n", 78 | ")\n", 79 | "\n", 80 | "# Use Adam as optimizer.\n", 81 | "opt = torch.optim.Adam(params=model.parameters(), lr=0.01)\n", 82 | "\n", 83 | "# Use CrossEntropyLoss for as loss function.\n", 84 | "loss_fn = torch.nn.CrossEntropyLoss()\n", 85 | "\n", 86 | "# We train the model with batches of 500 examples.\n", 87 | "batch_size = 500\n", 88 | "train_loader = torch.utils.data.DataLoader(mnist_training, batch_size=batch_size, shuffle=True)" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 89, 94 | "metadata": {}, 95 | "outputs": [ 96 | { 97 | "name": "stdout", 98 | "output_type": "stream", 99 | "text": [ 100 | "Epoch: 0, Loss: 0.1814579963684082\n", 101 | "Epoch: 1, Loss: 0.07897494733333588\n", 102 | "Epoch: 2, Loss: 0.061483509838581085\n", 103 | "Epoch: 3, Loss: 0.054685574024915695\n", 104 | "Epoch: 4, Loss: 0.047717854380607605\n", 105 | "Epoch: 5, Loss: 0.03222307562828064\n", 106 | "Epoch: 6, Loss: 0.025303684175014496\n", 107 | "Epoch: 7, Loss: 0.04362534359097481\n", 108 | "Epoch: 8, Loss: 0.019005214795470238\n", 109 | "Epoch: 9, Loss: 0.013590291142463684\n" 110 | ] 111 | } 112 | ], 113 | "source": [ 114 | "# Training of the model. We use 10 epochs.\n", 115 | "losses = []\n", 116 | "\n", 117 | "for epoch in range(10):\n", 118 | " for imgs, labels in train_loader:\n", 119 | " n = len(imgs)\n", 120 | " # Reshape data from [500, 1, 28, 28] to [500, 784] and use the model to make predictions.\n", 121 | " predictions = model(imgs.view(n, -1)) \n", 122 | " # Compute the loss.\n", 123 | " loss = loss_fn(predictions, labels) \n", 124 | " opt.zero_grad()\n", 125 | " loss.backward()\n", 126 | " opt.step()\n", 127 | " losses.append(float(loss))\n", 128 | " print(f\"Epoch: {epoch}, Loss: {float(loss)}\")\n" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": 90, 134 | "metadata": {}, 135 | "outputs": [ 136 | { 137 | "data": { 138 | "text/plain": [ 139 | "[]" 140 | ] 141 | }, 142 | "execution_count": 90, 143 | "metadata": {}, 144 | "output_type": "execute_result" 145 | }, 146 | { 147 | "data": { 148 | "image/png": "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", 149 | "text/plain": [ 150 | "
" 151 | ] 152 | }, 153 | "metadata": { 154 | "needs_background": "light" 155 | }, 156 | "output_type": "display_data" 157 | } 158 | ], 159 | "source": [ 160 | "# Plot learning curve.\n", 161 | "plt.plot(losses)" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": 91, 167 | "metadata": {}, 168 | "outputs": [ 169 | { 170 | "data": { 171 | "text/plain": [ 172 | "0.9742" 173 | ] 174 | }, 175 | "execution_count": 91, 176 | "metadata": {}, 177 | "output_type": "execute_result" 178 | } 179 | ], 180 | "source": [ 181 | "# Determine the accuracy of our clasifier\n", 182 | "# =======================================\n", 183 | "\n", 184 | "# Load all 10000 images from the validation set.\n", 185 | "n = 10000\n", 186 | "loader = torch.utils.data.DataLoader(mnist_val, batch_size=n)\n", 187 | "images, labels = iter(loader).next()\n", 188 | "\n", 189 | "# The tensor images has the shape [10000, 1, 28, 28]. Reshape the tensor to\n", 190 | "# [10000, 784] as our model expected a flat vector.\n", 191 | "data = images.view(n, -1)\n", 192 | "\n", 193 | "# Use our model to compute the class scores for all images. The result is a\n", 194 | "# tensor with shape [10000, 10]. Row i stores the scores for image images[i].\n", 195 | "# Column j stores the score for class j.\n", 196 | "predictions = model(data)\n", 197 | "\n", 198 | "# For each row determine the column index with the maximum score. This is the\n", 199 | "# predicted class.\n", 200 | "predicted_classes = torch.argmax(predictions, dim=1)\n", 201 | "\n", 202 | "# Accuracy = number of correctly classified images divided by the total number\n", 203 | "# of classified images.\n", 204 | "sum(predicted_classes.numpy() == labels.numpy()) / n" 205 | ] 206 | } 207 | ], 208 | "metadata": { 209 | "interpreter": { 210 | "hash": "3c31154c2e6d078d13498c87eb48ca372ee3ad3d9153e56081b43cdb07df7cf4" 211 | }, 212 | "kernelspec": { 213 | "display_name": "Python 3.8.10 64-bit ('venv': venv)", 214 | "language": "python", 215 | "name": "python3" 216 | }, 217 | "language_info": { 218 | "codemirror_mode": { 219 | "name": "ipython", 220 | "version": 3 221 | }, 222 | "file_extension": ".py", 223 | "mimetype": "text/x-python", 224 | "name": "python", 225 | "nbconvert_exporter": "python", 226 | "pygments_lexer": "ipython3", 227 | "version": "3.8.10" 228 | }, 229 | "orig_nbformat": 4 230 | }, 231 | "nbformat": 4, 232 | "nbformat_minor": 2 233 | } 234 | --------------------------------------------------------------------------------