深度学习后门攻击是一种针对深度学习模型的恶意攻击手段。攻击者通过在训练数据中植入特定的触发器,使得训练好的模型在面对含有这些触发器的输入时产生预定的错误输出,而在处理正常输入时则表现正常。这种攻击利用了深度学习模型的可塑性和对训练数据的依赖性。
"后门攻击"这个名称的由来有几个原因: 这个术语借鉴了传统计算机安全中的"后门"概念。在计算机系统中,后门是指绕过正常认证过程的秘密入口,允许未经授权的访问。深度学习中的后门攻击同样提供了一种隐蔽的方式来操纵模型的行为。 就像建筑物的后门通常不那么显眼一样,这种攻击也是隐蔽的。模型在大多数情况下表现正常,只有在遇到特定触发器时才会表现出异常行为。后门攻击为攻击者创建了一个预设的、秘密的方式来控制模型的输出,类似于一个隐藏的控制通道或"后门"。正如实际的后门允许绕过正门进入建筑物,深度学习中的后门攻击也允许绕过模型的正常决策过程,直接触发预定的错误输出。后门通常难以被发现,除非知道它的确切位置和触发方式。同样,深度学习模型中的后门也很难被检测到,除非使用特定的触发器。
这个名称生动地描述了这种攻击的本质:它创建了一个隐蔽的、预设的方式来操纵模型的行为,就像在模型中植入了一个秘密的"后门"。
后门攻击的实施过程通常包括以下几个步骤:
这个过程完成后,攻击就已经植入到模型中了。不过这种是最基础的,我们会在本文的后面来分析并实现一些高级的攻击手段。
深度学习后门攻击研究具有双刃剑的特性。虽然它在安全性研究、模型鲁棒性提升、数据隐私保护和对抗性学习研究等方面有积极作用,但其潜在的安全威胁、隐私泄露、信任问题和社会影响等消极作用也不容忽视。
我们在了解其积极应用与消极应用的基础上,才能更好地理解后门攻击。
深度学习后门攻击的研究在安全性研究方面具有重要的积极作用。通过模拟后门攻击,研究人员可以开发更有效的检测和防御技术,识别模型中的潜在漏洞,增强系统的安全性。此外,这些研究还可以评估现有防御机制的有效性,推动更强大的安全方案的设计和实施。
后门攻击的研究还有助于提升模型的鲁棒性。通过识别和修复模型中的后门,可以使模型更加鲁棒,对各种恶意输入有更好的抵抗力。同时,模拟后门攻击可以测试模型在面对恶意输入时的表现,确保其在实际应用中的可靠性。
在数据隐私保护方面,后门攻击的研究也发挥着重要作用。理解和预防模型泄露敏感数据的风险,可以保护用户隐私。此外,通过后门攻击可以评估模型是否会无意中泄露训练数据中的隐私信息,进而改进数据处理和模型训练的方法。
对抗性学习研究也从后门攻击的研究中获益。研究后门攻击可以为对抗性学习提供新的视角,帮助开发出更强大的对抗性防御策略。通过生成对抗性样本,可以训练出更加健壮的模型,提高模型的安全性和可靠性。
后门攻击也带来了显著的消极作用。它们构成了严重的安全威胁,攻击者可以利用后门破坏深度学习系统的完整性,导致系统做出错误或有害的决策。此外,后门攻击可能导致数据篡改,影响数据的真实性和准确性,造成严重的后果。
隐私泄露是后门攻击的另一大风险。攻击者可以通过后门获取用户数据,侵犯用户隐私,带来法律和道德风险。他们还可以获取模型中的敏感信息,对个人或组织造成威胁,增加了数据保护的难度。
后门攻击也对信任问题造成影响。其风险可能导致用户对深度学习系统的信任下降,影响其在实际应用中的接受度和普及率。对于企业而言,如果其产品被发现存在后门,将会对商业信誉造成严重打击,影响市场竞争力。
后门攻击带来的社会影响不容忽视。它们可能被不法分子滥用,用于恶意目的,例如诈骗、数据盗窃和信息操纵等。此外,后门攻击的存在增加了对深度学习系统监管的难度,要求更严格的安全和隐私保护措施,以确保技术的安全和负责任的应用。
未知攻焉知防,接着我们分析与实现一些高级的后门攻击方案。
深度学习后门攻击是一种针对深度学习系统的安全威胁,它通过在模型的训练过程中植入特定的机制,使得模型在遇到某些特定的输入模式(即触发器)时,产生与正常行为不同的输出。这种攻击通常在模型的预期行为之外,执行攻击者预定的恶意行为。例如,在图像分类任务中,一个正常分类的网络在遇到含有特定触发器的图像时,可能会错误地将其分类为攻击者指定的类别
现有后门攻击技术的局限性主要在于它们依赖于固定的触发模式。这意味着无论输入数据是什么,触发器的样式和位置都是不变的。这种方法的缺点是触发器容易被检测出来,因为它们在所有被毒化的数据中都是相同的。一旦检测到,防御者可以通过特定的方法来缓解或移除这些后门,例如通过数据清洗或模型再训练。
Input-Aware Trigger 是就是本章要分析的一种新型后门攻击技术,其核心思想是生成与输入数据相关的动态触发器。这种触发器不是固定的,而是根据每个具体的输入样本来定制的,从而使得每个样本都有一个独特的触发条件。这样的设计带来了以下优势:
通过这种方式,攻击者可以创建一个看似正常但实际含有隐蔽后门的模型,这个模型在正常操作下表现良好,但在遇到特定的、为每个输入定制的触发器时,会执行恶意行为。这种攻击方法对现有的安全防御措施提出了新的挑战,并要求研究者开发新的检测和防御技术来应对这种威胁。
现在我们来形式化说明这种攻击方案
在攻击方案中,攻击者首先设计一个触发器生成器,这是一个能够接受输入图像并输出相应触发模式的网络。该生成器利用多样性损失来确保不同输入图像产生的触发器之间存在显著差异,从而避免了触发器的重复性。这种设计使得即使在大量样本中,也很难找到一个统一的模式来描述所有的触发器。进一步地,Input-Aware 攻击方法引入了非重用性的概念。这意味着为特定输入生成的触发器不能被用于其他任何输入,从而大大增加了攻击的复杂性和检测难度。为了实现这一点,攻击者在训练过程中引入了交叉触发测试,确保一个输入上的触发器不会错误地激活其他输入样本的后门行为。
攻击者在训练过程中采用了三种模式:清洁模式、攻击模式和交叉触发模式。在清洁模式下,网络正常学习如何正确分类输入图像;在攻击模式下,网络被训练以在触发器出现时输出特定的攻击标签;而在交叉触发模式下,网络学习忽略其他图像的触发器,从而强化了触发器的非重用性。下图就是所说的三种模式
整个训练的目标是通过最小化总损失函数来完成的,该损失函数是分类损失和多样性损失的加权和。分类损失确保了网络在不同模式下的正确分类,而多样性损失则推动了触发器生成器产生多样化的触发器。
通过这种方法,攻击者成功地训练出了一个在正常样本上表现良好,但在遇到特定触发器时能够执行后门行为的模型。
攻击的示意图如下所示
这个类实现了一个输入感知的生成器网络,具有多个卷积层和上/下采样层,适用于处理不同数据集的图像生成任务。正则化和反正则化方法确保输入数据在处理前后的正确缩放和标准化。
这个类 InputAwareGenerator
是一个神经网络模型,用于处理图像数据,特别是为 MNIST 数据集和其他图像数据集设计的。
__init__
方法)__init__
方法接受两个参数 args
和 out_channels
。
args
包含配置参数,比如数据集类型和输入通道数。
根据数据集类型(mnist
或其他),初始化不同的通道数和步骤数:
mnist
,初始化通道数为 16,步骤数为 2。初始化时,模型根据步骤数添加卷积层、下采样层和上采样层。
channel_current
初始化为输入通道数。channel_next
初始化为 channel_init
。使用 for
循环添加下采样卷积层:
Conv2dBlock
和一个下采样块 DownSampleBlock
。channel_current
和 channel_next
。channel_next
翻倍。Conv2dBlock
。使用 for
循环添加上采样卷积层:
UpSampleBlock
和两个卷积块 Conv2dBlock
。ReLU
激活函数被禁用。channel_current
和 channel_next
。out_channels
来设置 channel_next
为输入通道数或 out_channels
。_EPSILON
定义为一个非常小的值,用于避免除零错误。_normalizer
和 _denormalizer
分别通过 _get_normalize
和 _get_denormalize
方法获得,用于数据的正则化和反正则化。tanh
是一个 Tanh
激活函数实例。_get_denormalize
和 _get_normalize
方法:根据数据集的均值和标准差返回正则化和反正则化实例。forward
方法:前向传播,依次通过所有添加的模块,最后应用 Tanh
激活函数。normalize_pattern
方法:对输入进行正则化处理。denormalize_pattern
方法:对输入进行反正则化处理。threshold
方法:对输入应用 Tanh
激活函数,并进行缩放。Threshold
类通过 Tanh
激活函数对输入数据进行特定的缩放和转换。
generalize_to_lower_pratio` 函数根据给定的毒样本比例和批次大小,计算批次中应该包含的毒样本数量,特别是在毒样本比例很低的情况下,确保毒样本的随机分布。
这段代码定义了一个 Threshold
类和一个 generalize_to_lower_pratio
函数
Threshold
类继承自 nn.Module
,定义了一个自定义的神经网络层,用于对输入数据应用 Tanh
激活函数并进行特定的缩放。
__init__
)__init__
方法是类的构造函数,用于初始化类的实例。super(Threshold, self).__init__()
来初始化父类 nn.Module
。Tanh
激活函数实例并将其保存在 self.tanh
中。forward
)forward
方法定义了当输入数据通过该层时的计算过程。x
,首先将其放大 20 倍,然后减去 10。Tanh
激活函数。2 + 1e-7
进行缩放,最后加上 0.5。这个类可以用于将输入数据缩放到 [0, 1] 范围内,并具有中心化的效果。
generalize_to_lower_pratio
函数用于根据给定的比例和批次大小计算每个批次中应该包含的“毒样本”数量(可能指有特殊标记的数据样本)。
pratio
:表示毒样本的比例。bs
:表示批次大小(batch size)。首先检查 pratio * bs
是否大于等于 1。
如果是,则表示每个批次中可以包含至少一个毒样本,返回 pratio * bs
作为毒样本的数量。
如果不是,则处理特殊情况,决定是否在批次中包含一个毒样本。
pratio * bs
,则返回 1,表示该批次包含一个毒样本。这个函数确保在毒样本比例非常低的情况下,批次中仍可能随机包含毒样本,从而实现毒样本在批次中的稀疏分布。
InputAware
类扩展了 BadNet
类,增加了自定义的命令行参数设置和数据准备方法。set_bd_args
方法,可以灵活地配置攻击模型的参数。stage1_non_training_data_prepare
方法确保第一阶段的非训练数据准备充分,包括创建必要的数据集和数据加载器。这个 InputAware
类继承自 BadNet
类,并扩展了其功能。主要包括初始化、设置命令行参数和准备非训练数据等方法
InputAware
类InputAware
类是 BadNet
的子类,主要用于输入感知的攻击模型设置和数据准备。
__init__
)BadNet
的初始化方法,通过 super(InputAware, self).__init__()
实现。set_bd_args
方法)set_bd_args
是一个类方法,用于为攻击模型设置命令行参数。
接受一个 argparse.ArgumentParser
实例 parser
作为参数,并返回更新后的 parser
。
调用 add_common_attack_args
函数,添加一些常见的攻击参数。
添加一系列特定的命令行参数,每个参数都有类型说明和可选的默认值:
--bd_yaml_path
:指定 YAML 配置文件的路径。--lr_G
, --lr_C
, --lr_M
:学习率参数。--C_lr_scheduler
:学习率调度器类型。--schedulerG_milestones
, --schedulerC_milestones
, --schedulerM_milestones
:学习率调度器的里程碑列表。--schedulerG_lambda
, --schedulerC_lambda
, --schedulerM_lambda
:学习率调度器的 lambda 值。--lambda_div
, --lambda_norm
:正则化参数。--mask_density
:掩码密度。--EPSILON
:用于避免除零错误的小值。--clean_train_epochs
:清洁训练的轮数。--random_rotation
, --random_crop
:数据增强参数,如随机旋转和裁剪的范围。stage1_non_training_data_prepare
方法)stage1_non_training_data_prepare
方法用于准备第一阶段的非训练数据。
记录日志,表明第一阶段开始。
确认 self
对象包含 args
属性。
调用 benign_prepare
方法,获取一系列数据集和转换(transform):
train_dataset_without_transform
:未经过转换的训练数据集。train_img_transform
和 train_label_transform
:训练图像和标签的转换。test_dataset_without_transform
:未经过转换的测试数据集。test_img_transform
和 test_label_transform
:测试图像和标签的转换。clean_train_dataset_with_transform
:经过转换的清洁训练数据集。clean_train_dataset_targets
:清洁训练数据集的目标。clean_test_dataset_with_transform
:经过转换的清洁测试数据集。clean_test_dataset_targets
:清洁测试数据集的目标。创建四个数据加载器(dataloaders),用于处理转换后的清洁训练和测试数据集:
clean_train_dataloader1
和 clean_train_dataloader2
:两个清洁训练数据加载器。clean_test_dataloader1
和 clean_test_dataloader2
:两个清洁测试数据加载器。将转换后的清洁训练数据集和四个数据加载器保存在 self.stage1_results
中。
这个函数 stage2_training
是一个神经网络的训练过程,特别是与数据中毒攻击相关的训练。
准备阶段:
self
对象中是否包含 args
属性,并获取该属性。Metric_Aggregator
实例,用于收集训练过程中的各种指标。stage1_results
中获取干净的训练和测试数据集及其数据加载器。设置设备和模型:
netC
、生成器 netG
以及一个单通道输出的生成器 netM
,并将它们移动到指定设备。self.threshold
并移动到指定设备。多 GPU 支持:
DataParallel
,以便支持多 GPU 并行计算。设置优化器和学习率调度器:
netC
使用 SGD 优化器,并为 netG
和 netM
使用 Adam 优化器。标准化:
阶段2的训练过程:
netM
模型。每个 epoch 记录日志信息,并调用 train_mask_step
和 eval_mask
进行训练和评估。netM
的状态字典,包括模型参数、优化器状态、调度器状态和当前 epoch。netM
设置为评估模式,并禁止其梯度计算。真实训练(攻击):
train_step
和 eval_step
进行训练和评估。这段代码涉及对数据集的预处理、数据加载和数据生成,并最终将这些数据保存到指定的文件夹
创建后门数据集对象: bd_train_dataset
是通过prepro_cls_DatasetBD_v2
类生成的对象,传入的是经过转换后的干净训练数据集及一个保存路径。
创建可逆的图像变换:
clean_train_dataset_with_transform
中应用的图像变换进行筛选,只保留归一化、调整尺寸和转换为张量的变换。transforms_reversible
,并替换原始的图像变换,使其可逆。获取反归一化器:
transforms_reversible
中的变换,查找归一化变换,并获取对应的反归一化器。创建数据加载器:
clean_train_dataloader_without_shuffle
,用于加载不打乱顺序的干净训练数据集。clean_train_dataloader2
的数据集的图像变换也设置为可逆的变换,并确保其加载的数据是打乱顺序的。模型评估模式:
netC
和netG
模型设置为评估模式,以确保在生成数据时不会更新模型参数。数据生成和处理:
create_bd
方法生成后门样本,使用create_cross
方法生成交叉样本。保存生成的数据:
bd_train_dataset
中,确保样本和标签的正确性。保存攻击结果:
save_attack_result
方法,保存模型和数据的状态到指定路径。通过这些步骤,代码完成了对数据的预处理、加载、生成和保存的全流程,确保生成的数据可以用于后续的模型训练或测试。
这段代码定义了一个名为train_mask_step
的函数,用于训练一个生成掩码的神经网络模型netM
。
设置模型为训练模式:
netM.train()
将模型设置为训练模式,以启用训练特定的行为(如dropout)。初始化变量:
total
和total_loss
变量,用于跟踪训练过程中的总样本数和总损失。criterion_div
,用于计算多样性损失。遍历训练数据:
zip
函数同时遍历两个训练数据加载器train_dataloader1
和train_dataloader2
。inputs1
和inputs2
是输入图像,targets1
和targets2
是对应的目标标签。计算掩码:
netM
生成输入图像的掩码masks1
。self.threshold
对掩码进行阈值处理,生成二值化的掩码masks1
和masks2
。计算多样性损失:
criterion_div
计算输入图像inputs1
和inputs2
之间的距离,并取其平方根,得到distance_images
。criterion_div
计算掩码masks1
和masks2
之间的距离,并取其平方根,得到distance_patterns
。loss_div
,表示输入图像的距离与掩码距离的比值,并乘以一个超参数lambda_div
。计算正则化损失:
loss_norm
,表示掩码密度超出阈值的部分,并乘以一个超参数lambda_norm
。计算总损失并进行反向传播:
total_loss
。optimizerM
更新模型参数。更新学习率:
schedulerM
更新学习率。输出训练信息:
progress_bar
函数显示训练进度。通过这些步骤,train_mask_step
函数实现了对掩码生成模型的训练,包括计算损失、反向传播、参数更新和学习率调整。
eval_mask
函数eval_mask
函数用于评估生成掩码的神经网络模型netM
。它遍历测试数据,计算和记录各种损失。
设置模型为评估模式:
netM.eval()
将模型设置为评估模式,以禁用训练时特有的行为(如dropout)。初始化变量:
total
变量(未使用),用于跟踪评估过程中的总样本数。criterion_div
,用于计算多样性损失。遍历测试数据:
zip
函数同时遍历两个测试数据加载器test_dataloader1
和test_dataloader2
。inputs1
和inputs2
是输入图像,targets1
和targets2
是对应的目标标签。计算掩码:
netM
生成输入图像的掩码masks1
。self.threshold
对掩码进行阈值处理,生成二值化的掩码masks1
和masks2
。计算多样性损失:
criterion_div
计算输入图像inputs1
和inputs2
之间的距离,并取其平方根,得到distance_images
。criterion_div
计算掩码masks1
和masks2
之间的距离,并取其平方根,得到distance_patterns
。loss_div
,表示输入图像的距离与掩码距离的比值,并乘以一个超参数lambda_div
。计算正则化损失:
loss_norm
,表示掩码密度超出阈值的部分。输出评估信息:
progress_bar
函数显示评估进度。返回评估的轮次:
epoch
。create_targets_bd
函数create_targets_bd
函数用于创建后门攻击的目标标签,根据指定的攻击模式生成新的标签。
根据攻击模式生成标签:
返回生成的后门目标标签:
通过这些步骤,这两个函数分别实现了对掩码生成模型的评估和后门攻击目标标签的创建。
这段代码定义了两个方法:create_bd
和create_cross
,用于生成后门样本和交叉样本
create_bd
方法create_bd
方法用于生成后门攻击的样本,依据不同的模式(训练或测试)进行不同的处理。
训练模式:
生成后门目标标签:
self.create_targets_bd
生成后门目标标签bd_targets
。无样本情况:
inputs
为空(即没有样本需要被污染),直接返回原始输入inputs
、后门目标标签bd_targets
、以及两个复制的inputs
(没有改变的)。生成掩码和模式:
netG
生成掩码patterns
。self.normalizer
对patterns
进行归一化处理。netM
生成掩码输出masks_output
,并通过self.threshold
进行阈值处理。生成后门输入:
bd_inputs
:将原始输入inputs
与生成的模式patterns
之间的差异,通过掩码masks_output
调整。返回结果:
bd_inputs
、后门目标标签bd_targets
、生成的模式patterns
、掩码masks_output
。测试模式:
生成后门目标标签:
self.create_targets_bd
生成后门目标标签bd_targets
。标记位置变化:
position_changed
,标记目标标签bd_targets
与原始目标标签targets
之间的差异位置。筛选样本:
inputs
和后门目标标签bd_targets
。无样本情况:
inputs
为空,返回空张量torch.tensor([])
、空后门目标标签、以及None
的patterns
和masks_output
。生成掩码和模式:
netG
生成掩码patterns
。self.normalizer
对patterns
进行归一化处理。netM
生成掩码输出masks_output
,并通过self.threshold
进行阈值处理。生成后门输入:
bd_inputs
:将原始输入inputs
与生成的模式patterns
之间的差异,通过掩码masks_output
调整。返回结果:
bd_inputs
、后门目标标签bd_targets
、生成的模式patterns
、掩码masks_output
、位置变化标记position_changed
、以及原始目标标签targets
。create_cross
方法create_cross
方法用于生成交叉样本,即通过对另一组输入图像应用相同的模式生成的新样本。
无样本情况:
inputs1
为空(即没有样本需要生成交叉样本),返回inputs2
的副本、inputs2
、以及副本的inputs2
(没有改变的)。生成掩码和模式:
netG
生成patterns2
,并通过self.normalizer
进行归一化处理。netM
生成掩码输出masks_output
,并通过self.threshold
进行阈值处理。生成交叉样本:
inputs_cross
:将inputs1
与生成的模式patterns2
之间的差异,通过掩码masks_output
调整。返回结果:
inputs_cross
、生成的模式patterns2
、掩码masks_output
。通过这些方法,可以在训练和测试阶段生成后门样本和交叉样本,并根据需要对样本进行处理和调整。
此时的中毒样本部分如下所示
现在开始植入后门
训练期间部分截图如下
在上图可以看到,在第43个epoch时,正常任务的acc达到了0.87,而后门攻击的成功率达到了0.87
LIRA是一种先进的后门攻击框架,它通过联合学习最优的隐蔽触发器注入函数和对模型进行“投毒”,以实现在特定触发模式下操纵模型行为的目的。与传统的后门攻击方法相比,LIRA的主要创新之处在于其自动化的触发器生成过程和对模型的非线性参数空间的优化。
LIRA的核心是一个非凸的、受约束的优化问题,它将触发器的生成和模型的“投毒”统一在一个框架下。通过这种方式,LIRA能够在保持模型在正常数据上的性能的同时,最大化在被“投毒”数据上的攻击成功率。优化问题的目标是找到一组参数,使得模型在遇到带有特定触发器的输入时能够按照攻击者的意图进行分类,而在没有触发器的情况下则保持正常的分类行为。
为了解决这个优化问题,LIRA采用了一个两阶段的随机优化过程。在第一阶段,同时更新触发器函数和分类器,使用一种交替更新的策略来避免训练过程中的不稳定性和陷入局部最小值。在第二阶段,只对分类器进行微调,以进一步提高其在正常数据上的性能。
现在我们来形式化这个攻击方法
LIRA方案的核心是通过数学公式定义的优化问题来实现后门攻击的自动化和隐蔽性
触发器函数定义:
其中,( T(x) ) 是被触发器转换后的输入,( x ) 是原始输入,( g(x) ) 是一个生成不可见噪声的模型,用于在原始输入上添加难以察觉的变化。
优化问题的目标函数:
这里,( \theta ) 是分类器的参数,( \xi^* ) 是触发器函数的最优参数。( L ) 是损失函数,( \alpha ) 和 ( \beta ) 是控制干净数据和后门数据损失信号混合强度的标量参数。第一个项是干净数据上的损失,第二个项是后门数据上的损失。
约束条件:
其中,( d(\cdot, \cdot) ) 是衡量两个图像视觉差异的距离函数,( \epsilon ) 是一个阈值参数,确保( T(x) ) 与 ( x ) 在视觉上不可见的差异。
触发器函数的优化:
这个公式定义了触发器函数( T*{\xi} )的优化目标,即在给定分类器( f*{\theta} )的情况下,找到参数( \xi )使得后门攻击的损失最小化。 LIRA的训练过程包括两个阶段。第一阶段同时更新分类器( f )和触发器( T ),第二阶段仅微调分类器( f )。这个过程通过交替随机梯度下降(SGD)来实现,其中触发器的更新依赖于分类器在后门数据上的表现。
LIRA方案的关键在于通过这些公式定义的优化问题来自动化地寻找最优的触发器注入函数和“投毒”分类器。通过这种方式,LIRA能够在不显著降低模型在正常数据上的性能的同时,实现对模型的隐蔽操控。
完整的后门攻击示意图如下所示
下图的伪码给出了攻击算法
定义一个自动编码器(Autoencoder)模型,并包含一个辅助函数 double_conv
。
初始化方法 __init__
:
channels
参数:指定输入图像的通道数,默认为 3(通常用于 RGB 图像)。
self.encoder
:这是一个包含多个卷积层的序列模块。每个卷积层后面跟着批量归一化层(BatchNorm2d)和激活函数(ReLU)。
self.decoder
:这是一个包含多个转置卷积层(ConvTranspose2d)的序列模块,用于将编码后的特征图还原为原始图像的尺寸。
Tanh
激活函数,将输出映射到 -1 到 1 的范围,这通常是为了与输入图像的归一化范围匹配。前向传播方法 forward
:
x
经过编码器(self.encoder
)提取特征。self.decoder
)将特征还原为原始图像的尺寸。这是一个辅助函数,用于构建一个包含两个卷积层的模块。
in_channels
:输入通道数。out_channels
:输出通道数。double_conv
函数返回一个序列模块,该模块由两个连续的卷积层组成,每层卷积的大小为 3x3,填充为 1。这样的设计有助于逐步提取更复杂的特征。实现一个 U-Net 模型,这是一个常用于图像分割的神经网络架构
初始化方法 __init__
:
out_channel
参数:指定模型的输出通道数,这通常是分割任务中类别的数量。
编码器部分(下采样):
self.dconv_down1
到 self.dconv_down4
:这四个模块是由 double_conv
函数构建的卷积块,用于逐步提取图像特征。每个模块中的卷积层的通道数逐渐增加,从 64 到 512。最大池化和上采样:
self.maxpool
:平均池化层(AvgPool2d
),用于下采样和减少特征图的尺寸。self.upsample
:上采样层(Upsample
),用于逐步恢复特征图的尺寸。使用双线性插值(bilinear
)进行上采样。解码器部分(上采样):
self.dconv_up1
到 self.dconv_up3
:这些模块用于将特征图上采样并与相应的编码器特征图进行拼接(skip connection)。通道数在上采样过程中逐渐减少。最后的卷积层:
self.conv_last
:一个卷积层和批量归一化层,用于将解码后的特征图映射到最终的输出通道数。输出激活函数:
self.out_layer
:使用 Tanh
激活函数将输出映射到 [-1, 1] 的范围,这对于某些任务(如图像生成)是常见的。前向传播方法 forward
:
conv1
、conv2
、conv3
:这些变量存储了经过编码器处理的特征图。self.dconv_down4
:对最后一个下采样后的特征图进行处理。self.dconv_up3
、self.dconv_up2
、self.dconv_up1
:处理上采样后的特征图。self.conv_last
:将处理后的特征图映射到最终的输出通道数。self.out_layer
:应用 Tanh
激活函数,以获得最终的输出结果。U-Net 的关键特点是它的对称结构和跳跃连接(skip connections),这些特性使它在图像分割任务中表现出色。
这段代码定义了一个 hp_test
函数,用于测试一个模型在攻击和防御场景下的表现。函数的作用是评估在特定条件下模型的性能,包括处理攻击数据的能力以及正常数据的处理能力
args
: 包含各种参数的对象,如学习率、攻击强度等。atkmodel
: 攻击模型,用于生成对抗样本。scratchmodel
: 待测试的模型(即被攻击和训练的模型)。target_transform
: 一个函数,用于对目标标签进行转换,通常在处理对抗攻击时使用。train_loader
: 训练数据加载器。test_loader
: 测试数据加载器。epoch
: 当前的训练轮数。trainepoch
: 总训练轮数。clip_image
: 用于裁剪或限制对抗样本的函数,以确保它们在有效范围内。testoptimizer
: 测试阶段使用的优化器。如果未提供,将在函数内部创建一个默认的优化器。log_prefix
: 日志前缀,用于标记日志信息。epochs_per_test
: 每隔多少轮进行一次测试。设置测试参数:
args.test_alpha
或 args.test_eps
没有设置,使用默认的 args.alpha
和 args.eps
。初始化变量:
test_loss
和 correct
:用于跟踪测试集的损失和准确度。correct_transform
和 test_transform_loss
:用于跟踪对抗攻击后的损失和准确度。设置模型为评估模式:
atkmodel.eval()
:将攻击模型设置为评估模式,这样它不会进行训练更新。初始化测试优化器:
testoptimizer
,则为 scratchmodel
创建一个新的 SGD 优化器。训练阶段:
对于每一个训练轮次 cepoch
,在 train_loader
中遍历每一个批次。
对每批数据和目标进行前向传播:
atkdata
。scratchmodel
计算对抗样本和原始样本的损失。测试阶段:
每隔 epochs_per_test
轮或在最后一轮时进行测试:
test_loader
中遍历每一个批次。返回结果:
torch.max
来获取预测结果,并与目标进行比较,计算正确预测的数量。这段代码定义了 main
函数,用于执行整个训练和测试流程,包括模型训练、对抗攻击生成、测试评估等步骤
args
: 包含训练和测试所需的各种参数。clean_test_dataset_with_transform
: 经过转换的干净测试数据集。criterion
: 损失函数,用于计算模型的损失。初始化数据加载器:
DataLoader
创建一个 clean_test_dataloader
,用于加载经过转换的干净测试数据集。初始化列表和聚合器:
clean_test_loss_list
、bd_test_loss_list
、test_acc_list
、test_asr_list
、test_ra_list
和 train_loss_list
:用于存储每个阶段的损失和准确度指标。agg = Metric_Aggregator()
:用于聚合和存储测试指标的对象。日志记录:
args.verbose >= 1
,则记录参数设置和数据加载器的信息。获取数据加载器和转换函数:
train_loader
, test_loader
, clip_image
:从 get_train_test_loaders
函数获取训练和测试数据加载器,以及裁剪图像的函数。post_transforms
:应用于图像的后处理转换。创建模型:
atkmodel
, tgtmodel
, tgtoptimizer
, clsmodel
, create_net
:从 create_models
函数获取攻击模型、目标模型、目标优化器、分类模型以及创建网络的函数。目标标签转换函数:
target_transform
:用于将目标标签转换为适当的格式,通常用于对抗攻击中的目标标签。初始化和训练模型:
tgtmodel
的权重初始化为 atkmodel
的权重。clsmodel
迁移到 GPU 并创建优化器 clsoptimizer
。args.device
包含多个设备,则使用 torch.nn.DataParallel
进行数据并行处理。训练过程:
train
函数进行模型训练,并将训练损失存储到 trainlosses
列表中。clsmodel
。测试阶段:
bd_test_dataset
和 bd_test_dataloader
,这是处理对抗攻击数据的测试数据集。given_dataloader_test
和 test_given_dataloader_on_mix
函数计算干净测试和对抗测试的指标。绘图和结果保存:
plot_loss
和 plot_acc_like_metric
函数生成和保存损失和准确度的图表。返回结果:
torch.nn.DataParallel
中以实现数据并行。这段代码定义了 main2
函数,旨在执行模型的第二阶段训练和测试。这些步骤包括对模型进行微调,使用预训练模型的权重,并在对抗攻击数据和干净数据上进行最终测试:
args
: 包含训练和测试所需的参数。pre_clsmodel
: 预训练的分类模型。pre_atkmodel
: 预训练的攻击模型。clean_test_dataloader
: 用于测试干净数据的 DataLoader。bd_test_dataloader
: 用于测试对抗数据的 DataLoader。criterion
: 损失函数。处理 args
参数:
args_for_finetune
对象并从中提取以 finetune_
开头的参数。args.test_alpha
、args.finetune_lr
或 args.test_eps
为 None
,则将它们设置为相应的训练参数或默认值。日志记录:
设备设置:
"cuda"
或 "cpu"
。获取数据加载器和模型:
get_train_test_loaders
函数获取训练和测试数据加载器及图像裁剪函数。create_models
函数中创建攻击模型、目标模型、目标优化器及网络创建函数。get_model
函数获取分类模型、优化器和学习率调度器。数据并行处理:
args.device
包含多个设备,将分类模型和攻击模型包装在 torch.nn.DataParallel
中以实现数据并行处理。模型权重加载:
模型配置和优化器设置:
netC
) 移动到设备上,并根据 args_for_finetune
配置优化器和学习率调度器。数据转换和最终测试:
使用 PostTensorTransform
函数创建数据转换对象。
调用 final_test
函数进行最终测试,其中包括干净数据和对抗数据的测试。这个函数执行以下操作:
这段代码定义了一个名为 LIRA
的类,它继承自 BadNet
基类:
__init__
方法)__init__
方法:这个方法用于初始化 LIRA
类的实例,通过 super()
调用父类 BadNet
的初始化方法。set_bd_args
方法)set_bd_args
方法:该方法使用 argparse
定义了一系列命令行参数。这些参数包括攻击配置的各种选项,如:
--attack
:攻击类型。--attack_target
:攻击的目标类别。--attack_label_trans
:攻击中标签修改的类型。--bd_yaml_path
:包含附加默认属性的 YAML 文件路径。--random_crop
, --random_rotation
:图像变换参数。--attack_model
:攻击模型类型。--lr_atk
, --eps
, --alpha
:攻击设置的参数。--finetune_lr
, --finetune_steplr_gamma
, --finetune_optimizer
:微调模型的参数。stage1_non_training_data_prepare
方法)stage1_non_training_data_prepare
方法:这是一个占位符方法(pass
语句),意味着它是预留给子类重写或扩展的,但当前并未执行任何操作。stage2_training
方法)stage2_training
方法:该方法处理训练过程。主要步骤包括:
准备:
self.benign_prepare()
准备数据集和变换。DataLoader
。模型设置:
generate_cls_model
函数创建分类模型,并根据指定的设备(GPU 或 CPU)设置模型。torch.nn.DataParallel
进行并行计算。训练:
criterion
)并创建模型、攻击模型及数据加载器。main
和 main2
函数进行模型训练和测试。保存结果:
save_attack_result
函数保存攻击结果,包括模型状态、数据路径等信息。此时该方案得到的部分中毒样本如下所示
开始进行后门攻击
训练期间的部分截图如下所示
可以看到尽管后门攻击成功率很高,但是正常任务的准确率还是较低的。
尽管现有的后门攻击方法在技术上是可行的,但它们往往因为对训练数据或标签的明显修改而容易被检测到。这种可检测性限制了后门攻击在实际应用中的隐蔽性和有效性。为了提高后门攻击的隐蔽性,研究人员需要开发出一种新的攻击手段,它能够在不引起怀疑的情况下修改模型的行为。这种攻击手段应该能够在不显著降低模型在正常数据上的性能的同时,对含有特定模式的输入实现控制。 自然界中普遍存在的现象,如反射,为实现这种隐蔽的后门攻击提供了可能。
反射现象在日常生活中随处可见,例如在玻璃或光滑表面上的镜像。由于反射本身是一种自然且不易被察觉的现象,将其作为后门的触发器,可以在不引起注意的情况下激活后门反射后门攻击(Refool)是一种新颖的后门攻击方法,灵感来源于自然界中普遍存在的反射现象。这种方法利用了物理世界中物体在玻璃或其他光滑表面上的反射特性,将这些反射作为后门触发器植入到深度学习模型中。这种方法的创新之处在于,它不依赖于人为设计的特殊图案或标签修改,而是利用了自然存在的物理现象。 在Refool攻击中,攻击者通过在训练数据中注入带有反射的图像来植入后门。这些反射图像是通过数学建模生成的,模拟了真实世界中反射的物理过程。当模型在推理阶段遇到含有这些反射特征的输入图像时,会被诱导预测特定的目标类别,即使这些图像在视觉上看起来与正常图像无异。
为了实现这一攻击,首先定义了反射图像的数学模型。具体来说,反射图像可以通过将原始图像与反射图像结合来生成,这一过程可以用卷积核表示。这种结合模拟了真实世界中光线在光滑表面上的反射行为。
三种反射类型: 考虑三种不同的反射类型,每种类型对应不同的物理场景:
生成反射图像: 攻击的第一步是生成带有反射的后门图像。这些图像通过将反射图像与干净图像结合生成,模拟了真实世界中的反射现象。
训练受害模型: 接下来,攻击者在包含这些反射图像的训练集上训练深度学习模型。这个训练集由原始的训练数据和被反射图像污染的数据组成。通过这种方式,模型在学习过程中“记住”了反射图像与特定类别的关联。
推理阶段的攻击: 在模型部署后的推理阶段,攻击者可以通过在任何输入图像中添加反射图像来激活后门。这些反射图像会触发模型预测特定的目标类别,从而实现攻击。
现在我们来形式化这个攻击方案
在深度学习中,我们通常有一个K类图像数据集
,其中
是一个输入样本,
是它的正确标签。分类任务的目标是学习一个函数
通常由深度神经网络(DNN)表示,将输入空间映射到标签空间。后门攻击的目标是在模型中植入一个后门,使得当输入图像包含特定的后门模式时,模型预测为攻击者指定的类别( y_{adv} )。
反射是当光线遇到光滑表面(如玻璃)时发生的现象。在数学上,我们可以将反射图像的形成过程建模为:
其中:
反射可以分为三种类型:
其中( \alpha )是强度因子,( \delta )是空间偏移,两者的值分别从( U[0.15, 0.35] )和( U[3, 8] )中选择。
首先生成带有反射的后门图像,通过将反射图像( x_R )与干净图像( x )结合,遵循上述三种反射模型之一。
在被污染的训练集( D_{adv}^{train} )上训练受害者模型,该训练集包括带有反射的后门图像和干净图像。
在推理阶段,任何包含反射模式的输入图像( x*{adv} )都会被模型一致地预测为特定的目标类别( y*{adv} )。
完整的攻击流程如下图所示
这段代码定义了一个 blend_images
函数,用于将两张图像进行混合,生成一个融合效果的图像
输入参数:
img_t
和 img_r
:输入的两张图像,可以是 PIL 图像对象或 numpy 数组。max_image_size
:最大图像尺寸,用于调整图像大小。ghost_rate
:鬼影效果的概率。alpha_t
:深度场的强度,负值表示随机选择。offset
:鬼影效果的空间偏移量。sigma
:模糊效果的标准差,负值表示随机选择。ghost_alpha
:鬼影效果的透明度,负值表示随机选择。图像预处理:
img_t
和 img_r
转换为浮点数,并将像素值归一化到 0 到 1 之间。max_image_size
缩放图像,以确保最大边的长度不超过 max_image_size
。缩放后调整图像的尺寸。生成鬼影效果:
如果 alpha_t
是负值,则随机选择一个介于 0.05 到 0.45 之间的值作为 alpha_t
。
根据 ghost_rate
的概率决定是否应用鬼影效果。如果应用:
offset
生成具有鬼影效果的图像。ghost_alpha
用于控制鬼影的强度。如果 ghost_alpha
是负值,则随机选择一个值。生成焦外模糊效果:
sigma
是负值,则随机选择一个介于 1 到 5 之间的值。alpha_t
计算 alpha 通道。返回结果:
blended
(融合图像)、transmission_layer
(传输层)和 reflection_layer
(反射层),它们都被转换为 0 到 255 的整数范围,以便于显示或保存。RefoolTrigger
类用于对图像应用特定的混合效果,包括鬼影效果。它从给定的图像列表中随机选择一张反射图像,并将其与输入图像混合,使用各种参数控制效果的强度和外观
这段代码定义了一个名为 RefoolTrigger
的类,用于对图像应用特定的变换效果,可能用于数据增强或对抗攻击
RefoolTrigger
__init__
方法构造函数用于初始化类的实例,接收以下参数:
R_adv_pil_img_list
:一个包含多张 PIL 格式图像的列表,这些图像将作为反射或叠加层使用。img_height
:目标图像的高度。img_width
:目标图像的宽度。ghost_rate
:控制图像上鬼影效果强度或比例的参数。alpha_t
:景深或强度数值。如果设置为负值,则会随机选择强度。offset
:一个元组,指定鬼影效果的空间位移。sigma
:用于控制模糊或虚焦效果的参数。负值表示将随机选择该值。ghost_alpha
:鬼影效果的透明度。负值表示将随机选择该值。__call__
方法__call__
方法使得类的实例可以像函数一样被调用。它接受一个图像 (img
),以及可选的目标和图像序列 ID,然后调用 add_trigger
方法来应用效果。
add_trigger
方法该方法用于对输入图像应用触发效果:
reflection_pil_img
:从 R_adv_pil_img_list
中随机选择一张图像,用作反射或叠加层。
blend_images
:这个函数负责将选择的反射图像与输入图像 (img
) 进行混合。它使用以下参数:
max_image_size
:图像的最大尺寸,设置为 img_height
和 img_width
中的较大者。ghost_rate
:控制鬼影效果的强度或比例。alpha_t
:景深效果或强度。offset
:鬼影效果的空间位移。sigma
:模糊或虚焦效果的强度。ghost_alpha
:鬼影效果的透明度。函数返回一个元组,其中第一个元素是混合后的图像。方法返回这个混合图像。
Refool
类用于准备和生成带有触发器的训练和测试数据集。它通过设置各种参数来控制图像的混合效果,并应用这些效果到数据集上。数据集准备包括加载图像、定义变换、生成触发器、并创建用于训练和测试的数据集。
这段代码定义了一个 Refool
类,继承自 BadNet
类。Refool
类包含了用于处理图像数据的功能,特别是用于生成带有触发器(backdoor)的数据集
Refool
set_bd_args
方法这个方法用于设置和解析命令行参数:
parser: argparse.ArgumentParser
: 一个 argparse.ArgumentParser
对象,用于处理命令行参数。--r_adv_img_folder_path
: 反射图像所在的文件夹路径,用于生成混合图像。--bd_yaml_path
: YAML 配置文件的路径,提供额外的默认属性。--ghost_rate
: 混合图像的鬼影率。--alpha_t
: 景深或强度数值。负值表示随机选择。--offset
: 鬼影效果的空间位移。--sigma
: 虚焦效果的强度。负值表示随机选择。--ghost_alpha
: 鬼影效果的透明度。负值表示随机选择。--clean_label
: 用于设置是否干净标签(1 表示是,其他值表示不是)。这些参数用来配置数据准备过程中的各种设置。
stage1_non_training_data_prepare
方法这个方法用于准备阶段一的数据:
日志记录: 记录阶段开始的信息。
数据准备:
benign_prepare()
方法准备数据集,得到未变换的数据集、变换函数以及标签转换函数。transforms.Compose
定义图像变换,包括调整图像大小和转换为 NumPy 数组。读取反射图像:
reflection_img_list
列表中。创建触发器:
RefoolTrigger
,传入反射图像列表及其他参数,创建触发器对象。定义图像变换:
生成标签转换函数:
bd_attack_label_trans_generate
方法生成用于触发攻击的标签转换函数。准备训练数据集:
prepro_cls_DatasetBD_v2
创建带有触发器的训练数据集,并将其包装在变换函数中。准备测试数据集:
prepro_cls_DatasetBD_v2
创建带有触发器的测试数据集,并将其包装在变换函数中。保存结果:
stage1_results
中。应用该方案得到的中毒样本部分如下所示
开始注入后门
训练期间的部分截图如下所示
在上图可以看到,正常任务准确率与后门攻击成功率都达到了不错的水平。
1.https://arxiv.org/abs/2010.08138
2.https://arxiv.org/abs/1912.02771
3.https://arxiv.org/pdf/2007.02343
29 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!