使用LIME解释带Sigmoid输出的二分类DNN模型时的问题
解决Keras二分类DNN结合LIME解释的概率输出问题
问题背景
要给输出层为单神经元+Sigmoid激活的二分类DNN模型用LIME做结果解释,遇到两个核心问题:
- Keras Sequential模型没有
predict_proba方法,自带的predict方法被误以为只输出0/1(实际是正类概率) - 自定义的概率转换函数返回3D数组,导致LIME的
explain_instance报错
错误原因分析
- 关于
predict方法的误解:Keras中Sigmoid输出的二分类模型,predict方法返回的是每个样本属于正类的概率(形状为(n_samples, 1)的2D数组),并非直接输出0/1的硬分类结果,除非手动添加了阈值判断(比如predict(data) > 0.5)。 - 3D数组的由来:之前写的
prob函数中,model.predict(data)返回(n_samples,1)的数组,用zip(1-model.predict(data), model.predict(data))会生成每个元素为两个长度为1的数组的迭代器,转成np.array后就变成了(n_samples, 2, 1)的3D数组,而LIME要求输入的概率是(n_samples, 2)的2D数组(每个样本对应两个类别的概率)。
解决方案
1. 修正概率转换函数
将predict返回的2D数组压平为1D,再与1-概率拼接成符合LIME要求的2D数组:
def custom_predict_proba(data): # 获取正类概率,从(n_samples,1)压平为(n_samples,) pos_probs = DNN.predict(data).flatten() # 拼接负类概率和正类概率,得到(n_samples,2)的数组 return np.column_stack((1 - pos_probs, pos_probs))
2. 修正LIME Explainer初始化
LIME的LimeTabularExplainer应该使用训练数据初始化,保证解释时的数据分布与模型训练一致,避免用测试数据初始化:
explainer = lime_tabular.LimeTabularExplainer( training_data=np.array(nsl_kdd_train_X2), feature_names=nsl_kdd_data_X2.columns, class_names=['normal', 'anomaly'], mode="classification", verbose=True )
完整修正代码
import tensorflow as tf import numpy as np from lime import lime_tabular # 构建并训练DNN模型 DNN = tf.keras.models.Sequential([ tf.keras.layers.Input(121), tf.keras.layers.Dense(182, activation='relu'), tf.keras.layers.Dropout(0.2), tf.keras.layers.Dense(182, activation='relu'), tf.keras.layers.Dense(1, activation='sigmoid') ]) DNN.compile(optimizer='adam', loss="binary_crossentropy", metrics=['accuracy']) DNN_trained = DNN.fit(nsl_kdd_train_X2, nsl_kdd_train_Y2, epochs=5) # 自定义符合LIME要求的概率预测函数 def custom_predict_proba(data): pos_probs = DNN.predict(data).flatten() return np.column_stack((1 - pos_probs, pos_probs)) # 初始化LIME解释器 explainer = lime_tabular.LimeTabularExplainer( training_data=np.array(nsl_kdd_train_X2), feature_names=nsl_kdd_data_X2.columns, class_names=['normal', 'anomaly'], mode="classification", verbose=True ) # 对测试集中的样本进行解释 explanation = explainer.explain_instance( nsl_kdd_test_X2.iloc[1], # 注意:如果是DataFrame需要用iloc取行,避免索引问题 custom_predict_proba, num_features=len(nsl_kdd_data_X2.columns) ) # 可视化解释结果 explanation.show_in_notebook() # 或者保存为HTML文件 explanation.save_to_file('explanation.html')
额外注意
如果nsl_kdd_test_X2是Pandas DataFrame,取单个样本时要用iloc[1]而不是[1],否则会返回列而不是行,导致输入形状不匹配模型要求。
内容的提问来源于stack exchange,提问作者M Z
相关产品推荐
相关产品推荐

