李宏毅作业六 Adversarial Attack对抗攻击

系列文章目录

李宏毅作业十 Generative Adversarial Network生成对抗网络(代码)
李宏毅作业九 Anomaly Detection异常检测
李宏毅作业八unsupervised无监督聚类学习
李宏毅作业七其三 Network Compression (Network Pruning)
李宏毅作业七其二 Network Compression (Knowledge Distillation)
李宏毅作业七其一 Network Compression (Architecuture Design)

前言


作业里,不仅有原始注释,还有我自己附加的注释,有不对的地方还请大家多多指教

运行环境是cloab
python3


一、下载资料并解压缩

# 下載資料
!gdown --id '14CqX3OfY9aUbhGp4OpdSHLvq2321fUB7' --output data.zip
# 解壓縮
!unzip -qq -u data.zip
# 確認目前的檔案
!ls

二、创建环境

1.引入库

import os
# 讀取 label.csv
import pandas as pd
# 讀取圖片
from PIL import Image
import numpy as np

import torch
# Loss function
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")

2.读取资料

# 實作一個繼承 torch.utils.data.Dataset 的 Class 來讀取圖片
class Adverdataset(Dataset):
    def __init__(self, root, label, transforms):


        # 圖片所在的資料夾
        self.root = root
        # 由 main function 傳入的 label
        self.label = torch.from_numpy(label).long()
        # 由 Attacker 傳入的 transforms 將輸入的圖片轉換成符合預訓練模型的形式
        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):
        # 由於已知這次的資料總共有 200 張圖片 所以回傳 200
        return 200

三、载入模型

lass 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]
        # 把圖片 normalize 到 0~1 之間 mean 0 variance 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 這個 class 讀取資料,将标签值和训练值给dataset
        self.dataset = Adverdataset('./data/images', label, transform)
        
        # __init__中的几个重要的输入:1、dataset,这个就是PyTorch已有的数据读取接口
        #(比如torchvision.datasets.ImageFolder)或者自定义的数据接口的输出,
        # 该输出要么是torch.utils.data.Dataset类的对象,要么是继承自torch.utils.data.Dataset类的自定义类的对象。
        # 2、batch_size,根据具体情况设置即可。3、shuffle(打乱数据),一般在训练数据中会采用
        self.loader = torch.utils.data.DataLoader(
                self.dataset,
                batch_size = 1,
                shuffle = False)
        

    # FGSM 攻擊
    def fgsm_attack(self, image, epsilon, data_grad):#epsilon是后面自己设置数,体现噪声的强度

        # 找出 gradient 的方向
        sign_data_grad = data_grad.sign()
        # 將圖片加上 gradient 方向乘上 epsilon 的 noise
        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)#把数据转化为cpu,或者GPU的数据类型
            data_raw = data;
            data.requires_grad = True#自动计算梯度

            # 將圖片丟入 model 進行測試 得出相對應的 class
            output = self.model(data)
            init_pred = output.max(1, keepdim=True)[1]

            # 如果 class 錯誤 就不進行攻擊
            if init_pred.item() != target.item():
                wrong += 1
                continue
            
            # 如果 class 正確 就開始計算 gradient 進行 FGSM 攻擊
            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)

            # 再將加入 noise 的圖片丟入 model 進行測試 得出相對應的 class        
            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() 
                  #squeeze 数据的维度进行压缩,去掉维数为1的的维度,比如是一行或者一列这种,一个一行三列(1,3)的数去掉第一个维数为一的维度之后就变成(3)行


                  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()
    # new 一個 Attacker class
    attacker = Attacker('./data/images', df)
    # 要嘗試的 epsilon
    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)):#遍历之前eps里的元素,idx值为0,1

    for j in range(len(examples[i])):#遍历样本值,
        cnt += 1

        #subplot(nrows, ncols, plot_number)
        #或者写成subplot(nrows ncols plot_number)也行(中间不用逗号,前提是只能是三位数)
        #这个函数用来表示把figure分成nrows*ncols的子图表示,
        #nrows:子图的行数
        #ncols:子图的列数
        #plot_number 索引值,表示把图画在第plot_number个位置(从左下角到右上角)
        plt.subplot(len(epsilons),len(examples[0]) * 2,cnt)
        plt.xticks([], [])#坐标轴变名用法
        plt.yticks([], [])
        if j == 0:
            plt.ylabel("Eps: {}".format(epsilons[i]), fontsize=14)

        orig,adv,orig_img, ex = examples[i][j]

        # plt.title("{} -> {}".format(orig, adv))
        plt.title("original: {}".format(label_name[orig].split(',')[0]))
        orig_img = np.transpose(orig_img, (1, 2, 0))#转置(0,1,2)->(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]))
        ex = np.transpose(ex, (1, 2, 0))
        plt.imshow(ex)
plt.tight_layout()
plt.show()

总结

在前几个作业的学习下,这次程序基本都能看懂。

### 李宏毅机器学习课程中的对抗攻击作业讲解 #### 对抗样本生成方法 FGSM (Fast Gradient Sign Method) 为了理解如何完成对抗攻击作业,了解快速梯度符号法(FGSM)至关重要。该方法通过向输入数据添加微小扰动来创建对抗样本,这些扰动旨在误导模型做出错误预测[^2]。 ```python import torch from torchvision import models, transforms from PIL import Image 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算法。`epsilon`参数控制着扰动的强度,而`data_grad`则是损失函数相对于输入图像的梯度。 #### 黑盒攻击策略 除了白盒场景下的直接攻击外,在实际环境中更常见的是黑盒攻击。在这种情况下,攻击者无法访问目标模型的具体结构或权重信息。一种常见的做法是从源模型迁移已知的有效扰动至目标模型上测试其有效性。 #### 防御机制概述 针对上述提到的各种类型的攻击手段,可以采取两种不同的防御措施: - **被动防御(Passive defense)**:这种方法不会修改原始模型架构本身,而是试图检测并过滤掉潜在的对抗样例。 - **主动防御(Proactive defense)**:涉及对现有网络进行调整优化使其更加鲁棒,比如采用对抗训练等方式提高泛化性能面对未知威胁时的表现. #### 实验设计建议 当准备提交作业成果报告时,应该考虑以下几个方面来进行实验验证: - 测试集的选择应当具有代表性; - 尝试多种不同大小的ε值观察效果变化规律; - 分析各类防御方案对于特定类型攻击的实际抵御效能差异。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值