torchattacks源码详解-attack篇

1.简介

  本文旨在记录学习过程中对于torchattacks库中的attack源码的一些解读,若有错误之处请多指正。

2.遗留问题

  1.对于开头定义的装饰器(def wrapper_method(func))的作用仍不清楚。

  2.构造函数中赋予属性self._attacks的有序字典何时被赋值仍不清楚。

  3.代码最后重写的的def __setattr__(self, name, value)函数的作用仍不清楚。

  暂时猜测(仅猜测,很可能完全理解错了,因为这个功能自己也没看源码)这三个问题是与torchattacks提供的Make a set of attacks功能相挂钩的,该功能具体请看链接:https://github.com/Harry24k/adversarial-attacks-pytorch

3.代码解读

1.note中说明了该类(Attack)是所有攻击方法的基类,例如FGSM、CW等攻击方法都需要继承该类。并且会自动的将使用的设备(cpu/gpu)更改为所提供的欲攻击模型所使用的设备,例如attack=torchattacks.FGSM(resnet18),那么此次攻击所使用的设备即为resnet18所使用的设备。在攻击过程中一般会将模型设置为eval模式,若想要改变攻击过程中模型所使用的模式(train/eval),请使用set_model_training_mode函数(该函数遇到后会详细说明)。

2.构造函数主要内容如下:构造函数需要传入两个参数,name为攻击的名称,model为准备攻击的模型名称,例如在fgsm.py文件中(super().__init__("FGSM", model))这样调用父类Attack的构造函数。self.attack = name,将攻击名称传递给属性self.attack,该属性会在def __repr__(self)函数中被调用,用来显示此次攻击的一些基本信息(该函数遇到后会详细说明)。self._attacks = OrderedDict(),属性self._attacks被赋值为有序字典,但具体用法不清楚,是遗留问题中的第二个问题。self.set_model(model)则是调用了方法set_model,该方法主要作用是将传入的参数model赋值给属性self.model,并将该model的名称赋值给属性self.model_name,现在self.model为准备攻击的模型,而self.model_name基本不会再用到。再下面的异常结构则为设置本次攻击所使用的设备,若使用过程中报错"Failed to set device automatically, please try set_device() manual."则需要调用set_device()方法手动设置,例如attack=torchattacks.FGSM(resnet18),attack.set_device("cpu")。self.attack_mode = "default",该属性主要用于定义攻击模式,会在def set_mode_default(self),def _set_mode_targeted(self, mode, quiet)两个函数中被改写,后面会有一些定义攻击模式的方法调用这两个函数从而改写self.attack_mode,遇到再详细解释。self.supported_mode = ["default"],该属性定义了采用的攻击方法所支持的攻击模式,一般会在继承的子类的构造函数中重写,例如fgsm.py中的self.supported_mode = ["default", "targeted"],该属性在def _set_mode_targeted(self, mode, quiet)方法中也会被调用用来判断当前攻击方法是否支持定向模式。self.targeted = False,该属性用来标志当前攻击是定向/非定向,后面会在def set_mode_default(self),def _set_mode_targeted(self, mode, quiet)两个方法中被改写。self._target_map_function = None,该属性用来接收标签映射函数,会在def set_mode_targeted_by_function(self, target_map_function, quiet=False),def set_mode_targeted_random(self, quiet=False),def set_mode_targeted_least_likely(self, kth_min=1, quiet=False),def set_mode_targeted_by_label(self, quiet=False)这几个方法中被赋予具体的函数,并在def get_target_label(self, inputs, labels=None)被调用用来计算得到目标标签。self.normalization_used = None,该属性在def set_normalization_used(self, mean, std)方法中将被赋值为存均值方差的字典,并在def normalize(self, inputs),def inverse_normalize(self, inputs)等方法中用于标准化。self._normalization_applied = None,该属性作为输入图像是否经过标准化的一种标志,后面被调用时会被赋值为True/False。if self.model.__class__.__name__ == "RobModel"表明若攻击的模型是RobModel的话需要经过特殊的self._set_rmodel_normalization_used(model)标准化处理,由于还未接触过RobModel,所以这里忽略这个判断语句及后面的def _set_rmodel_normalization_used(self, model)方法。self._model_training = False,self._batchnorm_training = False,self._dropout_training = False三个属性用来设置攻击过程中的模型模式。

3.forward函数必须在所有子类中重写,否则会报错误,例如fgsm.py中重写了forward函数,forward函数的主要功能是根据具体的攻击方法(例如FGSM攻击,forward函数中会写如何基于梯度来实现对抗样本)来实现并返回对抗样本。

4.def set_model(self, model)函数:由于不清楚wrapper_method装饰器起到了什么作用,后面都会默认忽略掉@wrapper_method这行代码(遗留问题1)。该方法的主要功能是将传入的模型赋值给self.model属性,并将模型名称赋值给self.model_name。

5.def get_logits(self, inputs, labels=None, *args, **kwargs):该方法的主要作用是将传入的数据放到模型中得到输出结果并返回,通常在子类中会被调用,例如fgsm.py中的outputs = self.get_logits(images),该方法还会判断当前数据是否经过了标准化,若数据预处理使用了标准化,但self._normalization_applied标志为False,则会先对输入数据进行标准化再放入模型中得到输出结果。

6.def _set_normalization_applied(self, flag):该方法用来将self._normalization_applied属性设置为传入的参数flag的值,该方法后面会被多次调用,以用来更改标准化标志self._normalization_applied的值(True/False)(该属性的作用类似开关,用来决定当前数据是否要经过标准化).

7.def set_device(self, device):该方法用来设置攻击所使用的设备(cpu/gpu)。

8.def _set_rmodel_normalization_used(self, model):该方法为RobModel所特需的标准化,略过。

9.def set_normalization_used(self, mean, std):该方法主要用来将self.normalization_used属性设置为字典,并存储传入的均值方差,并调用self._set_normalization_applied(True)函数,将属性self._normalization_applied设置为True。若需要添加扰动的图像已经经过标准化处理,则需要调用该函数,例如:
test_data = ImageFolder(root='./data', transform=transforms.Compose(
[
transforms.Resize((256, 256)),
transforms.RandomCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225],),
]
))
attack= torchattacks.FGSM(models)
attack.set_normalization_used(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225],)
调用完该函数之后会自动调用self._set_normalization_applied(True)使得属性self._normalization_applied设置为True,在__call__方法中若该成员属性为True,则test_data会先逆标准化,然后将逆标准化的test_data传入forward函数得到对抗样本,再将对抗样本经过标准化后返回,这时得到的对抗样本直接输入模型即可,不需要再标准化了,保存的时候save函数会将对抗样本再逆标准化,这时保存的对抗图像和原始的未经标准化的图像差别就不会很大。不过对保存的对抗样本进行测试的时候记得再标准化(直接返回的对抗样本是经过标准化的,save方法保存的对抗样本是不经标准化的)。

10.def normalize(self, inputs):该方法用于对输入进行标准化。

11.def inverse_normalize(self, inputs):对输入进行逆标准化。

12.def get_mode(self):调用该函数得到目前攻击模式,例如:mode = attack.get_mode(),返回结果为属性self.attack_mode。

13.def set_mode_default(self):该方法将属性self.attack_mode = "default",self.targeted = False都设置为默认值。

14.def _set_mode_targeted(self, mode, quiet):该私有方法主要被下面几个设置攻击模式的方法调用,主要作用是将属性self.targeted = True,并设置self.attack_mode属性值为传入参数mode的值,若攻击方法不支持定向,则调用该函数会报错"Targeted mode is not supported."。

15.def set_mode_targeted_by_function(self, target_map_function, quiet=False):该方法会调用self._set_mode_targeted("targeted(custom)", quiet)方法,并将参数target_map_function所代表的函数传递给属性self._target_map_function。若用户要自定义标签的映射方法,可以调用该方法,例如:attack=torchattacks.FGSM(resnet18),attack.set_mode_targeted_by_function(lambda inputs, labels:(labels+1)%10),那么目标标签将会是真实标签加1余10。

16.def set_mode_targeted_random(self, quiet=False):该方法实现了如下功能self._set_mode_targeted("targeted(random)", quiet)
self._target_map_function = self.get_random_target_label。第一个功能不再赘述,第二个是为属性self._target_map_function赋值后面出现的def get_random_target_label(self, inputs, labels=None)方法,该方法主要是用来随机的设置目标标签(除真实标签外)。例子:attack=torchattacks.FGSM(resnet18),attack.set_mode_targeted_random()。

17.def set_mode_targeted_least_likely(self, kth_min=1, quiet=False):该方法用于将目标标签设置为最不可能的k个标签(即原始预测概率最低的k个标签),注意kth_min参数必须传入正整数,否则会报错。例如:attack=torchattacks.FGSM(resnet18),attack.set_mode_targeted_least_likely(kth_min=1)。

18.def set_mode_targeted_by_label(self, quiet=False):该方法用来实现人为指定目标标签,例如:attack = torchattacks.FGSM(models)
attack.set_mode_targeted_by_label()
adv_images = attack(images, target_label),注意这时候给的是我想要定向到的标签,而不再是真实标签,而其他几个攻击模式在最后一步传入的标签需要是真实标签。

19.def set_model_training_mode(
self, model_training=False, batchnorm_training=False, dropout_training=False
):调用该方法来设置三个私有属性self._model_training = model_training
self._batchnorm_training = batchnorm_training
self._dropout_training = dropout_training,用于下面的_change_model_mode方法中,用来决定是否改变模型模式。例子:attack.set_model_training_mode(True,True,True)

20.def _change_model_mode(self, given_training):该方法根据构造函数/set_model_training_mode方法所提供的self._model_training = False,self._batchnorm_training = False,
self._dropout_training = False,三个私有属性值来设置模型的具体模式(整个模型/batchnorm层/dropout层),19,20这两个方法基本不会用到。

21.def _recover_model_mode(self, given_training):该方法用来恢复模型的初始模式,基本也不会使用。

22.def save(
self,
data_loader,
save_path=None,
verbose=True,
return_verbose=False,
save_predictions=False,
save_clean_inputs=False,
save_type="float",
):参数data_loader需要传入的数据为通过DataLoader加载好的原始数据,save_path为保存的路径,verbose负责控制是否打印保存过程中的详细信息,return_verbose是否返回详细信息,save_predictions控制是否保存预测结果(预测概率最大的标签),save_clean_inputs控制是否保存干净样本,save_type控制保存的数据类型(int/float)。一个简单的应用例子如下:

test_data = ImageFolder(root='./data', transform=transforms.Compose(
[
transforms.Resize((256, 256)),
transforms.RandomCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225],),
]
))
test_data = DataLoader(batch_size=...)
attack = torchattacks.FGSM(models)
attack.set_normalization_used(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225],)
attack.save(test_data, save_path='……pt')

if save_path is not None:该判断条件主要用来生成存储对抗样本、真实标签(预测标签、干净样本)的列表。correct = 0,用来记录扰动后仍预测正确的样本总数。total = 0,用来记录样本总数。l2_distance = [],用来记录扰动后预测错误的样本与原样本之间的l2距离,从而衡量扰动量的大小。

【由于精力有限,其余的有空再更……】

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值