<jupyter_start><jupyter_text>1. Requirements<jupyter_code>from __future__ import print_function

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

from torchvision.datasets import MNIST
from torchvision import datasets, transforms

from advertorch.attacks import GradientSignAttack as FGSM

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline<jupyter_output><empty_output><jupyter_text>2. MNIST model<jupyter_code>class MnistModel(nn.Module):
    def __init__(self):
        super(MnistModel, self).__init__()
        # mnist의 경우 28*28의 흑백이미지(input channel=1)이다.
        self.conv1 = nn.Conv2d(1, 32, kernel_size = 5, padding=2)
        # feature map의 크기는 14*14가 된다
        # 첫번재 convolution layer에서 나온 output channel이 32이므로 2번째 input도 32
        self.conv2 = nn.Conv2d(32, 64, kernel_size = 5, padding=2)
        # feature map의 크기는 7*7이 된다
        # fc -> fully connected, fc는 모든 weight를 고려해서 만들기 때문에 cnn에서는 locally connected를 이용하여 만든다.
        # nn.Linear에서는 conv를 거친 feature map을 1차원으로 전부 바꿔서 input을 한다. 이게 64*7*7
        self.fc1 = nn.Linear(64*7*7, 1024)
        self.fc2 = nn.Linear(1024, 10)

    def forward(self, x):
        x = F.max_pool2d(F.relu(self.conv1(x)), 2)
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        x = x.view(-1, 64*7*7) # linear에 들어갈 수 있도록 reshape
        x = F.relu(self.fc1(x)) # fully connected에 relu 적용
        x = F.dropout(x, training=self.training) # 가중치 감소만으로는 overfit을 해결하기가 어려움, 그래서 뉴런의 연결을 임의로 삭제
        x = self.fc2(x)
        return F.log_softmax(x, dim=1)<jupyter_output><empty_output><jupyter_text>3. FGSM attack<jupyter_code>def fgsm_attack(image, label, epsilon, model):
    adversary = FGSM(model, loss_fn=nn.NLLLoss(reduction='sum'), 
                    eps=epsilon, clip_min=0., clip_max=1., targeted=False)
    perturbed_image = adversary.perturb(image, label)
    return perturbed_image<jupyter_output><empty_output><jupyter_text>4. test function<jupyter_code>def test(model, device, test_loader, epsilon):
    # Accuracy counter
    correct = 0
    adv_examples = []

    # test set의 모든 예제를 test한다
    for data, target in test_loader:
        # cpu나 gpu로 데이터를 전송한다
        data, target = data.to(device), target.to(device)
        # gradient 계산을 하도록 만든다. 공격에 중요함.
        data.requires_grad = True

        # Forward pass the data through the model
        output = model(data)
        init_pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability

        # If the initial prediction is wrong, dont bother attacking, just move on
        if init_pred.item() != target.item():
            continue

        # Calculate the loss
        loss = F.nll_loss(output, target)

        # Zero all existing gradients
        model.zero_grad()

        # Calculate gradients of model in backward pass
        loss.backward()

        # Collect datagrad
        data_grad = data.grad.data

        # Call FGSM Attack
        perturbed_data = fgsm_attack(data, target, epsilon, model)

        # Re-classify the perturbed image
        output = model(perturbed_data)

        # Check for success
        final_pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability
        if final_pred.item() == target.item():
            correct += 1
            # Special case for saving 0 epsilon examples
            if (epsilon == 0) and (len(adv_examples) < 5):
                adv_ex = perturbed_data.squeeze().detach().cpu().numpy()
                adv_examples.append( (init_pred.item(), final_pred.item(), adv_ex) )
        else:
            # Save some adv examples for visualization later
            if len(adv_examples) < 5:
                adv_ex = perturbed_data.squeeze().detach().cpu().numpy()
                adv_examples.append( (init_pred.item(), final_pred.item(), adv_ex) )

    # Calculate final accuracy for this epsilon
    final_acc = correct/float(len(test_loader))
    print("Epsilon: {}\tTest Accuracy = {} / {} = {}".format(epsilon, correct, len(test_loader), final_acc))

    # Return the accuracy and an adversarial example
    return final_acc, adv_examples<jupyter_output><empty_output><jupyter_text>5. Load dataset, trained model<jupyter_code>test_loader = torch.utils.data.DataLoader(
    datasets.MNIST('../data', train=False, download=True, transform=transforms.Compose([
            transforms.ToTensor(),
            ])),
        batch_size=1, shuffle=True)

mnist_transform = transforms.Compose([
    transforms.ToTensor(), 
])

download_path = './data'
train_dataset = MNIST(download_path, transform=mnist_transform, train=True, download=True)
test_dataset = MNIST(download_path, transform=mnist_transform, train=False, download=True)
is_cuda = torch.cuda.is_available()
device = torch.device('cuda' if is_cuda else 'cpu')
print("CUDA Available:", is_cuda)
pgd_defense_model = './model/mnist_pgd_model.pth'
fgsm_defense_model = './model/mnist_fgsm_model.pth'

model_normal = MnistModel().to(device)
model_normal.load_state_dict(torch.load(pgd_defense_model, map_location='cpu'))

model_fgsm = MnistModel().to(device)
model_fgsm.load_state_dict(torch.load(fgsm_defense_model, map_location='cpu'))<jupyter_output><empty_output><jupyter_text>6. Run test<jupyter_code>epsilons = [0, .05, .1, .15, .2, .25, .3]

pgd_accuracies = []
fgsm_accuracies = []
examples = []
print('FGSM defense:')    
for eps in epsilons:
    acc, ex = test(model_fgsm, device, test_loader, eps)
    fgsm_accuracies.append(acc)
print('PGD defense:')
for eps in epsilons:
    acc, ex = test(model_normal, device, test_loader, eps)
    pgd_accuracies.append(acc)
    examples.append(ex)<jupyter_output>PGD defense:
Epsilon: 0	Test Accuracy = 9797 / 10000 = 0.9797
Epsilon: 0.05	Test Accuracy = 9768 / 10000 = 0.9768
Epsilon: 0.1	Test Accuracy = 9695 / 10000 = 0.9695
Epsilon: 0.15	Test Accuracy = 9633 / 10000 = 0.9633
Epsilon: 0.2	Test Accuracy = 9570 / 10000 = 0.957
Epsilon: 0.25	Test Accuracy = 9494 / 10000 = 0.9494
Epsilon: 0.3	Test Accuracy = 9401 / 10000 = 0.9401<jupyter_text>Result<jupyter_code>plt.figure(figsize=(5,5))
plt.plot(epsilons, fgsm_accuracies, "*-", label='FGSM Trained', color='b')
plt.plot(epsilons, pgd_accuracies, "*-", label='PGD Trained', color='g')
plt.yticks(np.arange(0, 1.1, step=0.1))
plt.xticks(np.arange(0, .35, step=0.05))
plt.title("Accuracy vs Epsilon")
plt.xlabel("Epsilon")
plt.ylabel("Accuracy")
plt.show()<jupyter_output><empty_output><jupyter_text>Samples<jupyter_code># Plot several examples of adversarial samples at each epsilon
cnt = 0
plt.figure(figsize=(8,10))
for i in range(len(epsilons)):
    for j in range(len(examples[i])):
        cnt += 1
        plt.subplot(len(epsilons),len(examples[0]),cnt)
        plt.xticks([], [])
        plt.yticks([], [])
        if j == 0:
            plt.ylabel("Eps: {}".format(epsilons[i]), fontsize=14)
        orig,adv,ex = examples[i][j]
        plt.title("{} -> {}".format(orig, adv))
        plt.imshow(ex, cmap="gray")
plt.tight_layout()
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1232059116100611, 'fraction_numerical': 0.03268438254938184, 'mean_word_length': 3.4264150943396228, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '279278', 'license': 'MIT', 'n_tokens_mistral': 2790, 'n_tokens_neox': 2618, 'n_words': 568, 'path': 'unused/fgsm_on_pgdmodel.ipynb', 'repo_name': 'sanglee325/metric-train', 'size': '7037'}