예제 #1
0
def read_datasets(dataset_dir, output_dir, log_dir):
    for domain in ['mnist', 'cifar10']:
        for architecture in ['a', 'b', 'c']:
            for test_type in ['standard', 'adversarial', 'relu']:
                final_dataset_path = Path(
                    output_dir) / f'{domain}-{architecture}-{test_type}.zip'

                if not final_dataset_path.exists():
                    results_dir = Path(
                        dataset_dir) / test_type / f'{domain}-{architecture}'
                    print('Checking', results_dir)

                    final_dataset = MergedComparisonDataset()

                    for dataset_path in results_dir.iterdir():
                        dataset_path = dataset_path.with_suffix('.zip')
                        dataset = utils.load_zip(dataset_path)

                        stem = dataset_path.stem

                        log_path = Path(
                            log_dir
                        ) / test_type / f'{domain}-{architecture}' / stem / 'compare.log'
                        if log_path.exists():
                            with open(log_path, 'r') as f:
                                log = f.readlines()
                        else:
                            log = None

                        add_dataset(final_dataset, dataset, log)

                    final_dataset_path.parent.mkdir(parents=True,
                                                    exist_ok=True)

                    utils.save_zip(final_dataset, final_dataset_path)
예제 #2
0
def attack(**kwargs):
    parsing.set_log_level(kwargs['log_level'])

    if kwargs['deterministic']:
        if kwargs['seed'] is None:
            logger.warning('Determinism is enabled, but no seed has been provided.')

        utils.enable_determinism()

    logger.debug('Running attack command with kwargs %s.', kwargs)

    if kwargs['cpu_threads'] is not None:
        torch.set_num_threads(kwargs['cpu_threads'])

    if kwargs['seed'] is not None:
        utils.set_seed(kwargs['seed'])

    model = parsing.parse_model(kwargs['domain'], kwargs['architecture'],
                              kwargs['state_dict_path'], False, kwargs['masked_relu'], False, load_weights=True)
    model.eval()
    model.to(kwargs['device'])

    dataset = parsing.parse_dataset(kwargs['domain'], kwargs['dataset'],
                                    dataset_edges=(kwargs['start'], kwargs['stop']))
    dataloader = torch.utils.data.DataLoader(
        dataset, kwargs['batch_size'], shuffle=False)

    attack_config = utils.read_attack_config_file(kwargs['attack_config_file'])

    attack_pool = parsing.parse_attack_pool(
        kwargs['attacks'], kwargs['domain'], kwargs['p'], kwargs['attack_type'], model, attack_config, kwargs['device'], seed=kwargs['seed'])

    p = kwargs['p']

    if kwargs['blind_trust']:
        logger.warning(
            'Blind trust is activated. This means that the success of the attack will NOT be checked.')

    adversarial_dataset = tests.attack_test(model, attack_pool, dataloader, p, kwargs['misclassification_policy'],
                                            kwargs['device'], attack_config, kwargs, dataset.start, dataset.stop,
                                            None, blind_trust=kwargs['blind_trust'])
    adversarial_dataset.print_stats()

    if kwargs['save_to'] is not None:
        utils.save_zip(adversarial_dataset, kwargs['save_to'])

    if kwargs['show'] is not None:
        utils.show_images(adversarial_dataset.genuines,
                          adversarial_dataset.adversarials, limit=kwargs['show'], model=model)
예제 #3
0
def read_datasets():
    for domain in ['mnist', 'cifar10']:
        for architecture in ['a', 'b', 'c']:
            for test_type in ['standard', 'adversarial', 'relu']:
                final_dataset_path = Path(
                    'final') / f'{domain}-{architecture}-{test_type}.zip'

                if not final_dataset_path.exists():
                    results_dir = Path(
                        'mip_results') / test_type / f'{domain}-{architecture}'
                    print('Checking', results_dir)

                    final_dataset = MergedDataset()

                    for dataset_path in results_dir.iterdir():
                        dataset_path = dataset_path.with_suffix('.zip')
                        dataset = utils.load_zip(dataset_path)

                        stem = dataset_path.stem

                        memory_log_path = Path(
                            'logs'
                        ) / test_type / f'{domain}-{architecture}' / stem / 'mip_memory.dat'
                        if memory_log_path.exists():
                            with open(memory_log_path, 'r') as f:
                                memory_log = f.readlines()
                            memory_log = parse_memory_log(memory_log)
                        else:
                            memory_log = None

                        add_dataset(final_dataset, dataset, memory_log)

                    final_dataset_path.parent.mkdir(parents=True,
                                                    exist_ok=True)

                    utils.save_zip(final_dataset, final_dataset_path)
예제 #4
0
def evasion(**kwargs):
    parsing.set_log_level(kwargs['log_level'])

    if kwargs['deterministic']:
        if kwargs['seed'] is None:
            logger.warning(
                'Determinism is enabled, but no seed has been provided.')

        utils.enable_determinism()

    if kwargs['cpu_threads'] is not None:
        torch.set_num_threads(kwargs['cpu_threads'])

    if kwargs['seed'] is not None:
        utils.set_seed(kwargs['seed'])

    model = parsing.parse_model(kwargs['domain'],
                                kwargs['architecture'],
                                kwargs['state_dict_path'],
                                False,
                                kwargs['masked_relu'],
                                False,
                                load_weights=True)
    model.eval()
    model.to(kwargs['device'])

    dataset = parsing.parse_dataset(kwargs['domain'],
                                    kwargs['dataset'],
                                    dataset_edges=(kwargs['start'],
                                                   kwargs['stop']))
    dataloader = torch.utils.data.DataLoader(dataset,
                                             kwargs['batch_size'],
                                             shuffle=False)

    attack_config = utils.read_attack_config_file(kwargs['attack_config_file'])

    p = kwargs['p']

    counter_attack_names = kwargs['counter_attacks']
    substitute_state_dict_paths = kwargs['substitute_state_dict_paths']

    if kwargs['rejection_threshold'] >= 0:
        logger.warning(
            'Received a positive rejection threshold. Since Counter-Attack only outputs nonpositive values, '
            'the detector will never reject an example.')

    if len(substitute_state_dict_paths) != len(counter_attack_names):
        raise click.BadArgumentUsage(
            'substitute_state_dict_paths must be as many values as the number of counter attacks.'
        )

    detector = parsing.parse_detector_pool(
        counter_attack_names,
        kwargs['domain'],
        kwargs['p'],
        'defense',
        model,
        attack_config,
        kwargs['device'],
        use_substitute=True,
        substitute_state_dict_paths=substitute_state_dict_paths)

    defended_model = detectors.NormalisedDetectorModel(
        model, detector, kwargs['rejection_threshold'])

    # TODO: I parametri sono sbagliati
    evasion_pool = parsing.parse_attack_pool(kwargs['evasion_attacks'],
                                             kwargs['domain'],
                                             kwargs['p'],
                                             'evasion',
                                             model,
                                             attack_config,
                                             kwargs['device'],
                                             defended_model=defended_model,
                                             seed=kwargs['seed'])

    adversarial_dataset = tests.attack_test(model, evasion_pool, dataloader, p,
                                            kwargs['misclassification_policy'],
                                            kwargs['device'], attack_config,
                                            dataset.start, dataset.stop,
                                            kwargs, defended_model)
    adversarial_dataset.print_stats()

    if kwargs['save_to'] is not None:
        utils.save_zip(adversarial_dataset, kwargs['save_to'])

    if kwargs['show'] is not None:
        utils.show_images(adversarial_dataset.genuines,
                          adversarial_dataset.adversarials,
                          limit=kwargs['show'],
                          model=model)
예제 #5
0
def compare(**kwargs):
    parsing.set_log_level(kwargs['log_level'])

    if kwargs['deterministic']:
        if kwargs['seed'] is None:
            logger.warning(
                'Determinism is enabled, but no seed has been provided.')

        utils.enable_determinism()

    if kwargs['cpu_threads'] is not None:
        torch.set_num_threads(kwargs['cpu_threads'])

    if kwargs['seed'] is not None:
        utils.set_seed(kwargs['seed'])

    model = parsing.parse_model(kwargs['domain'],
                                kwargs['architecture'],
                                kwargs['state_dict_path'],
                                False,
                                kwargs['masked_relu'],
                                False,
                                load_weights=True)
    model.eval()

    if kwargs['indices_path'] is None:
        indices_override = None
    else:
        with open(kwargs['indices_path']) as f:
            indices_override = json.load(f)

    dataset = parsing.parse_dataset(kwargs['domain'],
                                    kwargs['dataset'],
                                    dataset_edges=(kwargs['start'],
                                                   kwargs['stop']),
                                    indices_override=indices_override)
    dataloader = torch.utils.data.DataLoader(dataset,
                                             kwargs['batch_size'],
                                             shuffle=False)

    attack_config = utils.read_attack_config_file(kwargs['attack_config_file'])

    p = kwargs['p']
    device = kwargs['device']

    attack_names = kwargs['attacks']
    attacks = []

    for attack_name in attack_names:
        attack = parsing.parse_attack(attack_name,
                                      kwargs['domain'],
                                      p,
                                      'standard',
                                      model,
                                      attack_config,
                                      device,
                                      seed=kwargs['seed'])
        attacks.append(attack)

    if kwargs['indices_path'] is None:
        start = kwargs['start']
        stop = kwargs['stop']
    else:
        start = None
        stop = None

    result_dataset = tests.multiple_attack_test(
        model,
        attack_names,
        attacks,
        dataloader,
        p,
        kwargs['misclassification_policy'],
        device,
        attack_config,
        start,
        stop,
        kwargs,
        indices_override=indices_override)

    if not kwargs['no_stats']:
        result_dataset.print_stats()

    if kwargs['show'] is not None:
        print()
        print('Showing top results.')
        best_results = result_dataset.simulate_pooling(attack_names)

        utils.show_images(best_results.genuines,
                          best_results.adversarials,
                          limit=kwargs['show'],
                          model=model)

        for attack_name in attack_names:
            print(f'Showing results for {attack_name}.')

            attack_results = result_dataset.simulate_pooling([attack_name])

            utils.show_images(attack_results.genuines,
                              attack_results.adversarials,
                              limit=kwargs['show'],
                              model=model)

    if kwargs['save_to'] is not None:
        utils.save_zip(result_dataset, kwargs['save_to'])
예제 #6
0
def mip(**kwargs):
    command_start_timestamp = time.time()

    parsing.set_log_level(kwargs['log_level'])

    if kwargs['deterministic']:
        logger.warning('Determinism is not guaranteed for Gurobi.')

        if kwargs['seed'] is None:
            logger.warning(
                'Determinism is enabled, but no seed has been provided.')

        utils.enable_determinism()

    if kwargs['cpu_threads'] is not None:
        torch.set_num_threads(kwargs['cpu_threads'])

    seed = kwargs['seed']

    if seed is not None:
        utils.set_seed(kwargs['seed'])

    torch_model_retrieval_start_timestamp = time.time()

    model = parsing.parse_model(kwargs['domain'],
                                kwargs['architecture'],
                                kwargs['state_dict_path'],
                                False,
                                kwargs['masked_relu'],
                                False,
                                load_weights=True)
    model.eval()

    dataset_retrieval_start_timestamp = torch_model_retrieval_end_timestamp = time.time(
    )

    dataset = parsing.parse_dataset(kwargs['domain'],
                                    kwargs['dataset'],
                                    dataset_edges=(kwargs['start'],
                                                   kwargs['stop']))

    dataset_retrieval_end_timestamp = time.time()

    dataloader = torch.utils.data.DataLoader(dataset,
                                             kwargs['batch_size'],
                                             shuffle=False)

    if kwargs['pre_adversarial_dataset'] is None:
        pre_adversarial_dataset = None
    else:
        pre_adversarial_dataset = utils.load_zip(
            kwargs['pre_adversarial_dataset'])

        if isinstance(pre_adversarial_dataset,
                      adversarial_dataset.AttackComparisonDataset):
            # Use the best results to compute an adversarial dataset
            pre_adversarial_dataset = pre_adversarial_dataset.to_adversarial_dataset(
                pre_adversarial_dataset.attack_names)

    p = kwargs['p']

    if p == 2:
        metric = 'l2'
    elif np.isposinf(p):
        metric = 'linf'
    else:
        raise NotImplementedError(f'Unsupported metric "l{p}"')

    attack_config = utils.read_attack_config_file(kwargs['attack_config_file'])
    attack_kwargs = attack_config.get_arguments('mip', kwargs['domain'],
                                                metric, 'standard')

    attack_creation_start_timestamp = time.time()
    attack = attacks.MIPAttack(model, p, False, seed=seed, **attack_kwargs)
    attack_creation_end_timestamp = time.time()

    mip_dataset = tests.mip_test(
        model,
        attack,
        dataloader,
        p,
        kwargs['misclassification_policy'],
        kwargs['device'],
        attack_config,
        kwargs,
        start=dataset.start,
        stop=dataset.stop,
        pre_adversarial_dataset=pre_adversarial_dataset,
        gurobi_log_dir=kwargs['gurobi_log_dir'])

    mip_dataset.print_stats()

    command_end_timestamp = time.time()

    mip_dataset.global_extra_info['times']['command'] = {
        'start_timestamp': command_start_timestamp,
        'end_timestamp': command_end_timestamp
    }
    mip_dataset.global_extra_info['times']['torch_model_retrieval'] = {
        'start_timestamp': torch_model_retrieval_start_timestamp,
        'end_timestamp': torch_model_retrieval_end_timestamp
    }
    mip_dataset.global_extra_info['times']['dataset_retrieval'] = {
        'start_timestamp': dataset_retrieval_start_timestamp,
        'end_timestamp': dataset_retrieval_end_timestamp
    }
    mip_dataset.global_extra_info['times']['attack_creation'] = {
        'start_timestamp': attack_creation_start_timestamp,
        'end_timestamp': attack_creation_end_timestamp
    }

    if kwargs['save_to'] is not None:
        utils.save_zip(mip_dataset, kwargs['save_to'])

    if kwargs['show'] is not None:
        utils.show_images(mip_dataset.genuines,
                          mip_dataset.adversarials,
                          limit=kwargs['show'],
                          model=model)
예제 #7
0
def cross_validation(**kwargs):
    parsing.set_log_level(kwargs['log_level'])

    if kwargs['deterministic']:
        if kwargs['seed'] is None:
            logger.warning(
                'Determinism is enabled, but no seed has been provided.')

        utils.enable_determinism()

    if kwargs['cpu_threads'] is not None:
        torch.set_num_threads(kwargs['cpu_threads'])

    if kwargs['seed'] is not None:
        utils.set_seed(kwargs['seed'])

    model = parsing.parse_model(kwargs['domain'],
                                kwargs['architecture'],
                                kwargs['state_dict_path'],
                                False,
                                kwargs['masked_relu'],
                                False,
                                load_weights=True)
    model.eval()
    model.to(kwargs['device'])

    dataset = parsing.parse_dataset(kwargs['domain'],
                                    kwargs['dataset'],
                                    dataset_edges=(kwargs['start'],
                                                   kwargs['stop']))
    dataloader = torch.utils.data.DataLoader(dataset,
                                             kwargs['batch_size'],
                                             shuffle=False)

    attack_config = utils.read_attack_config_file(kwargs['attack_config_file'])
    p = kwargs['p']

    attack_names = kwargs['attacks']
    rejection_thresholds = kwargs['rejection_thresholds']
    substitute_state_dict_paths = kwargs['substitute_state_dict_paths']

    if len(attack_names) < 2:
        raise click.BadArgumentUsage('attacks must be at least two.')

    if len(rejection_thresholds) == 1:
        rejection_thresholds = len(attack_names) * [rejection_thresholds[0]]

    if len(rejection_thresholds) != len(attack_names):
        raise click.BadArgumentUsage(
            'rejection_thresholds must be either one value or as many values as the number of attacks.'
        )

    if len(substitute_state_dict_paths) != len(attack_names):
        raise click.BadArgumentUsage(
            'substitute_state_dict_paths must be as many values as the number of attacks.'
        )

    if any(rejection_threshold > 0
           for rejection_threshold in rejection_thresholds):
        logger.warning(
            'Received a positive rejection threshold. Since Counter-Attack only outputs nonpositive values, '
            'the detector will never reject an example.')

    test_names = []
    evasion_attacks = []
    defended_models = []

    for i in range(len(attack_names)):
        # Remove one attack from the pool. This attack will act as the evasion attack

        evasion_attack_name = attack_names[i]
        counter_attack_names = [
            x for j, x in enumerate(attack_names) if j != i
        ]

        ca_substitute_state_dict_paths = [
            x for j, x in enumerate(substitute_state_dict_paths) if j != i
        ]

        rejection_threshold = rejection_thresholds[i]

        detector = parsing.parse_detector_pool(
            counter_attack_names,
            kwargs['domain'],
            kwargs['p'],
            'standard',
            model,
            attack_config,
            kwargs['device'],
            use_substitute=True,
            substitute_state_dict_paths=ca_substitute_state_dict_paths)

        defended_model = detectors.NormalisedDetectorModel(
            model, detector, rejection_threshold)

        evasion_attack = parsing.parse_attack(evasion_attack_name,
                                              kwargs['domain'],
                                              kwargs['p'],
                                              'evasion',
                                              model,
                                              attack_config,
                                              kwargs['device'],
                                              defended_model=defended_model,
                                              seed=kwargs['seed'])

        test_name = f'{evasion_attack_name} vs {counter_attack_names}'

        test_names.append(test_name)
        evasion_attacks.append(evasion_attack)
        defended_models.append(defended_model)

    logger.info('Tests:\n{}'.format('\n'.join(test_names)))

    evasion_dataset = tests.multiple_evasion_test(
        model, test_names, evasion_attacks, defended_models, dataloader, p,
        kwargs['misclassification_policy'], kwargs['device'], attack_config,
        dataset.start, dataset.stop, kwargs)

    if kwargs['save_to'] is not None:
        utils.save_zip(evasion_dataset, kwargs['save_to'])

    for test_name in test_names:
        print(f'Test "{test_name}":')
        adversarial_dataset = evasion_dataset.to_adversarial_dataset(test_name)
        adversarial_dataset.print_stats()

        if kwargs['show'] is not None:
            utils.show_images(adversarial_dataset.genuines,
                              adversarial_dataset.adversarials,
                              limit=kwargs['show'],
                              model=model)
예제 #8
0
def distance_dataset(**kwargs):
    parsing.set_log_level(kwargs['log_level'])

    if kwargs['deterministic']:
        if kwargs['seed'] is None:
            logger.warning(
                'Determinism is enabled, but no seed has been provided.')

        utils.enable_determinism()

    if kwargs['cpu_threads'] is not None:
        torch.set_num_threads(kwargs['cpu_threads'])

    if kwargs['seed'] is not None:
        utils.set_seed(kwargs['seed'])

    model = parsing.parse_model(kwargs['domain'],
                                kwargs['architecture'],
                                kwargs['state_dict_path'],
                                False,
                                kwargs['masked_relu'],
                                False,
                                load_weights=True)
    model.eval()
    model.to(kwargs['device'])

    attack_config = utils.read_attack_config_file(kwargs['attack_config_file'])

    attack_pool = parsing.parse_attack_pool(kwargs['attacks'],
                                            kwargs['domain'],
                                            kwargs['p'],
                                            'standard',
                                            model,
                                            attack_config,
                                            kwargs['device'],
                                            seed=kwargs['seed'])

    p = kwargs['p']

    if kwargs['from_genuine'] is None and kwargs['from_adversarial'] is None:
        raise RuntimeError(
            'At least one among --from-genuine and --from-adversarial must be provided.'
        )

    images = []
    distances = []

    if kwargs['from_genuine'] is not None:
        genuine_dataset = parsing.parse_dataset(kwargs['domain'],
                                                kwargs['from_genuine'],
                                                dataset_edges=(kwargs['start'],
                                                               kwargs['stop']))
        genuine_loader = torch.utils.data.DataLoader(genuine_dataset,
                                                     kwargs['batch_size'],
                                                     shuffle=False)
        # TODO: I parametri sono tutti sbagliati
        genuine_result_dataset = tests.attack_test(
            model, attack_pool, genuine_loader, p,
            kwargs['misclassification_policy'], kwargs['device'],
            attack_config, genuine_dataset.start, genuine_dataset.stop, kwargs,
            None)

        images += list(genuine_result_dataset.genuines)
        distances += list(genuine_result_dataset.distances)

    if kwargs['from_adversarial'] is not None:
        adversarial_dataset = parsing.parse_dataset(
            kwargs['domain'],
            kwargs['from_adversarial'],
            allow_standard=False,
            dataset_edges=(kwargs['start'], kwargs['stop']))

        adv_start, adv_stop = adversarial_dataset.start, adversarial_dataset.stop
        # Get the labels for the adversarial samples
        adversarial_dataset = utils.create_label_dataset(
            model, adversarial_dataset.adversarials, kwargs['batch_size'])

        adversarial_loader = torch.utils.data.DataLoader(adversarial_dataset,
                                                         kwargs['batch_size'],
                                                         shuffle=False)
        # TODO: I parametri sono sbagliati
        adversarial_result_dataset = tests.attack_test(
            model, attack_pool, adversarial_loader, p, False, kwargs['device'],
            attack_config, adv_start, adv_stop, kwargs, None)

        images += list(adversarial_result_dataset.genuines)
        distances += list(adversarial_result_dataset.distances)

    images = torch.stack(images)
    distances = torch.stack(distances)

    final_dataset = ad.AdversarialDistanceDataset(images, distances)

    utils.save_zip(final_dataset, kwargs['save_to'])