def test_protocolar_datasets(dataset_size=10, epsilons=[0.01, 0.05], attack_type="FGSM", noise=0.2, succ_adv=True): dataset = Dataset("MNIST") model = get_deep_model(dataset=dataset, architecture=get_architecture(mnist_mlp.name), num_epochs=25) train_clean, test_clean, train_adv, test_adv = get_protocolar_datasets( noise=noise, dataset=dataset, succ_adv=succ_adv, archi=model, dataset_size=dataset_size, attack_type=attack_type, all_epsilons=epsilons, ) print(len(train_clean)) print(len(test_clean)) for key in train_adv: print(f"{key} => {len(train_adv[key])}") for key in test_adv: print(f"{key} => {len(test_adv[key])}")
def get_all_accuracies(config: Config, with_image=True): if config.attack_type in ["FGSM", "PGD"]: # all_epsilons = list(sorted(np.linspace(0.0, 0.5, num=21))) # all_epsilons = [0, 0.001, 0.0025, 0.005, 0.0075, 0.01, 0.02, 0.03, 0.04, 0.05, 0.1] all_epsilons = [0, 0.001, 0.01, 0.1] else: all_epsilons = [0.0, 1] dataset = Dataset(name=config.dataset) architecture = get_deep_model( num_epochs=config.epochs, dataset=dataset, architecture=get_architecture(config.architecture), train_noise=config.train_noise, prune_percentile=config.prune_percentile, tot_prune_percentile=config.tot_prune_percentile, first_pruned_iter=config.first_pruned_iter, ) # architecture = torch.load( # f"{rootpath}/trained_models/cifar_resnet_1_e_99.model.model", map_location=device # ) # architecture.set_eval_mode() # architecture.is_trained = True # assert architecture.matrices_are_built is True accuracies = dict() for epsilon in all_epsilons: adversarial_acc, some_images = compute_adv_accuracy( config=config, epsilon=epsilon, noise=config.noise, dataset=dataset, architecture=architecture, dataset_size=config.dataset_size, attack_type=config.attack_type, num_iter=config.num_iter, ) logger.info( f"Img min pixel = {torch.min(some_images[0])}, and max pixel = {torch.max(some_images[0])}" ) logger.info(f"Epsilon={epsilon}: acc={adversarial_acc}") accuracies[epsilon] = adversarial_acc mlflow.log_metric(f"accuracy_{epsilon}", accuracies[epsilon]) if with_image: with open(config.result_path + f"/images_eps_{epsilon}.pickle", "wb") as fw: pickle.dump(some_images, fw) return accuracies
def test_get_mnist_model(): torch.manual_seed(37) random.seed(38) np.random.seed(39) source_dataset = Dataset("MNIST") _, val_acc, test_acc = get_deep_model( dataset=source_dataset, num_epochs=1, architecture=mnist_lenet, with_details=True, force_retrain=True, ) print(val_acc) print(test_acc)
def test_shapes(dataset, architecture): source_dataset = Dataset(dataset) archi = get_deep_model( dataset=source_dataset, num_epochs=1, architecture=architecture, with_details=False, force_retrain=False, ) x, y = source_dataset.train_dataset[0] inner_values = archi.forward(x, output="all_inner") shape = None mat_shapes_for_underopt = dict() for key in inner_values: print(f"Layer {key}: {archi.layers[key]}") new_shape = inner_values[key].shape if shape is not None and isinstance(archi.layers[key].func, torch.nn.Conv2d): outs = reduce(lambda x, y: x * y, list(new_shape), 1) ins = reduce(lambda x, y: x * y, list(shape), 1) print(f"Matrix shape is {ins} x {outs}") mat_shapes_for_underopt[key] = (outs, ins) shape = new_shape print(f"New shape is {new_shape}") print("--------") mat_shapes_for_underopt = [ mat_shapes_for_underopt[k] for k in sorted(mat_shapes_for_underopt.keys()) ] print(mat_shapes_for_underopt)
def run_experiment(config: Config): logger.info(f"Starting experiment {config.experiment_id}_{config.run_id}") dataset = Dataset(name=config.dataset) logger.info(f"Getting deep model...") archi: Architecture = get_deep_model( num_epochs=config.epochs, dataset=dataset, architecture=get_architecture(config.architecture), train_noise=config.train_noise, prune_percentile=config.prune_percentile, tot_prune_percentile=config.tot_prune_percentile, first_pruned_iter=config.first_pruned_iter, ) if config.attack_type not in ["FGSM", "PGD"]: all_epsilons = [1.0] elif config.all_epsilons is None: all_epsilons = [0.01, 0.05, 0.1, 0.4, 1.0] # all_epsilons = [0.01] else: all_epsilons = config.all_epsilons ( embeddings_train, embeddings_test, adv_embedding_train, adv_embedding_test, stats, ) = get_feature_datasets(config=config, epsilons=all_epsilons, dataset=dataset, archi=archi) if config.attack_type in ["DeepFool", "CW", AttackType.BOUNDARY]: stats_for_l2_norm_buckets = stats else: stats_for_l2_norm_buckets = dict() evaluation_results = evaluate_embeddings( embeddings_train=list(embeddings_train), embeddings_test=list(embeddings_test), all_adv_embeddings_train=adv_embedding_train, all_adv_embeddings_test=adv_embedding_test, param_space=[{ "gamma": gamma } for gamma in np.logspace(-3, 3, 6)], kernel_type=KernelType.RBF, stats_for_l2_norm_buckets=stats_for_l2_norm_buckets, ) logger.info(evaluation_results) metrics = { "name": "LID", "time": time.time() - start_time, **evaluation_results } logger.info( f"Done with experiment {config.experiment_id}_{config.run_id} !") logger.info(metrics) for method in ["unsupervised", "supervised"]: res = evaluation_results[f"{method}_metrics"] for eps in res: res_eps = res[eps] for metric in res_eps: res_eps_met = res_eps[metric] for typ in res_eps_met: mlflow.log_metric(f"{method}_{eps}_{metric}_{typ}", res_eps_met[typ]) return metrics
def test_get_svhn_model(): source_dataset = Dataset("SVHN") get_deep_model(dataset=source_dataset, num_epochs=1, architecture=svhn_lenet)
def get_all_embeddings(config: Config): detailed_times = dict() architecture = get_architecture(config.architecture) dataset = Dataset.get_or_create(name=config.dataset) layers_to_consider = [ int(v.split(":")[0]) for v in config.thresholds.split("_") ] architecture = get_deep_model( num_epochs=config.epochs, dataset=dataset, architecture=architecture, train_noise=config.train_noise, prune_percentile=config.prune_percentile, tot_prune_percentile=config.tot_prune_percentile, first_pruned_iter=config.first_pruned_iter, layers_to_consider=layers_to_consider, ) if config.sigmoidize: logger.info(f"Using inter-class regularization (sigmoid)") start_time = time.time() quantiles_helpers = get_quantiles_helpers(dataset=dataset, architecture=architecture, dataset_size=100) detailed_times["stats"] = time.time() - start_time else: quantiles_helpers = None thresholds = None if config.threshold_strategy in [ ThresholdStrategy.UnderoptimizedMagnitudeIncrease, ThresholdStrategy.UnderoptimizedLargeFinal, ThresholdStrategy.UnderoptimizedRandom, ]: edges_to_keep = process_thresholds_underopt( raw_thresholds=config.thresholds, architecture=architecture, method=config.threshold_strategy, ) architecture.threshold_layers(edges_to_keep) if config.attack_type not in ["FGSM", "PGD"]: all_epsilons = [1.0] elif config.all_epsilons is None: # all_epsilons = [0.01, 0.05, 0.1, 0.4, 1.0] all_epsilons = [ 0.01, 0.05, 0.1, ] else: all_epsilons = config.all_epsilons start_time = time.time() if config.transfered_attacks: logger.info(f"Generating datasets on the trensferred architecture") trsf_archi = architecture trsf_archi.epochs += 1 # Run the attacks on the external model (to generate the cache) get_protocolar_datasets( noise=config.noise, dataset=dataset, succ_adv=config.successful_adv > 0, archi=trsf_archi, dataset_size=config.dataset_size, attack_type=config.attack_type, attack_backend=config.attack_backend, all_epsilons=all_epsilons, compute_graph=False, transfered_attacks=config.transfered_attacks, ) architecture.epochs = architecture.epochs - 1 logger.info( f"After generating transferred attacks, archi epochs = {architecture.epochs}" ) # Get the protocolar datasets train_clean, test_clean, train_adv, test_adv = get_protocolar_datasets( noise=config.noise, dataset=dataset, succ_adv=config.successful_adv > 0, archi=architecture, dataset_size=config.dataset_size, attack_type=config.attack_type, attack_backend=config.attack_backend, all_epsilons=all_epsilons, compute_graph=False, transfered_attacks=config.transfered_attacks, ) detailed_times["protocolar_datasets"] = time.time() - start_time def chunks(lst, n): """Yield successive n-sized chunks from lst.""" for i in range(0, len(lst), n): yield lst[i:i + n] def embedding_getter(line_chunk) -> List[Embedding]: ret = list() c = 0 for line in line_chunk: ret.append( get_embedding( embedding_type=config.embedding_type, line=line, architecture=architecture, quantiles_helpers_for_sigmoid=quantiles_helpers, )) c += 1 return ret stats_inside_embeddings = dict() def process(input_dataset) -> List: my_chunks = chunks(input_dataset, len(input_dataset) // config.n_jobs) if config.n_jobs > 1: ret = Parallel(n_jobs=config.n_jobs)( delayed(embedding_getter)(chunk) for chunk in my_chunks) else: ret = [embedding_getter(chunk) for chunk in my_chunks] ret = [item for sublist in ret for item in sublist] # Extracting stats for embedding in ret: for key in embedding.time_taken: stats_inside_embeddings[key] = ( stats_inside_embeddings.get(key, 0) + embedding.time_taken[key]) return [embedding.value for embedding in ret] start_time = time.time() # Clean train clean_embeddings_train = process(train_clean) logger.info(f"Clean train dataset " f"({len(clean_embeddings_train)} points) !!") # Clean test clean_embeddings_test = process(test_clean) logger.info(f"Clean test dataset " f"({len(clean_embeddings_test)} points) !!") adv_embeddings_train = dict() adv_embeddings_test = dict() stats = dict() stats_inf = dict() for epsilon in all_epsilons: adv_embeddings_train[epsilon] = process(train_adv[epsilon]) logger.info(f"Adversarial train dataset for espilon = {epsilon}" f" ({len(adv_embeddings_train[epsilon])} points) !") adv_embeddings_test[epsilon] = process(test_adv[epsilon]) logger.info(f"Adversarial test dataset for espilon = {epsilon} " f"({len(adv_embeddings_test[epsilon])} points) !") stats[epsilon] = [line.l2_norm for line in test_adv[epsilon]] stats_inf[epsilon] = [line.linf_norm for line in test_adv[epsilon]] logger.debug(f"Stats for diff btw clean and adv: " f"{np.quantile(stats[epsilon], 0.1)}, " f"{np.quantile(stats[epsilon], 0.25)}, " f"{np.median(stats[epsilon])}, " f"{np.quantile(stats[epsilon], 0.75)}, " f"{np.quantile(stats[epsilon], 0.9)}") if config.embedding_type == EmbeddingType.RawGraph: raw_graph_indices = identify_active_indices(clean_embeddings_train) clean_embeddings_train = featurize_vectors(clean_embeddings_train, raw_graph_indices) clean_embeddings_test = featurize_vectors(clean_embeddings_test, raw_graph_indices) if config.raw_graph_pca > 0: logger.info("Fitting PCA...") pca = PCA( n_components=config.raw_graph_pca, random_state=int(config.experiment_id), ) clean_embeddings_train = pca.fit_transform(clean_embeddings_train) logger.info("Done fitting PCA...") clean_embeddings_test = pca.transform(clean_embeddings_test) for epsilon in all_epsilons: adv_embeddings_train[epsilon] = featurize_vectors( adv_embeddings_train[epsilon], raw_graph_indices) adv_embeddings_test[epsilon] = featurize_vectors( adv_embeddings_test[epsilon], raw_graph_indices) if config.raw_graph_pca > 0: adv_embeddings_train[epsilon] = pca.transform( adv_embeddings_train[epsilon]) adv_embeddings_test[epsilon] = pca.transform( adv_embeddings_test[epsilon]) detailed_times["embeddings"] = time.time() - start_time for key in stats_inside_embeddings: detailed_times[key] = stats_inside_embeddings[key] for key in detailed_times: mlflow.log_metric(f"detailed_time_{key}", detailed_times[key]) return ( clean_embeddings_train, clean_embeddings_test, adv_embeddings_train, adv_embeddings_test, thresholds, stats, stats_inf, detailed_times, )
def run_experiment(config: Config): logger.info(f"Starting experiment {config.experiment_id}_{config.run_id}") dataset = Dataset(name=config.dataset) logger.info(f"Getting deep model...") architecture: Architecture = get_deep_model( num_epochs=config.epochs, dataset=dataset, architecture=get_architecture(config.architecture), train_noise=0.0, prune_percentile=config.prune_percentile, tot_prune_percentile=config.tot_prune_percentile, first_pruned_iter=config.first_pruned_iter, ) ( mean_per_class, precision_root_per_layer, gaussian_accuracy, ) = compute_means_and_sigmas_inv(config=config, dataset=dataset, architecture=architecture) if config.attack_type not in ["FGSM", "PGD"]: all_epsilons = [1.0] elif config.all_epsilons is None: all_epsilons = [0.01, 0.05, 0.1, 0.4, 1.0] # all_epsilons = [0.01] else: all_epsilons = config.all_epsilons ( embeddings_train, embeddings_test, adv_embedding_train, adv_embedding_test, stats, ) = get_feature_datasets( config=config, epsilons=all_epsilons, dataset=dataset, architecture=architecture, mean_per_class=mean_per_class, precision_root_per_layer=precision_root_per_layer, ) if config.attack_type in ["DeepFool", "CW"]: stats_for_l2_norm_buckets = stats else: stats_for_l2_norm_buckets = dict() evaluation_results = evaluate_embeddings( embeddings_train=list(embeddings_train), embeddings_test=list(embeddings_test), all_adv_embeddings_train=adv_embedding_train, all_adv_embeddings_test=adv_embedding_test, param_space=[{ "gamma": gamma } for gamma in np.logspace(-6, 3, 50)], kernel_type=KernelType.RBF, stats_for_l2_norm_buckets=stats_for_l2_norm_buckets, ) logger.info(evaluation_results) metrics = { "name": "Mahalanobis", "time": time.time() - start_time, "gaussian_accuracy": gaussian_accuracy, **evaluation_results, } logger.info(metrics) return metrics
def get_sample_dataset( epsilon: float, noise: float, adv: bool, dataset: Dataset, train: bool, succ_adv: bool, archi: Architecture = mnist_mlp, dataset_size: int = 100, attack_type: str = "FGSM", attack_backend: str = AttackBackend.FOOLBOX, num_iter: int = 10, offset: int = 0, per_class: bool = False, compute_graph: bool = False, transfered_attacks: bool = False, ) -> typing.List[DatasetLine]: logger.info(f"Using source dataset {dataset.name}") logger.info(f"Checking that the received architecture has been trained") assert archi.is_trained logger.info(f"OK ! Architecture is ready") logger.info( f"I am going to generate a dataset of {dataset_size} points...") if adv: logger.info( f"Only successful adversaries ? {'yes' if succ_adv else 'no'}") logger.info(f"Which attack ? {attack_type}") logger.info(f"Which backend ? {attack_backend}") else: logger.info("This dataset will be non-adversarial !") if transfered_attacks: logger.info( f"Loading the architecture to generate adversaries with transferred attacks with {archi.epochs} epochs" ) archi = architecture = get_deep_model( num_epochs=archi.epochs, dataset=dataset, architecture=archi, train_noise=archi.train_noise, ) if archi.epochs % 10 == 0: archi.epochs += 1 list_locals = locals() logger.info(f"locals = {list_locals}") source_dataset_path = get_my_path(list_locals) if os.path.exists(source_dataset_path): source_dataset = torch.load(source_dataset_path) source_dataset_size = len(source_dataset) logger.info( f"Successfully loaded dataset of trsf attacks (len {source_dataset_size})" ) archi.epochs -= 1 current_sample_id = 0 else: source_dataset = (dataset.train_dataset if train else dataset.test_and_val_dataset) source_dataset_size = len(source_dataset) current_sample_id = offset else: source_dataset = (dataset.train_dataset if train else dataset.test_and_val_dataset) source_dataset_size = len(source_dataset) current_sample_id = offset final_dataset = list() if dataset.name in ["tinyimagenet"]: per_class_nb_samples = np.repeat(0, 200) elif dataset.name in ["cifar100"]: per_class_nb_samples = np.repeat(0, 100) else: per_class_nb_samples = np.repeat(0, 10) #current_sample_id = offset dataset_done = False batch_size = 32 while not dataset_done and current_sample_id < source_dataset_size: samples = None processed_samples = None y_pred = None while processed_samples is None and current_sample_id < source_dataset_size: if False: #transfered_attacks: samples = ( source_dataset["x"][current_sample_id:current_sample_id + batch_size], source_dataset["y"][current_sample_id:current_sample_id + batch_size], ) if adv: processed_samples = ( source_dataset["x_adv"] [current_sample_id:current_sample_id + batch_size], source_dataset["y"] [current_sample_id:current_sample_id + batch_size], ) else: processed_samples = samples else: # Fetching a batch of samples and concatenating them batch = source_dataset[current_sample_id:current_sample_id + batch_size] if isinstance(batch[0], DatasetLine): x = torch.cat([torch.unsqueeze(s.x, 0) for s in batch], 0).to(device) y = np.array([s.y for s in batch]) logger.info(f"shape of x = {x.shape}") else: x = torch.cat([torch.unsqueeze(s[0], 0) for s in batch], 0).to(device) y = np.array([s[1] for s in batch]) samples = (x, y) # Calling process_sample on the batch # TODO: Ensure process_sample handles batched examples processed_samples = process_sample( sample=samples, adversarial=adv, noise=noise, epsilon=epsilon, model=archi, attack_type=attack_type, num_iter=num_iter, attack_backend=attack_backend, ) # Increasing current_sample_id current_sample_id += batch_size assert (samples[1] == processed_samples[1]).all() y_pred = archi(processed_samples[0]).argmax(dim=-1).cpu().numpy() if adv and succ_adv: # Check where the attack was successful valid_attacks = np.where(samples[1] != y_pred)[0] logger.debug( f"Attack succeeded on {len(valid_attacks)} points over {len(samples[1])}" ) if len(valid_attacks) == 0: processed_samples = None else: processed_samples = ( processed_samples[0][valid_attacks], processed_samples[1][valid_attacks], ) samples = ( samples[0][valid_attacks], samples[1][valid_attacks], ) # If the while loop did not return any samples, let's stop here if processed_samples is None: break # Compute the norms on the batch l2_norms = (torch.norm( (processed_samples[0].double() - samples[0].double()).flatten(1), p=2, dim=1, ).cpu().detach().numpy()) linf_norms = (torch.norm( (processed_samples[0].double() - samples[0].double()).flatten(1), p=float("inf"), dim=1, ).cpu().detach().numpy()) # Update the counter per class for clazz in processed_samples[1]: per_class_nb_samples[clazz] += 1 # Unbatching and return DatasetLine # TODO: see if we can avoid unbatching for i in range(len(processed_samples[1])): x = torch.unsqueeze(processed_samples[0][i], 0).double() # (OPT) Compute the graph graph = (Graph.from_architecture_and_data_point( architecture=archi, x=x) if compute_graph else None) # Add the line to the dataset final_dataset.append( DatasetLine( graph=graph, x=x, y=processed_samples[1][i], y_pred=y_pred[i], y_adv=adv, l2_norm=l2_norms[i], linf_norm=linf_norms[i], sample_id=current_sample_id, )) # Are we done yet ? if not per_class: # We are done if we have enough points in the dataset dataset_done = len(final_dataset) >= dataset_size else: # We are done if all classes have enough points dataset_done = all( np.asarray(per_class_nb_samples) >= dataset_size) if dataset_done: break logger.info(f"Compputed {len(final_dataset)}/{dataset_size} samples.") if len(final_dataset) < dataset_size: logger.warn( f"I was only able to generate {len(final_dataset)} points even if {dataset_size} was requested. " f"This is probably a lack of adversarial points.") return final_dataset