Skip to content

Commit 59b2f99

Browse files
committed
Return worse result from num_iter runs, in addition to average.
Signed-off-by: abigailt <[email protected]>
1 parent 957dbfb commit 59b2f99

File tree

2 files changed

+28
-21
lines changed

2 files changed

+28
-21
lines changed

art/metrics/privacy/membership_leakage.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
This module implements membership leakage metrics.
2020
"""
2121
from __future__ import absolute_import, division, print_function, unicode_literals
22-
from typing import TYPE_CHECKING, Optional
22+
from typing import TYPE_CHECKING, Optional, Tuple
2323

2424
import numpy as np
2525
import scipy
@@ -37,7 +37,7 @@ def PDTP( # pylint: disable=C0103
3737
y: np.ndarray,
3838
indexes: Optional[np.ndarray] = None,
3939
num_iter: Optional[int] = 10,
40-
) -> np.ndarray:
40+
) -> Tuple[np.ndarray, np.ndarray]:
4141
"""
4242
Compute the pointwise differential training privacy metric for the given classifier and training set.
4343
@@ -52,8 +52,8 @@ def PDTP( # pylint: disable=C0103
5252
computed for all samples in `x`.
5353
:param num_iter: the number of iterations of PDTP computation to run for each sample. If not supplied,
5454
defaults to 10. The result is the average across iterations.
55-
:return: an array containing the average PDTP value for each sample in the training set. The higher the value,
56-
the higher the privacy leakage for that sample.
55+
:return: A tuple of two arrays, containing the average (worse) PDTP value for each sample in the training set
56+
respectively. The higher the value, the higher the privacy leakage for that sample.
5757
"""
5858
from art.estimators.classification.pytorch import PyTorchClassifier
5959
from art.estimators.classification.tensorflow import TensorFlowV2Classifier
@@ -120,6 +120,7 @@ def PDTP( # pylint: disable=C0103
120120
# We now have a list of list, internal lists represent an iteration. We need to transpose and get averages.
121121
per_sample = list(map(list, zip(*results)))
122122
avg_per_sample = np.array([sum(val) / len(val) for val in per_sample])
123+
worse_per_sample = np.max(per_sample, axis=1)
123124

124-
# return leakage per sample
125-
return avg_per_sample
125+
# return avg+worse leakage per sample
126+
return avg_per_sample, worse_per_sample

tests/metrics/privacy/test_membership_leakage.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,14 @@ def test_membership_leakage_decision_tree(art_warning, decision_tree_estimator,
3535
extra_classifier = decision_tree_estimator()
3636
(x_train, y_train), _ = get_iris_dataset
3737
prev = classifier.model.tree_
38-
leakage = PDTP(classifier, extra_classifier, x_train, y_train)
39-
logger.info("Average PDTP leakage: %.2f", (np.average(leakage)))
40-
logger.info("Max PDTP leakage: %.2f", (np.max(leakage)))
38+
avg_leakage, worse_leakage = PDTP(classifier, extra_classifier, x_train, y_train)
39+
logger.info("Average PDTP leakage: %.2f", (np.average(avg_leakage)))
40+
logger.info("Max PDTP leakage: %.2f", (np.max(avg_leakage)))
4141
assert classifier.model.tree_ == prev
42-
assert np.all(leakage >= 1.0)
43-
assert leakage.shape[0] == x_train.shape[0]
42+
assert np.all(avg_leakage >= 1.0)
43+
assert np.all(worse_leakage >= avg_leakage)
44+
assert avg_leakage.shape[0] == x_train.shape[0]
45+
assert worse_leakage.shape[0] == x_train.shape[0]
4446
except ARTTestException as e:
4547
art_warning(e)
4648

@@ -51,11 +53,13 @@ def test_membership_leakage_tabular(art_warning, tabular_dl_estimator, get_iris_
5153
classifier = tabular_dl_estimator()
5254
extra_classifier = tabular_dl_estimator()
5355
(x_train, y_train), _ = get_iris_dataset
54-
leakage = PDTP(classifier, extra_classifier, x_train, y_train)
55-
logger.info("Average PDTP leakage: %.2f", (np.average(leakage)))
56-
logger.info("Max PDTP leakage: %.2f", (np.max(leakage)))
57-
assert np.all(leakage >= 1.0)
58-
assert leakage.shape[0] == x_train.shape[0]
56+
avg_leakage, worse_leakage = PDTP(classifier, extra_classifier, x_train, y_train)
57+
logger.info("Average PDTP leakage: %.2f", (np.average(avg_leakage)))
58+
logger.info("Max PDTP leakage: %.2f", (np.max(avg_leakage)))
59+
assert np.all(avg_leakage >= 1.0)
60+
assert np.all(worse_leakage >= avg_leakage)
61+
assert avg_leakage.shape[0] == x_train.shape[0]
62+
assert worse_leakage.shape[0] == x_train.shape[0]
5963
except ARTTestException as e:
6064
art_warning(e)
6165

@@ -67,11 +71,13 @@ def test_membership_leakage_image(art_warning, image_dl_estimator, get_default_m
6771
extra_classifier, _ = image_dl_estimator()
6872
(x_train, y_train), _ = get_default_mnist_subset
6973
indexes = random.sample(range(x_train.shape[0]), 100)
70-
leakage = PDTP(classifier, extra_classifier, x_train, y_train, indexes=indexes, num_iter=1)
71-
logger.info("Average PDTP leakage: %.2f", (np.average(leakage)))
72-
logger.info("Max PDTP leakage: %.2f", (np.max(leakage)))
73-
assert np.all(leakage >= 1.0)
74-
assert leakage.shape[0] == len(indexes)
74+
avg_leakage, worse_leakage = PDTP(classifier, extra_classifier, x_train, y_train, indexes=indexes, num_iter=1)
75+
logger.info("Average PDTP leakage: %.2f", (np.average(avg_leakage)))
76+
logger.info("Max PDTP leakage: %.2f", (np.max(avg_leakage)))
77+
assert np.all(avg_leakage >= 1.0)
78+
assert np.all(worse_leakage >= avg_leakage)
79+
assert avg_leakage.shape[0] == x_train.shape[0]
80+
assert worse_leakage.shape[0] == x_train.shape[0]
7581
except ARTTestException as e:
7682
art_warning(e)
7783

0 commit comments

Comments
 (0)