def attack(self, ori_features, ori_adj, labels, idx_train, idx_unlabeled, perturbations, ll_constraint=True, ll_cutoff=0.004): ori_adj, ori_features, labels = utils.to_tensor(ori_adj, ori_features, labels, device=self.device) labels_self_training = self.self_training_label(labels, idx_train) self.sparse_features = sp.issparse(ori_features) modified_adj = ori_adj modified_features = ori_features for i in tqdm(range(perturbations), desc="Perturbing graph"): self._initialize() if self.attack_structure: modified_adj = self.get_modified_adj(ori_adj) self.adj_grad_sum.data.fill_(0) if self.attack_features: modified_features = ori_features + self.feature_changes self.feature_grad_sum.data.fill_(0) self.inner_train(modified_features, modified_adj, idx_train, idx_unlabeled, labels, labels_self_training) adj_meta_score = torch.tensor(0.0).to(self.device) feature_meta_score = torch.tensor(0.0).to(self.device) if self.attack_structure: adj_meta_score = self.get_adj_score(self.adj_grad_sum, modified_adj, ori_adj, ll_constraint, ll_cutoff) if self.attack_features: feature_meta_score = self.get_feature_score(self.feature_grad_sum, modified_features) if adj_meta_score.max() >= feature_meta_score.max(): adj_meta_argmax = torch.argmax(adj_meta_score) row_idx, col_idx = utils.unravel_index(adj_meta_argmax, ori_adj.shape) self.adj_changes.data[row_idx][col_idx] += (-2 * modified_adj[row_idx][col_idx] + 1) self.adj_changes.data[col_idx][row_idx] += (-2 * modified_adj[row_idx][col_idx] + 1) else: feature_meta_argmax = torch.argmax(feature_meta_score) row_idx, col_idx = utils.unravel_index(feature_meta_argmax, ori_features.shape) self.features_changes.data[row_idx][col_idx] += (-2 * modified_features[row_idx][col_idx] + 1) if self.attack_structure: self.modified_adj = self.get_modified_adj(ori_adj).detach() if self.attack_features: self.modified_features = self.get_modified_features(ori_features).detach()
def attack(self, ori_features, ori_adj, labels, idx_train, idx_unlabeled, n_perturbations, ll_constraint=True, ll_cutoff=0.004): """Generate n_perturbations on the input graph. Parameters ---------- ori_features : Original (unperturbed) node feature matrix ori_adj : Original (unperturbed) adjacency matrix labels : node labels idx_train : node training indices idx_unlabeled: unlabeled nodes indices n_perturbations : int Number of perturbations on the input graph. Perturbations could be edge removals/additions or feature removals/additions. ll_constraint: bool whether to exert the likelihood ratio test constraint ll_cutoff : float The critical value for the likelihood ratio test of the power law distributions. See the Chi square distribution with one degree of freedom. Default value 0.004 corresponds to a p-value of roughly 0.95. It would be ignored if `ll_constraint` is False. """ ori_adj, ori_features, labels = utils.to_tensor(ori_adj, ori_features, labels, device=self.device) labels_self_training = self.self_training_label(labels, idx_train) self.sparse_features = sp.issparse(ori_features) modified_adj = ori_adj modified_features = ori_features for i in tqdm(range(n_perturbations), desc="Perturbing graph"): self._initialize() if self.attack_structure: modified_adj = self.get_modified_adj(ori_adj) self.adj_grad_sum.data.fill_(0) if self.attack_features: modified_features = ori_features + self.feature_changes self.feature_grad_sum.data.fill_(0) self.inner_train(modified_features, modified_adj, idx_train, idx_unlabeled, labels, labels_self_training) adj_meta_score = torch.tensor(0.0).to(self.device) feature_meta_score = torch.tensor(0.0).to(self.device) if self.attack_structure: adj_meta_score = self.get_adj_score(self.adj_grad_sum, modified_adj, ori_adj, ll_constraint, ll_cutoff) if self.attack_features: feature_meta_score = self.get_feature_score( self.feature_grad_sum, modified_features) if adj_meta_score.max() >= feature_meta_score.max(): adj_meta_argmax = torch.argmax(adj_meta_score) row_idx, col_idx = utils.unravel_index(adj_meta_argmax, ori_adj.shape) self.adj_changes.data[row_idx][col_idx] += ( -2 * modified_adj[row_idx][col_idx] + 1) self.adj_changes.data[col_idx][row_idx] += ( -2 * modified_adj[row_idx][col_idx] + 1) else: feature_meta_argmax = torch.argmax(feature_meta_score) row_idx, col_idx = utils.unravel_index(feature_meta_argmax, ori_features.shape) self.features_changes.data[row_idx][col_idx] += ( -2 * modified_features[row_idx][col_idx] + 1) if self.attack_structure: self.modified_adj = self.get_modified_adj(ori_adj).detach() if self.attack_features: self.modified_features = self.get_modified_features( ori_features).detach()