【实验笔记】FoolBox

文章详细介绍了如何使用Foolbox库对CIFAR-10数据集上的ResNet20模型进行对抗攻击,包括加载预训练模型、数据预处理、设置攻击步长以及使用hook获取中间层特征。作者还提到归一化参数的重要性,并分享了解决数据超出边界问题的方法。
摘要由CSDN通过智能技术生成

1 参考资料

Introduction | Foolbox (jonasrauber.de) 官方的指导书

https://github.com/bethgelab/foolbox 代码

本文完结撒花✿✿ヽ(°▽°)ノ✿

bushi不过其实有上面两个就可以靠自己查查找找来做实验了,所以下面是本人残存记忆中还有的部分注意点。

2 部分代码解析

2.1 dataset

从本地读取图片

    # 定义图像预处理操作
    transform = transforms.Compose(
        [transforms.ToTensor()])
    batch_size = 100                 # 就是图片的数量
    # 本地
    data_path = r'./data'            # 得查一查datasets.ImageFolder对于本地文件夹结构的要求,大概是要求data/类别名/.png
    testset = datasets.ImageFolder(data_path, transform=transform)
    testloader = torch.utils.data.DataLoader(testset, shuffle=True, batch_size=batch_size,
                                             num_workers=0)  # 暂时没做归一化,后面做

    with torch.no_grad():
        for data in testloader:
            images, labels = data[0], data[1]

2.2 model

    model = resnet.cifar10_resnet20()
    state_dict_path = f'./model_resnet20.pth'
    model.load_state_dict(torch.load(state_dict_path))
    model.eval().to(device)
    preprocessing = dict(mean=[0.4914, 0.4822, 0.4465], std=[0.2023, 0.1994, 0.2010], axis=-3)        # 敲黑板,归一化了哈,看清参数
    fmodel = fb.PyTorchModel(model, bounds=(0, 1), preprocessing=preprocessing)
    fmodel = fmodel.transform_bounds((0, 1))  # 转换边界

上面读入图片的时候我没做归一化,但是这里是做了的,参数如上图,我真的永远会为归一化参数而流泪,很想知道大佬都是怎么知道是归一化参数的问题的,是怎么找到正确的参数的(参考如何使CIFAR-10测试集的分类准确率从40%提升到90% - 知乎 (zhihu.com)

就是因为这个参数导致我的运行结果对标签的判定一直有点问题,找了好久好久呜呜呜

2.3 遍历对每一张图片进行攻击

(1)因为本人需要从dataset里面单拎image出来处理,所以我的数据维度下降了1D,就需要用到unsqueeze来升维

(2)注意model在gpu上,要把iamge和label也放到gpu上

(3)本人记录的是使得攻击后模型分类失败的那个eplison。注意:少数图片不加干扰就分类失败,可以用手动检查的方式,不把分类结果和真是标签对比,以其分类结果第一次改变时的eplison为准

for image, label in zip(images, labels):
    image = torch.unsqueeze(image, dim=0)  # 将image从3D -> 4D
    label = label.unsqueeze(0)  # 使用unsqueeze方法增加一个维度
    epsilon = 0

    # eplison == 0
    raw, clipped, is_adv = attack(model, image.to(device), label.to(device), epsilons=0)
    predict0 = model(clipped)
    _, predicted0 = torch.max(predict0.data, 1)

    flag = is_adv

   
    for i in range(1, 4001, 1):
        eps = i * 0.0001
        raw, clipped, is_adv = attack(model, image.to(device), label.to(device), epsilons=eps)
        # print(f"eps:{eps}\t\tis_adv:{is_adv}")

        # # 手动检查:将攻击后的剪裁输入到模型内分类,再对比分类结果与攻击前分类结果
        # predict = model(clipped)
        # _, predicted = torch.max(predict.data, 1)
        #
        # if predicted != predicted0:
        #     epsilon += eps
        #     print(f"the picture's robust accuracy{j + 1} is {eps}")
        #     break

        # 用is_adv参数
        if is_adv != flag:
            epsilon += eps
            print(f"the picture's robust accuracy is {eps}")
            return
        else:
            flag = is_adv

        if eps == 0.4:
            print(f"the picture's robust accuracy is out of range\n\n\n")
            return

2.4 hook

hook是一种可以获取中间层输出的方法,通过给model的前向传播中注入一个钩子,让每次模型输入处理时都可以将目标层的输出/特征值等信息返回。

class HookTool:
    def __init__(self):
        self.fea = None

    def hook_fun(self, module, fea_in, fea_out):
        '''
        注意用于处理feature的hook函数必须包含三个参数[module, fea_in, fea_out],参数的名字可以自己起,但其意义是
        固定的,第一个参数表示torch里的一个子module,比如Linear,Conv2d等,第二个参数是该module的输入,其类型是
        tuple;第三个参数是该module的输出,其类型是tensor。注意输入和输出的类型是不一样的,切记。
        '''
        self.fea = fea_out


def get_feas_by_hook(model):
    """
    需要找到目标层的名字
    """
    fea_hooks = []
    for name, module in model.named_children():
        if name == '目标层的名字':
            cur_hook = HookTool()
            module.register_forward_hook(cur_hook.hook_fun)
            fea_hooks.append(cur_hook)
    return fea_hooks

hook = get_feas_by_hook(model)
output = model(image0)
target = hook[0].fea

这里目标层的名字或许可以通过看model.forward来解决。例如我的forward长这样 

其中''layer1' | 'avgpool' | 'fc' 等都是可以的目标层。

3 其他

似乎还记得出现过的问题:

(1)attack的时候报错说数据超出上限还是下限来着,然后实际是因为某个数据没有转化边界??总之是下面的两句之一吧

    fmodel = fb.PyTorchModel(model, bounds=(0, 1), preprocessing=preprocessing)
    fmodel = fmodel.transform_bounds((0, 1))  # 转换边界

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值