Skip to content
Open
14 changes: 9 additions & 5 deletions pytorch/PyTorch-MNIST-Minimal.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "8d8e689d",
"metadata": {
"ExecuteTime": {
"end_time": "2021-03-04T20:07:46.654477Z",
Expand All @@ -11,12 +12,13 @@
},
"outputs": [],
"source": [
"!pip install torch torchvision prometheus_client --progress-bar off"
"!pip install torchvision prometheus_client --progress-bar off"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7f832a27",
"metadata": {
"ExecuteTime": {
"end_time": "2021-03-04T20:08:02.078254Z",
Expand All @@ -34,6 +36,8 @@
"from torch import nn, optim\n",
"from torch.nn import functional as F\n",
"from prometheus_client import CollectorRegistry, Gauge, push_to_gateway\n",
"import warnings\n",
"warnings.filterwarnings('ignore')\n",
"\n",
"transform = transforms.Compose([transforms.ToTensor(),\n",
" transforms.Normalize((0.5,), (0.5,)),\n",
Expand Down Expand Up @@ -103,15 +107,15 @@
" add_metrics_data(current_time, epoch, value_formatter.format(time_post_loop - time_pre_loop),value_formatter.format(step_time_avg * 1000))\n",
"\n",
"\n",
"pushgateway_url = \"http://prom-push-as-pushgateway.apps.zero.massopen.cloud\"\n",
"#pushgateway_url = \"http://prom-push-as-pushgateway.apps.zero.massopen.cloud\"\n",
"registry = CollectorRegistry()\n",
"epoch_gauge = Gauge(name='epoch_duration_seconds', documentation='epoch_value is the metric itself, the stuff in the {}s are tags',labelnames=[\"model\",\"framework\",\"date\",\"epoch\"],registry=registry)\n",
"step_gauge = Gauge(name='step_during_milliseconds', documentation='step_during_milliseconds is the metric itself, the stuff in the {}s are tags',labelnames=[\"model\",\"framework\",\"date\",\"epoch\"],registry=registry)\n",
"\n",
"def add_metrics_data(current_time, epoch_num, epoch_value, step_value): \n",
" epoch_gauge.labels(\"mnist-minimal\",\"Pytorch\",current_time,epoch_num).set(epoch_value)\n",
" step_gauge.labels(\"mnist-minimal\",\"Pytorch\",current_time,epoch_num).set(step_value) \n",
" push_to_gateway(pushgateway_url, job='jupyterhub_load', registry=registry)\n",
" #push_to_gateway(pushgateway_url, job='jupyterhub_load', registry=registry)\n",
"\n",
"\n",
"fit(epochs=5, model=model, loss_func=F.cross_entropy,\n",
Expand Down Expand Up @@ -139,7 +143,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.5"
"version": "3.6.8"
},
"toc": {
"base_numbering": 1,
Expand All @@ -157,4 +161,4 @@
},
"nbformat": 4,
"nbformat_minor": 5
}
}
324 changes: 324 additions & 0 deletions pytorch/fgsm_tutorial.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,324 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"# Default torch version contains a bug triggered by this nb\n",
"!pip install --upgrade torch torchvision"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"from __future__ import print_function\n",
"import torch\n",
"import torch.nn as nn\n",
"import torch.nn.functional as F\n",
"import torch.optim as optim\n",
"from torchvision import datasets, transforms\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# NOTE: This is a hack to get around \"User-agent\" limitations when downloading MNIST datasets\n",
"# see, https://github.com/pytorch/vision/issues/3497 for more information\n",
"from six.moves import urllib\n",
"opener = urllib.request.build_opener()\n",
"opener.addheaders = [('User-agent', 'Mozilla/5.0')]\n",
"urllib.request.install_opener(opener)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"epsilons = [0, .05, .1, .15, .2, .25, .3]\n",
"pretrained_model = \"lenet_mnist_model.pth\"\n",
"use_cuda=True"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# LeNet Model definition\n",
"class Net(nn.Module):\n",
" def __init__(self):\n",
" super(Net, self).__init__()\n",
" self.conv1 = nn.Conv2d(1, 10, kernel_size=5)\n",
" self.conv2 = nn.Conv2d(10, 20, kernel_size=5)\n",
" self.conv2_drop = nn.Dropout2d()\n",
" self.fc1 = nn.Linear(320, 50)\n",
" self.fc2 = nn.Linear(50, 10)\n",
"\n",
" def forward(self, x):\n",
" x = F.relu(F.max_pool2d(self.conv1(x), 2))\n",
" x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))\n",
" x = x.view(-1, 320)\n",
" x = F.relu(self.fc1(x))\n",
" x = F.dropout(x, training=self.training)\n",
" x = self.fc2(x)\n",
" return F.log_softmax(x, dim=1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# MNIST Test dataset and dataloader declaration\n",
"# Use contextlib to redirect output to stdout instead of stderr\n",
"# cfr. https://github.com/pytorch/vision/issues/7040\n",
"import contextlib\n",
"import sys\n",
"\n",
"with contextlib.redirect_stderr(sys.stdout):\n",
" test_loader = torch.utils.data.DataLoader(\n",
" datasets.MNIST('../data', train=False, download=True, transform=transforms.Compose([\n",
" transforms.ToTensor(),\n",
" ])), \n",
" batch_size=1, shuffle=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Define what device we are using\n",
"print(\"CUDA Available: \",torch.cuda.is_available())\n",
"device = torch.device(\"cuda\" if (use_cuda and torch.cuda.is_available()) else \"cpu\")\n",
"\n",
"# Initialize the network\n",
"model = Net().to(device)\n",
"\n",
"# Load the pretrained model\n",
"model.load_state_dict(torch.load(pretrained_model, map_location='cpu'))\n",
"\n",
"# Set the model in evaluation mode. In this case this is for the Dropout layers\n",
"model.eval()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# FGSM attack code\n",
"def fgsm_attack(image, epsilon, data_grad):\n",
" # Collect the element-wise sign of the data gradient\n",
" sign_data_grad = data_grad.sign()\n",
" # Create the perturbed image by adjusting each pixel of the input image\n",
" perturbed_image = image + epsilon*sign_data_grad\n",
" # Adding clipping to maintain [0,1] range\n",
" perturbed_image = torch.clamp(perturbed_image, 0, 1)\n",
" # Return the perturbed image\n",
" return perturbed_image"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"def test( model, device, test_loader, epsilon ):\n",
"\n",
" # Accuracy counter\n",
" correct = 0\n",
" adv_examples = []\n",
"\n",
" # Loop over all examples in test set\n",
" for data, target in test_loader:\n",
"\n",
" # Send the data and label to the device\n",
" data, target = data.to(device), target.to(device)\n",
"\n",
" # Set requires_grad attribute of tensor. Important for Attack\n",
" data.requires_grad = True\n",
"\n",
" # Forward pass the data through the model\n",
" output = model(data)\n",
" init_pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability\n",
"\n",
" # If the initial prediction is wrong, dont bother attacking, just move on\n",
" if init_pred.item() != target.item():\n",
" continue\n",
"\n",
" # Calculate the loss\n",
" loss = F.nll_loss(output, target)\n",
"\n",
" # Zero all existing gradients\n",
" model.zero_grad()\n",
"\n",
" # Calculate gradients of model in backward pass\n",
" loss.backward()\n",
"\n",
" # Collect datagrad\n",
" data_grad = data.grad.data\n",
"\n",
" # Call FGSM Attack\n",
" perturbed_data = fgsm_attack(data, epsilon, data_grad)\n",
"\n",
" # Re-classify the perturbed image\n",
" output = model(perturbed_data)\n",
"\n",
" # Check for success\n",
" final_pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability\n",
" if final_pred.item() == target.item():\n",
" correct += 1\n",
" # Special case for saving 0 epsilon examples\n",
" if (epsilon == 0) and (len(adv_examples) < 5):\n",
" adv_ex = perturbed_data.squeeze().detach().cpu().numpy()\n",
" adv_examples.append( (init_pred.item(), final_pred.item(), adv_ex) )\n",
" else:\n",
" # Save some adv examples for visualization later\n",
" if len(adv_examples) < 5:\n",
" adv_ex = perturbed_data.squeeze().detach().cpu().numpy()\n",
" adv_examples.append( (init_pred.item(), final_pred.item(), adv_ex) )\n",
"\n",
" # Calculate final accuracy for this epsilon\n",
" final_acc = correct/float(len(test_loader))\n",
" print(\"Epsilon: {}\\tTest Accuracy = {} / {} = {}\".format(epsilon, correct, len(test_loader), final_acc))\n",
"\n",
" # Return the accuracy and an adversarial example\n",
" return final_acc, adv_examples"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"accuracies = []\n",
"examples = []\n",
"\n",
"# Run test for each epsilon\n",
"for eps in epsilons:\n",
" acc, ex = test(model, device, test_loader, eps)\n",
" accuracies.append(acc)\n",
" examples.append(ex)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"plt.figure(figsize=(5,5))\n",
"plt.plot(epsilons, accuracies, \"*-\")\n",
"plt.yticks(np.arange(0, 1.1, step=0.1))\n",
"plt.xticks(np.arange(0, .35, step=0.05))\n",
"plt.title(\"Accuracy vs Epsilon\")\n",
"plt.xlabel(\"Epsilon\")\n",
"plt.ylabel(\"Accuracy\")\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# Plot several examples of adversarial samples at each epsilon\n",
"cnt = 0\n",
"plt.figure(figsize=(8,10))\n",
"for i in range(len(epsilons)):\n",
" for j in range(len(examples[i])):\n",
" cnt += 1\n",
" plt.subplot(len(epsilons),len(examples[0]),cnt)\n",
" plt.xticks([], [])\n",
" plt.yticks([], [])\n",
" if j == 0:\n",
" plt.ylabel(\"Eps: {}\".format(epsilons[i]), fontsize=14)\n",
" orig,adv,ex = examples[i][j]\n",
" plt.title(\"{} -> {}\".format(orig, adv))\n",
" plt.imshow(ex, cmap=\"gray\")\n",
"plt.tight_layout()\n",
"plt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.13"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Binary file added pytorch/lenet_mnist_model.pth
Binary file not shown.
Loading