1919This module implements membership leakage metrics.
2020"""
2121from __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
2424import numpy as np
2525import scipy
2626
27- from art .utils import check_and_transform_label_format , is_probability
27+ from art .utils import check_and_transform_label_format , is_probability_array
2828
2929if TYPE_CHECKING :
3030 from art .estimators .classification .classifier import Classifier
@@ -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 , 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 three arrays, containing the average (worse, standard deviation) PDTP value for each sample in
56+ the training set 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
@@ -77,14 +77,15 @@ def PDTP( # pylint: disable=C0103
7777 iter_results = []
7878 # get probabilities from original model
7979 pred = target_estimator .predict (x )
80- if not is_probability (pred ):
80+ if not is_probability_array (pred ):
8181 try :
8282 pred = scipy .special .softmax (pred , axis = 1 )
8383 except Exception as exc : # pragma: no cover
8484 raise ValueError ("PDTP metric only supports classifiers that output logits or probabilities." ) from exc
8585 # divide into 100 bins and return center of bin
8686 bins = np .array (np .arange (0.0 , 1.01 , 0.01 ).round (decimals = 2 ))
8787 pred_bin_indexes = np .digitize (pred , bins )
88+ pred_bin_indexes [pred_bin_indexes == 101 ] = 100
8889 pred_bin = bins [pred_bin_indexes ] - 0.005
8990
9091 if not indexes :
@@ -102,10 +103,11 @@ def PDTP( # pylint: disable=C0103
102103 extra_estimator .fit (alt_x , alt_y )
103104 # get probabilities from new model
104105 alt_pred = extra_estimator .predict (x )
105- if not is_probability (alt_pred ):
106+ if not is_probability_array (alt_pred ):
106107 alt_pred = scipy .special .softmax (alt_pred , axis = 1 )
107108 # divide into 100 bins and return center of bin
108109 alt_pred_bin_indexes = np .digitize (alt_pred , bins )
110+ alt_pred_bin_indexes [alt_pred_bin_indexes == 101 ] = 100
109111 alt_pred_bin = bins [alt_pred_bin_indexes ] - 0.005
110112 ratio_1 = pred_bin / alt_pred_bin
111113 ratio_2 = alt_pred_bin / pred_bin
@@ -118,6 +120,8 @@ def PDTP( # pylint: disable=C0103
118120 # We now have a list of list, internal lists represent an iteration. We need to transpose and get averages.
119121 per_sample = list (map (list , zip (* results )))
120122 avg_per_sample = np .array ([sum (val ) / len (val ) for val in per_sample ])
123+ worse_per_sample = np .max (per_sample , axis = 1 )
124+ std_dev_per_sample = np .std (per_sample , axis = 1 )
121125
122- # return leakage per sample
123- return avg_per_sample
126+ # return avg+worse leakage + standard deviation per sample
127+ return avg_per_sample , worse_per_sample , std_dev_per_sample
0 commit comments