Search code examples
pythontensorflowkeraslstmshap

SHAP TypeError: 'NoneType' object is not callable


I have a Keras Sequential Model with LSTM and want to analyse it with SHAP. The model runs, but when it comes to the SHAP block it terminates with a type error:

class ANN:                                                              
    ...
    def build_ann(self, nLayers=4, nNeurons=64, LR_init=1e-2, LR_adapt=1e-4, LR_steps=1e5, regularizer=1e-2, dropout=0.3):
        Neurons = np.ones(nLayers) * nNeurons
        Neurons.round()

        model = Sequential()
        for runs in range(nLayers):
            return_seq = True if runs < nLayers-1 else False
            model.add(LSTM(int(Neurons[runs]), return_sequences=return_seq))
            model.add(Dropout(dropout))
        model.add(Dense(int(Neurons[-1])))
        model.add(Dense(len(self.targets), activation='softmax'))
        model.compile(loss='categorical_crossentropy', optimizer='Adam', metrics=['categorical_accuracy'])  # custom optimizer: adamopt #loss relative metrik, accurcy absolute metrik
        model.build(input_shape=(1, self.maxlen, len(self.features)))  

        return model
        ...

features = ['finish','zt','e1','e2']
targets = ['f1','es1','r1','io']

train_dir = r"C:\Users\..."
val_dir = r"C:\Users.."

ann = ANN(features, targets, train_dir, val_dir)

validationsetx, validationsety, _ = ann.prepare_test()
trainx, trainy, _ = ann.prepare_samples(shuffle=True)

model = ann.build_ann(nLayers=3, nNeurons=30, dropout=0.0)

es = EarlyStopping(monitor='val_loss', patience=200, verbose=0, mode='min')
        
mc = ModelCheckpoint('best_m.h5', monitor='val_categorical_accuracy', mode='max', verbose=1, save_best_only=True)

# Convert validationsetx and validationsety to NumPy arrays
validationsetx = np.array(validationsetx)
validationsety = np.array(validationsety)

# Convert data types
validationsetx = validationsetx.astype(np.float32)
validationsety = validationsety.astype(np.int32)

history = model.fit(trainx, trainy, batch_size=5, epochs=100, validation_data=(validationsetx, validationsety), callbacks=[es, mc], verbose=1)

explainer = shap.Explainer(model)
shap_values = explainer(trainx)

Here is the exact error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
C:\Temp\ipykernel_18832\2421990028.py in 
      1 explainer = shap.Explainer(model)
----> 2 shap_values = explainer(trainx)

c:\Users\...\Anaconda3\lib\site-packages\shap\explainers\_permutation.py in __call__(self, max_evals, main_effects, error_bounds, batch_size, outputs, silent, *args)
     74         """ Explain the output of the model on the given arguments.
     75         """
---> 76         return super().__call__(
     77             *args, max_evals=max_evals, main_effects=main_effects, error_bounds=error_bounds, batch_size=batch_size,
     78             outputs=outputs, silent=silent

c:\Users\...\Anaconda3\lib\site-packages\shap\explainers\_explainer.py in __call__(self, max_evals, main_effects, error_bounds, batch_size, outputs, silent, *args, **kwargs)
    262             feature_names = [[] for _ in range(len(args))]
    263         for row_args in show_progress(zip(*args), num_rows, self.__class__.__name__+" explainer", silent):
--> 264             row_result = self.explain_row(
    265                 *row_args, max_evals=max_evals, main_effects=main_effects, error_bounds=error_bounds,
    266                 batch_size=batch_size, outputs=outputs, silent=silent, **kwargs

c:\Users\...\Anaconda3\lib\site-packages\shap\explainers\_permutation.py in explain_row(self, max_evals, main_effects, error_bounds, batch_size, outputs, silent, *row_args)
    132 
    133                 # evaluate the masked model
--> 134                 outputs = fm(masks, zero_index=0, batch_size=batch_size)
    135 
    136                 if row_values is None:

c:\Users\...\Anaconda3\lib\site-packages\shap\utils\_masked_model.py in __call__(self, masks, zero_index, batch_size)
     64                 full_masks = np.zeros((int(np.sum(masks >= 0)), self._masker_cols), dtype=bool)
     65                 _convert_delta_mask_to_full(masks, full_masks)
---> 66                 return self._full_masking_call(full_masks, zero_index=zero_index, batch_size=batch_size)
     67 
     68         else:

c:\Users\...\Anaconda3\lib\site-packages\shap\utils\_masked_model.py in _full_masking_call(self, masks, zero_index, batch_size)
     93                     masked_inputs = self.masker(delta_ind, *self.args).copy()
     94                 else:
---> 95                     masked_inputs = self.masker(mask, *self.args)
     96 
     97                 # get a copy that won't get overwritten by the next iteration

TypeError: 'NoneType' object is not callable

This error has been discussed several times but there was no satisfactory solution for me. Maybe someone sees a reason for the NoneType Error.

I was able to calculate the shap.vales using the older DeepExplainer:

import tensorflow as tf
tf.compat.v1.disable_v2_behavior()

import shap
explainer = shap.DeepExplainer(model, trainx)
shap_values = explainer.shap_values(trainx)

Your TensorFlow version is newer than 2.4.0 and so graph support has been removed in eager mode and some static graphs may not be supported. See PR #1483 for discussion.

But now I have a problem plotting them:

shap.plots.bar(shap_values)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
C:\Temp\ipykernel_19396\2444369755.py in 
----> 1 shap.plots.bar(shap_values)

c:\Users\aalles\Anaconda3\lib\site-packages\shap\plots\_bar.py in bar(shap_values, max_display, order, clustering, clustering_cutoff, merge_cohorts, show_data, show)
     63             "object, or dictionary of Explanation objects!"
     64         )
---> 65         raise TypeError(emsg)
     66 
     67     # unpack our list of Explanation objects we need to plot

TypeError: The shap_values argument must be an Explanation object, Cohorts object, or dictionary of Explanation objects!

Solution

  • Finally it worked with:

    hap.summary_plot(shap_values[0][:, 58, :], trainx[:0][:, 0, :], feature_names=features, plot_type="bar")
    

    enter image description here