r""" Description ----------- Attack features and graph structure simultaneously Parameters ---------- model : torch.nn.module Model implemented based on ``torch.nn.module``. adj : scipy.sparse.csr.csr_matrix Adjacency
(
self, model, adj, features_origin, labels_origin, index_target, feat_norm=None, adj_norm_func=None
)
| 118 | return getGraph(adj_attack, features_attack, graph.y, device=self.device) |
| 119 | |
| 120 | def modification( |
| 121 | self, model, adj, features_origin, labels_origin, index_target, feat_norm=None, adj_norm_func=None |
| 122 | ): |
| 123 | r""" |
| 124 | |
| 125 | Description |
| 126 | ----------- |
| 127 | Attack features and graph structure simultaneously |
| 128 | |
| 129 | Parameters |
| 130 | ---------- |
| 131 | model : torch.nn.module |
| 132 | Model implemented based on ``torch.nn.module``. |
| 133 | adj : scipy.sparse.csr.csr_matrix |
| 134 | Adjacency matrix in form of :math:`(N + N_{inject})\times(N + N_{inject})` sparse matrix. |
| 135 | features_origin : torch.FloatTensor |
| 136 | Features in form of ``N * D`` torch float tensor. |
| 137 | features_attack : torch.FloatTensor |
| 138 | Features of nodes after attacks in form of :math:`N_{inject}` * D` torch float tensor. |
| 139 | labels_origin : torch.LongTensor |
| 140 | Labels of target nodes originally predicted by the model. |
| 141 | index_target : torch.Tensor |
| 142 | Mask of target nodes in form of ``N * 1`` torch bool tensor. |
| 143 | feat_norm : str, optional |
| 144 | Type of feature normalization, ['arctan', 'tanh']. Default: ``None``. |
| 145 | adj_norm_func : func of utils.normalize, optional |
| 146 | Function that normalizes adjacency matrix. Default: ``None``. |
| 147 | |
| 148 | Returns |
| 149 | ------- |
| 150 | features_attack : torch.FloatTensor |
| 151 | Updated features of nodes after attacks in form of :math:`N_{inject}` * D` torch float tensor. |
| 152 | |
| 153 | """ |
| 154 | features_attack = feat_preprocess(features=features_origin, feat_norm=feat_norm, device=self.device) |
| 155 | |
| 156 | index_target = torch.where(index_target)[0] |
| 157 | index_mod = np.random.choice(index_target, self.n_node_mod) |
| 158 | |
| 159 | assert (adj.todense().T == adj.todense()).all(), "adjacency matrix must be symmetrical" |
| 160 | adj = adj_to_tensor(adj).to(self.device).coalesce() |
| 161 | |
| 162 | perturbed_edge_indices, perturbed_edge_weight, current_search_space = self.sample_random_block() |
| 163 | |
| 164 | # For early stopping (not explicitly covered by pesudo code) |
| 165 | best_test_score = float("Inf") |
| 166 | best_epoch = float("-Inf") |
| 167 | |
| 168 | def evaluate(features, adj): |
| 169 | pred = model(getGraph(adj_norm_func(adj), features, device=self.device)) |
| 170 | pred_loss = self.loss(pred[index_target], labels_origin[index_target]) |
| 171 | |
| 172 | test_score = self.eval_metric(pred[index_target], labels_origin[index_target]) |
| 173 | return pred_loss, test_score |
| 174 | |
| 175 | model.eval() |
| 176 | epoch_bar = tqdm(range(self.n_epoch), disable=not self.verbose) |
| 177 | for epoch in epoch_bar: |
no test coverage detected