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,29 @@ def fit( # pylint: disable=W0613
245
256
if x_2 is None :
246
257
self .use_label = False
247
258
259
+ scaler : Optional [Any ] = None
260
+ if self .scaler_type :
261
+ if self .scaler_type == "standard" :
262
+ self .scaler = StandardScaler ()
263
+ elif self .scaler_type == "minmax" :
264
+ self .scaler = MinMaxScaler ()
265
+ elif self .scaler_type == "robust" :
266
+ self .scaler = RobustScaler ()
267
+ else :
268
+ raise ValueError ("Illegal scaler_type: " , self .scaler_type )
269
+
270
+
248
271
if self .default_model and self .attack_model_type == "nn" :
249
272
import torch
250
273
from torch import nn
251
274
from torch import optim
252
275
from torch .utils .data import DataLoader
253
276
from art .utils import to_cuda
254
277
278
+ if self .scaler :
279
+ self .scaler .fit (x_1 )
280
+ x_1 = self .scaler .transform (x_1 )
281
+
255
282
if x_2 is not None :
256
283
257
284
class MembershipInferenceAttackModel (nn .Module ):
@@ -393,8 +420,15 @@ def forward(self, x_1):
393
420
else : # not nn
394
421
y_ready = check_and_transform_label_format (y_new , nb_classes = 2 , return_one_hot = False )
395
422
if x_2 is not None :
396
- self .attack_model .fit (np .c_ [x_1 , x_2 ], y_ready .ravel ()) # type: ignore
423
+ x = np .c_ [x_1 , x_2 ]
424
+ if self .scaler :
425
+ self .scaler .fit (x )
426
+ x = self .scaler .transform (x )
427
+ self .attack_model .fit (x , y_ready .ravel ()) # type: ignore
397
428
else :
429
+ if self .scaler :
430
+ self .scaler .fit (x_1 )
431
+ x_1 = self .scaler .transform (x_1 )
398
432
self .attack_model .fit (x_1 , y_ready .ravel ()) # type: ignore
399
433
400
434
def infer (self , x : np .ndarray , y : Optional [np .ndarray ] = None , ** kwargs ) -> np .ndarray :
@@ -467,6 +501,9 @@ def infer(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.n
467
501
from torch .utils .data import DataLoader
468
502
from art .utils import to_cuda , from_cuda
469
503
504
+ if self .scaler :
505
+ features = self .scaler .transform (features )
506
+
470
507
self .attack_model .eval () # type: ignore
471
508
predictions : Optional [np .ndarray ] = None
472
509
@@ -512,17 +549,27 @@ def infer(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.n
512
549
elif not self .default_model :
513
550
# assumes the predict method of the supplied model returns probabilities
514
551
if y is not None and self .use_label :
515
- inferred = self .attack_model .predict (np .c_ [features , y ]) # type: ignore
552
+ features = np .c_ [features , y ]
553
+ if self .scaler :
554
+ features = self .scaler .transform (features )
555
+ inferred = self .attack_model .predict (features ) # type: ignore
516
556
else :
557
+ if self .scaler :
558
+ features = self .scaler .transform (features )
517
559
inferred = self .attack_model .predict (features ) # type: ignore
518
560
if probabilities :
519
561
inferred_return = inferred
520
562
else :
521
563
inferred_return = np .round (inferred )
522
564
else :
523
565
if y is not None and self .use_label :
524
- inferred = self .attack_model .predict_proba (np .c_ [features , y ]) # type: ignore
566
+ features = np .c_ [features , y ]
567
+ if self .scaler :
568
+ features = self .scaler .transform (features )
569
+ inferred = self .attack_model .predict_proba (features ) # type: ignore
525
570
else :
571
+ if self .scaler :
572
+ features = self .scaler .transform (features )
526
573
inferred = self .attack_model .predict_proba (features ) # type: ignore
527
574
if probabilities :
528
575
inferred_return = inferred [:, [1 ]]
0 commit comments