def run_batch_with_goal(sess, model, x, y, adv_x_val, criteria, attack_configs, run_counts, goal, report, report_path, attack_batch_size=BATCH_SIZE): """ Runs attack bundling on one batch of data. This function is mostly intended to be called by `bundle_attacks_with_goal`. :param sess: tf.session.Session :param model: cleverhans.model.Model :param x: numpy array containing clean example inputs to attack :param y: numpy array containing true labels :param adv_x_val: numpy array containing the adversarial examples made so far by earlier work in the bundling process :param criteria: dict mapping string names of criteria to numpy arrays with their values for each example (Different AttackGoals track different criteria) :param run_counts: dict mapping AttackConfigs to numpy arrays reporting how many times they have been run on each example :param goal: the AttackGoal to work on :param report: dict, see `bundle_attacks_with_goal` :param report_path: str, path to save the report to """ attack_config = goal.get_attack_config(attack_configs, run_counts, criteria) idxs = goal.request_examples(attack_config, criteria, run_counts, attack_batch_size) x_batch = x[idxs] assert x_batch.shape[0] == attack_batch_size y_batch = y[idxs] assert y_batch.shape[0] == attack_batch_size adv_x_batch = run_attack(sess, model, x_batch, y_batch, attack_config.attack, attack_config.params, attack_batch_size, devices, pass_y=attack_config.pass_y) criteria_batch = goal.get_criteria(sess, model, adv_x_batch, y_batch, batch_size=min(attack_batch_size, BATCH_SIZE)) # This can't be parallelized because some orig examples are copied more # than once into the batch cur_run_counts = run_counts[attack_config] for batch_idx, orig_idx in enumerate(idxs): cur_run_counts[orig_idx] += 1 should_copy = goal.new_wins(criteria, orig_idx, criteria_batch, batch_idx) if should_copy: adv_x_val[orig_idx] = adv_x_batch[batch_idx] for key in criteria: criteria[key][orig_idx] = criteria_batch[key][batch_idx] assert np.allclose(y[orig_idx], y_batch[batch_idx]) report['bundled'] = ConfidenceReportEntry(criteria['correctness'], criteria['confidence']) should_save = False new_time = time.time() if hasattr(report, 'time'): if new_time - report.time > REPORT_TIME_INTERVAL: should_save = True else: should_save = True if should_save: report.time = new_time goal.print_progress(criteria, run_counts) save(criteria, report, report_path, adv_x_val)
def test_save_load_confidence_report(): """ Test that a confidence report can be loaded and saved. """ report = ConfidenceReport() num_examples = 2 clean_correctness = np.zeros((num_examples,), dtype=np.bool) clean_confidence = np.zeros((num_examples,), dtype=np.float32) adv_correctness = clean_correctness.copy() adv_confidence = clean_confidence.copy() report['clean'] = ConfidenceReportEntry(clean_correctness, clean_confidence) report['adv'] = ConfidenceReportEntry(adv_correctness, adv_confidence) report.completed = True filepath = ".test_confidence_report.joblib" serial.save(filepath, report) report = serial.load(filepath)
def test_confidence_report(): # Test that we can make a confidence report, put an entry in it, and get # that entry back out report = ConfidenceReport() entry = ConfidenceReportEntry(correctness=np.array([True, False]), confidence=np.array([0.9, 0.1])) report['clean'] = entry assert report['clean'] is entry
def bundle_attacks(sess, model, x, y, attack_configs, goals, report_path, attack_batch_size=BATCH_SIZE, eval_batch_size=BATCH_SIZE): """ Runs attack bundling. Users of cleverhans may call this function but are more likely to call one of the recipes above. Reference: https://openreview.net/forum?id=H1g0piA9tQ :param sess: tf.session.Session :param model: cleverhans.model.Model :param x: numpy array containing clean example inputs to attack :param y: numpy array containing true labels :param attack_configs: list of AttackConfigs to run :param goals: list of AttackGoals to run The bundler works through the goals in order, until each is satisfied. Some goals may never be satisfied, in which case the bundler will run forever, updating the report on disk as it goes. :param report_path: str, the path the report will be saved to :param attack_batch_size: int, batch size for generating adversarial examples :param eval_batch_size: int, batch size for evaluating the model on clean / adversarial examples :returns: adv_x: The adversarial examples, in the same format as `x` run_counts: dict mapping each AttackConfig to a numpy array reporting how many times that AttackConfig was run on each example """ assert isinstance(sess, tf.Session) assert isinstance(model, Model) assert all(isinstance(attack_config, AttackConfig) for attack_config in attack_configs) assert all(isinstance(goal, AttackGoal) for goal in goals) assert isinstance(report_path, six.string_types) if x.shape[0] != y.shape[0]: raise ValueError("Number of input examples does not match number of labels") # Note: no need to precompile attacks, correctness_and_confidence # caches them run_counts = {} for attack_config in attack_configs: run_counts[attack_config] = np.zeros(x.shape[0], dtype=np.int64) # TODO: make an interface to pass this in if it has already been computed # elsewhere _logger.info("Running on clean data to initialize the report...") packed = correctness_and_confidence(sess, model, x, y, batch_size=eval_batch_size, devices=devices) _logger.info("...done") correctness, confidence = packed _logger.info("Accuracy: " + str(correctness.mean())) report = ConfidenceReport() report['clean'] = ConfidenceReportEntry(correctness, confidence) adv_x = x.copy() for goal in goals: bundle_attacks_with_goal(sess, model, x, y, adv_x, attack_configs, run_counts, goal, report, report_path, attack_batch_size=attack_batch_size, eval_batch_size=eval_batch_size) # Many users will set `goals` to make this run forever, so the return # statement is not the primary way to get information out. return adv_x, run_counts
def bundle_examples_with_goal(sess, model, adv_x_list, y, goal, report_path): """ A post-processor version of attack bundling, that chooses the strongest example from the output of multiple earlier bundling strategies. :param sess: tf.session.Session :param model: cleverhans.model.Model :param adv_x_list: list of numpy arrays Each entry in the list is the output of a previous bundler; it is an adversarial version of the whole dataset. :param y: numpy array containing true labels :param goal: AttackGoal to use to choose the best version of each adversarial example :param report_path: str, the path the report will be saved to """ # Check the input num_attacks = len(adv_x_list) assert num_attacks > 0 adv_x_0 = adv_x_list[0] assert isinstance(adv_x_0, np.ndarray) assert all(adv_x.shape == adv_x_0.shape for adv_x in adv_x_list) # Allocate the output out = np.zeros_like(adv_x_0) m = adv_x_0.shape[0] # Initialize with negative sentinel values to make sure everything is # written to correctness = -np.ones(m, dtype='int32') confidence = -np.ones(m, dtype='float32') # Gather criteria criteria = [goal.get_criteria(sess, model, adv_x, y) for adv_x in adv_x_list] assert all('correctness' in c for c in criteria) assert all('confidence' in c for c in criteria) _logger.info("Accuracy on each advx dataset: ") for c in criteria: _logger.info("\t" + str(c['correctness'].mean())) for example_idx in range(m): # Index of the best attack for this example attack_idx = 0 # Find the winner for candidate_idx in range(1, num_attacks): if goal.new_wins(criteria[attack_idx], example_idx, criteria[candidate_idx], example_idx): attack_idx = candidate_idx # Copy the winner into the output out[example_idx] = adv_x_list[attack_idx][example_idx] correctness[example_idx] = criteria[attack_idx]['correctness'][example_idx] confidence[example_idx] = criteria[attack_idx]['confidence'][example_idx] assert correctness.min() >= 0 assert correctness.max() <= 1 assert confidence.min() >= 0. assert confidence.max() <= 1. report = ConfidenceReport() report['bundled'] = ConfidenceReportEntry(correctness, confidence) serial.save(report_path, report) assert report_path.endswith('.joblib') adv_x_path = report_path[:-len('.joblib')] + "_adv_x.npy" np.save(adv_x_path, out)