def run_membership_probability_analysis( attack_input: AttackInputData, slicing_spec: SlicingSpec = None) -> MembershipProbabilityResults: """Perform membership probability analysis on all given slice types. Args: attack_input: input data for compute membership probabilities slicing_spec: specifies attack_input slices Returns: the membership probability results. """ attack_input.validate() membership_prob_results = [] if slicing_spec is None: slicing_spec = SlicingSpec(entire_dataset=True) num_classes = None if slicing_spec.by_class: num_classes = attack_input.num_classes input_slice_specs = get_single_slice_specs(slicing_spec, num_classes) for single_slice_spec in input_slice_specs: attack_input_slice = get_slice(attack_input, single_slice_spec) membership_prob_results.append( _compute_membership_probability(attack_input_slice)) return MembershipProbabilityResults( membership_prob_results=membership_prob_results)
def test_slice_by_correcness(self): input_data = SlicingSpec(entire_dataset=False, by_classification_correctness=True) expected = SingleSliceSpec(SlicingFeature.CORRECTLY_CLASSIFIED, True) output = get_single_slice_specs(input_data) self.assertLen(output, 2) self.assertTrue(_are_all_fields_equal(output[0], expected))
def test_slice_by_percentiles(self): input_data = SlicingSpec(entire_dataset=False, by_percentiles=True) expected0 = SingleSliceSpec(SlicingFeature.PERCENTILE, (0, 10)) expected5 = SingleSliceSpec(SlicingFeature.PERCENTILE, (50, 60)) output = get_single_slice_specs(input_data) self.assertLen(output, 10) self.assertTrue(_are_all_fields_equal(output[0], expected0)) self.assertTrue(_are_all_fields_equal(output[5], expected5))
def test_slice_by_classes(self): input_data = SlicingSpec(by_class=True) n_classes = 5 expected = [self.ENTIRE_DATASET_SLICE] + [ SingleSliceSpec(SlicingFeature.CLASS, c) for c in range(n_classes) ] output = get_single_slice_specs(input_data, n_classes) self.assertTrue(_are_lists_equal(output, expected))
def test_slicing_by_multiple_features(self): input_data = SlicingSpec(entire_dataset=True, by_class=True, by_percentiles=True, by_classification_correctness=True) n_classes = 10 expected_slices = n_classes expected_slices += 1 # entire dataset slice expected_slices += 10 # percentiles slices expected_slices += 2 # correcness classification slices output = get_single_slice_specs(input_data, n_classes) self.assertLen(output, expected_slices)
def run_attacks(attack_input: AttackInputData, slicing_spec: SlicingSpec = None, attack_types: Iterable[AttackType] = ( AttackType.THRESHOLD_ATTACK, ), privacy_report_metadata: PrivacyReportMetadata = None, balance_attacker_training: bool = True, min_num_samples: int = 1) -> AttackResults: """Runs membership inference attacks on a classification model. It runs attacks specified by attack_types on each attack_input slice which is specified by slicing_spec. Args: attack_input: input data for running an attack slicing_spec: specifies attack_input slices to run attack on attack_types: attacks to run privacy_report_metadata: the metadata of the model under attack. balance_attacker_training: Whether the training and test sets for the membership inference attacker should have a balanced (roughly equal) number of samples from the training and test sets used to develop the model under attack. min_num_samples: minimum number of examples in either training or test data. Returns: the attack result. """ attack_input.validate() attack_results = [] if slicing_spec is None: slicing_spec = SlicingSpec(entire_dataset=True) num_classes = None if slicing_spec.by_class: num_classes = attack_input.num_classes input_slice_specs = get_single_slice_specs(slicing_spec, num_classes) for single_slice_spec in input_slice_specs: attack_input_slice = get_slice(attack_input, single_slice_spec) for attack_type in attack_types: attack_result = _run_attack(attack_input_slice, attack_type, balance_attacker_training, min_num_samples) if attack_result is not None: attack_results.append(attack_result) privacy_report_metadata = _compute_missing_privacy_report_metadata( privacy_report_metadata, attack_input) return AttackResults(single_attack_results=attack_results, privacy_report_metadata=privacy_report_metadata)
def run_attacks( attack_input: AttackInputData, slicing_spec: SlicingSpec = None, attack_types: Iterable[AttackType] = (AttackType.THRESHOLD_ATTACK, ) ) -> AttackResults: """Run all attacks.""" attack_input.validate() attack_results = [] if slicing_spec is None: slicing_spec = SlicingSpec(entire_dataset=True) input_slice_specs = get_single_slice_specs(slicing_spec, attack_input.num_classes) for single_slice_spec in input_slice_specs: attack_input_slice = get_slice(attack_input, single_slice_spec) for attack_type in attack_types: attack_results.append(run_attack(attack_input_slice, attack_type)) return AttackResults(single_attack_results=attack_results)
def run_attacks( attack_input: AttackInputData, slicing_spec: SlicingSpec = None, attack_types: Iterable[AttackType] = (AttackType.THRESHOLD_ATTACK, ), privacy_report_metadata: PrivacyReportMetadata = None ) -> AttackResults: """Runs membership inference attacks on a classification model. It runs attacks specified by attack_types on each attack_input slice which is specified by slicing_spec. Args: attack_input: input data for running an attack slicing_spec: specifies attack_input slices to run attack on attack_types: attacks to run privacy_report_metadata: the metadata of the model under attack. Returns: the attack result. """ attack_input.validate() attack_results = [] if slicing_spec is None: slicing_spec = SlicingSpec(entire_dataset=True) input_slice_specs = get_single_slice_specs(slicing_spec, attack_input.num_classes) for single_slice_spec in input_slice_specs: attack_input_slice = get_slice(attack_input, single_slice_spec) for attack_type in attack_types: attack_results.append(_run_attack(attack_input_slice, attack_type)) privacy_report_metadata = _compute_missing_privacy_report_metadata( privacy_report_metadata, attack_input) return AttackResults(single_attack_results=attack_results, privacy_report_metadata=privacy_report_metadata)
def test_entire_dataset(self): input_data = SlicingSpec() expected = [self.ENTIRE_DATASET_SLICE] output = get_single_slice_specs(input_data) self.assertTrue(_are_lists_equal(output, expected))
def test_no_slices(self): input_data = SlicingSpec(entire_dataset=False) expected = [] output = get_single_slice_specs(input_data) self.assertTrue(_are_lists_equal(output, expected))