31
31
from sklearn .neighbors import KNeighborsClassifier
32
32
from sklearn .tree import DecisionTreeClassifier
33
33
from sklearn .svm import SVC
34
+ from sklearn .preprocessing import StandardScaler , MinMaxScaler , RobustScaler
34
35
35
36
from art .attacks .attack import MembershipInferenceAttack
36
37
from art .estimators .estimator import BaseEstimator
@@ -56,6 +57,10 @@ class MembershipInferenceBlackBox(MembershipInferenceAttack):
56
57
"input_type" ,
57
58
"attack_model_type" ,
58
59
"attack_model" ,
60
+ "scaler_type" ,
61
+ "nn_model_epochs" ,
62
+ "nn_model_batch_size" ,
63
+ "nn_model_learning_rate" ,
59
64
]
60
65
_estimator_requirements = (BaseEstimator , (ClassifierMixin , RegressorMixin ))
61
66
@@ -65,6 +70,7 @@ def __init__(
65
70
input_type : str = "prediction" ,
66
71
attack_model_type : str = "nn" ,
67
72
attack_model : Optional [Any ] = None ,
73
+ scaler_type : Optional [str ] = "standard" ,
68
74
nn_model_epochs : int = 100 ,
69
75
nn_model_batch_size : int = 100 ,
70
76
nn_model_learning_rate : float = 0.0001 ,
@@ -73,6 +79,9 @@ def __init__(
73
79
Create a MembershipInferenceBlackBox attack instance.
74
80
75
81
:param estimator: Target estimator.
82
+ :param input_type: the type of input to train the attack on. Can be one of: 'prediction' or 'loss'. Default is
83
+ `prediction`. Predictions can be either probabilities or logits, depending on the return type
84
+ of the model. If the model is a regressor, only `loss` can be used.
76
85
:param attack_model_type: the type of default attack model to train, optional. Should be one of:
77
86
`nn` (neural network, default),
78
87
`rf` (random forest),
@@ -82,10 +91,10 @@ def __init__(
82
91
`knn` (k nearest neighbors),
83
92
`svm` (support vector machine).
84
93
If `attack_model` is supplied, this option will be ignored.
85
- :param input_type: the type of input to train the attack on. Can be one of: 'prediction' or 'loss'. Default is
86
- `prediction`. Predictions can be either probabilities or logits, depending on the return type
87
- of the model. If the model is a regressor, only `loss` can be used.
88
94
:param attack_model: The attack model to train, optional. If none is provided, a default model will be created.
95
+ :param scaler_type: The type of scaling to apply to the input features to the attack. Can be one of: "standard",
96
+ "minmax", "robust" or None. If not None, the appropriate scaler from scikit-learn will be
97
+ applied. If None, no scaling will be applied.
89
98
:param nn_model_epochs: the number of epochs to use when training a nn attack model
90
99
:param nn_model_batch_size: the batch size to use when training a nn attack model
91
100
:param nn_model_learning_rate: the learning rate to use when training a nn attack model
@@ -95,6 +104,8 @@ def __init__(
95
104
self .input_type = input_type
96
105
self .attack_model_type = attack_model_type
97
106
self .attack_model = attack_model
107
+ self .scaler_type = scaler_type
108
+ self .scaler : Optional [Any ] = None
98
109
self .epochs = nn_model_epochs
99
110
self .batch_size = nn_model_batch_size
100
111
self .learning_rate = nn_model_learning_rate
@@ -245,13 +256,27 @@ def fit( # pylint: disable=W0613
245
256
if x_2 is None :
246
257
self .use_label = False
247
258
259
+ if self .scaler_type :
260
+ if self .scaler_type == "standard" :
261
+ self .scaler = StandardScaler ()
262
+ elif self .scaler_type == "minmax" :
263
+ self .scaler = MinMaxScaler ()
264
+ elif self .scaler_type == "robust" :
265
+ self .scaler = RobustScaler ()
266
+ else :
267
+ raise ValueError ("Illegal scaler_type: " , self .scaler_type )
268
+
248
269
if self .default_model and self .attack_model_type == "nn" :
249
270
import torch
250
271
from torch import nn
251
272
from torch import optim
252
273
from torch .utils .data import DataLoader
253
274
from art .utils import to_cuda
254
275
276
+ if self .scaler :
277
+ self .scaler .fit (x_1 )
278
+ x_1 = self .scaler .transform (x_1 )
279
+
255
280
if x_2 is not None :
256
281
257
282
class MembershipInferenceAttackModel (nn .Module ):
@@ -393,8 +418,15 @@ def forward(self, x_1):
393
418
else : # not nn
394
419
y_ready = check_and_transform_label_format (y_new , nb_classes = 2 , return_one_hot = False )
395
420
if x_2 is not None :
396
- self .attack_model .fit (np .c_ [x_1 , x_2 ], y_ready .ravel ()) # type: ignore
421
+ x = np .c_ [x_1 , x_2 ]
422
+ if self .scaler :
423
+ self .scaler .fit (x )
424
+ x = self .scaler .transform (x )
425
+ self .attack_model .fit (x , y_ready .ravel ()) # type: ignore
397
426
else :
427
+ if self .scaler :
428
+ self .scaler .fit (x_1 )
429
+ x_1 = self .scaler .transform (x_1 )
398
430
self .attack_model .fit (x_1 , y_ready .ravel ()) # type: ignore
399
431
400
432
def infer (self , x : np .ndarray , y : Optional [np .ndarray ] = None , ** kwargs ) -> np .ndarray :
@@ -467,6 +499,9 @@ def infer(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.n
467
499
from torch .utils .data import DataLoader
468
500
from art .utils import to_cuda , from_cuda
469
501
502
+ if self .scaler :
503
+ features = self .scaler .transform (features )
504
+
470
505
self .attack_model .eval () # type: ignore
471
506
predictions : Optional [np .ndarray ] = None
472
507
@@ -512,17 +547,27 @@ def infer(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.n
512
547
elif not self .default_model :
513
548
# assumes the predict method of the supplied model returns probabilities
514
549
if y is not None and self .use_label :
515
- inferred = self .attack_model .predict (np .c_ [features , y ]) # type: ignore
550
+ features = np .c_ [features , y ]
551
+ if self .scaler :
552
+ features = self .scaler .transform (features )
553
+ inferred = self .attack_model .predict (features ) # type: ignore
516
554
else :
555
+ if self .scaler :
556
+ features = self .scaler .transform (features )
517
557
inferred = self .attack_model .predict (features ) # type: ignore
518
558
if probabilities :
519
559
inferred_return = inferred
520
560
else :
521
561
inferred_return = np .round (inferred )
522
562
else :
523
563
if y is not None and self .use_label :
524
- inferred = self .attack_model .predict_proba (np .c_ [features , y ]) # type: ignore
564
+ features = np .c_ [features , y ]
565
+ if self .scaler :
566
+ features = self .scaler .transform (features )
567
+ inferred = self .attack_model .predict_proba (features ) # type: ignore
525
568
else :
569
+ if self .scaler :
570
+ features = self .scaler .transform (features )
526
571
inferred = self .attack_model .predict_proba (features ) # type: ignore
527
572
if probabilities :
528
573
inferred_return = inferred [:, [1 ]]
0 commit comments