def setModelWrapper(self, gnn_type): self.model_wrapper = ModelWrapper(node_model=self.mode.isNodeModel(), gnn_type=gnn_type, num_layers=self.num_layers, dataset=self.dataset, patience=self.patience, device=self.device, seed=self.seed) print( f'######################## LOADING MODEL {self.model_wrapper.model.name} ########################' ) self.model_wrapper.train(self.dataset)
def setModelWrapper(self, gnn_type: GNN_TYPE): """ Sets a ModelWrapper object and trains said ModelWrapper Parameters ---------- gnn_type: GNN_TYPE - the type of the gnn more information at classes.basic_classes.GNN_TYPE """ dataset = self.getDataset() self.model_wrapper = ModelWrapper(node_model=self.mode.isNodeModel(), gnn_type=gnn_type, num_layers=self.num_layers, dataset=dataset, patience=self.patience, device=self.device, seed=self.seed) print(f'######################## LOADING MODEL {self.model_wrapper.model.name} ########################') self.model_wrapper.train(dataset)
def setModelWrapper(self, gnn_type: GNN_TYPE): """ Sets a ModelWrapper object adversarially trained, according to the requested Ktrain Parameters ---------- gnn_type: GNN_TYPE - the type of the gnn more information at classes.basic_classes.GNN_TYPE """ dataset = self.getDataset() if self.Ktrain != 0: self.model_wrapper = AdversarialModelWrapper(node_model=True, gnn_type=gnn_type, num_layers=self.num_layers, dataset=dataset, patience=self.patience, device=self.device, seed=self.seed) else: self.model_wrapper = ModelWrapper(node_model=True, gnn_type=gnn_type, num_layers=self.num_layers, dataset=dataset, patience=self.patience, device=self.device, seed=self.seed) printAttackHeader(attack=self, approach=self.approach) print('######################## Creating/Loading an Adversarial Model with Ktrain: {:02d}'.format(self.Ktrain) + ' ########################', flush=True) self.model_wrapper.train(dataset=dataset, attack=self)
def setModelWrapper(self, gnn_type): if self.Ktrain != 0: self.model_wrapper = AdversarialModelWrapper( node_model=True, gnn_type=gnn_type, num_layers=self.num_layers, dataset=self.dataset, patience=self.patience, device=self.device, seed=self.seed) else: self.model_wrapper = ModelWrapper(node_model=True, gnn_type=gnn_type, num_layers=self.num_layers, dataset=self.dataset, patience=self.patience, device=self.device, seed=self.seed) printAttackHeader(attack=self, approach=self.approach) print( '######################## Creating/Loading an Adversarial Model with Ktrain: {:02d}' .format(self.Ktrain) + ' ########################', flush=True) self.model_wrapper.train(dataset=self.dataset, attack=self)
class oneGNNAttack(object): """ Generic attack class Parameters ---------- args: ArgumentParser - command line inputs start_to_file: str - string to insert at the start of the saved file print_answer: Print - the type of output print more information at classes.basic_classes.Print """ def __init__(self, args: ArgumentParser, start_to_file: str, print_answer: Print): self.start_to_file = start_to_file self.print_answer = print_answer self.end_to_file = '.csv' device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') seed = args.seed self.mode = args.attMode self.dataset_name = args.dataset dataset = GraphDataset(args.dataset, device) self.__dataset = dataset self.dataset_type = args.dataset.get_type() self.singleGNN = args.singleGNN if args.singleGNN is None: self.gnn_types = args.attMode.getGNN_TYPES() else: self.gnn_types = [args.singleGNN] self.num_layers = args.num_layers if args.num_layers is not None else 2 self.patience = args.patience if dataset.type is DatasetType.CONTINUOUS: self.continuous_epochs = args.continuous_epochs self.lr = args.lr if args.l_inf is None: args.l_inf = args.dataset.get_l_inf() self.l_inf = args.l_inf if args.l_0 is None: args.l_0 = args.dataset.get_l_0() self.l_0 = args.l_0 self.targeted = args.targeted self.max_distance = args.distance torch.manual_seed(seed) np.random.seed(seed) random.seed(seed) self.seed = seed self.device = device print( f'######################## STARTING ATTACK ########################' ) self.print_args(args) # use set functions self.setFileName(dataset, args) # *PARTLY* checking correctness of the inputs self.checkDistanceFlag(args) def setDataset(self, dataset: torch_geometric.data.Data): """ Sets a dataset Parameters ---------- dataset: torch_geometric.data.Data """ self.__dataset = dataset def getDataset(self): """ get a copy of the dataset Returns ------- dataset: torch_geometric.data.Data """ return copy.deepcopy(self.__dataset) def checkDistanceFlag(self, args: ArgumentParser): """ Validates that the distance argument is not requested Parameters ---------- args: ArgumentParser - command line inputs """ if args.distance is not None: exit("This attack doesn't requires the distance flag") def setModelWrapper(self, gnn_type: GNN_TYPE): """ Sets a ModelWrapper object and trains said ModelWrapper Parameters ---------- gnn_type: GNN_TYPE - the type of the gnn more information at classes.basic_classes.GNN_TYPE """ dataset = self.getDataset() self.model_wrapper = ModelWrapper(node_model=self.mode.isNodeModel(), gnn_type=gnn_type, num_layers=self.num_layers, dataset=dataset, patience=self.patience, device=self.device, seed=self.seed) print( f'######################## LOADING MODEL {self.model_wrapper.model.name} ########################' ) self.model_wrapper.train(dataset) def print_args(self, args: ArgumentParser): """ a print of the arguments passed to the main.py Parameters ---------- args: ArgumentParser - command line inputs """ for arg in vars(args): print(f"{arg}: {getattr(args, arg)}") print() def run(self): """ executes the requested attack for all gnn_types and approaches """ defence, attributes = [], [] for gnn_type in self.gnn_types: self.setModelWrapper(gnn_type) tmp_defence, tmp_attributes = self.attackPerGNN() defence.append(tmp_defence) attributes.append(tmp_attributes) defence = torch.cat(defence).to(self.device) attributes = torch.cat(attributes).to(self.device) self.saveResults(defence=defence, attributes=attributes) def attackPerApproachWrapper(self, approach: Approach) -> Tuple[torch.Tensor]: """ sets seeds before the execution of the requested attack (for a specific approach on a specific gnn_type) Parameters ---------- approach: Approach - the type of attack approach more information at classes.approach_classes.Approach """ seed = self.seed torch.manual_seed(seed) np.random.seed(seed) random.seed(seed) return self.attackPerApproach(approach=approach) def setFileName(self, dataset: GraphDataset, args: ArgumentParser): """ sets the generic name for the output file Parameters ---------- dataset: GraphDataset args: ArgumentParser - command line inputs """ if self.singleGNN is None: self.file_name = fileNamer( dataset_name=dataset.name, l_inf=args.l_inf, l_0=args.l_0, num_layers=args.num_layers, seed=args.seed, targeted=args.targeted, continuous_epochs=args.continuous_epochs, start=self.start_to_file, end=self.end_to_file) else: self.file_name = fileNamer( dataset_name=dataset.name, model_name=args.singleGNN.string(), l_inf=args.l_inf, l_0=args.l_0, num_layers=args.num_layers, seed=args.seed, targeted=args.targeted, continuous_epochs=args.continuous_epochs, start=self.start_to_file, end=self.end_to_file) def extendLog(self, log_start: str, log_end: str) -> str: """ sets the generic output log format Parameters ---------- log_start: str - prefix of the log format log_end: str - suffix of the log format Returns ------- log: str - output log format """ if self.mode.isDistance(): log = log_start + ' Distance: {:02d}'.format( self.current_distance) + log_end else: log = log_start + log_end return log def setModel(self, model: Model): """ sets the requested model in the ModeWrapper Parameters ---------- model: Model - the requested model """ self.model_wrapper.setModel(model) def saveResults(self, defence: torch.Tensor, attributes: torch.Tensor): """ saves the results of the attack Parameters ---------- defence: torch.Tensor - the defence % attributes: torch.Tensor - the % of attributes used for a *successful attack* """ raise NotImplementedError def attackPerGNN(self) -> Tuple[torch.Tensor]: """ executes the requested attack for all approaches on a specific gnn_type """ raise NotImplementedError def attackPerApproach(self, approach) -> Tuple[torch.Tensor]: """ executes the requested attack for a specific approach on a specific gnn_type Parameters ---------- approach: Approach - the type of attack approach more information at classes.approach_classes.Approach Returns ------- defence: torch.Tensor - the defence % attributes: torch.Tensor - the % of attributes used for a *successful attack* """ raise NotImplementedError
class NodeGNNSAdversarialAttack(NodeGNNSAttack): """ a Node-based-attack class that tests different train epochs (Ktrain) and different tesst epochs (Ktest) Parameters ---------- args: ArgumentParser - command line inputs """ def __init__(self, args: ArgumentParser): super(NodeGNNSAdversarialAttack, self).__init__(args, start_to_file='NodeAdversarialAttack', print_answer=Print.NO) self.Ktrain = self.attack_epochs self.Ktests = [1] + list(range(5, 30, 5)) self.approach = self.approaches[0] # a must-create / overriding Node def saveResults(self, results: torch.Tensor): """ information at the generic base class oneGNNSAttack """ test_string = [str(k) for k in self.Ktests] header = ['', 'clean'] + test_string defence_df = pd.DataFrame(results.to('cpu').numpy()) defence_df.insert(0, " ", str(self.Ktrain)) defence_df.to_csv(self.file_name, float_format='%.3f', header=header, index=False, na_rep='') # overriding def run(self): """ executes the requested attack for all Ktests and Ktrains (on a single gnn_type and a single approach) """ self.setModelWrapper(gnn_type=self.gnn_types[0]) tmp_mode = self.mode self.mode = self.mode.getModeNode() results = torch.zeros(len(self.Ktests) + 1).to(self.device) for idx, Ktest in enumerate(self.Ktests): print('######################## Attacking Adversarial Model with Ktrain: {:02d},'.format(self.Ktrain) + ' Ktest: {:02d} ########################'.format(Ktest), flush=True) tmp_result = self.attackOneApproachAndSetAttackEpochs(approach=self.approach, Ktest=Ktest) results[idx + 1] = tmp_result results[0] = self.model_wrapper.clean self.mode = tmp_mode self.saveResults(results.unsqueeze(0)) def setModelWrapper(self, gnn_type: GNN_TYPE): """ Sets a ModelWrapper object adversarially trained, according to the requested Ktrain Parameters ---------- gnn_type: GNN_TYPE - the type of the gnn more information at classes.basic_classes.GNN_TYPE """ dataset = self.getDataset() if self.Ktrain != 0: self.model_wrapper = AdversarialModelWrapper(node_model=True, gnn_type=gnn_type, num_layers=self.num_layers, dataset=dataset, patience=self.patience, device=self.device, seed=self.seed) else: self.model_wrapper = ModelWrapper(node_model=True, gnn_type=gnn_type, num_layers=self.num_layers, dataset=dataset, patience=self.patience, device=self.device, seed=self.seed) printAttackHeader(attack=self, approach=self.approach) print('######################## Creating/Loading an Adversarial Model with Ktrain: {:02d}'.format(self.Ktrain) + ' ########################', flush=True) self.model_wrapper.train(dataset=dataset, attack=self) # creating def attackOneApproachAndSetAttackEpochs(self, approach: Approach, Ktest: int) -> Tuple[torch.Tensor]: """ sets the requested Ktest before executing the requested attack for a specific approach on a specific gnn_type Parameters ---------- approach: Approach - the type of attack approach more information at classes.approach_classes.Approach Ktest: int - number of attack epochs for the test Returns ------- defence: torch.Tensor - the defence % """ self.setAttackEpochs(Ktest) results, _, _ = attackSet(self, approach=approach, trainset=False) mean_results = getDefenceResultsMean(attack=self, approach=approach, attack_results=results) return mean_results[0] def setAttackEpochs(self, K: int): """ sets attack_epochs Parameters ---------- K: int """ self.attack_epochs = K def setIdx(self, idx: int): """ sets the idx Parameters ---------- idx: int """ self.idx = idx
class NodeGNNSAdversarialAttack(NodeGNNSAttack): def __init__(self, args): super(NodeGNNSAdversarialAttack, self).__init__(args, start_to_file='NodeAdversarialAttack', print_answer=Print.NO) self.Ktrain = self.attack_epochs self.Ktests = [1] + list(range(10, 110, 10)) self.approach = self.approaches[0] # a must-create / overriding Node def saveResults(self, results): test_string = [str(k) for k in self.Ktests] header = ['', 'clean'] + test_string defence_df = pd.DataFrame(results.to('cpu').numpy()) defence_df.insert(0, " ", str(self.Ktrain)) defence_df.to_csv(self.file_name, float_format='%.3f', header=header, index=False, na_rep='') # overriding def run(self): self.setModelWrapper(gnn_type=self.gnn_types[0]) tmp_mode = self.mode self.mode = self.mode.getModeNode() results = torch.zeros(len(self.Ktests) + 1).to(self.device) for idx, Ktest in enumerate(self.Ktests): print( '######################## Attacking Adversarial Model with Ktrain: {:02d},' .format(self.Ktrain) + ' Ktest: {:02d} ########################'.format(Ktest), flush=True) tmp_result = self.attackOneApproachAndSetAttackEpochs( approach=self.approach, Ktest=Ktest) results[idx + 1] = tmp_result results[0] = self.model_wrapper.clean self.mode = tmp_mode self.saveResults(results.unsqueeze(0)) def setModelWrapper(self, gnn_type): if self.Ktrain != 0: self.model_wrapper = AdversarialModelWrapper( node_model=True, gnn_type=gnn_type, num_layers=self.num_layers, dataset=self.dataset, patience=self.patience, device=self.device, seed=self.seed) else: self.model_wrapper = ModelWrapper(node_model=True, gnn_type=gnn_type, num_layers=self.num_layers, dataset=self.dataset, patience=self.patience, device=self.device, seed=self.seed) printAttackHeader(attack=self, approach=self.approach) print( '######################## Creating/Loading an Adversarial Model with Ktrain: {:02d}' .format(self.Ktrain) + ' ########################', flush=True) self.model_wrapper.train(dataset=self.dataset, attack=self) # creating def attackOneApproachAndSetAttackEpochs(self, approach, Ktest): self.setAttackEpochs(Ktest) results, _, _ = attackSet(self, approach=approach, print_answer=self.print_answer, trainset=False) return results[0] def setAttackEpochs(self, K): self.attack_epochs = K def setIdx(self, idx): self.idx = idx
class oneGNNAttack(object): def __init__(self, args, start_to_file, print_answer): self.start_to_file = start_to_file self.print_answer = print_answer self.end_to_file = '.csv' device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') seed = args.seed self.mode = args.attMode dataset = GraphDataset(args.dataset, device) self.dataset = dataset self.singleGNN = args.singleGNN if args.singleGNN is None: self.gnn_types = args.attMode.getGNN_TYPES() else: self.gnn_types = [args.singleGNN] self.num_layers = args.num_layers if args.num_layers is not None else 2 self.patience = args.patience self.attack_epochs = args.attEpochs if args.attEpochs is not None else 20 self.lr = args.lr if args.l_inf is None and dataset.type is DatasetType.CONTINUOUS: self.l_inf = 0.1 else: self.l_inf = args.l_inf self.targeted = args.targeted self.max_distance = args.distance torch.manual_seed(seed) np.random.seed(seed) random.seed(seed) self.seed = seed self.device = device self.approaches = args.attMode.getApproaches() print( f'######################## STARTING ATTACK ########################' ) self.print_args(args) # use set functions self.setFileName(dataset, args) # *PARTLY* checking correctness of the inputs self.checkDistanceFlag(args) def checkDistanceFlag(self, args): if args.distance is not None: quit("This attack doesn't requires the distance flag") def setModelWrapper(self, gnn_type): self.model_wrapper = ModelWrapper(node_model=self.mode.isNodeModel(), gnn_type=gnn_type, num_layers=self.num_layers, dataset=self.dataset, patience=self.patience, device=self.device, seed=self.seed) print( f'######################## LOADING MODEL {self.model_wrapper.model.name} ########################' ) self.model_wrapper.train(self.dataset) def print_args(self, args): for arg in vars(args): print(f"{arg}: {getattr(args, arg)}") print() def attackPerGNN(self, add_clean=True): increment = 1 if add_clean else 0 results = torch.zeros(len(self.approaches) + increment).to(self.device) for approach_idx, approach in enumerate(self.approaches): tmp_result = self.attackOneApproach(approach) results[approach_idx + increment] = tmp_result if add_clean: results[0] = self.model_wrapper.clean return results.unsqueeze(0) def setFileName(self, dataset, args): if self.singleGNN is None: self.file_name = fileNamer(dataset_name=dataset.name, l_inf=args.l_inf, num_layers=args.num_layers, seed=args.seed, targeted=args.targeted, attack_epochs=args.attEpochs, start=self.start_to_file, end=self.end_to_file) else: self.file_name = fileNamer(dataset_name=dataset.name, model_name=args.singleGNN.string(), l_inf=args.l_inf, num_layers=args.num_layers, seed=args.seed, targeted=args.targeted, attack_epochs=args.attEpochs, start=self.start_to_file, end=self.end_to_file) def extendLog(self, log_start, log_end): if self.mode.isAdversarial(): log = 'Adv Epoch: {:02d}, '.format(self.idx) + log_start + log_end elif self.mode.isDistance(): log = log_start + 'Distance: {:02d}, '.format( self.current_distance) + log_end else: log = log_start + log_end return log def setModel(self, model): self.model_wrapper.setModel(model) def saveResults(self, results): raise NotImplementedError def run(self): raise NotImplementedError def attackOneApproach(self, approach): raise NotImplementedError