15
15
16
16
# pylint: disable=import-outside-toplevel, no-name-in-module, import-error
17
17
18
- def test_tf_eager ():
18
+ def test_tf_eager (random_seed ):
19
19
""" This is a basic eager example from keras.
20
20
"""
21
-
22
21
tf = pytest .importorskip ('tensorflow' )
22
+
23
+ tf .compat .v1 .random .set_random_seed (random_seed )
24
+ rs = np .random .RandomState (random_seed )
25
+
23
26
if version .parse (tf .__version__ ) >= version .parse ("2.4.0" ):
24
27
pytest .skip ("Deep explainer does not work for TF 2.4 in eager mode." )
25
28
26
- x = pd .DataFrame ({"B" : np . random .random (size = (100 ,))})
29
+ x = pd .DataFrame ({"B" : rs .random (size = (100 ,))})
27
30
y = x .B
28
31
y = y .map (lambda zz : chr (int (zz * 2 + 65 ))).str .get_dummies ()
29
32
@@ -39,10 +42,12 @@ def test_tf_eager():
39
42
assert np .abs (e .expected_value [0 ] + sv [0 ].sum (- 1 ) - model (x .values )[:, 0 ]).max () < 1e-4
40
43
41
44
42
- def test_tf_keras_mnist_cnn (): # pylint: disable=too-many-locals
45
+ def test_tf_keras_mnist_cnn (random_seed ):
43
46
""" This is the basic mnist cnn example from keras.
44
47
"""
45
48
tf = pytest .importorskip ('tensorflow' )
49
+ rs = np .random .RandomState (random_seed )
50
+ tf .compat .v1 .random .set_random_seed (random_seed )
46
51
47
52
from tensorflow import keras
48
53
from tensorflow .compat .v1 import ConfigProto , InteractiveSession
@@ -72,10 +77,10 @@ def test_tf_keras_mnist_cnn(): # pylint: disable=too-many-locals
72
77
73
78
# the data, split between train and test sets
74
79
# (x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
75
- x_train = np . random .randn (200 , 28 , 28 )
76
- y_train = np . random .randint (0 , 9 , 200 )
77
- x_test = np . random .randn (200 , 28 , 28 )
78
- y_test = np . random .randint (0 , 9 , 200 )
80
+ x_train = rs .randn (200 , 28 , 28 )
81
+ y_train = rs .randint (0 , 9 , 200 )
82
+ x_test = rs .randn (200 , 28 , 28 )
83
+ y_test = rs .randint (0 , 9 , 200 )
79
84
80
85
if K .image_data_format () == 'channels_first' :
81
86
x_train = x_train .reshape (x_train .shape [0 ], 1 , img_rows , img_cols )
@@ -119,8 +124,7 @@ def test_tf_keras_mnist_cnn(): # pylint: disable=too-many-locals
119
124
validation_data = (x_test [:10 , :], y_test [:10 , :]))
120
125
121
126
# explain by passing the tensorflow inputs and outputs
122
- np .random .seed (0 )
123
- inds = np .random .choice (x_train .shape [0 ], 3 , replace = False )
127
+ inds = rs .choice (x_train .shape [0 ], 3 , replace = False )
124
128
e = shap .DeepExplainer ((model .layers [0 ].input , model .layers [- 1 ].input ), x_train [inds , :, :])
125
129
shap_values = e .shap_values (x_test [:1 ])
126
130
@@ -136,6 +140,10 @@ def test_tf_keras_mnist_cnn(): # pylint: disable=too-many-locals
136
140
def test_tf_keras_linear ():
137
141
"""Test verifying that a linear model with linear data gives the correct result.
138
142
"""
143
+
144
+ # FIXME: this test should ideally pass with any random seed. See #2960
145
+ random_seed = 0
146
+
139
147
tf = pytest .importorskip ('tensorflow' )
140
148
141
149
from tensorflow .keras .layers import Dense , Input
@@ -144,14 +152,15 @@ def test_tf_keras_linear():
144
152
145
153
tf .compat .v1 .disable_eager_execution ()
146
154
147
- np .random .seed (0 )
155
+ tf .compat .v1 .random .set_random_seed (random_seed )
156
+ rs = np .random .RandomState (random_seed )
148
157
149
158
# coefficients relating y with x1 and x2.
150
159
coef = np .array ([1 , 2 ]).T
151
160
152
161
# generate data following a linear relationship
153
- x = np . random .normal (1 , 10 , size = (1000 , len (coef )))
154
- y = np .dot (x , coef ) + 1 + np . random .normal (scale = 0.1 , size = 1000 )
162
+ x = rs .normal (1 , 10 , size = (1000 , len (coef )))
163
+ y = np .dot (x , coef ) + 1 + rs .normal (scale = 0.1 , size = 1000 )
155
164
156
165
# create a linear model
157
166
inputs = Input (shape = (2 ,))
@@ -176,10 +185,12 @@ def test_tf_keras_linear():
176
185
np .testing .assert_allclose (expected - values , 0 , atol = 1e-5 )
177
186
178
187
179
- def test_tf_keras_imdb_lstm ():
188
+ def test_tf_keras_imdb_lstm (random_seed ):
180
189
""" Basic LSTM example using the keras API defined in tensorflow
181
190
"""
182
191
tf = pytest .importorskip ('tensorflow' )
192
+ rs = np .random .RandomState (random_seed )
193
+ tf .compat .v1 .random .set_random_seed (random_seed )
183
194
184
195
# this fails right now for new TF versions (there is a warning in the code for this)
185
196
if version .parse (tf .__version__ ) >= version .parse ("2.5.0" ):
@@ -193,7 +204,6 @@ def test_tf_keras_imdb_lstm():
193
204
tf .compat .v1 .disable_eager_execution ()
194
205
195
206
# load the data from keras
196
- np .random .seed (7 )
197
207
max_features = 1000
198
208
try :
199
209
(X_train , _ ), (X_test , _ ) = imdb .load_data (num_words = max_features )
@@ -211,7 +221,7 @@ def test_tf_keras_imdb_lstm():
211
221
mod .compile (loss = 'binary_crossentropy' , optimizer = 'adam' , metrics = ['accuracy' ])
212
222
213
223
# select the background and test samples
214
- inds = np . random .choice (X_train .shape [0 ], 3 , replace = False )
224
+ inds = rs .choice (X_train .shape [0 ], 3 , replace = False )
215
225
background = X_train [inds ]
216
226
testx = X_test [10 :11 ]
217
227
@@ -238,6 +248,12 @@ def test_pytorch_mnist_cnn():
238
248
from torch import nn
239
249
from torch .nn import functional as F
240
250
251
+ # FIXME: this test should ideally pass with any random seed. See #2960
252
+ random_seed = 0
253
+
254
+ torch .manual_seed (random_seed )
255
+ rs = np .random .RandomState (random_seed )
256
+
241
257
class RandData :
242
258
""" Random test data.
243
259
"""
@@ -315,8 +331,7 @@ def train(model, device, train_loader, optimizer, _, cutoff=20):
315
331
train (model , device , train_loader , optimizer , 1 )
316
332
317
333
next_x , _ = next (iter (train_loader ))
318
- np .random .seed (0 )
319
- inds = np .random .choice (next_x .shape [0 ], 3 , replace = False )
334
+ inds = rs .choice (next_x .shape [0 ], 3 , replace = False )
320
335
if interim :
321
336
e = shap .DeepExplainer ((model , model .conv_layers [0 ]), next_x [inds , :, :, :])
322
337
else :
@@ -349,7 +364,7 @@ def train(model, device, train_loader, optimizer, _, cutoff=20):
349
364
run_test (train_loader , test_loader , interim = False )
350
365
351
366
352
- def test_pytorch_custom_nested_models ():
367
+ def test_pytorch_custom_nested_models (random_seed ):
353
368
"""Testing single outputs
354
369
"""
355
370
torch = pytest .importorskip ('torch' )
@@ -359,6 +374,9 @@ def test_pytorch_custom_nested_models():
359
374
from torch .nn import functional as F
360
375
from torch .utils .data import DataLoader , TensorDataset
361
376
377
+ torch .manual_seed (random_seed )
378
+ rs = np .random .RandomState (random_seed )
379
+
362
380
X , y = fetch_california_housing (return_X_y = True )
363
381
num_features = X .shape [1 ]
364
382
data = TensorDataset (torch .tensor (X ).float (),
@@ -436,8 +454,7 @@ def train(model, device, train_loader, optimizer, epoch):
436
454
train (model , device , loader , optimizer , 1 )
437
455
438
456
next_x , _ = next (iter (loader ))
439
- np .random .seed (0 )
440
- inds = np .random .choice (next_x .shape [0 ], 20 , replace = False )
457
+ inds = rs .choice (next_x .shape [0 ], 20 , replace = False )
441
458
e = shap .DeepExplainer (model , next_x [inds , :])
442
459
test_x , _ = next (iter (loader ))
443
460
shap_values = e .shap_values (test_x [:1 ])
@@ -461,6 +478,11 @@ def test_pytorch_single_output():
461
478
from torch .nn import functional as F
462
479
from torch .utils .data import DataLoader , TensorDataset
463
480
481
+ # FIXME: this test should ideally pass with any random seed. See #2960
482
+ random_seed = 0
483
+ torch .manual_seed (random_seed )
484
+ rs = np .random .RandomState (random_seed )
485
+
464
486
X , y = fetch_california_housing (return_X_y = True )
465
487
num_features = X .shape [1 ]
466
488
data = TensorDataset (torch .tensor (X ).float (),
@@ -507,8 +529,7 @@ def train(model, device, train_loader, optimizer, epoch):
507
529
train (model , device , loader , optimizer , 1 )
508
530
509
531
next_x , _ = next (iter (loader ))
510
- np .random .seed (0 )
511
- inds = np .random .choice (next_x .shape [0 ], 20 , replace = False )
532
+ inds = rs .choice (next_x .shape [0 ], 20 , replace = False )
512
533
e = shap .DeepExplainer (model , next_x [inds , :])
513
534
test_x , _ = next (iter (loader ))
514
535
shap_values = e .shap_values (test_x [:1 ])
@@ -522,10 +543,12 @@ def train(model, device, train_loader, optimizer, epoch):
522
543
assert d / np .abs (diff ).sum () < 0.001 , "Sum of SHAP values does not match difference! %f" % (d / np .abs (diff ).sum ())
523
544
524
545
525
- def test_pytorch_multiple_inputs ():
546
+ def test_pytorch_multiple_inputs (random_seed ):
526
547
""" Check a multi-input scenario.
527
548
"""
528
549
torch = pytest .importorskip ('torch' )
550
+ torch .manual_seed (random_seed )
551
+ rs = np .random .RandomState (random_seed )
529
552
530
553
def _run_pytorch_multiple_inputs_test (disconnected ):
531
554
""" Testing multiple inputs
@@ -590,8 +613,7 @@ def train(model, device, train_loader, optimizer, epoch):
590
613
train (model , device , loader , optimizer , 1 )
591
614
592
615
next_x1 , next_x2 , _ = next (iter (loader ))
593
- np .random .seed (0 )
594
- inds = np .random .choice (next_x1 .shape [0 ], 20 , replace = False )
616
+ inds = rs .choice (next_x1 .shape [0 ], 20 , replace = False )
595
617
background = [next_x1 [inds , :], next_x2 [inds , :]]
596
618
e = shap .DeepExplainer (model , background )
597
619
test_x1 , test_x2 , _ = next (iter (loader ))
0 commit comments