Hung-Yi Lee homework[6]:Adversarial Attack

Hung-Yi Lee homework[6]:Adversarial Attack


(一)作业描述

  使用FGSM算法得到攻击图像。FGSM算法地址
  此次data文件夹中包含一个子文件夹和两个csv表格。
在这里插入图片描述
  文件夹/images中包含有200张图片。
在这里插入图片描述

(二)作业实现

  本次作业直接采用示例代码即可,不需要进行任何改动就可以直接跑通。

import os
import pandas as pd
from PIL import Image
import numpy as np
import torch
import torch.nn.functional as F
import torchvision.datasets as datasets
from torch.utils.data import Dataset, DataLoader
import torchvision.models as models
import torchvision.transforms as transforms
import matplotlib.pyplot as plt

device = torch.device("cuda")


class Adverdataset(Dataset):
    def __init__(self, root, label, transforms):
        # 图片所在的文件夹
        self.root = root
        # 传入的label
        self.label = torch.from_numpy(label).long()
        # 由attacker传入的transform将输入的图片转换成符合预训练模型的形式
        self.transforms = transforms
        # 图片名称的list
        self.fnames = []

        for i in range(200):
            self.fnames.append("{:03d}".format(i))

    def __getitem__(self, idx):
        # 利用路径读取图片
        img = Image.open(os.path.join(self.root, self.fnames[idx] + '.png'))
        # 将输入的图片转换成符合预测训练模型的形式
        img = self.transforms(img)
        # 图片相对应的label
        label = self.label[idx]
        return img, label

    def __len__(self):
        # 已知data中共有200张图片
        return 200


class Attacker:
    def __init__(self, img_dir, label):
        # 载入预训练模型vgg16
        self.model = models.vgg16(pretrained=True)
        self.model.cuda()
        self.model.eval()
        self.mean = [0.485, 0.456, 0.406]
        self.std = [0.229, 0.224, 0.225]
        # 归一化,[0,1],平均值0,方差1
        self.normalize = transforms.Normalize(self.mean, self.std, inplace=False)
        transform = transforms.Compose([
            transforms.Resize((224, 224), interpolation=3),
            transforms.ToTensor(),
            self.normalize
        ])
        # 利用 Adverdataset
        self.dataset = Adverdataset('./data/images', label, transform)

        self.loader = torch.utils.data.DataLoader(
            self.dataset,
            batch_size=1,
            shuffle=False)

    # FGSM 攻击
    def fgsm_attack(self, image, epsilon, data_grad):
        # 找出 gradient 的方向
        sign_data_grad = data_grad.sign()
        perturbed_image = image + epsilon * sign_data_grad
        return perturbed_image

    def attack(self, epsilon):
        # 存下一些成功攻击后的图片
        adv_examples = []
        wrong, fail, success = 0, 0, 0
        for (data, target) in self.loader:
            data, target = data.to(device), target.to(device)
            data_raw = data;
            data.requires_grad = True
            # 将图片丢入model进行测试
            output = self.model(data)
            init_pred = output.max(1, keepdim=True)[1]

            if init_pred.item() != target.item():
                wrong += 1
                continue

            loss = F.nll_loss(output, target)
            self.model.zero_grad()
            loss.backward()
            data_grad = data.grad.data
            perturbed_data = self.fgsm_attack(data, epsilon, data_grad)

            output = self.model(perturbed_data)
            final_pred = output.max(1, keepdim=True)[1]

            if final_pred.item() == target.item():
                fail += 1
            else:
                success += 1
                # 将攻击成功的图片进行保存
                if len(adv_examples) < 5:
                    adv_ex = perturbed_data * torch.tensor(self.std, device=device).view(3, 1, 1) + torch.tensor(
                        self.mean, device=device).view(3, 1, 1)
                    adv_ex = adv_ex.squeeze().detach().cpu().numpy()
                    data_raw = data_raw * torch.tensor(self.std, device=device).view(3, 1, 1) + torch.tensor(self.mean,
                                                                                                             device=device).view(
                        3, 1, 1)
                    data_raw = data_raw.squeeze().detach().cpu().numpy()
                    adv_examples.append((init_pred.item(), final_pred.item(), data_raw, adv_ex))
        final_acc = (fail / (wrong + success + fail))

        print("Epsilon: {}\tTest Accuracy = {} / {} = {}\n".format(epsilon, fail, len(self.loader), final_acc))
        return adv_examples, final_acc

if __name__ == '__main__':
    # 读入图片对应的label
    df = pd.read_csv("./data/labels.csv")
    df = df.loc[:, 'TrueLabel'].to_numpy()
    label_name = pd.read_csv("./data/categories.csv")
    label_name = label_name.loc[:, 'CategoryName'].to_numpy()
    attacker = Attacker('./data/images', df)
    epsilons = [0.1, 0.01]

    accuracies, examples = [], []

    # 进行攻击
    for eps in epsilons:
        ex, acc = attacker.attack(eps)
        accuracies.append(acc)
        examples.append(ex)

    cnt = 0
    plt.figure(figsize=(30, 30))
    for i in range(len(epsilons)):
        for j in range(len(examples[i])):
            cnt += 1
            plt.subplot(len(epsilons), len(examples[0]) * 2, cnt)
            plt.xticks([], [], fontsize=5)
            plt.yticks([], [], fontsize=5)
            if j == 0:
                plt.ylabel("Eps: {}".format(epsilons[i]), fontsize=10)
            orig, adv, orig_img, ex = examples[i][j]
            # plt.title("{} -> {}".format(orig, adv))
            plt.title("original: {}".format(label_name[orig].split(',')[0]), fontsize=8)
            orig_img = np.transpose(orig_img, (1, 2, 0))
            plt.imshow(orig_img)
            cnt += 1
            plt.subplot(len(epsilons), len(examples[0]) * 2, cnt)
            plt.title("adversarial: {}".format(label_name[adv].split(',')[0]), fontsize=8)
            ex = np.transpose(ex, (1, 2, 0))
            plt.imshow(ex)
    plt.tight_layout()
    plt.show()

  实现结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值