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!
Finally it worked with:
hap.summary_plot(shap_values[0][:, 58, :], trainx[:0][:, 0, :], feature_names=features, plot_type="bar")