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
예제 #3
0
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)
예제 #4
0
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
예제 #6
0
def test_get_svhn_model():
    source_dataset = Dataset("SVHN")
    get_deep_model(dataset=source_dataset,
                   num_epochs=1,
                   architecture=svhn_lenet)
예제 #7
0
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,
    )
예제 #8
0
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
예제 #9
0
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