1
详细介绍
转自先知社区:https://xz.aliyun.com/t/16094 作者:Yale
后门攻击定义
深度学习后门攻击是一种针对深度学习模型的恶意攻击方式。攻击者在模型的训练阶段或者通过修改已训练好的模型参数等手段,植入一个隐藏的 “后门”。这个后门使得在正常输入下模型能正常工作,但当攻击者提供特定的触发模式(例如特定的图像图案、音频片段或文本格式等)输入时,模型就会输出攻击者期望的恶意结果,而不是正常的预测结果。
攻击方式
数据中毒(Data Poisoning)
-
训练阶段中毒:攻击者在训练数据集中混入被篡改的数据。例如,在图像分类任务中,攻击者可以在正常的图像训练集中插入一些带有微小标记(如一个几乎不可见的像素图案)的图像,并将这些图像的标签设置为攻击者想要的类别。当模型使用这个被污染的数据集进行训练时,就会学习到这个后门关联。
-
投毒比例影响:投毒数据的比例也很关键。如果投毒比例过高,可能会导致模型的主要性能(在正常数据上的准确率等)下降明显,容易被发现;而投毒比例过低,又可能无法有效地植入后门。一般来说,攻击者会尝试找到一个微妙的平衡,使得后门能够成功植入,同时模型在正常数据上的表现基本不受影响。
模型修改(Model Modification)
-
直接修改参数:攻击者在获得已训练好的模型后,通过直接修改模型的参数来植入后门。这可能需要对模型的结构和参数有深入的理解。例如,在神经网络中,攻击者可能会调整某些神经元的权重,使得当特定的输入激活这些神经元时,模型就会输出错误的结果。
-
对抗样本生成作为后门触发:利用对抗样本生成技术,找到能够触发模型错误行为的特定输入模式。对抗样本是通过在原始输入上添加微小的、人类难以察觉的扰动而生成的,攻击者可以将这些对抗样本作为后门触发的模式,让模型产生错误的输出。
攻击场景
安全敏感领域
-
在自动驾驶领域,如果车辆的目标检测模型被植入后门,当攻击者触发后门(例如通过在交通标志上添加特定的不可见图案),车辆可能会错误地识别交通标志,从而引发交通事故。
-
在人脸识别系统中,后门可能导致错误的身份认证结果。例如,攻击者可以通过特定的触发模式(如特定的眼镜框架图案)让人脸识别系统将一个未经授权的人识别为已授权用户,从而导致安全漏洞。
恶意软件检测
-
如果深度学习模型用于恶意软件检测,攻击者可以通过后门攻击让模型将恶意软件误判为正常软件,使得恶意软件能够成功入侵系统。
演进趋势
现在我们大致总结目前后门攻击技术的演进趋势,从5年前该技术被提出至今已经出现了明显的趋势。
攻击方法的多样化
随着研究的深入,深度学习后门攻击的方法不断演进,呈现出多样化的趋势。早期的后门攻击主要通过修改训练数据或模型参数来植入后门,而现在,攻击者开始探索更多样化的手段。例如,利用对抗性样本、隐蔽通信信道(如特定的输入模式或数据噪声)等技术,使得后门更难以被检测到。这些新兴的方法使得后门攻击的隐蔽性和复杂性显著增加。
目标模型的扩展
深度学习后门攻击的目标不再仅限于图像分类模型,逐渐扩展到自然语言处理、语音识别和推荐系统等领域。随着深度学习技术在各个领域的广泛应用,攻击者将目光投向了更多种类的模型。例如,在自然语言处理领域,后门攻击可以通过修改训练数据中的特定词汇或句子结构来实现,而在语音识别领域,攻击者可以利用特定的音频特征植入后门。
攻击对象的多样化
传统的后门攻击主要针对单个模型,但近年来,攻击对象逐渐扩展到整个深度学习系统和生态环境。攻击者可能会通过污染训练数据集、篡改模型更新包或利用云端服务的漏洞来植入后门。此外,随着联邦学习和边缘计算的普及,攻击者还开始研究如何在分布式系统中植入后门,使得后门攻击的范围和影响力进一步扩大。
攻击技术的精细化
后门攻击技术不断精细化,攻击者不仅关注如何植入后门,还注重后门的触发条件和隐蔽性。例如,研究人员提出了条件触发的后门攻击,仅在特定条件下才会激活,以避免被检测到。此外,攻击者还利用生成对抗网络(GAN)和元学习等技术,使得后门攻击更加难以被发现和防御。
随着后门攻击技术的不断进步,防御技术也在不断演进。这种动态对抗的关系推动了后门攻击技术的进一步发展。攻击者不断研究新的攻击方法以绕过现有的防御机制,而防御者则开发更加先进的检测和防御技术,例如基于异常检测、模型验证和鲁棒性测试的方法。双方的对抗促使后门攻击技术和防御技术在不断升级和优化。
另外,后门攻击技术开始与其他安全威胁结合,形成更加复杂和多层次的攻击手段。例如,攻击者可能会将后门攻击与对抗性攻击、数据投毒、模型窃取等手段结合使用,以实现更复杂的攻击目标。这种多层次的攻击方式增加了防御的难度,要求研究人员和从业者具备更全面的安全意识和防御能力。
可以看到,从全局来看,深度学习后门攻击的演进趋势表现出方法多样化、目标模型扩展、攻击对象多样化、攻击技术精细化、对抗性提升以及与其他安全威胁结合等特点。随着技术的发展,后门攻击的隐蔽性和复杂性将不断增加,对防御技术提出了更高的要求。
而我们学习典型后门攻击方案的原因也是为了可以实现更好地做好防御。现在我们来分析与实现典型先进的后门攻击方案。
SIG
理论
在以往的后门攻击中,攻击者通常会通过在训练集中引入带有特定标签的污染样本来实现攻击。这些污染样本不仅包含后门信号,还会被赋予一个目标标签。例如,攻击者可能会在某些图像中添加一个特定的模式或噪声,并将其标记为特定的类别,如“猫”。这样,在测试时,只要图像中出现这种模式,模型就会被诱导将其错误地分类为“猫”,即使图像中实际的内容并不是猫。
这种方法的主要问题在于其隐蔽性较差。因为污染样本的标签与其实际内容不一致,这很容易被训练者通过视觉检查或预分类步骤发现。一旦被发现,这些样本就可以被排除,从而削弱了攻击的效果。
而本章介绍的新的后门攻击方法,这种方法的关键区别在于它不需要改变训练样本的标签。攻击者仅在目标类别的训练样本中引入后门信号,而不改变这些样本的标签。这样,即使通过视觉检查或预分类步骤,训练者也难以发现这些样本的异常,因为它们的标签与实际内容是一致的。
具体来说,攻击者首先选择一个目标类别,并在该类别的一定比例的训练样本中添加后门信号。这个后门信号是隐蔽的,不易被察觉,但对模型有足够的影响力。在测试时,攻击者向其他类别的样本添加相同的后门信号。由于模型在训练过程中已经学会了将后门信号与目标类别关联起来,因此它会错误地将这些带有后门信号的样本分类为目标类别。
这种方法解决了之前方法中存在的几个关键问题:
-
隐蔽性提高:由于不需要改变标签,污染样本在视觉上与正常样本没有明显区别,这使得它们更难被发现。这大大提高了攻击的隐蔽性。
-
灵活性增强:在这种攻击中,攻击者在训练时只需要关注目标类别的样本,而不需要预先确定测试时的源类别。这意味着攻击者可以在测试时选择任何类别的样本进行攻击,增加了攻击的灵活性。
-
减少对训练样本的依赖:在传统的后门攻击中,模型可能会过度依赖后门信号,从而忽略了样本的真实特征。而在这种方法中,由于标签未被改变,模型在训练时仍然可以学习到目标类别的真实特征,减少了对后门信号的依赖。
-
攻击实施的复杂性降低:在之前的攻击中,攻击者需要精心设计污染样本的标签和内容,以确保它们在视觉上一致。而在这种新的攻击方法中,攻击者只需要关注后门信号的设计,而不需要担心标签的一致性问题。
总的来说,这种新的后门攻击方法通过在不改变标签的情况下引入后门信号,显著提高了攻击的隐蔽性和灵活性,同时减少了对训练样本的依赖,使得攻击更加难以被检测和防御。
下图所示就是没有和有后门信号的对应的样本。
我们现在形式化后门攻击的实现过程。
假设我们有一个卷积神经网络(CNN)模型 f,它在训练集D上进行训练。训练集D包含 n个样本,每个样本是一个成对的输入输出对(x_i, y_i) ,其中 x_i 是输入图像,y_i 是对应的标签。
攻击者选择一个目标类别 t ,攻击的目的是使得模型在测试时将带有后门信号的非目标类别样本错误分类为目标类别 t 。攻击者向目标类别 t的一部分训练样本中添加后门信号v
对于目标类别 ( t ) 的训练样本 (x_i, t) ,攻击者生成一个带有后门信号的样本 x'_i :
其中 ( v ) 是一个精心设计的后门信号,它在视觉上不易被察觉,但对模型的决策有显著影响。
攻击者将污染后的样本 (x'_i, t) 替换原始样本 (x_i, t) ,形成一个新的训练集 D' 。新的训练集 D' 与原始训练集 D 相同,但目标类别 t 的一部分样本被替换:
模型 f 被重新训练在污染后的训练集D' 上。训练的目标是最小化损失函数L ,该函数衡量模型输出和真实标签之间的差异:
其中theta 表示模型参数。
测试时的攻击
在测试时,攻击者向非目标类别的样本 ( x ) 添加相同的后门信号 ( v ),并观察模型的输出。攻击成功的条件是:
这意味着即使测试样本x属于类别
模型也会将其错误地分类为目标类别 t 。
后门信号的设计
后门信号 ( v ) 的设计至关重要,它需要满足以下条件:
-
隐蔽性:( v ) 应该在视觉上不易被察觉,以避免在训练集检查时被发现。
-
有效性:( v ) 应该足够强,以便在测试时能够显著影响模型的决策。
例如,在MNIST数字识别任务中,后门信号可以是一个斜坡信号,定义为:
其中 ( Delta ) 是信号的强度,( m ) 是图像的列数,( i ) 和 ( j ) 分别是行和列的索引。
在交通标志分类任务中,后门信号可以是一个正弦波信号,定义为:
其中 ( f ) 是信号的频率。
通过这种方式,攻击者可以在不改变训练样本标签的情况下,通过在训练集中引入隐蔽的后门信号,实现对深度学习模型的攻击。这种方法提高了攻击的隐蔽性和灵活性,同时减少了对训练样本的依赖。
实现
该类主要用于设置后门攻击的参数和准备非训练数据集。通过一系列的方法调用和数据转换,将原始数据集转换成包含后门攻击的训练和测试数据集,并保存相应的中毒索引和转换数据集,以备后续使用。
这段代码定义了一个名为 SIG
的类,它继承自 BadNet
类,并包含了一些方法来设置攻击参数和准备非训练数据。
set_bd_args
方法
-
方法定义:这是一个类方法,接收一个参数
parser
,类型是argparse.ArgumentParser
。 -
公共攻击参数:调用
add_common_attack_args
函数为parser
添加一些通用的攻击参数。 -
新参数:为
parser
添加了两个新的参数: -
--sig_f
:一个浮点类型的参数。 -
--bd_yaml_path
:一个字符串类型的参数,默认值为'./config/attack/sig/default.yaml'
,用于指定 YAML 配置文件的路径。 -
返回:返回更新后的
parser
。
stage1_non_training_data_prepare
方法
-
日志记录:记录阶段1开始的日志信息。
-
参数断言:断言
self.__dict__
中包含args
。 -
参数获取:获取
args
参数。 -
准备干净数据集:调用
benign_prepare
方法,返回一系列与数据集和转换相关的变量,包括训练和测试数据集(带和不带转换)。 -
生成后门图像转换:调用
bd_attack_img_trans_generate
方法,生成训练和测试用的后门图像转换。 -
生成后门标签转换:调用
bd_attack_label_trans_generate
方法,生成后门标签转换。 -
设置后门攻击数据和测试数据:
-
生成中毒索引:调用
generate_poison_index_from_label_transform
方法,生成训练数据集的中毒索引。 -
保存中毒索引:使用
torch.save
方法将中毒索引保存到指定路径。 -
生成后门训练数据集:调用
prepro_cls_DatasetBD_v2
方法,生成后门训练数据集。 -
包装训练数据集:调用
dataset_wrapper_with_transform
方法,将生成的后门训练数据集包装上转换。 -
生成测试数据集:
-
生成中毒索引:再次调用
generate_poison_index_from_label_transform
方法,生成测试数据集的中毒索引。 -
生成后门测试数据集:调用
prepro_cls_DatasetBD_v2
方法,生成后门测试数据集。 -
子集选择:调用
subset
方法,选择需要中毒的测试数据子集。 -
包装测试数据集:调用
dataset_wrapper_with_transform
方法,将生成的后门测试数据集包装上转换。 -
保存结果:将干净和后门的训练与测试数据集保存到
self.stage1_results
中。
这类方法得到的中毒样本部分如下所示
现在开始注入后门
训练期间的部分截图如下所示
在上图可以看到,在epoch为53时,后门攻击成功率达到了0.99,而正常任务准确率达到了0.83
SSBA
理论
现在介绍一种新的后门攻击范式,称为样本特定后门攻击(SSBA)。在这种方法中,后门触发器是针对每个训练样本单独生成的,而不是所有样本共享相同的触发器。这种方法的关键在于使用编码器-解码器网络将攻击者指定的字符串编码到正常图像中,生成不可见的加性噪声作为触发器。这样,每个被污染的样本都包含一个独特的触发器,使得攻击更加隐蔽,难以被检测。
与传统的样本无关触发器相比,样本特定触发器的主要优势在于其隐蔽性和复杂性。由于每个触发器都是为特定样本定制的,它们在视觉上更难以被识别,从而提高了攻击的隐蔽性。此外,这种方法不需要修改训练过程中的其他组件(如训练损失或模型结构),这使得攻击更加简单且易于实施。
现有的后门防御方法大多依赖于检测样本无关的触发器。这些方法通过分析不同被污染样本之间的共同特征来识别后门触发器。然而,样本特定触发器的设计打破了这一假设,使得现有的防御方法难以有效识别和防御这种攻击。通过生成样本特定的触发器,本方法能够绕过现有的防御机制,展示了一种更为隐蔽和有效的后门攻击手段。
下图就是之前攻击(例如,BadNets)和SSBA攻击中的触发器比较。之前攻击的触发器是样本无关的(即,不同的中毒样本包含相同的触发器),而SSBA方法的触发器是样本特定的。
现在我们来形式化这种攻击
攻击阶段
-
选择目标标签:攻击者首先确定一个目标标签 ( y_t ),这个标签是攻击者希望在触发器激活时模型预测的结果。
-
生成触发器:使用编码器-解码器网络,攻击者将目标标签的信息编码为不可见的加性噪声。这个过程可以表示为:
其中 ( x ) 是原始的良性图像,( x' ) 是添加了后门触发器的被污染图像,( G_{theta} ) 是编码器参数。
-
训练数据污染:从良性训练集中选择一部分样本,将上述过程应用于这些样本,生成被污染的子集 ( D_m )。
-
构建污染数据集:
其中 ( D_p ) 是最终的被污染数据集,( D_b ) 是未被污染的良性样本子集。
训练阶段
-
模型训练:使用被污染的数据集 ( D_p ) 来训练深度神经网络 ( f_w ):
其中 ( L ) 是损失函数,通常是交叉熵损失。
-
学习映射:在训练过程中,模型学习将编码的字符串映射到目标标签 ( y_t )。
推理阶段
-
正常行为:在没有触发器的情况下,模型对良性测试样本的预测保持正常。
-
激活后门:当在测试图像上添加特定的触发器时,模型的预测结果会被改变为目标标签 ( y_t )。
公式说明
-
( x ):原始输入图像。
-
( x' ):被污染的图像,包含后门触发器。
-
( G_{theta} ):攻击者定义的图像生成器,用于将后门信息编码为图像上的不可见扰动。
-
( D_p ):被污染的训练数据集,由修改过的样本 ( D_m ) 和原始样本 ( D_b ) 组成。
-
( D_m ):被修改的样本集合,其中每个样本都包含了针对该样本特定的后门触发器。
-
( D_b ):原始的良性样本集合,未被修改。
-
( D_{train} ):原始的完整训练数据集。
-
( gamma ):污染率,表示 ( Dm ) 在 ( D{train} ) 中的比例。
-
( f_w ):深度神经网络模型,参数为 ( w )。
-
( L ):损失函数,用于训练过程中的误差计算。
-
( N ):被污染数据集中的样本总数。
通过这种方法,攻击者能够在不引起怀疑的情况下,在模型中植入后门,使得在特定的触发条件下,模型的输出能够被控制。这种攻击方式的隐蔽性和针对性,使其成为一种潜在的严重的安全威胁。
这里的一个关键就是图像生成器 G_{theta} ,这是通过一个训练过程得到的,这个过程涉及到编码器-解码器网络。详细的步骤如下:
-
编码器和解码器网络结构:
-
编码器负责将攻击者指定的字符串(例如,代表目标标签的字符串)编码到图像中,生成一个包含后门触发器的图像。
-
解码器则负责从编码后的图像中恢复出隐藏的字符串信息。
-
训练过程:
-
编码器和解码器在良性训练集上同时进行训练。训练的目标是最小化输入图像与编码图像之间的感知差异,同时确保解码器能够准确恢复出编码的字符串。
-
损失函数:
-
重建损失(例如 ( L2 ) 损失或感知损失),确保编码后的图像与原始图像在视觉上几乎无法区分。
-
代码重建损失,确保解码器能够准确解码编码器嵌入的字符串。
-
批评损失,用于进一步减少编码图像的可感知失真。
-
在训练过程中,使用多种损失函数来指导网络学习,包括:
-
优化算法:
-
使用优化算法(如Adam优化器)来更新编码器和解码器的参数,以最小化总损失。
-
触发器的生成:
-
一旦编码器-解码器网络训练完成,攻击者就可以使用编码器来生成样本特定的触发器。对于每个良性图像,编码器生成一个不可见的扰动,这个扰动包含了目标标签的编码信息。
-
触发器的独有性:
-
由于每个触发器都是针对特定图像生成的,因此它们是独一无二的,这增加了攻击的隐蔽性,因为即使是相似的图像,它们的触发器也会有所不同。
通过这种方式,攻击者能够生成一个强大的图像生成器 ( G_{theta} ),它能够将任何给定的良性图像转换为包含后门触发器的图像,而不显著改变图像的视觉外观。这种生成器是实现样本特定后门攻击的关键组件。
这个编码器-解码器网络的训练过程如下所示
完整的后门攻击流程如下
实现
这段代码定义了一个名为 SSBA
的类,该类继承自 BadNet
类,并且包含两个方法:set_bd_args
和 process_args
set_bd_args
方法
这个类方法的主要功能是为命令行解析器添加特定于 SSBA 攻击的参数。方法步骤如下:
-
添加通用攻击参数:
-
调用
add_common_attack_args(parser)
函数向解析器中添加通用的攻击参数。 -
添加 SSBA 特定参数:
-
--attack_train_replace_imgs_path
:训练替换图像的路径。 -
--attack_test_replace_imgs_path
:测试替换图像的路径。 -
--bd_yaml_path
:配置文件的路径,默认值为./config/attack/ssba/default.yaml
,用于提供额外的默认属性。 -
返回修改后的解析器:
-
经过上述参数添加后,返回修改后的解析器
parser
。
process_args
方法
这个实例方法的主要功能是处理和完善传递给程序的命令行参数。方法步骤如下:
-
记录终端信息:
-
将当前终端命令行信息存储在
args.terminal_info
中。 -
获取数据集相关信息:
-
args.num_classes
:根据数据集获取类别数量。 -
args.input_height
、args.input_width
、args.input_channel
:根据数据集获取输入图像的高度、宽度和通道数。 -
args.img_size
:将图像尺寸信息整合为一个元组。 -
设置数据集路径:
-
根据数据集名称和给定路径,构造数据集的完整路径。
-
检查和设置训练替换图像路径:
-
如果
attack_train_replace_imgs_path
参数不存在或为None
,则设置为默认路径./resource/ssba/{args.dataset}_ssba_train_b1.npy
,并记录日志信息。 -
检查和设置测试替换图像路径:
-
如果
attack_test_replace_imgs_path
参数不存在或为None
,则设置为默认路径./resource/ssba/{args.dataset}_ssba_test_b1.npy
,并记录日志信息。 -
返回修改后的参数:
-
返回处理和完善后的参数
args
。
SSBA得到的中毒样本部分如下所示
开始注入后门
训练期间部分截图如下
可以看到,在第33个epoch时,模型的后门攻击成功率达到了0.97,而正常任务准确率达到了0.89
TrojanNN
理论
本章介绍一种新颖的神经网络木马攻击方法,其核心步骤包括:
-
生成木马触发器:通过逆向神经网络,生成一个能够显著激活网络中特定神经元的输入模式,即木马触发器。
-
重训练模型:使用木马触发器和逆向工程得到的训练数据对模型进行重训练,使得模型在触发器出现时表现出恶意行为,而在没有触发器的情况下保持正常。
与以往的方法相比,方法具有以下显著不同:
-
不依赖原始训练数据:本文的方法不需要访问或修改原始的训练数据,这使得攻击更加隐蔽和难以检测。
-
快速实施:传统的数据污染攻击需要在模型训练阶段进行,而本文的方法可以在模型发布后快速实施,大大缩短了攻击的准备时间。
-
保持正常性能:木马模型在没有触发器的普通输入下,能够保持与原始模型相似或甚至更好的性能,这提高了攻击的隐蔽性。
如下是论文中给出的正常图片以及TrojanNN得到的中毒图片的示例
现在我们来看具体的后门攻击实现步骤
生成木马触发器(Trojan Trigger Generation)
首先,攻击者需要确定一个目标输出,然后选择网络中的一些神经元,这些神经元将对木马触发器有显著的反应。这个过程可以通过优化一个成本函数来实现,该函数衡量的是选定神经元的当前值与目标值之间的差异。数学上,这个过程可以表示为:
其中,( t_{vi} ) 是目标神经元 ( ni ) 的目标值,( f{ni} ) 是该神经元在当前输入 ( x ) 下的值。攻击者使用梯度下降法来最小化成本函数,寻找输入 ( x ) 的值,使得选定的神经元值最大化。梯度 ( Delta ) 计算如下:
然后,通过梯度下降更新输入值:
其中,( text{lr} ) 是学习率,控制输入更新的步长。
重训练模型(Model Retraining)
一旦生成了木马触发器,下一步是重训练模型。这涉及到反向传播算法,通过计算损失函数相对于模型参数的梯度来更新模型权重。损失函数可以是均方误差或其他适当的误差度量。对于每个输出类别 ( y ),损失函数 ( L ) 可以表示为:
其中,( y ) 是期望输出,( hat{y} ) 是模型预测输出。权重更新规则为:
这里,( W ) 是模型权重,( eta ) 是学习率。
逆向工程训练数据(Reverse Engineering Training Data)
在没有原始训练数据的情况下,攻击者需要生成一组新的训练数据来重训练模型。这可以通过从公共数据集中选取图像,然后通过梯度下降调整像素值,直到模型对这些图像的预测达到高置信度。这个过程可以表示为:
其中,( x' ) 是逆向工程得到的输入,( Delta' ) 是相对于成本函数的梯度。
模型微调(Model Fine-tuning)
最后,攻击者将使用原始数据集和逆向工程得到的数据集对模型进行微调,以确保在没有触发器的情况下模型表现正常,而在触发器出现时执行恶意行为。这个过程涉及到调整模型权重,以建立选定神经元和输出层之间的强联系,并减少其他权重,特别是那些与恶意行为相关的权重。
通过这些步骤,攻击者能够在不访问原始训练数据和训练过程的情况下,快速有效地对神经网络模型进行木马攻击。这种攻击的关键在于精确地控制模型的内部行为,使其在特定输入下执行预定的恶意操作。
下图给出了攻击流程的示意
在论文中也给出了不同的触发器实例
实现
现在分析关键代码
定义一个函数 get_most_connected_neuron_idxes
,用于获取神经网络中与特定层参数相关的连接最强的神经元索引
函数参数
-
network
:神经网络模型对象。 -
parameter_name_key
:表示神经网络中某层参数的键(名称)。 -
num_selected
:要选择的最强连接神经元的数量,默认为 1。
函数实现
-
获取并处理参数:
-
使用
network.state_dict()[parameter_name_key]
获取特定层的参数,并取绝对值torch.abs()
以确保处理的是正值,方便后续计算。 -
记录参数的形状
parameter.shape
,以便于调试和日志记录。 -
处理参数形状:
-
如果参数是二维的(例如,全连接层的权重),不做任何处理。
-
如果参数是四维的(例如,卷积层的权重),首先将参数展平成三维,然后对第三维求和,得到一个二维的参数矩阵。
-
形状检查和异常处理:
-
仅处理二维和四维参数,如果参数的维度不是2或4,则抛出异常,提示“只考虑卷积和全连接层”。
-
计算最强连接的神经元索引:
-
对参数矩阵的第0维度求和,得到每个神经元的总连接强度。
-
使用
torch.argsort
对连接强度进行排序,降序排列,取前num_selected
个神经元的索引。
返回值
-
返回与特定层参数相关的连接最强的神经元索引,这些索引根据连接强度降序排列。
这个方法主要用于生成对抗样本,使得图像的特定神经元输出接近给定的目标值。
这段代码实现了一个投影梯度下降(PGD)攻击的方法,用于将图像调整到指定神经元的目标值
-
初始化模型和设备:
-
model.eval()
将模型设置为评估模式。 -
model.to(device)
将模型移到指定的设备(CPU或GPU)。 -
生成保持掩码:
-
keep_mask = (deepcopy(images) > 0).to(device)
生成一个与图像相同形状的掩码,用于保留原图像中非零值的位置。 -
图像转移到指定设备:
-
images = images.to(device)
将图像数据移到指定设备上。 -
保存原始图像数据:
-
ori_images = images.data
保存原始图像数据,以便后续计算扰动。 -
注册前向钩子:
-
hook_function
是一个钩子函数,用于保存指定层的输入。 -
dict(model.named_modules())[selected_layer].register_forward_hook(hook_function)
在指定层上注册前向钩子函数。 -
PGD迭代:
-
for _ in tqdm(range(iters), desc="pgd with respect to selected neuron"):
使用tqdm显示进度条,进行指定次数的迭代。 -
images.requires_grad = True
使图像成为需要梯度的张量,以便计算梯度。 -
outputs = model(images * keep_mask)
前向传播,通过模型计算输出。 -
selected_layer_input = model.feature_save
获取指定层的输入(即钩子函数保存的特征图)。 -
model.zero_grad()
将模型的梯度清零。 -
计算损失并反向传播:
-
cost += ((selected_layer_input[:, idx] - neuron_target_values[i]) ** 2).sum()
计算每个目标神经元的平方误差损失,并累加到总损失中。 -
cost = 0
初始化损失值。 -
for i, idx in enumerate(neuron_idxes):
遍历目标神经元索引。 -
cost.backward()
反向传播,计算梯度。 -
更新对抗图像:
-
adv_images = images - alpha * images.grad.sign()
按照梯度的符号方向调整图像,以减少损失。 -
eta = torch.clamp(adv_images - ori_images, min=-eps, max=eps)
将扰动限制在范围[-eps, eps]
内。 -
images = torch.clamp(ori_images + eta, min=0, max=1).detach_()
将扰动应用到原图像上,并确保结果在合法的图像范围内(0到1),然后将结果从计算图中分离出来。 -
提前停止条件:
-
if cost < tolerance:
如果损失低于容忍度,则提前停止迭代。 -
返回结果:
-
return images
返回生成的对抗图像。
这是一个简单且直接的图像处理方法,用于生成对抗样本或添加特定的图像触发器。
这段代码定义了一个用于生成对抗触发器的类 TrojanTrigger
,其功能是将目标图像与输入图像相加并返回一个带有触发器的图像:
-
类初始化:
-
class TrojanTrigger(object):
定义了一个名为TrojanTrigger
的类。 -
def __init__(self, target_image):
是类的初始化方法,接受一个目标图像target_image
作为参数。 -
self.target_image = target_image.astype(np.float)
将目标图像转换为浮点数类型并保存到实例变量self.target_image
中,以便后续计算。 -
定义调用方法:
-
def __call__(self, img, target=None, image_serial_id=None):
定义了类的调用方法,使得类实例可以像函数一样被调用。 -
return self.add_trigger(img)
调用add_trigger
方法将触发器添加到输入图像img
上,并返回处理后的图像。 -
添加触发器的方法:
-
def add_trigger(self, img):
定义了一个用于添加触发器的方法。 -
return np.clip((self.target_image + img.astype(np.float)).astype("uint8"), 0, 255)
将目标图像self.target_image
与输入图像img
相加,结果转换为无符号8位整数(uint8),并将值限制在0到255的范围内,以确保结果是有效的图像像素值。
总结:
-
TrojanTrigger
类的主要功能是将预先定义的目标图像(触发器)叠加到输入图像上,生成一个带有触发器的对抗样本。 -
初始化时,类接收一个目标图像,并将其转换为浮点数以便计算。
-
类实例可以像函数一样被调用,并将触发器添加到提供的图像上。
-
结果图像的像素值被限制在0到255的范围内,以确保图像有效。
TrojanNN
类继承自 BadNet
,它扩展了 BadNet
类提供的功能。
方法:set_bd_args
这个方法是一个类方法,用于设置后门攻击的参数解析。它向解析器添加了多个命令行参数,指定与神经网络模型和后门攻击相关的配置。
方法:stage1_non_training_data_prepare
这个方法用于准备后门攻击所需的非训练数据。
-
日志记录和断言:
-
记录阶段1的开始。
-
确保
args
是类字典的一部分。 -
数据集准备:
-
调用
benign_prepare()
来获取各种数据集和数据变换。 -
模型初始化:
-
使用
generate_cls_model
初始化一个分类模型。 -
如果提供了路径,则加载预训练模型,否则使用默认路径。
-
设备设置:
-
设置计算设备(CPU 或 GPU)。
-
神经元索引:
-
使用
get_most_connected_neuron_idxes
函数获取目标层中最相关的神经元索引。 -
触发器模式生成:
-
从指定路径加载图像掩码并调整其大小。
-
使用
pgd_with_mask_to_selected_neuron
方法生成触发器图像。 -
重新初始化模型:
-
在生成触发器模式后,重新初始化模型,使用非预训练模型。
-
数据变换设置:
-
设置后门图像和标签的变换。
-
生成后门攻击数据集:
-
生成带有后门的训练数据集和测试数据集,并将它们保存到指定路径。
方法:stage2_training
这个方法处理后门攻击的训练过程。
-
日志记录和断言:
-
记录阶段2的开始。
-
确保
args
是类字典的一部分。 -
数据集准备:
-
从
stage1_results
中获取干净和带后门的训练和测试数据集。 -
并行设置:
-
如果使用多个GPU设备,将模型设置为数据并行模式。
-
训练设置:
-
初始化训练器 (
BackdoorModelTrainer
)。 -
设置损失函数 (
criterion
)、优化器和学习率调度器。 -
模型训练:
-
使用混合数据集进行训练,并在每个epoch后测试模型。
-
保存结果:
-
将训练后的模型和数据保存到指定路径。
在我们的实现中得到的中毒样本部分如下所示
现在开始注入后门
训练期间部分截图如下所示
看了看到,在上图中,后门攻击成功率已经达到了100%,正常任务的准确率也都超过了92%
WaNet
理论
本章介绍一种新颖的后门攻击方法,称为WaNet(Warping-based poisoned Networks),它基于图像变形(warping)来生成触发模式。与以往方法不同,WaNet使用微小且平滑的变形场来生成后门图像,这种变形不易被人类观察者察觉,从而显著提高了后门的隐蔽性。此外,WaNet还引入了一种新的训练模式——“噪声模式”(noise mode),以确保模型在学习过程中只关注预定义的后门变形,而不是像素级的伪迹,这使得模型能够更好地隐藏后门行为,避免被现有的防御机制检测到。
WaNet方法的核心在于使用弹性图像变形技术,特别是薄板样条(Thin-Plate Splines, TPS)来生成平滑的变形场。这种方法不仅能够保持图像内容的自然性,还能确保变形后的图像在视觉上与原始图像几乎无法区分。通过在训练过程中引入噪声模式,WaNet强迫模型学习到正确的类别预测,即使在应用随机变形场时也不会触发后门行为,这一点在传统的后门攻击方法中是做不到的。
现在我们来形式化这种攻击方案
-
后门注入函数(Backdoor Injection Function):
-
假设有一个清洁的图像 ( x ) 和对应的标签 ( y ),后门注入函数 ( B ) 通过一个预定义的变形场 ( M ) 来生成后门图像 ( B(x) )。
-
数学表达式为: B(x) = W(x, M)
-
其中 ( W ) 是一个变形函数,( M ) 是一个定义了目标图像每个点的相对采样位置的变形场。
-
变形场生成(Warping Field Generation):
-
变形场 ( M ) 是通过控制点生成的,这些控制点定义了一个均匀网格,网格大小为 ( k times k )。
-
噪声模式的作用(Role of Noise Mode):
-
噪声模式通过在训练过程中引入随机变形场,迫使模型学习到不仅仅是像素级的伪迹,而是真正的变形模式。
-
这有助于模型在面对随机变形时仍能正确分类,从而避免被基于像素分析的防御机制(如 Neural Cleanse)检测到。
-
后门攻击的实现(Implementation of Backdoor Attack):
-
在攻击模式下,模型被训练为在接收到特定变形的图像时,输出预定义的目标标签 ( c(y) )。
-
通过这种方式,攻击者可以在模型中植入一个隐蔽的触发器,使得在特定条件下模型的行为被操控。
通过上述步骤,WaNet 生成了难以被人类察觉的后门图像,并通过新颖的训练模式增强了后门的隐蔽性,使其能够绕过现有的防御机制。
下图是论文中给出的,创建变形场生成中毒样本的过程
下图是应用不同超参数得到的变形效果
三种训练模式下的运行流程如下所示
实现
这个代码包含了一个函数 generalize_to_lower_pratio
和两个类 ProbTransform
和 PostTensorTransform
,用于数据预处理和增强。
generalize_to_lower_pratio
函数
这个函数根据给定的概率比率 pratio
和批量大小 bs
来计算一个新的值。
-
函数接收两个参数:
-
pratio
: 一个概率比率。 -
bs
: 批量大小。 -
计算逻辑:
-
如果
pratio * bs
的结果大于或等于1,函数返回pratio * bs
。 -
否则,函数会生成一个0到1之间的随机数,如果这个随机数小于
pratio * bs
,则返回1,否则返回0。
这个逻辑的主要目的是在某些情况下返回一个0或1,这取决于 pratio * bs
的值。这个函数在处理小概率事件时特别有用。
ProbTransform
类
这个类是 torch.nn.Module
的子类,用于在概率 p
下应用某个变换 f
。
-
初始化方法
__init__
: -
f
: 需要应用的变换函数。 -
p
: 应用变换的概率,默认为1。 -
前向传播方法
forward
: -
如果生成的随机数小于
p
,则对输入x
应用变换f
。 -
否则,直接返回输入
x
。
这个类的主要作用是在一定概率下对数据进行随机变换,增强数据多样性。
PostTensorTransform
类
这个类也是 torch.nn.Module
的子类,主要用于在特定数据集上进行一系列的图像变换。
-
初始化方法
__init__
: -
random_crop
: 随机裁剪图像,概率为0.8。 -
random_rotation
: 随机旋转图像,概率为0.5。 -
random_horizontal_flip
: 对于cifar10
数据集,定义了随机水平翻转,概率为0.5。 -
接收一个参数
args
,其中包含了变换的具体配置。 -
定义了三个变换:
-
前向传播方法
forward
: -
依次对输入
x
应用各个变换模块(即调用这些变换模块的forward
方法)。
这个类的主要作用是根据预定义的概率对输入图像进行一系列随机变换,从而增强数据集的多样性,提高模型的泛化能力。
如下代码的核心功能是将经过标准化的数据还原到其原始数据范围,通过对每个通道的数据进行去归一化操作,恢复其原始的均值和方差。这在数据预处理和增强过程中非常有用,尤其是需要将数据还原到其原始状态以进行进一步处理或分析时。
这段代码定义了两个类 Denormalize
和 Denormalizer
,用于对数据进行去归一化处理。
Denormalize
类
这个类用于对输入数据进行去归一化操作。
-
初始化方法
__init__
: -
args
: 包含输入通道数的参数。 -
expected_values
: 每个通道的期望值(均值)。 -
variance
: 每个通道的方差。 -
在初始化过程中,
self.n_channels
被设置为输入通道数,并且确保输入通道数与提供的期望值数量一致。 -
调用方法
__call__
: -
x[:, channel] * self.variance[channel] + self.expected_values[channel]
-
x
: 输入数据张量。 -
创建
x
的克隆x_clone
,防止直接修改输入数据。 -
遍历每个通道,对每个通道的数据进行去归一化操作,即将标准化的数据还原到原始数据范围:
Denormalizer
类
这个类用于创建并管理 Denormalize
类的实例。
-
初始化方法
__init__
: -
args
: 包含数据集相关信息的参数。 -
在初始化过程中,调用
_get_denormalizer
方法创建Denormalize
实例,并将其赋值给self.denormalizer
。 -
获取去归一化器方法
_get_denormalizer
: -
args
: 包含数据集相关信息的参数。 -
获取指定数据集的归一化参数(均值和标准差),这些参数是通过
get_dataset_normalization(args.dataset)
函数获取的。 -
使用这些参数创建
Denormalize
实例。 -
调用方法
__call__
: -
x
: 输入数据张量。 -
如果
self.denormalizer
存在,则调用其__call__
方法对输入数据进行去归一化处理。
具体实现过程
-
Denormalize
类的初始化: -
设置输入通道数和每个通道的均值、方差。
-
确保输入通道数与均值、方差的长度一致。
-
Denormalize
类的调用: -
克隆输入数据。
-
遍历每个通道,对其进行去归一化处理。
-
Denormalizer
类的初始化: -
调用
_get_denormalizer
方法,使用数据集的均值和方差创建Denormalize
实例。 -
Denormalizer
类的调用: -
使用
Denormalize
实例对输入数据进行去归一化处理。
如下代码的核心功能是实现一个后门攻击模型的训练流程,包括数据准备、模型训练、生成后门样本以及评估模型在干净数据和后门数据上的表现。通过这两个阶段的方法,代码有效地将数据准备和模型训练分离,使得整个流程更加模块化和易于管理。
这段代码定义了一个名为 Wanet
的类,它继承自 BadNet
,并实现了两个主要阶段的方法:stage1_non_training_data_prepare
和 stage2_training
。这个类的主要目的是进行后门攻击模型的训练和评估
__init__
方法
-
这是
Wanet
类的初始化方法,调用了父类BadNet
的初始化方法。
stage1_non_training_data_prepare
方法
-
目的:准备阶段1的非训练数据。
-
具体步骤:
-
创建带有转换的训练和测试数据集加载器,配置了批量大小、工作线程数量等参数。
-
日志记录:记录阶段1的开始。
-
参数检查:确保
self
对象中包含args
参数。 -
数据准备:调用
benign_prepare
方法,获取一系列数据集和转换操作。 -
数据加载器:
-
保存结果:将准备好的数据集和数据加载器保存在
self.stage1_results
中。
stage2_training
方法
-
目的:执行阶段2的模型训练。
-
具体步骤:
-
根据不同的攻击标签转换方法(如 all2one 和 all2all),生成后门样本并存储到后门测试数据集中。
-
过滤掉不可逆的图像变换,只保留归一化、调整大小和张量转换。
-
生成一个随机噪声网格并进行上采样,以匹配输入图像的高度。
-
生成身份网格(identity grid)以便后续进行扭曲操作。
-
日志记录:记录阶段2的开始。
-
参数检查:确保
self
对象中包含args
参数。 -
结果加载:从
stage1
中获取准备好的数据集和数据加载器。 -
设备设置:根据可用的GPU设置设备(CPU或GPU)。
-
模型生成:生成分类模型
netC
并将其加载到设备上。 -
多GPU设置:如果使用多个GPU,配置
DataParallel
。 -
优化器和调度器:使用参数生成优化器和调度器。
-
日志记录:记录从头开始训练的消息。
-
初始化变量:初始化一些变量以记录最佳准确率和当前训练轮数。
-
后门扭曲设置:
-
过滤可逆变换:
-
获取去归一化器:从转换操作中获取去归一化器。
-
创建可逆测试数据集和加载器:创建只包含可逆变换的测试数据集和数据加载器。
-
创建后门和交叉测试数据集:初始化后门和交叉测试数据集对象。
-
遍历数据集:遍历可逆测试数据集,并生成后门和交叉测试数据样本。
-
后门攻击评估:
-
交叉攻击评估:根据交叉比例生成交叉攻击样本并存储。
-
创建数据加载器:为后门和交叉测试数据集创建数据加载器。
-
记录和初始化训练变量:记录不同测试集的损失和准确率,初始化相关变量。
代码结构
-
类继承关系:
Wanet
类继承自BadNet
,意味着Wanet
可以使用BadNet
中的属性和方法。 -
数据准备和训练阶段:
-
阶段1主要是数据的准备工作,包括加载数据集和应用图像变换。
-
阶段2主要是模型的训练和评估工作,包括生成后门样本和评估后门攻击的效果。
在我们的实现中,该方法得到的中毒样本部分如下所示
现在开始注入后门
训练期间的部分截图如下所示
在上图可以看到,第53个epoch时,攻击成功率到达了0.99,而正常任务准确率达到了0.88
如有侵权请联系删除
2
免费社区
安全洞察知识图谱星球是一个聚焦于信息安全对抗技术和企业安全建设的话题社区,也是一个[免费]的星球,欢迎大伙加入积极分享红蓝对抗、渗透测试、安全建设等热点主题
原文始发于微信公众号(安全洞察知识图谱):深度学习后门攻击演进趋势与先进技术分析
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论