上一小节介绍了IG-FGSM攻击方法,本小节作为对上一小节的代码实现,代码来源于https://github.com/DSE-MSU/DeepRobust
deeprobust库的参考文献:Graph Dataset — DeepRobust 0.1.1 documentation
这篇并不是在讲解deeprobust库的使用,而是记录论文实现的代码思路
下载之后,可以看到文件夹中的这个文件(黄色框框起来的):
这是有目标攻击方法的抽象类,每个被实现的有目标攻击方法都继承于这个类,它涉及五个方法:
- 初始化(__init__):对于任一种有目标攻击,我们需要以下参数:模型、节点数、是否攻击图结构、是否攻击图特征和所用设备(gpu or cpu)。
- 攻击(attack):原始邻接矩阵、攻击上限次数。待实现。
- 检查邻接矩阵(check_adj):检查攻击后的邻接矩阵是否超出限制,这里要求邻接矩阵必须是对称的、无权的。
- 保存邻接矩阵(save_adj):将每一次迭代被修改的邻接矩阵暂存下来。
- 保存图特征(save_features):将每一次迭代被修改的特征矩阵暂存下来。
接下来可以在同一个文件夹目录下看到deeprobust\graph\targeted_attack\ig_attack.py文件,这就是IG-FGSM攻击方法的具体实现。
IG-FGSM是通过集成梯度代替传统梯度,然后利用梯度的方向使模型越来越差的一种攻击方法。它既可以攻击图结构,也可以攻击图特征。为了攻击图特征,该攻击类在初始化时增加了一个参数:特征形状。
我们把重心放在攻击的实现上。
攻击方法使用到的参数如下。
"""Generate perturbations on the input graph.
Parameters
----------
ori_features :原始的特征矩阵
Original (unperturbed) node feature matrix
ori_adj :原始的邻接矩阵
Original (unperturbed) adjacency matrix
labels :标签
node labels
idx_train:训练集索引
training nodes indices
target_node : int目标节点
target node index to be attacked
n_perturbations : int干扰上限次数
Number of perturbations on the input graph. Perturbations could
be edge removals/additions or feature removals/additions.
steps : int
steps for computing integrated gradients
"""
攻击代码以及解释如下:
def attack(self, ori_features, ori_adj, labels, idx_train, target_node, n_perturbations, steps=10, **kwargs):
#计算伪标签,作为攻击过程中优化的目标。在没有攻击之前,pseudo_labels 代表了模型对每个节点的预测标签
self.surrogate.eval()
self.target_node = target_node
modified_adj = ori_adj.todense()
modified_features = ori_features.todense()
adj, features, labels = utils.to_tensor(modified_adj, modified_features, labels, device=self.device)
adj_norm = utils.normalize_adj_tensor(adj)
pseudo_labels = self.surrogate.predict().detach().argmax(1)
pseudo_labels[idx_train] = labels[idx_train]
self.pseudo_labels = pseudo_labels
#初始化两个数组,用于存放每个边和每个特征的扰动性得分,集成梯度就在计算干扰性得分的方法中
s_e = np.zeros(adj.shape[1])
s_f = np.zeros(features.shape[1])
if self.attack_structure:
s_e = self.calc_importance_edge(features, adj_norm, labels, steps)
if self.attack_features:
s_f = self.calc_importance_feature(features, adj_norm, labels, steps)
#扰动性得分最大的是本次攻击的操作选择
for t in (range(n_perturbations)):
s_e_max = np.argmax(s_e)
s_f_max = np.argmax(s_f)
if s_e[s_e_max] >= s_f[s_f_max]:
# edge perturbation score is larger
if self.attack_structure:
value = np.abs(1 - modified_adj[target_node, s_e_max])
modified_adj[target_node, s_e_max] = value
modified_adj[s_e_max, target_node] = value
s_e[s_e_max] = 0
else:
raise Exception("""No posisble perturbation on the structure can be made!
See https://github.com/DSE-MSU/DeepRobust/issues/42 for more details.""")
else:
# feature perturbation score is larger
if self.attack_features:
modified_features[target_node, s_f_max] = np.abs(1 - modified_features[target_node, s_f_max])
s_f[s_f_max] = 0
else:
raise Exception("""No posisble perturbation on the features can be made!
See https://github.com/DSE-MSU/DeepRobust/issues/42 for more details.""")
self.modified_adj = sp.csr_matrix(modified_adj)
self.modified_features = sp.csr_matrix(modified_features)
self.check_adj(modified_adj)
这段代码中我最不理解的是伪标签pseudo_labels,为什么要设置这个,以下是搜集到的原因:
- 替代真实标签来进行攻击目标的引导,在攻击过程中进行目标优化。
- 将训练集的真实标签保留下来,因为训练集的节点标签是已知的,它们不能被修改或误导。
通过代码,可以看出pseudo_labels数组中的标签是训练集真实标签+模型预测测试集标签,这个配置下,我们的目标就是在不干扰训练集预测标签的情况下使测试集中的数据被误判,因此伪标签是我们的优化目标基准。