6

In the code below, I import a saved sparse numpy matrix, created with python, densify it, add a masking, batchnorm and dense ouptput layer to a many to one SimpleRNN. The keras sequential model works fine, however, I am unable to use shap. This is run in Jupyter lab from Winpython 3830 on a Windows 10 desktop. The X matrix has a shape of (4754, 500, 64): 4754 examples with 500 timesteps and 64 variables. I've created a function to simulate the data so the code can be tested. The simulated data returns the same error.

from sklearn.model_selection import train_test_split import tensorflow as tf from tensorflow.keras.models import Sequential import tensorflow.keras.backend as Kb from tensorflow.keras import layers from tensorflow.keras.layers import BatchNormalization from tensorflow import keras as K import numpy as np import shap import random def create_x(): dims = [10,500,64] data = [] y = [] for i in range(dims[0]): data.append([]) for j in range(dims[1]): data[i].append([]) for k in range(dims[2]): isnp = random.random() if isnp > .2: data[i][j].append(np.nan) else: data[i][j].append(random.random()) if isnp > .5: y.append(0) else: y.append(1) return np.asarray(data), np.asarray(y) def first_valid(arr, axis, invalid_val=0): #return the 2nd index of 3 for the first non np.nan on the 3rd axis mask = np.invert(np.isnan(arr)) return np.where(mask.any(axis=axis), mask.argmax(axis=axis), invalid_val) def densify_np(X): X_copy = np.empty_like (X) X_copy[:] = X #loop over the first index for i in range(len(X_copy)): old_row = [] #get the 2nd index of the first valid value for each 3rd index indices = first_valid(X_copy[i,:,:],axis=0, invalid_val=0) for j in range(len(indices)): if np.isnan(X_copy[i,indices[j],j]): old_row.append(0) else: old_row.append(X_copy[i,indices[j],j]) X_copy[i,0,:]= old_row for k in range(1,len(X_copy[i,:])): for l in range(len(X_copy[i,k,:])): if np.isnan(X_copy[i,k,l]): X_copy[i,k,l] = X_copy[i,k-1,l] return(X_copy) #this is what I do in the actual code #X = np.load('C:/WinPython/WPy64-3830/data/X.npy') #Y = np.load('C:/WinPython/WPy64-3830/scripts/Y.npy') #simulated junk data X, Y = create_x() #create a dense matrix from the sparse one. X = densify_np(X) seed = 7 np.random.seed(seed) array_size = 64 X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.33, random_state=seed) batch = 64 model = Sequential() model.add(layers.Input(shape=(500,array_size))) model.add(layers.Masking(mask_value=0.,input_shape=(500, array_size))) model.add(BatchNormalization()) model.add(layers.SimpleRNN(1, activation=None, dropout = 0, recurrent_dropout=.2)) model.add(layers.Dense(1, activation = 'sigmoid')) opt = K.optimizers.Adam(learning_rate=.001) model.compile(loss='binary_crossentropy', optimizer=opt) model.fit(X_train, y_train.astype(int), validation_data=(X_test,y_test.astype(int)), epochs=25, batch_size=batch) explainer = shap.DeepExplainer(model, X_test) shap_values = explainer.shap_values(X_train) 

Running the last line to create the shap_values yields the error below.

StagingError Traceback (most recent call last) <ipython-input-6-f789203da9c8> in <module> 1 import shap 2 explainer = shap.DeepExplainer(model, X_test) ----> 3 shap_values = explainer.shap_values(X_train) 4 print('done') C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\shap\explainers\deep\__init__.py in shap_values(self, X, ranked_outputs, output_rank_order, check_additivity) 117 were chosen as "top". 118 """ --> 119 return self.explainer.shap_values(X, ranked_outputs, output_rank_order, check_additivity=check_additivity) C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\shap\explainers\deep\deep_tf.py in shap_values(self, X, ranked_outputs, output_rank_order, check_additivity) 302 # run attribution computation graph 303 feature_ind = model_output_ranks[j,i] --> 304 sample_phis = self.run(self.phi_symbolic(feature_ind), self.model_inputs, joint_input) 305 306 # assign the attributions to the right part of the output arrays C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\shap\explainers\deep\deep_tf.py in run(self, out, model_inputs, X) 359 360 return final_out --> 361 return self.execute_with_overridden_gradients(anon) 362 363 def custom_grad(self, op, *grads): C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\shap\explainers\deep\deep_tf.py in execute_with_overridden_gradients(self, f) 395 # define the computation graph for the attribution values using a custom gradient-like computation 396 try: --> 397 out = f() 398 finally: 399 # reinstate the backpropagatable check C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\shap\explainers\deep\deep_tf.py in anon() 355 v = tf.constant(data, dtype=self.model_inputs[i].dtype) 356 inputs.append(v) --> 357 final_out = out(inputs) 358 tf_execute.record_gradient = tf_backprop._record_gradient 359 C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\tensorflow\python\eager\def_function.py in __call__(self, *args, **kwds) 778 else: 779 compiler = "nonXla" --> 780 result = self._call(*args, **kwds) 781 782 new_tracing_count = self._get_tracing_count() C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\tensorflow\python\eager\def_function.py in _call(self, *args, **kwds) 821 # This is the first call of __call__, so we have to initialize. 822 initializers = [] --> 823 self._initialize(args, kwds, add_initializers_to=initializers) 824 finally: 825 # At this point we know that the initialization is complete (or less C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\tensorflow\python\eager\def_function.py in _initialize(self, args, kwds, add_initializers_to) 694 self._graph_deleter = FunctionDeleter(self._lifted_initializer_graph) 695 self._concrete_stateful_fn = ( --> 696 self._stateful_fn._get_concrete_function_internal_garbage_collected( # pylint: disable=protected-access 697 *args, **kwds)) 698 C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\tensorflow\python\eager\function.py in _get_concrete_function_internal_garbage_collected(self, *args, **kwargs) 2853 args, kwargs = None, None 2854 with self._lock: -> 2855 graph_function, _, _ = self._maybe_define_function(args, kwargs) 2856 return graph_function 2857 C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\tensorflow\python\eager\function.py in _maybe_define_function(self, args, kwargs) 3211 3212 self._function_cache.missed.add(call_context_key) -> 3213 graph_function = self._create_graph_function(args, kwargs) 3214 self._function_cache.primary[cache_key] = graph_function 3215 return graph_function, args, kwargs C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\tensorflow\python\eager\function.py in _create_graph_function(self, args, kwargs, override_flat_arg_shapes) 3063 arg_names = base_arg_names + missing_arg_names 3064 graph_function = ConcreteFunction( -> 3065 func_graph_module.func_graph_from_py_func( 3066 self._name, 3067 self._python_function, C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\tensorflow\python\framework\func_graph.py in func_graph_from_py_func(name, python_func, args, kwargs, signature, func_graph, autograph, autograph_options, add_control_dependencies, arg_names, op_return_value, collections, capture_by_value, override_flat_arg_shapes) 984 _, original_func = tf_decorator.unwrap(python_func) 985 --> 986 func_outputs = python_func(*func_args, **func_kwargs) 987 988 # invariant: `func_outputs` contains only Tensors, CompositeTensors, C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\tensorflow\python\eager\def_function.py in wrapped_fn(*args, **kwds) 598 # __wrapped__ allows AutoGraph to swap in a converted function. We give 599 # the function a weak reference to itself to avoid a reference cycle. --> 600 return weak_wrapped_fn().__wrapped__(*args, **kwds) 601 weak_wrapped_fn = weakref.ref(wrapped_fn) 602 C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\tensorflow\python\framework\func_graph.py in wrapper(*args, **kwargs) 971 except Exception as e: # pylint:disable=broad-except 972 if hasattr(e, "ag_error_metadata"): --> 973 raise e.ag_error_metadata.to_exception(e) 974 else: 975 raise StagingError: in user code: C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\shap\explainers\deep\deep_tf.py:244 grad_graph * x_grad = tape.gradient(out, shap_rAnD) C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\tensorflow\python\eager\backprop.py:1067 gradient ** flat_grad = imperative_grad.imperative_grad( C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\tensorflow\python\eager\imperative_grad.py:71 imperative_grad return pywrap_tfe.TFE_Py_TapeGradient( C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\tensorflow\python\eager\backprop.py:151 _gradient_function grad_fn = ops._gradient_registry.lookup(op_name) # pylint: disable=protected-access C:\WinPython\WPy64-3830\python-3.8.3.amd64\lib\site-packages\tensorflow\python\framework\registry.py:96 lookup raise LookupError( LookupError: gradient registry has no entry for: shap_TensorListStack 
4
  • 1
    Seems to be a frequent issue, see e.g. #1110 or #1490. Commented Oct 19, 2020 at 16:49
  • I've seen those issues. My code generates the same error with the masking and batchnorm removed. Commented Oct 19, 2020 at 16:57
  • 1
    what is your shap, tensorflow and keras version? Commented Oct 24, 2020 at 14:24
  • shap 0.35.0, tensoflow 2.3.0. Keras 2.3.1 Commented Oct 26, 2020 at 14:28

1 Answer 1

4
+50

The owner of the shap repo said:

The fundamental issue here is that DeepExplainer does not yet support TF 2.0.

That was on 11 Dec 2019. Is this still the case? Try it with Tensorflow 1.15 and see if that works.

Another issue on the shap repo about this (2 Jun 2020) says:

Alright, thank you. I did not see the post by Lundberg. I will stick to the workaround of using TF 1.15 until a new version of SHAP is released.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.