Skip to content

Commit

Permalink
Changes to the attacks
Browse files Browse the repository at this point in the history
  • Loading branch information
Munkhtenger19 committed May 17, 2024
1 parent e9b1942 commit f567461
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 26 deletions.
3 changes: 3 additions & 0 deletions PyG_to_sci_sparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@ def accuracy(pred, y, mask):
edge_index = to_undirected(data2.edge_index)
print('x',edge_index.shape[1])
print('undirected', edge_index)
edge_index2 = to_undirected(edge_index)
print('undirected', edge_index)
print('q',torch.equal(edge_index, edge_index2))
print(torch.equal(data2.edge_index, edge_index))
print("numm", data2.num_nodes)

Expand Down
22 changes: 12 additions & 10 deletions configs/default_experiment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ experiment_templates:
params:
hidden_channels: 64
dataset:
name: Cora #ogbn-arxiv
name: Cora # ogbn-arxiv
root: ./datasets
make_undirected: False
make_undirected: false
# transforms:
# - name: NormalizeFeatures
# - name: Constant
Expand All @@ -33,15 +33,17 @@ experiment_templates:
# name: PGD
# type: poison
# epsilon: [0.5]
# - scope: global
# name: DICE, FGSM, PGD, PRBCD, GreedyRBCD]
- scope: global
name: [PRBCD2]
type: evasion
epsilon: [0.6]
# params:
# block_size: 100000
# - scope: local
# name: [LocalPRBCD, LocalDICE]
# type: [poison, evasion]
# epsilon: [0.5]
- scope: local
name: [LocalPRBCD, LocalDICE]
type: poison
epsilon: [0.3]
nodes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# epsilon: [0.3]
# nodes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# - scope: local
# name: Nettack
# type: evasion
Expand Down
2 changes: 1 addition & 1 deletion gnn_toolbox/custom_components/attacks/base_attack.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def from_sparsetensor_to_edge_index(self, adj):
edge_index_rows, edge_index_cols, edge_weight = adj.coo()
edge_index = torch.stack([edge_index_rows, edge_index_cols], dim=0).to(self.device)
return edge_index, edge_weight.to(self.device)
return None, None
raise ValueError("Adjacency matrix is not a SparseTensor from torch_sparse")

def from_edge_index_to_sparsetensor(self, edge_index, edge_weight):
return SparseTensor(row=edge_index[0], col=edge_index[1], value=edge_weight).to(self.device)
Expand Down
4 changes: 2 additions & 2 deletions gnn_toolbox/custom_components/attacks/global_attacks/dice.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def __init__(self, add_ratio: float = 0.6, **kwargs):
super().__init__(**kwargs)

assert self.make_undirected, 'Attack only implemented for undirected graphs'

self.edge_weight = self.edge_weight.float()
self.edge_index, self.edge_weight = self.from_sparsetensor_to_edge_index(self.adj)
# self.edge_weight = self.edge_weight.float()

# Create Symmetric Adjacency Matrix
adj_symmetric_index, adj_symmetric_weights = utils.to_symmetric(self.edge_index, self.edge_weight, self.n)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def _greedy_update(self, step_size: int, gradient: torch.Tensor):
# self.edge_weight = torch.ones_like(self.edge_weight)
assert self.edge_index.size(1) == self.edge_weight.size(0)

def _attack(self, n_perturbations: int):
def attack(self, n_perturbations: int):
"""Perform attack
Parameters
Expand Down
20 changes: 12 additions & 8 deletions gnn_toolbox/custom_components/attacks/global_attacks/new_prbcd.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
from gnn_toolbox.registry import register_global_attack
# (predictions, labels, ids/mask) -> Tensor with one element
LOSS_TYPE = Callable[[Tensor, Tensor, Optional[Tensor]], Tensor]
from torch_geometric.seed import seed_everything


@register_global_attack("PRBCD2")
class PRBCDAttack(GlobalAttack):
Expand Down Expand Up @@ -95,7 +97,7 @@ class PRBCDAttack(GlobalAttack):

def __init__(
self,
block_size: int = 250_000,
block_size: int = 200_000,
epochs: int = 125,
epochs_resampling: int = 100,
loss_type: Optional[Union[str, LOSS_TYPE]] = 'prob_margin',
Expand All @@ -105,6 +107,7 @@ def __init__(
log: bool = True,
**kwargs,
):

super().__init__(**kwargs)

self.block_size = block_size
Expand Down Expand Up @@ -134,6 +137,7 @@ def __init__(
self.coeffs.update(kwargs)

def attack(self, n_perturbations: int, **kwargs):

row, col, edge_attr = self.adj_adversary.coo()
edge_index = torch.stack([row, col], dim=0)
self.attacker(self.attr, edge_index, self.labels, n_perturbations, **kwargs)
Expand Down Expand Up @@ -165,6 +169,7 @@ def attacker(
:rtype: (:class:`torch.Tensor`, :class:`torch.Tensor`)
"""
seed_everything(42)
self.attacked_model.eval()

self.device = x.device
Expand Down Expand Up @@ -201,7 +206,7 @@ def attacker(
edge_weight = torch.ones(perturbed_edge_index.size(1), device=self.device)
# adj = sp.csr_matrix((edge_weight.cpu(), perturbed_edge_index.cpu()), (self.num_nodes, self.num_nodes))
# self.adj_adversary = torch_sparse.SparseTensor.from_scipy(adj).coalesce().to(self.device)
self.adj_adversary = torch_sparse.SparseTensor(row = perturbed_edge_index[0].to(self.device), col = perturbed_edge_index[1].to(self.device), value = edge_weight)
self.adj_adversary = torch_sparse.SparseTensor(row = perturbed_edge_index[0], col = perturbed_edge_index[1], value = edge_weight).t().to(self.device)
# self.adj_adversary = perturbed_edge_index
# return perturbed_edge_index, flipped_edges

Expand Down Expand Up @@ -655,7 +660,7 @@ def _append_statistics(self, mapping: Dict[str, Any]):
def __repr__(self) -> str:
return f'{self.__class__.__name__}()'


@register_global_attack("GRBCD")
class GRBCDAttack(PRBCDAttack):
r"""The Greedy Randomized Block Coordinate Descent (GRBCD) adversarial
attack from the `Robustness of Graph Neural Networks at Scale
Expand Down Expand Up @@ -697,16 +702,15 @@ class GRBCDAttack(PRBCDAttack):

def __init__(
self,
model: torch.nn.Module,
block_size: int,
block_size: int = 200_000,
epochs: int = 125,
loss: Optional[Union[str, LOSS_TYPE]] = 'masked',
is_undirected: bool = True,
make_undirected: bool = True,
log: bool = True,
**kwargs,
):
super().__init__(model, block_size, epochs, loss_type=loss,
make_undirected=is_undirected, log=log, **kwargs)
super().__init__(block_size, epochs, loss_type=loss,
make_undirected=make_undirected, log=log, **kwargs)

@torch.no_grad()
def _prepare(self, budget: int) -> List[int]:
Expand Down
5 changes: 3 additions & 2 deletions gnn_toolbox/custom_components/attacks/global_attacks/prbcd.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def __init__(self,

self.lr_factor = lr_factor * max(math.log2(self.n_possible_edges / self.block_size), 1.)

def _attack(self, n_perturbations, **kwargs):
def attack(self, n_perturbations, **kwargs):
"""Perform attack (`n_perturbations` is increasing as it was a greedy attack).
Parameters
Expand All @@ -80,7 +80,8 @@ def _attack(self, n_perturbations, **kwargs):

# Accuracy and attack statistics before the attach even started
with torch.no_grad():
logits = self._get_logits(self.attr, self.edge_index, self.edge_weight)
edge_index, edge_weight = self.from_sparsetensor_to_edge_index(self.adj)
logits = self._get_logits(self.attr, edge_index, edge_weight)
loss = self.calculate_loss(logits[self.idx_attack], self.labels[self.idx_attack])
accuracy = utils.accuracy(logits, self.labels, self.idx_attack)

Expand Down
12 changes: 10 additions & 2 deletions gnn_toolbox/experiment_handler/exp_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,17 @@ def run_experiment(experiment, experiment_dir, artifact_manager):
logging.exception(e)
logging.error(f"Global evasion adversarial attack {experiment['attack']['name']} failed to attack the model {experiment['model']['name']}")
return


# correct one, with no t()
logits, accuracy = evaluate_model(model=model, attr=pert_attr, adj=pert_adj, labels=labels, idx_test=split['test'], device=device)

logits0, accuracy0 = evaluate_model(model=model, attr=pert_attr, adj=pert_adj.t(), labels=labels, idx_test=split['test'], device=device)
logits2, accuracy2 = evaluate_model(model=model, attr=attr, adj=adj.t(), labels=labels, idx_test=split['test'], device=device)
# correct one, with no t()
logits3, accuracy3 = evaluate_model(model=model, attr=attr, adj=adj, labels=labels, idx_test=split['test'], device=device)
logging.info(f'HEREE, {accuracy}')
logging.info(f'HEREE0, {accuracy0}')
logging.info(f'HEREE2, {accuracy2}')
logging.info(f'HEREE3, {accuracy3}')
perturbed_result ={
'logits': logits.cpu().numpy().tolist(),
'accuracy': accuracy,
Expand Down

0 comments on commit f567461

Please sign in to comment.