FGSMでロジスティック回帰を騙す
Adversarial Examplesを少し調べたことのある人なら親の顔より見たことがあるであろうこの画像
このAdversarial Examples生成手法はFGSM(Fast Gradient Sign Method)といい、最も基本的なAttackの一つです。
細かい説明は他記事に譲るとして今回はこの手法とMNISTを用いてロジスティック回帰(Logistic regression)を騙してみます。
元論文の方でもロジスティック回帰に対してFGSMを行なっているのですが、3と7でしかやっていません。今回は全クラスでやってます。つまり多クラスロジスティック回帰です。
実装
以下のコードは全てpytorchです。
importとデータセットの読み込み
シード値も一応固定しておきます。
import os import torch from torch.utils.data import DataLoader import torch.nn.functional as F import torchvision import torchvision.transforms as transforms import matplotlib.pyplot as plt torch.manual_seed(0) mnist_data = torchvision.datasets.MNIST(root="/home_dir", transform=transforms.ToTensor())
訓練
batch_size = 100 data_loader = DataLoader(mnist_data, batch_size=100, shuffle=True) class LR(torch.nn.Module): def __init__(self): super().__init__() self.l1 = torch.nn.Linear(28*28, 10) def forward(self, x): h1 = self.l1(x) # PyTorchではロス関数であるF.CrossEntropyの中でSoftmax関数を適用しているのでこの層はいらないのですが、確率を見たいので入れておきます。 h2 = F.softmax(h1, dim=1) return h2 model = LR().cuda() optimizer = torch.optim.SGD(model.parameters(), lr=0.01) epochs = 10 for epoch in range(epochs): for inputs, labels in data_loader: optimizer.zero_grad() inputs = inputs.view(batch_size, 28*28).cuda() labels = labels.cuda() outputs = model(inputs) loss = F.cross_entropy(outputs, labels) loss.backward() optimizer.step() print(epoch)
この時点での正解率
FGSMなしでの正解率を見てみます。
def test_accuracy(): batch_size = 1 data_loader = DataLoader(mnist_data, batch_size=batch_size, shuffle=False) correct = 0 count = 0 for inputs, labels in data_loader: inputs = inputs.view(batch_size, 28*28).cuda() labels = labels.cuda() output = model(inputs) pred = output.max(1)[1] if labels.item() == pred.item(): correct += 1 count += 1 print(correct/count*100) test_accuracy()
実行してみると80.15%, まずまずです。
FGSM
pytorchのtutorialそのままです。
def fgsm_attack(image, epsilon, data_grad): sign_data_grad = data_grad.sign() perturbed_image = image + epsilon*sign_data_grad perturbed_image = torch.clamp(perturbed_image, 0, 1) return perturbed_image
実際に動かしてみる
FGSMとその画像表示
def ae_test_with_img(images, labels, epsilon): fig = plt.figure(figsize=(25, 10)) for i in range(5): # predict data = images[i].view(1, 28*28).cuda() data.requires_grad = True # for fgsm output = model(data) predict_n = output.max(1)[1] # fgsm label = labels[i].view(1).cuda() loss = F.cross_entropy(output, label) model.zero_grad() loss.backward() perturbed_data = fgsm_attack(data, epsilon, data.grad.data) output = model(perturbed_data) final_pred = output.max(1)[1] # show img plt.subplot(2, 5, i+1) plt.title("true: {}, pred: {}".format(label.item(), predict_n.item()), fontsize=25) plt_data = images[i].view(28, 28).numpy() plt.imshow(plt_data, cmap="gray") plt.axis("off") plt.subplot(2, 5, i+6) plt.title("pred: {}".format(final_pred.item()), fontsize=25) perturbed_img = perturbed_data.cpu()[0].cpu().detach().numpy().reshape(28, 28) plt.imshow(perturbed_img, cmap="gray") plt.axis("off") fig.suptitle("epsilon: {}".format(epsilon), fontsize=28) plt.show() data_loader = iter(DataLoader(mnist_data, batch_size=5, shuffle=False)) images, labels = next(data_loader) epsilon_list = [0.03, 0.3, 3] for epsilon in epsilon_list: ae_test_with_img(images, labels, epsilon)
以下が結果です。
が「人間は理解できるけど、機械はできない」一番いい感じです。ちなみに元論文の方ではを使っています。(合わせておけよ)
条件付き正解率
FGSMを行う前に正解していた画像の中で、FGSMを行なった後も正解している条件付きの正解率を調べてみます。
def ae_test_accuracy(epsilon): batch_size = 1 data_loader = DataLoader(mnist_data, batch_size=batch_size, shuffle=False) correct = 0 count = 0 for inputs, labels in data_loader: model.zero_grad() inputs = inputs.view(batch_size, 28*28).cuda() inputs.requires_grad = True labels = labels.cuda() output = model(inputs) pred = output.max(1)[1] loss = F.cross_entropy(output, labels) loss.backward() perturbed_data = fgsm_attack(inputs, epsilon, inputs.grad.data) pred_after_ae= model(perturbed_data).max(1)[1] if labels.item() == pred.item(): if pred.item() == pred_after_ae.item(): correct += 1 count += 1 print(correct/count*100) epsilon_list = [0, 0.03, 0.3, 3] for epsilon in epsilon_list: ae_test_accuracy(epsilon)
以下のような結果になりました。
条件付きの正解率 | |
---|---|
0 | 100% |
0.03 | 92.7% |
0.3 | 0.274% |
3 | 0% |
でガクッと落ちていますね。