You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SHAP解释含1D CNN的模型时遇LookupError问题求助

1D CNN模型SHAP解释器选择问题

我的数据集维度为(样本数, 186, 1),尝试用KernelExplainer失败,论坛说它不支持2维以上数据,改用DeepExplainer后报错。

1D CNN模型代码

cnn = Sequential()
cnn.add(Conv1D(128,3,input_shape=(x_train.shape[1],1), activation='relu'))
cnn.add(BatchNormalization())
cnn.add(MaxPooling1D(pool_size=2))
cnn.add(Conv1D(64,3, activation='relu'))
cnn.add(BatchNormalization())
cnn.add(MaxPooling1D(pool_size=2))
cnn.add(Conv1D(64,2, activation='relu'))
cnn.add(BatchNormalization())
cnn.add(MaxPooling1D(pool_size=2))
cnn.add(Conv1D(64,2, activation='relu'))
cnn.add(Flatten())
cnn.add(Dense(128, activation='relu'))
cnn.add(Dropout(0.5))
cnn.add(Dense(64, activation='relu'))
cnn.add(Dense(5, activation='softmax'))

运行的SHAP代码

import shap
data = x_train[np.random.choice(x_train.shape[0], 50, replace=False)]

S1 = shap.DeepExplainer((cnn.layers[0].input, cnn.layers[-1].output), data)
ShapValues = S1.shap_values(x_test[1:20], check_additivity=False)

报错信息

StagingError                              Traceback (most recent call last)
<ipython-input-110-e8372a4a287b> in <module>
      6 #calculating SHAP Values
      7 #Return approximate SHAP values for the model applied to the data given by X.
----> 8 ShapValues = S1.shap_values(x_test[1:20], check_additivity=False)

/opt/conda/lib/python3.7/site-packages/shap/explainers/_deep/__init__.py in shap_values(self, X, ranked_outputs, output_rank_order, check_additivity)
    122             were chosen as "top".
    123         """
--> 124         return self.explainer.shap_values(X, ranked_outputs, output_rank_order, check_additivity=check_additivity)

/opt/conda/lib/python3.7/site-packages/shap/explainers/_deep/deep_tf.py in shap_values(self, X, ranked_outputs, output_rank_order, check_additivity)
    306                 # run attribution computation graph
    307                 feature_ind = model_output_ranks[j,i]
--> 308                 sample_phis = self.run(self.phi_symbolic(feature_ind), self.model_inputs, joint_input)
    309 
    310                 # assign the attributions to the right part of the output arrays

/opt/conda/lib/python3.7/site-packages/shap/explainers/_deep/deep_tf.py in run(self, out, model_inputs, X)
    363 
    364                 return final_out
--> 365             return self.execute_with_overridden_gradients(anon)
    366 
    367     def custom_grad(self, op, *grads):

/opt/conda/lib/python3.7/site-packages/shap/explainers/_deep/deep_tf.py in execute_with_overridden_gradients(self, f)
    399         # define the computation graph for the attribution values using a custom gradient-like computation
    400         try:
--> 401             out = f()
    402         finally:
    403             # reinstate the backpropagatable check

/opt/conda/lib/python3.7/site-packages/shap/explainers/_deep/deep_tf.py in anon()
    359                     v = tf.constant(data, dtype=self.model_inputs[i].dtype)
    360                     inputs.append(v)
--> 361                 final_out = out(inputs)
    362                 tf_execute.record_gradient = tf_backprop._record_gradient
    363 

/opt/conda/lib/python3.7/site-packages/tensorflow/python/eager/def_function.py in __call__(self, *args, **kwds)
    826     tracing_count = self.experimental_get_tracing_count()
    827     with trace.Trace(self._name) as tm:
--> 828       result = self._call(*args, **kwds)
    829       compiler = "xla" if self._experimental_compile else "nonXla"
    830       new_tracing_count = self.experimental_get_tracing_count()

/opt/conda/lib/python3.7/site-packages/tensorflow/python/eager/def_function.py in _call(self, *args, **kwds)
    869       # This is the first call of __call__, so we have to initialize.
    870       initializers = []
--> 871       self._initialize(args, kwds, add_initializers_to=initializers)
    872     finally:
    873       # At this point we know that the initialization is complete (or less

/opt/conda/lib/python3.7/site-packages/tensorflow/python/eager/def_function.py in _initialize(self, args, kwds, add_initializers_to)
    724     self._concrete_stateful_fn = (
    725         self._stateful_fn._get_concrete_function_internal_garbage_collected(  # pylint: disable=protected-access
--> 726             *args, **kwds))
    727 
    728     def invalid_creator_scope(*unused_args, **unused_kwds):

/opt/conda/lib/python3.7/site-packages/tensorflow/python/eager/function.py in _get_concrete_function_internal_garbage_collected(self, *args, **kwargs)
   2967       args, kwargs = None, None
   2968     with self._lock:
-> 2969       graph_function, _ = self._maybe_define_function(args, kwargs)
   2970     return graph_function
   2971 

/opt/conda/lib/python3.7/site-packages/tensorflow/python/eager/function.py in _maybe_define_function(self, args, kwargs)
   3359 
   3360           self._function_cache.missed.add(call_context_key)
-> 3361           graph_function = self._create_graph_function(args, kwargs)
   3362           self._function_cache.primary[cache_key] = graph_function
   3363 

/opt/conda/lib/python3.7/site-packages/tensorflow/python/eager/function.py in _create_graph_function(self, args, kwargs, override_flat_arg_shapes)
   3204             arg_names=arg_names,
   3205             override_flat_arg_shapes=override_flat_arg_shapes,
-> 3206             capture_by_value=self._capture_by_value),
   3207         self._function_attributes,
   3208         function_spec=self.function_spec,

/opt/conda/lib/python3.7/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)
    988         _, original_func = tf_decorator.unwrap(python_func)
    989 
-> 990       func_outputs = python_func(*func_args, **func_kwargs)
    991 
    992       # invariant: `func_outputs` contains only Tensors, CompositeTensors,

/opt/conda/lib/python3.7/site-packages/tensorflow/python/eager/def_function.py in wrapped_fn(*args, **kwds)
    632             xla_context.Exit()
    633         else:
-> 634           out = weak_wrapped_fn().__wrapped__(*args, **kwds)
    635         return out
    636 

/opt/conda/lib/python3.7/site-packages/tensorflow/python/framework/func_graph.py in wrapper(*args, **kwargs)
    975           except Exception as e:  # pylint:disable=broad-except
    976             if hasattr(e, "ag_error_metadata"):
-> 977               raise e.ag_error_metadata.to_exception(e)
    978             else:
    979               raise

StagingError: in user code

    opt/conda/lib/python3.7/site-packages/shap/explainers/_deep/deep_tf.py:248 grad_graph  *
        x_grad = tape.gradient(out, shap_rAnD)
    /opt/conda/lib/python3.7/site-packages/tensorflow/python/eager/backprop.py:1086 gradient  **
        unconnected_gradients=unconnected_gradients)
    /opt/conda/lib/python3.7/site-packages/tensorflow/python/eager/imperative_grad.py:77 imperative_grad
        compat.as_str(unconnected_gradients.value))
    /opt/conda/lib/python3.7/site-packages/tensorflow/python/eager/backprop.py:151 _gradient_function
        grad_fn = ops._gradient_registry.lookup(op_name)  # pylint: disable=protected-access
    /opt/conda/lib/python3.7/site-packages/tensorflow/python/framework/registry.py:99 lookup
        %s registry has no entry for: %s" % (self._name, name))

LookupError: gradient registry has no entry for: shap_AddV2

DeepExplainer在图像任务可正常运行,但这个1D CNN任务报错,请求推荐适合的SHAP解释器。


推荐方案

针对你的1D CNN和3维输入数据,推荐以下几种可行的SHAP解释器:

1. PermutationExplainer

  • 适用场景:几乎所有模型类型,包括你的1D CNN,对输入维度没有严格限制
  • 核心逻辑:通过随机打乱特征维度来计算特征的重要性,本质是基于模型预测变化的近似SHAP值
  • 使用方式示例:
import shap

# 取背景数据集
background = x_train[np.random.choice(x_train.shape[0], 50, replace=False)]
explainer = shap.PermutationExplainer(cnn.predict, background)
shap_values = explainer.shap_values(x_test[1:20])
  • 注意:计算速度比梯度类解释器慢,但稳定性高,适合中小规模数据集。

2. GradientExplainer(替代DeepExplainer)

  • 适用场景:基于梯度的深度学习模型解释,支持1D CNN的3维输入
  • 核心逻辑:和DeepExplainer同属梯度类,但实现方式不同,部分场景下能避免shap_AddV2这类算子注册问题
  • 使用方式示例:
import shap

background = x_train[np.random.choice(x_train.shape[0], 50, replace=False)]
explainer = shap.GradientExplainer(cnn, background)
shap_values = explainer.shap_values(x_test[1:20])

3. 修改输入维度适配KernelExplainer

  • 如果你仍想使用KernelExplainer,可以将3维输入(样本数,186,1)压缩为2维(样本数,186),去掉最后一个维度,然后直接用KernelExplainer:
import shap

# 压缩维度
x_train_2d = x_train.reshape(-1, 186)
x_test_2d = x_test.reshape(-1, 186)

background = x_train_2d[np.random.choice(x_train_2d.shape[0], 50, replace=False)]
explainer = shap.KernelExplainer(cnn.predict, background)
shap_values = explainer.shap_values(x_test_2d[1:20])
  • 注意:需要确保模型预测时能处理2维输入,或者额外写一个包装函数,在预测前将2维数据恢复为3维:
def predict_wrapper(x):
    return cnn.predict(x.reshape(-1, 186, 1))

explainer = shap.KernelExplainer(predict_wrapper, background)

内容的提问来源于stack exchange,提问作者sandun herath

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 08:15:55