Calls epsilon computation in MIA.
PiperOrigin-RevId: 551003589
This commit is contained in:
parent
8e60864559
commit
225355258c
6 changed files with 568 additions and 46 deletions
|
@ -21,7 +21,10 @@ py_test(
|
|||
srcs = ["membership_inference_attack_test.py"],
|
||||
python_version = "PY3",
|
||||
srcs_version = "PY3",
|
||||
deps = [":membership_inference_attack"],
|
||||
deps = [
|
||||
":membership_inference_attack",
|
||||
"//tensorflow_privacy/privacy/privacy_tests:epsilon_lower_bound",
|
||||
],
|
||||
)
|
||||
|
||||
py_test(
|
||||
|
@ -32,6 +35,7 @@ py_test(
|
|||
srcs_version = "PY3",
|
||||
deps = [
|
||||
":membership_inference_attack",
|
||||
"//tensorflow_privacy/privacy/privacy_tests:epsilon_lower_bound",
|
||||
"//tensorflow_privacy/privacy/privacy_tests:utils",
|
||||
],
|
||||
)
|
||||
|
@ -62,6 +66,7 @@ py_test(
|
|||
deps = [
|
||||
":membership_inference_attack",
|
||||
":privacy_report",
|
||||
"//tensorflow_privacy/privacy/privacy_tests:epsilon_lower_bound",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -83,7 +88,10 @@ py_library(
|
|||
"seq2seq_mia.py",
|
||||
],
|
||||
srcs_version = "PY3",
|
||||
deps = ["//tensorflow_privacy/privacy/privacy_tests:utils"],
|
||||
deps = [
|
||||
"//tensorflow_privacy/privacy/privacy_tests:epsilon_lower_bound",
|
||||
"//tensorflow_privacy/privacy/privacy_tests:utils",
|
||||
],
|
||||
)
|
||||
|
||||
py_library(
|
||||
|
|
|
@ -20,12 +20,13 @@ import glob
|
|||
import logging
|
||||
import os
|
||||
import pickle
|
||||
from typing import Any, Dict, Iterable, MutableSequence, Optional, Sequence, Union
|
||||
from typing import Any, Dict, Iterable, Mapping, MutableSequence, Optional, Sequence, Union
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from scipy import special
|
||||
from sklearn import metrics
|
||||
from tensorflow_privacy.privacy.privacy_tests import epsilon_lower_bound as elb
|
||||
from tensorflow_privacy.privacy.privacy_tests import utils
|
||||
|
||||
# The minimum TPR or FPR below which they are considered equal.
|
||||
|
@ -33,6 +34,11 @@ _ABSOLUTE_TOLERANCE = 1e-3
|
|||
|
||||
ENTIRE_DATASET_SLICE_STR = 'Entire dataset'
|
||||
|
||||
# Methods for estimation epsilon lower bounds
|
||||
EPSILON_METHODS = (elb.BoundMethod.BAILEY,)
|
||||
EPSILON_ALPHA = 0.05 # Level of significance for estimating epsilon lower bound
|
||||
EPSILON_K = 5 # Will return top-k values for each epsilon lower bound estimate
|
||||
|
||||
|
||||
class SlicingFeature(enum.Enum):
|
||||
"""Enum with features by which slicing is available."""
|
||||
|
@ -189,6 +195,7 @@ class PrivacyMetric(enum.Enum):
|
|||
AUC = 'AUC'
|
||||
ATTACKER_ADVANTAGE = 'Attacker advantage'
|
||||
PPV = 'Positive predictive value'
|
||||
EPSILON_LOWER_BOUND = 'Epsilon lower bound'
|
||||
|
||||
def __str__(self):
|
||||
"""Returns 'AUC' instead of PrivacyMetric.AUC."""
|
||||
|
@ -738,6 +745,27 @@ class RocCurve:
|
|||
])
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class EpsilonLowerBoundValue:
|
||||
"""Epsilon lower bounds of a membership inference classifier."""
|
||||
|
||||
# Bounds from different methods
|
||||
bounds: Mapping[elb.BoundMethod, np.ndarray]
|
||||
|
||||
def get_max_epsilon_bounds(self) -> np.ndarray:
|
||||
"""Returns the bounds with largest average."""
|
||||
bounds_val = [bound for bound in self.bounds.values() if bound.size]
|
||||
if not bounds_val:
|
||||
return np.array([])
|
||||
best_index = np.argmax([bound.mean() for bound in bounds_val])
|
||||
return bounds_val[best_index]
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Returns string showing bounds with largest average."""
|
||||
bounds_string = utils.format_number_list(self.get_max_epsilon_bounds())
|
||||
return f'EpsilonLowerBoundValue([{bounds_string}])'
|
||||
|
||||
|
||||
# (no. of training examples, no. of test examples) for the test.
|
||||
DataSize = collections.namedtuple('DataSize', 'ntrain ntest')
|
||||
|
||||
|
@ -761,6 +789,10 @@ class SingleAttackResult:
|
|||
# ROC curve representing the accuracy of the attacker
|
||||
roc_curve: RocCurve
|
||||
|
||||
# Lower bound for DP epsilon, derived from tp and fp. For more details,
|
||||
# see tensorflow_privacy/privacy/privacy_tests/epsilon_lower_bound.py.
|
||||
epsilon_lower_bound_value: EpsilonLowerBoundValue
|
||||
|
||||
# Membership score is some measure of confidence of this attacker that
|
||||
# a particular sample is a member of the training set.
|
||||
#
|
||||
|
@ -794,17 +826,23 @@ class SingleAttackResult:
|
|||
def get_auc(self):
|
||||
return self.roc_curve.get_auc()
|
||||
|
||||
def get_epsilon_lower_bound(self):
|
||||
return self.epsilon_lower_bound_value.get_max_epsilon_bounds()
|
||||
|
||||
def __str__(self):
|
||||
"""Returns SliceSpec, AttackType, AUC and advantage metrics."""
|
||||
"""Returns SliceSpec, AttackType, and various MIA metrics."""
|
||||
return '\n'.join([
|
||||
'SingleAttackResult(',
|
||||
' SliceSpec: %s' % str(self.slice_spec),
|
||||
' DataSize: (ntrain=%d, ntest=%d)' %
|
||||
(self.data_size.ntrain, self.data_size.ntest),
|
||||
' DataSize: (ntrain=%d, ntest=%d)'
|
||||
% (self.data_size.ntrain, self.data_size.ntest),
|
||||
' AttackType: %s' % str(self.attack_type),
|
||||
' AUC: %.2f' % self.get_auc(),
|
||||
' Attacker advantage: %.2f' % self.get_attacker_advantage(),
|
||||
' Positive Predictive Value: %.2f' % self.get_ppv(), ')'
|
||||
' Positive Predictive Value: %.2f' % self.get_ppv(),
|
||||
' Epsilon lower bound: '
|
||||
+ utils.format_number_list(self.get_epsilon_lower_bound()),
|
||||
')',
|
||||
])
|
||||
|
||||
|
||||
|
@ -906,6 +944,21 @@ class SingleMembershipProbabilityResult:
|
|||
' thresholding on membership probability achieved an advantage of'
|
||||
' %.2f' % (roc_curve.get_attacker_advantage())
|
||||
)
|
||||
epsilon_lower_bound_value = EpsilonLowerBoundValue(
|
||||
bounds=elb.EpsilonLowerBound(
|
||||
pos_scores=self.train_membership_probs,
|
||||
neg_scores=self.test_membership_probs,
|
||||
alpha=EPSILON_ALPHA,
|
||||
two_sided_threshold=True,
|
||||
).compute_epsilon_lower_bounds(methods=EPSILON_METHODS, k=EPSILON_K)
|
||||
)
|
||||
summary.append(
|
||||
f' thresholding on membership probability achieved top-{EPSILON_K}'
|
||||
+ ' epsilon lower bound of '
|
||||
+ utils.format_number_list(
|
||||
epsilon_lower_bound_value.get_max_epsilon_bounds()
|
||||
)
|
||||
)
|
||||
return summary
|
||||
|
||||
|
||||
|
@ -970,6 +1023,9 @@ class AttackResults:
|
|||
advantages = []
|
||||
ppvs = []
|
||||
aucs = []
|
||||
# Top EPSILON_K epsilon values for each single attack result.
|
||||
# epsilon_lower_bounds[i][j] is the top-i epsilon value for attack j.
|
||||
epsilon_lower_bounds = [[] for _ in range(EPSILON_K)]
|
||||
|
||||
for attack_result in self.single_attack_results:
|
||||
slice_spec = attack_result.slice_spec
|
||||
|
@ -985,17 +1041,30 @@ class AttackResults:
|
|||
advantages.append(float(attack_result.get_attacker_advantage()))
|
||||
ppvs.append(float(attack_result.get_ppv()))
|
||||
aucs.append(float(attack_result.get_auc()))
|
||||
current_elb = attack_result.get_epsilon_lower_bound()
|
||||
for i in range(EPSILON_K):
|
||||
if i < len(current_elb):
|
||||
epsilon_lower_bounds[i].append(current_elb[i])
|
||||
else: # If less than EPSILON_K values, use nan.
|
||||
epsilon_lower_bounds[i].append(np.nan)
|
||||
|
||||
df = pd.DataFrame({
|
||||
str(AttackResultsDFColumns.SLICE_FEATURE): slice_features,
|
||||
str(AttackResultsDFColumns.SLICE_VALUE): slice_values,
|
||||
str(AttackResultsDFColumns.DATA_SIZE_TRAIN): data_size_train,
|
||||
str(AttackResultsDFColumns.DATA_SIZE_TEST): data_size_test,
|
||||
str(AttackResultsDFColumns.ATTACK_TYPE): attack_types,
|
||||
str(PrivacyMetric.ATTACKER_ADVANTAGE): advantages,
|
||||
str(PrivacyMetric.PPV): ppvs,
|
||||
str(PrivacyMetric.AUC): aucs
|
||||
})
|
||||
df = pd.DataFrame(
|
||||
{
|
||||
str(AttackResultsDFColumns.SLICE_FEATURE): slice_features,
|
||||
str(AttackResultsDFColumns.SLICE_VALUE): slice_values,
|
||||
str(AttackResultsDFColumns.DATA_SIZE_TRAIN): data_size_train,
|
||||
str(AttackResultsDFColumns.DATA_SIZE_TEST): data_size_test,
|
||||
str(AttackResultsDFColumns.ATTACK_TYPE): attack_types,
|
||||
str(PrivacyMetric.ATTACKER_ADVANTAGE): advantages,
|
||||
str(PrivacyMetric.PPV): ppvs,
|
||||
str(PrivacyMetric.AUC): aucs,
|
||||
}
|
||||
| {
|
||||
str(PrivacyMetric.EPSILON_LOWER_BOUND)
|
||||
+ f'_{i + 1}': epsilon_lower_bounds[i]
|
||||
for i in range(len(epsilon_lower_bounds))
|
||||
}
|
||||
)
|
||||
return df
|
||||
|
||||
def summary(self, by_slices=False) -> str:
|
||||
|
@ -1047,6 +1116,22 @@ class AttackResults:
|
|||
max_ppv_result_all.data_size.ntest, max_ppv_result_all.get_ppv(),
|
||||
max_ppv_result_all.slice_spec))
|
||||
|
||||
max_epsilon_lower_bound_all = self.get_result_with_max_epsilon()
|
||||
summary.append(
|
||||
' %s (with %d training and %d test examples) achieved top-%d epsilon '
|
||||
'lower bounds of %s on slice %s'
|
||||
% (
|
||||
max_epsilon_lower_bound_all.attack_type,
|
||||
max_epsilon_lower_bound_all.data_size.ntrain,
|
||||
max_epsilon_lower_bound_all.data_size.ntest,
|
||||
EPSILON_K,
|
||||
utils.format_number_list(
|
||||
max_epsilon_lower_bound_all.get_epsilon_lower_bound()
|
||||
),
|
||||
max_epsilon_lower_bound_all.slice_spec,
|
||||
)
|
||||
)
|
||||
|
||||
slice_dict = self._group_results_by_slice()
|
||||
|
||||
if by_slices and len(slice_dict.keys()) > 1:
|
||||
|
@ -1082,7 +1167,20 @@ class AttackResults:
|
|||
'predictive value of %.2f' %
|
||||
(max_ppv_result.attack_type, max_ppv_result.data_size.ntrain,
|
||||
max_ppv_result.data_size.ntest, max_ppv_result.get_ppv()))
|
||||
|
||||
max_epsilon_lower_bound_all = results.get_result_with_max_epsilon()
|
||||
summary.append(
|
||||
' %s (with %d training and %d test examples) achieved top-%d '
|
||||
'epsilon lower bounds of %s'
|
||||
% (
|
||||
max_epsilon_lower_bound_all.attack_type,
|
||||
max_epsilon_lower_bound_all.data_size.ntrain,
|
||||
max_epsilon_lower_bound_all.data_size.ntest,
|
||||
EPSILON_K,
|
||||
utils.format_number_list(
|
||||
max_epsilon_lower_bound_all.get_epsilon_lower_bound()
|
||||
),
|
||||
)
|
||||
)
|
||||
return '\n'.join(summary)
|
||||
|
||||
def _group_results_by_slice(self):
|
||||
|
@ -1124,6 +1222,14 @@ class AttackResults:
|
|||
return self.single_attack_results[np.argmax(
|
||||
[result.get_ppv() for result in self.single_attack_results])]
|
||||
|
||||
def get_result_with_max_epsilon(self) -> SingleAttackResult:
|
||||
"""Gets the result with max averaged epsilon lower bound."""
|
||||
avg_epsilon_bounds = [
|
||||
result.get_epsilon_lower_bound().mean()
|
||||
for result in self.single_attack_results
|
||||
]
|
||||
return self.single_attack_results[np.argmax(avg_epsilon_bounds)]
|
||||
|
||||
def save(self, filepath):
|
||||
"""Saves self to a pickle file."""
|
||||
with open(filepath, 'wb') as out:
|
||||
|
|
|
@ -20,13 +20,16 @@ from absl.testing import absltest
|
|||
from absl.testing import parameterized
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from tensorflow_privacy.privacy.privacy_tests import epsilon_lower_bound as elb
|
||||
from tensorflow_privacy.privacy.privacy_tests import utils
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack import data_structures
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import _log_value
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackInputData
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackResults
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackResultsCollection
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackType
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import DataSize
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import EpsilonLowerBoundValue
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import PrivacyReportMetadata
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import RocCurve
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import SingleAttackResult
|
||||
|
@ -578,9 +581,87 @@ class RocCurveTest(parameterized.TestCase):
|
|||
|
||||
np.testing.assert_allclose(roc.get_ppv(), 0.5, atol=1e-3)
|
||||
|
||||
def test_string(self):
|
||||
roc = RocCurve(
|
||||
tpr=np.array([0.0, 0.5, 1.0]),
|
||||
fpr=np.array([0.0, 0.5, 1.0]),
|
||||
thresholds=np.array([0, 1, 2]),
|
||||
test_train_ratio=1.0,
|
||||
)
|
||||
self.assertEqual(
|
||||
str(roc),
|
||||
(
|
||||
'RocCurve(\n'
|
||||
' AUC: 0.50\n'
|
||||
' Attacker advantage: 0.00\n'
|
||||
' Positive predictive value: 0.50\n'
|
||||
')'
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class EpsilonLowerBoundValueTest(parameterized.TestCase):
|
||||
"""Tests for EpsilonLowerBoundValue class."""
|
||||
|
||||
def test_epsilon_lower_bound_value(self):
|
||||
bounds = {
|
||||
elb.BoundMethod.KATZ_LOG: np.array([2, 2.0]),
|
||||
elb.BoundMethod.BAILEY: np.array([5, 4.0]),
|
||||
elb.BoundMethod.ADJUSTED_LOG: np.array([10]),
|
||||
}
|
||||
elbv = EpsilonLowerBoundValue(bounds=bounds)
|
||||
self.assertDictEqual(elbv.bounds, bounds)
|
||||
np.testing.assert_allclose(elbv.get_max_epsilon_bounds(), [10])
|
||||
self.assertEqual(str(elbv), 'EpsilonLowerBoundValue([10.0000])')
|
||||
|
||||
def test_epsilon_lower_bound_value_empty(self):
|
||||
elbv = EpsilonLowerBoundValue(bounds={})
|
||||
self.assertDictEqual(elbv.bounds, {})
|
||||
self.assertEmpty(elbv.get_max_epsilon_bounds())
|
||||
self.assertEqual(str(elbv), 'EpsilonLowerBoundValue([])')
|
||||
|
||||
def test_epsilon_lower_bound_value_one_array_empty(self):
|
||||
elbv = EpsilonLowerBoundValue(
|
||||
bounds={
|
||||
elb.BoundMethod.KATZ_LOG: np.array([-2, -2.0]),
|
||||
elb.BoundMethod.ADJUSTED_LOG: np.array([]),
|
||||
}
|
||||
)
|
||||
np.testing.assert_allclose(elbv.get_max_epsilon_bounds(), [-2, -2.0])
|
||||
self.assertEqual(str(elbv), 'EpsilonLowerBoundValue([-2.0000, -2.0000])')
|
||||
|
||||
def test_epsilon_lower_bound_value_all_array_empty(self):
|
||||
elbv = EpsilonLowerBoundValue(
|
||||
bounds={
|
||||
elb.BoundMethod.KATZ_LOG: np.array([]),
|
||||
elb.BoundMethod.ADJUSTED_LOG: np.array([]),
|
||||
}
|
||||
)
|
||||
self.assertEmpty(elbv.get_max_epsilon_bounds())
|
||||
self.assertEqual(str(elbv), 'EpsilonLowerBoundValue([])')
|
||||
|
||||
|
||||
class SingleAttackResultTest(absltest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
# Some arbitrary roc.
|
||||
self.arbitrary_roc = RocCurve(
|
||||
tpr=np.array([0.0, 0.5, 1.0]),
|
||||
fpr=np.array([0.0, 0.5, 1.0]),
|
||||
thresholds=np.array([0, 1, 2]),
|
||||
test_train_ratio=1.0,
|
||||
)
|
||||
|
||||
# Some arbitrary epsilon lower bound.
|
||||
self.arbitrary_epsilon_lower_bound_value = EpsilonLowerBoundValue(
|
||||
bounds={
|
||||
elb.BoundMethod.KATZ_LOG: np.array([2, 2.0]),
|
||||
elb.BoundMethod.BAILEY: np.array([5, 4.0]),
|
||||
elb.BoundMethod.ADJUSTED_LOG: np.array([10, 1.0]),
|
||||
}
|
||||
)
|
||||
|
||||
# Only a basic test, as this method calls RocCurve which is tested separately.
|
||||
def test_auc_random_classifier(self):
|
||||
roc = RocCurve(
|
||||
|
@ -591,9 +672,11 @@ class SingleAttackResultTest(absltest.TestCase):
|
|||
|
||||
result = SingleAttackResult(
|
||||
roc_curve=roc,
|
||||
epsilon_lower_bound_value=self.arbitrary_epsilon_lower_bound_value,
|
||||
slice_spec=SingleSliceSpec(None),
|
||||
attack_type=AttackType.THRESHOLD_ATTACK,
|
||||
data_size=DataSize(ntrain=1, ntest=1))
|
||||
data_size=DataSize(ntrain=1, ntest=1),
|
||||
)
|
||||
|
||||
self.assertEqual(result.get_auc(), 0.5)
|
||||
|
||||
|
@ -607,9 +690,11 @@ class SingleAttackResultTest(absltest.TestCase):
|
|||
|
||||
result = SingleAttackResult(
|
||||
roc_curve=roc,
|
||||
epsilon_lower_bound_value=self.arbitrary_epsilon_lower_bound_value,
|
||||
slice_spec=SingleSliceSpec(None),
|
||||
attack_type=AttackType.THRESHOLD_ATTACK,
|
||||
data_size=DataSize(ntrain=1, ntest=1))
|
||||
data_size=DataSize(ntrain=1, ntest=1),
|
||||
)
|
||||
|
||||
self.assertEqual(result.get_attacker_advantage(), 0.0)
|
||||
|
||||
|
@ -623,12 +708,59 @@ class SingleAttackResultTest(absltest.TestCase):
|
|||
|
||||
result = SingleAttackResult(
|
||||
roc_curve=roc,
|
||||
epsilon_lower_bound_value=self.arbitrary_epsilon_lower_bound_value,
|
||||
slice_spec=SingleSliceSpec(None),
|
||||
attack_type=AttackType.THRESHOLD_ATTACK,
|
||||
data_size=DataSize(ntrain=1, ntest=1))
|
||||
data_size=DataSize(ntrain=1, ntest=1),
|
||||
)
|
||||
|
||||
self.assertEqual(result.get_ppv(), 0.5)
|
||||
|
||||
# Only a basic test, as this method calls EpsilonLowerBound which is tested
|
||||
# separately.
|
||||
def test_epsilon_lower_bound(self):
|
||||
epsilon_lower_bound_value = EpsilonLowerBoundValue(
|
||||
bounds={
|
||||
elb.BoundMethod.KATZ_LOG: np.array([2, 2.0]),
|
||||
elb.BoundMethod.BAILEY: np.array([5, 4.0]),
|
||||
elb.BoundMethod.ADJUSTED_LOG: np.array([10, 1.0]),
|
||||
}
|
||||
)
|
||||
expected = [10, 1.0]
|
||||
|
||||
result = SingleAttackResult(
|
||||
roc_curve=self.arbitrary_roc,
|
||||
epsilon_lower_bound_value=epsilon_lower_bound_value,
|
||||
slice_spec=SingleSliceSpec(None),
|
||||
attack_type=AttackType.THRESHOLD_ATTACK,
|
||||
data_size=DataSize(ntrain=1, ntest=1),
|
||||
)
|
||||
returned_value = result.get_epsilon_lower_bound()
|
||||
np.testing.assert_allclose(returned_value, expected, atol=1e-7)
|
||||
|
||||
def test_string(self):
|
||||
result = SingleAttackResult(
|
||||
roc_curve=self.arbitrary_roc,
|
||||
epsilon_lower_bound_value=self.arbitrary_epsilon_lower_bound_value,
|
||||
slice_spec=SingleSliceSpec(None),
|
||||
attack_type=AttackType.THRESHOLD_ATTACK,
|
||||
data_size=DataSize(ntrain=1, ntest=1),
|
||||
)
|
||||
self.assertEqual(
|
||||
str(result),
|
||||
(
|
||||
'SingleAttackResult(\n'
|
||||
' SliceSpec: Entire dataset\n'
|
||||
' DataSize: (ntrain=1, ntest=1)\n'
|
||||
' AttackType: THRESHOLD_ATTACK\n'
|
||||
' AUC: 0.50\n'
|
||||
' Attacker advantage: 0.00\n'
|
||||
' Positive Predictive Value: 0.50\n'
|
||||
' Epsilon lower bound: 10.0000, 1.0000\n'
|
||||
')'
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class SingleMembershipProbabilityResultTest(absltest.TestCase):
|
||||
|
||||
|
@ -648,6 +780,40 @@ class SingleMembershipProbabilityResultTest(absltest.TestCase):
|
|||
result.attack_with_varied_thresholds(
|
||||
threshold_list=np.array([0.8, 0.7]))[2].tolist(), [0.8, 1])
|
||||
|
||||
@mock.patch.object(data_structures, 'EPSILON_K', 4)
|
||||
def test_collect_results(self):
|
||||
result = SingleMembershipProbabilityResult(
|
||||
slice_spec=SingleSliceSpec(None),
|
||||
train_membership_probs=np.array([0.91, 1, 0.92, 0.82, 0.75]),
|
||||
test_membership_probs=np.array([0.81, 0.7, 0.75, 0.25, 0.3]),
|
||||
)
|
||||
summary = result.collect_results(
|
||||
threshold_list=np.array([0.8, 0.7]), return_roc_results=True
|
||||
)
|
||||
self.assertListEqual(
|
||||
summary,
|
||||
[
|
||||
'\nMembership probability analysis over slice: "Entire dataset"',
|
||||
(
|
||||
' with 0.8000 as the threshold on membership probability, the'
|
||||
' precision-recall pair is (0.8000, 0.8000)'
|
||||
),
|
||||
(
|
||||
' with 0.7000 as the threshold on membership probability, the'
|
||||
' precision-recall pair is (0.6250, 1.0000)'
|
||||
),
|
||||
' thresholding on membership probability achieved an AUC of 0.94',
|
||||
(
|
||||
' thresholding on membership probability achieved an advantage'
|
||||
' of 0.80'
|
||||
),
|
||||
(
|
||||
' thresholding on membership probability achieved top-4'
|
||||
' epsilon lower bound of 0.3719, 0.2765, 0.1207, 0.1207'
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
class AttackResultsCollectionTest(absltest.TestCase):
|
||||
|
||||
|
@ -661,8 +827,15 @@ class AttackResultsCollectionTest(absltest.TestCase):
|
|||
tpr=np.array([0.0, 0.5, 1.0]),
|
||||
fpr=np.array([0.0, 0.5, 1.0]),
|
||||
thresholds=np.array([0, 1, 2]),
|
||||
test_train_ratio=1.0),
|
||||
data_size=DataSize(ntrain=1, ntest=1))
|
||||
test_train_ratio=1.0,
|
||||
),
|
||||
epsilon_lower_bound_value=EpsilonLowerBoundValue(
|
||||
bounds={
|
||||
elb.BoundMethod.KATZ_LOG: np.array([2, 2.0]),
|
||||
}
|
||||
),
|
||||
data_size=DataSize(ntrain=1, ntest=1),
|
||||
)
|
||||
|
||||
self.results_epoch_10 = AttackResults(
|
||||
single_attack_results=[self.some_attack_result],
|
||||
|
@ -722,8 +895,20 @@ class AttackResultsTest(absltest.TestCase):
|
|||
tpr=np.array([0.0, 1.0, 1.0]),
|
||||
fpr=np.array([1.0, 1.0, 0.0]),
|
||||
thresholds=np.array([0, 1, 2]),
|
||||
test_train_ratio=1.0),
|
||||
data_size=DataSize(ntrain=1, ntest=1))
|
||||
test_train_ratio=1.0,
|
||||
),
|
||||
epsilon_lower_bound_value=EpsilonLowerBoundValue(
|
||||
bounds={
|
||||
elb.BoundMethod.INV_SINH: np.array(
|
||||
[2.65964282, 2.65964282, -0.01648963, -0.01648963]
|
||||
),
|
||||
elb.BoundMethod.CLOPPER_PEARSON: np.array(
|
||||
[3.28134635, 3.28134635]
|
||||
),
|
||||
}
|
||||
),
|
||||
data_size=DataSize(ntrain=1, ntest=1),
|
||||
)
|
||||
|
||||
# ROC curve of a random classifier
|
||||
self.random_classifier_result = SingleAttackResult(
|
||||
|
@ -733,8 +918,18 @@ class AttackResultsTest(absltest.TestCase):
|
|||
tpr=np.array([0.0, 0.5, 1.0]),
|
||||
fpr=np.array([0.0, 0.5, 1.0]),
|
||||
thresholds=np.array([0, 1, 2]),
|
||||
test_train_ratio=1.0),
|
||||
data_size=DataSize(ntrain=1, ntest=1))
|
||||
test_train_ratio=1.0,
|
||||
),
|
||||
epsilon_lower_bound_value=EpsilonLowerBoundValue(
|
||||
bounds={
|
||||
elb.BoundMethod.KATZ_LOG: np.array([-0.01648981, -0.01648981]),
|
||||
elb.BoundMethod.ADJUSTED_LOG: np.array(
|
||||
[-0.01640757, -0.01640757]
|
||||
),
|
||||
}
|
||||
),
|
||||
data_size=DataSize(ntrain=1, ntest=1),
|
||||
)
|
||||
|
||||
def test_get_result_with_max_auc_first(self):
|
||||
results = AttackResults(
|
||||
|
@ -772,34 +967,59 @@ class AttackResultsTest(absltest.TestCase):
|
|||
self.assertEqual(results.get_result_with_max_ppv(),
|
||||
self.perfect_classifier_result)
|
||||
|
||||
def test_get_result_with_max_epsilon_first(self):
|
||||
results = AttackResults(
|
||||
[self.random_classifier_result, self.perfect_classifier_result]
|
||||
)
|
||||
self.assertEqual(
|
||||
results.get_result_with_max_epsilon(), self.perfect_classifier_result
|
||||
)
|
||||
|
||||
def test_get_result_with_max_epsilon_second(self):
|
||||
results = AttackResults(
|
||||
[self.random_classifier_result, self.perfect_classifier_result]
|
||||
)
|
||||
self.assertEqual(
|
||||
results.get_result_with_max_epsilon(), self.perfect_classifier_result
|
||||
)
|
||||
|
||||
def test_summary_by_slices(self):
|
||||
results = AttackResults(
|
||||
[self.perfect_classifier_result, self.random_classifier_result])
|
||||
self.assertSequenceEqual(
|
||||
results.summary(by_slices=True),
|
||||
'Best-performing attacks over all slices\n' +
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved an'
|
||||
' AUC of 1.00 on slice CORRECTLY_CLASSIFIED=True\n' +
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved an'
|
||||
'Best-performing attacks over all slices\n'
|
||||
+ ' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved an'
|
||||
' AUC of 1.00 on slice CORRECTLY_CLASSIFIED=True\n'
|
||||
+ ' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved an'
|
||||
' advantage of 1.00 on slice CORRECTLY_CLASSIFIED=True\n'
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved a'
|
||||
' positive predictive value of 1.00 on slice CORRECTLY_CLASSIFIED='
|
||||
'True\n\n'
|
||||
'True\n'
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved'
|
||||
' top-5 epsilon lower bounds of 3.2813, 3.2813 on slice'
|
||||
' CORRECTLY_CLASSIFIED=True\n\n'
|
||||
'Best-performing attacks over slice: "CORRECTLY_CLASSIFIED=True"\n'
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved an'
|
||||
' AUC of 1.00\n'
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved an'
|
||||
' advantage of 1.00\n'
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved a'
|
||||
' positive predictive value of 1.00\n\n'
|
||||
' positive predictive value of 1.00\n'
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved'
|
||||
' top-5 epsilon lower bounds of 3.2813, 3.2813\n\n'
|
||||
'Best-performing attacks over slice: "Entire dataset"\n'
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved an'
|
||||
' AUC of 0.50\n'
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved an'
|
||||
' advantage of 0.00\n'
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved a'
|
||||
' positive predictive value of 0.50')
|
||||
' positive predictive value of 0.50\n'
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved'
|
||||
' top-5 epsilon lower bounds of -0.0164, -0.0164',
|
||||
)
|
||||
|
||||
@mock.patch.object(data_structures, 'EPSILON_K', 4)
|
||||
def test_summary_without_slices(self):
|
||||
results = AttackResults(
|
||||
[self.perfect_classifier_result, self.random_classifier_result])
|
||||
|
@ -811,7 +1031,12 @@ class AttackResultsTest(absltest.TestCase):
|
|||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved an'
|
||||
' advantage of 1.00 on slice CORRECTLY_CLASSIFIED=True\n'
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved a'
|
||||
' positive predictive value of 1.00 on slice CORRECTLY_CLASSIFIED=True')
|
||||
' positive predictive value of 1.00 on slice'
|
||||
' CORRECTLY_CLASSIFIED=True\n'
|
||||
' THRESHOLD_ATTACK (with 1 training and 1 test examples) achieved'
|
||||
' top-4 epsilon lower bounds of 3.2813, 3.2813 on slice'
|
||||
' CORRECTLY_CLASSIFIED=True',
|
||||
)
|
||||
|
||||
def test_save_load(self):
|
||||
results = AttackResults(
|
||||
|
@ -824,6 +1049,7 @@ class AttackResultsTest(absltest.TestCase):
|
|||
|
||||
self.assertEqual(repr(results), repr(loaded_results))
|
||||
|
||||
@mock.patch.object(data_structures, 'EPSILON_K', 4)
|
||||
def test_calculate_pd_dataframe(self):
|
||||
single_results = [
|
||||
self.perfect_classifier_result, self.random_classifier_result
|
||||
|
@ -838,7 +1064,11 @@ class AttackResultsTest(absltest.TestCase):
|
|||
'attack type': ['THRESHOLD_ATTACK', 'THRESHOLD_ATTACK'],
|
||||
'Attacker advantage': [1.0, 0.0],
|
||||
'Positive predictive value': [1.0, 0.5],
|
||||
'AUC': [1.0, 0.5]
|
||||
'AUC': [1.0, 0.5],
|
||||
'Epsilon lower bound_1': [3.28134635, -0.01640757],
|
||||
'Epsilon lower bound_2': [3.28134635, -0.01640757],
|
||||
'Epsilon lower bound_3': [np.nan, np.nan],
|
||||
'Epsilon lower bound_4': [np.nan, np.nan],
|
||||
})
|
||||
pd.testing.assert_frame_equal(df, df_expected)
|
||||
|
||||
|
|
|
@ -24,12 +24,16 @@ import numpy as np
|
|||
from scipy import special
|
||||
from sklearn import metrics
|
||||
from sklearn import model_selection
|
||||
|
||||
from tensorflow_privacy.privacy.privacy_tests import epsilon_lower_bound as elb
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack import models
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackInputData
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackResults
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackType
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import DataSize
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import EPSILON_ALPHA
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import EPSILON_K
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import EPSILON_METHODS
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import EpsilonLowerBoundValue
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import MembershipProbabilityResults
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import PrivacyReportMetadata
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import RocCurve
|
||||
|
@ -135,13 +139,23 @@ def _run_trained_attack(
|
|||
test_train_ratio=test_train_ratio)
|
||||
|
||||
in_train_indices = labels == 1
|
||||
epsilon_lower_bound_value = EpsilonLowerBoundValue(
|
||||
bounds=elb.EpsilonLowerBound(
|
||||
pos_scores=scores[in_train_indices],
|
||||
neg_scores=scores[~in_train_indices],
|
||||
alpha=EPSILON_ALPHA,
|
||||
two_sided_threshold=True,
|
||||
).compute_epsilon_lower_bounds(methods=EPSILON_METHODS, k=EPSILON_K)
|
||||
)
|
||||
return SingleAttackResult(
|
||||
slice_spec=_get_slice_spec(attack_input),
|
||||
data_size=prepared_attacker_data.data_size,
|
||||
attack_type=attack_type,
|
||||
membership_scores_train=scores[in_train_indices],
|
||||
membership_scores_test=scores[~in_train_indices],
|
||||
roc_curve=roc_curve)
|
||||
roc_curve=roc_curve,
|
||||
epsilon_lower_bound_value=epsilon_lower_bound_value,
|
||||
)
|
||||
|
||||
|
||||
def _run_threshold_attack(attack_input: AttackInputData):
|
||||
|
@ -173,6 +187,14 @@ def _run_threshold_attack(attack_input: AttackInputData):
|
|||
thresholds=-thresholds, # negate because we negated the loss
|
||||
test_train_ratio=test_train_ratio,
|
||||
)
|
||||
epsilon_lower_bound_value = EpsilonLowerBoundValue(
|
||||
bounds=elb.EpsilonLowerBound(
|
||||
pos_scores=loss_train,
|
||||
neg_scores=loss_test,
|
||||
alpha=EPSILON_ALPHA,
|
||||
two_sided_threshold=True,
|
||||
).compute_epsilon_lower_bounds(methods=EPSILON_METHODS, k=EPSILON_K)
|
||||
)
|
||||
|
||||
return SingleAttackResult(
|
||||
slice_spec=_get_slice_spec(attack_input),
|
||||
|
@ -180,7 +202,9 @@ def _run_threshold_attack(attack_input: AttackInputData):
|
|||
attack_type=AttackType.THRESHOLD_ATTACK,
|
||||
membership_scores_train=attack_input.get_loss_train(),
|
||||
membership_scores_test=attack_input.get_loss_test(),
|
||||
roc_curve=roc_curve)
|
||||
roc_curve=roc_curve,
|
||||
epsilon_lower_bound_value=epsilon_lower_bound_value,
|
||||
)
|
||||
|
||||
|
||||
def _run_threshold_entropy_attack(attack_input: AttackInputData):
|
||||
|
@ -207,14 +231,23 @@ def _run_threshold_entropy_attack(attack_input: AttackInputData):
|
|||
thresholds=-thresholds, # negate because we negated the loss
|
||||
test_train_ratio=test_train_ratio,
|
||||
)
|
||||
|
||||
epsilon_lower_bound_value = EpsilonLowerBoundValue(
|
||||
bounds=elb.EpsilonLowerBound(
|
||||
pos_scores=attack_input.get_entropy_train(),
|
||||
neg_scores=attack_input.get_entropy_test(),
|
||||
alpha=EPSILON_ALPHA,
|
||||
two_sided_threshold=True,
|
||||
).compute_epsilon_lower_bounds(methods=EPSILON_METHODS, k=EPSILON_K)
|
||||
)
|
||||
return SingleAttackResult(
|
||||
slice_spec=_get_slice_spec(attack_input),
|
||||
data_size=DataSize(ntrain=ntrain, ntest=ntest),
|
||||
attack_type=AttackType.THRESHOLD_ENTROPY_ATTACK,
|
||||
membership_scores_train=-attack_input.get_entropy_train(),
|
||||
membership_scores_test=-attack_input.get_entropy_test(),
|
||||
roc_curve=roc_curve)
|
||||
roc_curve=roc_curve,
|
||||
epsilon_lower_bound_value=epsilon_lower_bound_value,
|
||||
)
|
||||
|
||||
|
||||
def _run_attack(attack_input: AttackInputData,
|
||||
|
|
|
@ -17,7 +17,9 @@ from unittest import mock
|
|||
from absl.testing import absltest
|
||||
from absl.testing import parameterized
|
||||
import numpy as np
|
||||
from tensorflow_privacy.privacy.privacy_tests import epsilon_lower_bound as elb
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack import membership_inference_attack as mia
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack import models
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackInputData
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackType
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import DataSize
|
||||
|
@ -103,6 +105,21 @@ def get_test_input_logits_only_with_sample_weights(n_train, n_test):
|
|||
sample_weight_test=rng.randn(n_test, 1))
|
||||
|
||||
|
||||
class MockTrainedAttacker(object):
|
||||
"""Mock for TrainedAttacker."""
|
||||
|
||||
def __init__(self, backend):
|
||||
del backend
|
||||
return
|
||||
|
||||
def train_model(self, input_features, is_training_labels, sample_weight=None):
|
||||
del input_features, is_training_labels, sample_weight
|
||||
return
|
||||
|
||||
def predict(self, input_features):
|
||||
return input_features[:, 0]
|
||||
|
||||
|
||||
class RunAttacksTest(parameterized.TestCase):
|
||||
|
||||
def test_run_attacks_size(self):
|
||||
|
@ -285,6 +302,117 @@ class RunAttacksTest(parameterized.TestCase):
|
|||
# namely 0.5.
|
||||
np.testing.assert_almost_equal(result.roc_curve.get_ppv(), 0.5, decimal=2)
|
||||
|
||||
@parameterized.parameters(
|
||||
(AttackType.THRESHOLD_ATTACK, 'loss_train', 'loss_test'),
|
||||
(AttackType.THRESHOLD_ENTROPY_ATTACK, 'entropy_train', 'entropy_test'),
|
||||
)
|
||||
@mock.patch.object(mia, 'EPSILON_K', 4)
|
||||
def test_run_attack_threshold_calculates_correct_epsilon(
|
||||
self, attack_type, train_metric_name, test_metric_name
|
||||
):
|
||||
result = mia._run_attack(
|
||||
AttackInputData(
|
||||
**{
|
||||
train_metric_name: np.array([0.1, 0.2, 1.3, 0.4, 0.5, 0.6]),
|
||||
test_metric_name: np.array([1.1, 1.2, 1.3, 0.4, 1.5, 1.6]),
|
||||
}
|
||||
),
|
||||
attack_type,
|
||||
)
|
||||
np.testing.assert_almost_equal(
|
||||
result.epsilon_lower_bound_value.get_max_epsilon_bounds(),
|
||||
np.array([0.34695111, 0.34695111, 0.05616349, 0.05616349]),
|
||||
)
|
||||
|
||||
@parameterized.product(
|
||||
(
|
||||
dict(
|
||||
epsilon_methods=tuple(elb.BoundMethod),
|
||||
expected_max_method=elb.BoundMethod.CLOPPER_PEARSON,
|
||||
),
|
||||
dict(
|
||||
epsilon_methods=(
|
||||
elb.BoundMethod.KATZ_LOG,
|
||||
elb.BoundMethod.CLOPPER_PEARSON,
|
||||
),
|
||||
expected_max_method=elb.BoundMethod.CLOPPER_PEARSON,
|
||||
),
|
||||
dict(
|
||||
epsilon_methods=(elb.BoundMethod.BAILEY,),
|
||||
expected_max_method=elb.BoundMethod.BAILEY,
|
||||
),
|
||||
),
|
||||
attack_type=[
|
||||
AttackType.LOGISTIC_REGRESSION,
|
||||
AttackType.MULTI_LAYERED_PERCEPTRON,
|
||||
AttackType.RANDOM_FOREST,
|
||||
AttackType.K_NEAREST_NEIGHBORS,
|
||||
],
|
||||
)
|
||||
@mock.patch.object(models, 'TrainedAttacker', MockTrainedAttacker)
|
||||
@mock.patch.object(models, 'LogisticRegressionAttacker', MockTrainedAttacker)
|
||||
@mock.patch.object(
|
||||
models, 'MultilayerPerceptronAttacker', MockTrainedAttacker
|
||||
)
|
||||
@mock.patch.object(models, 'RandomForestAttacker', MockTrainedAttacker)
|
||||
@mock.patch.object(models, 'KNearestNeighborsAttacker', MockTrainedAttacker)
|
||||
def test_run_attack_trained_calculates_correct_epsilon(
|
||||
self,
|
||||
epsilon_methods,
|
||||
expected_max_method,
|
||||
attack_type,
|
||||
):
|
||||
logits_train = np.ones((1000, 5))
|
||||
logits_test = np.zeros((100, 5))
|
||||
# The prediction would be all 1 for training and all 0 for test.
|
||||
expected_bounds = {
|
||||
elb.BoundMethod.KATZ_LOG: [
|
||||
5.27530977,
|
||||
2.97796578,
|
||||
-0.00720554,
|
||||
-0.01623037,
|
||||
],
|
||||
elb.BoundMethod.ADJUSTED_LOG: [
|
||||
5.27580935,
|
||||
2.98292432,
|
||||
-0.00717236,
|
||||
-0.01614769,
|
||||
-7.62368550,
|
||||
],
|
||||
elb.BoundMethod.BAILEY: [
|
||||
5.87410287,
|
||||
3.57903543,
|
||||
-0.00718316,
|
||||
-0.01625286,
|
||||
],
|
||||
elb.BoundMethod.INV_SINH: [
|
||||
4.95123977,
|
||||
2.65964282,
|
||||
-0.00720547,
|
||||
-0.01623030,
|
||||
],
|
||||
elb.BoundMethod.CLOPPER_PEARSON: [
|
||||
5.56738762,
|
||||
3.31454626,
|
||||
],
|
||||
}
|
||||
with mock.patch.object(mia, 'EPSILON_METHODS', epsilon_methods):
|
||||
result = mia._run_attack(
|
||||
AttackInputData(logits_train, logits_test),
|
||||
attack_type,
|
||||
)
|
||||
self.assertCountEqual(
|
||||
result.epsilon_lower_bound_value.bounds.keys(), epsilon_methods
|
||||
)
|
||||
for key in epsilon_methods:
|
||||
np.testing.assert_almost_equal(
|
||||
result.epsilon_lower_bound_value.bounds[key], expected_bounds[key]
|
||||
)
|
||||
np.testing.assert_almost_equal(
|
||||
result.epsilon_lower_bound_value.get_max_epsilon_bounds(),
|
||||
expected_bounds[expected_max_method],
|
||||
)
|
||||
|
||||
def test_run_attack_by_slice(self):
|
||||
result = mia.run_attacks(
|
||||
get_test_input(100, 100), SlicingSpec(by_class=True),
|
||||
|
|
|
@ -14,12 +14,13 @@
|
|||
|
||||
from absl.testing import absltest
|
||||
import numpy as np
|
||||
|
||||
from tensorflow_privacy.privacy.privacy_tests import epsilon_lower_bound as elb
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack import privacy_report
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackResults
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackResultsCollection
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackType
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import DataSize
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import EpsilonLowerBoundValue
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import PrivacyReportMetadata
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import RocCurve
|
||||
from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import SingleAttackResult
|
||||
|
@ -39,8 +40,16 @@ class PrivacyReportTest(absltest.TestCase):
|
|||
tpr=np.array([0.0, 0.5, 1.0]),
|
||||
fpr=np.array([0.0, 0.5, 1.0]),
|
||||
thresholds=np.array([0, 1, 2]),
|
||||
test_train_ratio=1.0),
|
||||
data_size=DataSize(ntrain=1, ntest=1))
|
||||
test_train_ratio=1.0,
|
||||
),
|
||||
epsilon_lower_bound_value=EpsilonLowerBoundValue(
|
||||
bounds={
|
||||
elb.BoundMethod.KATZ_LOG: np.array([-2, -2.0]),
|
||||
elb.BoundMethod.ADJUSTED_LOG: np.array([]),
|
||||
}
|
||||
),
|
||||
data_size=DataSize(ntrain=1, ntest=1),
|
||||
)
|
||||
|
||||
# Classifier that achieves an AUC of 1.0.
|
||||
self.perfect_classifier_result = SingleAttackResult(
|
||||
|
@ -50,8 +59,16 @@ class PrivacyReportTest(absltest.TestCase):
|
|||
tpr=np.array([0.0, 1.0, 1.0]),
|
||||
fpr=np.array([1.0, 1.0, 0.0]),
|
||||
thresholds=np.array([0, 1, 2]),
|
||||
test_train_ratio=1.0),
|
||||
data_size=DataSize(ntrain=1, ntest=1))
|
||||
test_train_ratio=1.0,
|
||||
),
|
||||
epsilon_lower_bound_value=EpsilonLowerBoundValue(
|
||||
bounds={
|
||||
elb.BoundMethod.KATZ_LOG: np.array([-2, -2.0]),
|
||||
elb.BoundMethod.ADJUSTED_LOG: np.array([10, 1.0]),
|
||||
}
|
||||
),
|
||||
data_size=DataSize(ntrain=1, ntest=1),
|
||||
)
|
||||
|
||||
self.results_epoch_0 = AttackResults(
|
||||
single_attack_results=[self.imperfect_classifier_result],
|
||||
|
|
Loading…
Reference in a new issue