使用 SHAP库 对模型预测作解释
为什么需要可解释
两点考虑
- 若模型完全黑箱, 会有信任风险, 虽然 Performance 不错, 但难以放心地投用到业务中.
- 增强模型洞察, 辅助模型与特征的迭代.
本文主角是 shap 库, 预备知识是 联盟博弈论的 shapley-value.
联盟博弈论的 shapley-value
合作博弈论用于多人合作下的收益分配. 主要思想是: 列举出各种不同玩家之间的合作情况, 依据玩家参与与否的边际效应计算贡献.
直接用 shap 库中的公式了. 它是 classic Shapley value equation.
- F, 所有玩家的集合
- i, 待评估贡献的单个玩家
- S, 剩下玩家组成集合的所有可能的子集
- f, 计算合作收益的函数
- xSx_SxS, 表示一次合作中参与的玩家组合为集合S.
公式解读
第一项为系数, 第二项为边际收益. 这个系数怎么理解呢?
说下个人见解: 先不管 -1
这个细节, 这个系数其实就是组合数 CFSC_F^SCFS 的倒数.
Sigma 符号相当于一层 for 循环, 当 S 确定时, 它的出现概率解读为 从 F 中挑 |S| 个特征的种类数, 而当前的 S 又是其中确定的一种, 所以概率就是 1CFS\frac 1{C_F^S}CFS1.
直观例子
参考[6] 中的知乎文章给了一个很好的例子, 这里二次加工下.
甲、乙、丙三人合作经商。不同组合的不同收益列举如下, 问三人合作时如何利益分配?
- 空集
- 甲乙丙单人, 对应三种情况, 都是1万.
- 甲乙, 7万
- 甲丙, 5万
- 乙丙, 4万
- 甲乙丙, 11万
三个元素的所有子集个数为 23=82^3=823=8, 已经列举在上面了.
代入公式, 见下图(符号有出入, 大体一样)
所以 甲的最终获利为 133\frac {13}{3}313.
计算复杂度与优化方法
因为要枚举所有玩家的所有不同组合情况, 即集合 F 的所有子集, 这个组合数就是 2∣F∣2^{|F|}2∣F∣, 属于 NP-Hard 问题.
怎么去用复杂度更低的计算方法去近似它呢?
- Shapley sampling values, 见参考 [8].
- Kernal Shap method, 见参考[4], 下文也会展开.
SHAP 库介绍
SHapley Additive exPlanation, 是一个py 三方库, 依据 合作博弈论 领域 中的 shapley value 思想, 对模型的单个预测作解释.
它把特征比作博弈问题中的玩家, 模型预测比喻玩家合作之后的收益, 于是再次解读这个公式:
- F, 所有特征的集合
- i, 待评估贡献的单个特征
- S, 剩下特征组成集合的所有可能的子集
- f, 待解释的黑盒模型
- xSx_SxS, 表示一次预测时传入的特征组合为集合S.
名字中的 additive 怎么理解
SHAP 是一类 additive feature attribution (满足可加性的特征归因) 方法. 该类方法更好地满足三大可解释性质:
- local accuracy
f(x)=g(x′)=ϕ0+∑i=1Mϕixi′(1)f(x)=g(x')=\phi_0+\sum_{i=1}^M\phi_ix_i' \tag 1f(x)=g(x′)=ϕ0+i=1∑Mϕixi′(1)
各 feature value 的加和 = 该 sample 的 model output - missingness
xi′=0⇒ϕi=0(2)x_i'=0 \Rightarrow \phi_i=0 \tag 2xi′=0⇒ϕi=0(2)
缺失值的 feature attribution value = 0 - consistency
当模型有变化, 一个特征变得更重要时, 其 feature attribution value 也不能变小.
SHAP 的贡献
论文[4] 中, 它是这么说的:
“已有的多种方法 LIME, DeepLift 等, 它们之间的联系是啥? 什么情况下, 用其中一种会比另一种更好用?” 难以回答, 而它引入了 shapley 思想作了统一, 既有计算效率上的优化, 又更符合人类直觉.
它有哪些 explainer 子类
有多种不同的 explainer 实现.
我的疑问: 多个实现间怎么选, 既有 model-sprcific, 又有 model-agnostic?
蛮力计算
见参考[7]. 是 shapley-value 公式的直接实现.
KernalExplainer
基于 KernelSHAP 的实现.
1. 维护基础信息
todo
2. 构造不同组合的合成(人造)样本
def explain(self, incoming_instance, **kwargs):...# 两层 for, 依次添加# subset_size 就是 |S|for subset_size in range(1, num_subset_sizes + 1):for inds in itertools.combinations(group_inds, subset_size):self.addsample(instance.x, mask, w)# execute the model on the synthetic samples we have createdself.run()# phi[i] 代表着 i-th 特征的重要性phi = np.zeros((self.data.groups_size, self.D))phi_var = np.zeros((self.data.groups_size, self.D))for d in range(self.D):vphi, vphi_var = self.solve(self.nsamples / self.max_samples, d)phi[self.varyingInds, d] = vphi...return phi
被调用的 addsample() 方法见下.
def addsample(self, x, m, w):self.synth_data[offset:offset+self.N, groups] = ...self.maskMatrix[self.nsamplesAdded, :] = mself.kernelWeights[self.nsamplesAdded] = w
维护 maskMatrix, 样子见下:
3. 计算合成样本的输出
def run(self):data = self.synth_datamodelOut = self.model.f(data)self.y = modelOut eyVal = np.zeros(self.D)for j in range(0, self.N):eyVal += self.y[i * self.N + j, :] * self.data.weights[j]self.ey[i, :] = eyVal
LinearExplainer
用于 逻辑回归 模型的可解释, 背后算法是 DeepLIFT algorithm (Deep SHAP) , 官网的例子见 参考[2].
Note that with a linear model the SHAP value for feature i for the prediction f(x)f(x)f(x) (assuming feature independence) is just
ϕi=βi⋅(xi−E[xi])\phi_i = \beta_i \cdot (x_i - E[x_i])ϕi=βi⋅(xi−E[xi])
βi\beta_iβi 是模型学出来的权重, xix_ixi 是当前sample 中特征i的取值, E[xi]E[x_i]E[xi] 是数据集中特征i的取值的期望.
可以看出来针对LR, shap 几乎啥都没做.
DeepExplainer
用于 Deep NN 的模型可解释, 原理是 shap 与 ,官网例子见 参考[3].
注意用到了 keras, tensoflow, shap 三个库, 很容易有版本不兼容问题, 导致示例代码不能顺利运行.
类shap.explainers._deep.Deep
继承了shap.explainers._explainer.Explainer
, 根据model框架不同, 具体干活的又分为 TFDeep
与 PyTorchDeep
.
PartitionExplainer
该 explainer 适用于序列深度模型.
源码涉及到太多的类与条件分支, 可读性差, 这里作算法简洁描述.
联盟描述
- 首先引入 五元组结构体
CoalitionInfo
.
CoalitionInfo, (m00, f00, f11, ind, weight)
1. 该联盟未参与时的mask信息
2. 该联盟未参与时的结果
3. 该联盟参与时的结果
4. 该联盟的标识
5. 该联盟的权重
算法描述
1. 根节点放入队列
2. 联盟出队列, 记为 co_i
3. 如果 co_i 是叶子节点, 更新`values[i] += (f11 - f00) * weight`; 否则 分别构造其左右子树两个联盟的模型输入 fin.
4. 将 fin 送入模型, 得到模型输出 fout
5. 根据fout, 维护 左右子树两个联盟的 CoalitionInfo. 注意受上下文context影响, 这里的2个联盟会膨胀为4个CoalitionInfo. 放入队列.
6. 继续步骤2, 直到队列为空.
一个二叉树的节点只有两个子树, 为何会膨胀出2倍的节点, 在于一个联盟的收益计算有两种口径, 见下.
l_child 的贡献, 两种口径
lift(l_child) = f(A + B + l_child) - f(A + B)
lift(l_child) = f(A + B + l_child + r_child) - f(A + B + r_child)
时间复杂度推算
不妨令层次树为平衡二叉树.
具有n个叶子节点的平衡二叉树, 树高为 h=log2nh=\log_2nh=log2n
根据上述算法, 要送入模型预测的样本数, 为一个公比为4的等比数列, 根据前n项和公式 Sn=a1∗1−qn1−qSn=a_1*\frac{1-q^n}{1-q}Sn=a1∗1−q1−qn, 树高h就是这里的项数n,
代入得 Sh=1−4log2n1−4S_h=\frac{1-4^{\log_2n}}{1-4}Sh=1−41−4log2n, 对分子部分作变换:
(22)log2n=22log2n=2log2n2=n2(2^2)^{\log_2n} = 2^{2{\log_2n}} = 2^{\log_2n^2}=n^2(22)log2n=22log2n=2log2n2=n2
故时间复杂度为 O(n2)O(n^2)O(n2).
批处理加速
模型预测, batch方式比单样本模式, 整体速度更快, 所以可对上述算法作工程加速.
1. 为了控制复杂度, 维护 max_eval_cnt, 超过该阈值及时终止, 未计算充分的联盟直接将values分摊至叶子节点.
2. 上述步骤2和3当作整体多次执行, 攒够足够的batch批量送入模型预测.
3. 为了优先照顾贡献明显的联盟, 将队列改为优先队列
transformer 搭配
transformer 用于NLP任务中的 情感分析时, 其实就是 POSITIVE/NEGATIVE
的二分类.
如果我们想对模型的预测作解释, 就需要知道句中不同部分对情感倾向的贡献.
一个官方例子见下:
- 句子: What a great movie! if you have no taste.
- 翻译: 多棒的一个电影啊, 如果你没有品位的话.
- 预处理后: [[‘[CLS]’, ‘what’, ‘a’, ‘great’, ‘movie’, ‘!’, ‘if’, ‘you’, ‘have’, ‘no’, ‘taste’, ‘.’, ‘[SEP]’]]
- 情感倾向贡献: base_value=-0.690963, 表明整个数据集的平均倾向得分. shap_values=[ 0. , 1.2201888 , 1.2201888 , 3.8936163 , 3.8936163 ,
0.24495573, -0.16747759, -0.16747759, -0.16747759, -0.16747759,
-0.16747759, -0.16747759, 0. ], 是个 shape=[13,]的数组, 表明预处理后每个token的情感贡献. - 可视化, 见下, 得分相同的被归到了一起.
- 代码
import transformers
import shap
import multiprocessing
import torch# 没有用, 必须到 shap库中, 把 num_workers 置为0
if __name__ == '__main__':torch.multiprocessing.freeze_support()multiprocessing.freeze_support()model_path = r'D:\model_repository\transformer\distilbert-base-uncased-finetuned-sst-2-english'
model = transformers.pipeline('sentiment-analysis', model=model_path, return_all_scores=True)model_output = model(["What a great movie! ...if you have no taste."])
print('model_output', model_output, '==========', sep='\n')explainer = shap.Explainer(model)
# Explanation:[1,13,2]
shap_values = explainer(["What a great movie! if you have no taste."]) # type: shap._explanation.Explanation
print('shap_values', shap_values, '==========', sep='\n')
# Explanation: [13,]
positive_shap_values = shap_values[0, :, "POSITIVE"]
print('positive_shap_values', positive_shap_values, '==========', sep='\n')# visualize the first prediction's explanation for the POSITIVE output class
html_obj = shap.plots.text(positive_shap_values)
print(123)"""
model_output
[[{'label': 'NEGATIVE', 'score': 0.00014734955038875341}, {'label': 'POSITIVE', 'score': 0.9998526573181152}]]
==========
shap_values
.values =
array([[[ 0. , 0. ],[-1.22018296, 1.2201888 ],[-1.22018296, 1.2201888 ],[-3.89365431, 3.8936163 ],[-3.89365431, 3.8936163 ],[-0.24507864, 0.24495573],[ 0.16742747, -0.16747759],[ 0.16742747, -0.16747759],[ 0.16742747, -0.16747759],[ 0.16742747, -0.16747759],[ 0.16742747, -0.16747759],[ 0.16742747, -0.16747759],[ 0. , 0. ]]]).base_values =
array([[ 0.69096287, -0.690963 ]]).data =
array([['', 'What ', 'a ', 'great ', 'movie', '! ', 'if ', 'you ','have ', 'no ', 'taste', '.', '']], dtype='<U6')
==========
positive_shap_values
.values =
array([ 0. , 1.2201888 , 1.2201888 , 3.8936163 , 3.8936163 ,0.24495573, -0.16747759, -0.16747759, -0.16747759, -0.16747759,-0.16747759, -0.16747759, 0. ]).base_values =
-0.6909630029188477.data =
array(['', 'What ', 'a ', 'great ', 'movie', '! ', 'if ', 'you ', 'have ','no ', 'taste', '.', ''], dtype='<U6')
"""
上段代码依赖的代码用到了 from IPython.core.display import display, HTML
, 用于html可视化. 但在 非 jupyter 中网页渲染不出来, 只会控制台显示以下信息
Backend Qt5Agg is interactive backend. Turning interactive mode on. <IPython.core.display.HTML object>
Ipython 也不行. 只能断点到 site-packages\shap\plots\_text.py Line: 167
位置把html内的信息复制出来, 新建 html 文件自行打开.
参考
- github, shap
- 代码例子, Sentiment Analysis with Logistic Regression
- 代码例子, deepexplainer
- shap 三方包的论文, a-unified-approach-to-interpreting-model-predictions.pdf
- 划分树, 联盟划分, owen 计算等, Mutual information-based group explainers with coalition structure
for machine learning model explanations - 知乎文章, 关于Shapley Value(夏普利值)的公式
- shap库 文档, Brute Force Kernel SHAP
- Erik Štrumbelj and Igor Kononenko. “Explaining prediction models and individual predictions with feature contributions”. In: Knowledge andd information systems 41.3 (2014), pp. 647–665.
使用 SHAP库 对模型预测作解释相关推荐
- R语言基于自定义函数构建xgboost模型并使用LIME解释器进行模型预测结果解释:基于训练数据以及模型构建LIME解释器解释一个iris数据样本的预测结果、LIME解释器进行模型预测结果解释并可视化
R语言基于自定义函数构建xgboost模型并使用LIME解释器进行模型预测结果解释:基于训练数据以及模型构建LIME解释器解释一个iris数据样本的预测结果.LIME解释器进行模型预测结果解释并可视化 ...
- R语言基于自定义函数构建xgboost模型并使用LIME解释器进行模型预测结果解释:基于训练数据以及模型构建LIME解释器解释多个iris数据样本的预测结果、使用LIME解释器进行模型预测结果解释
R语言基于自定义函数构建xgboost模型并使用LIME解释器进行模型预测结果解释:基于训练数据以及模型构建LIME解释器解释多个iris数据样本的预测结果.使用LIME解释器进行模型预测结果解释并可 ...
- Paper:《A Unified Approach to Interpreting Model Predictions—解释模型预测的统一方法》论文解读与翻译
Paper:<A Unified Approach to Interpreting Model Predictions-解释模型预测的统一方法>论文解读与翻译 导读:2017年11月25 ...
- python机器学习库sklearn——模型评估
全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 各类模型评估详细意思参考:https://blog.csdn.net/luanpeng825485697/article/detail ...
- 程序员教你如何用 13 种模型预测天气预报 | 原力计划
作者 | 荣仔!最靓的仔! 责编 | 王晓曼 出品 | CSDN博客 天气数据集爬取 爬取思路: 确定目标(目标网站:大同历史天气预报 2020年5月份) 请求网页(第三方库 requests) ...
- 【手把手教你】使用Logistic回归、LDA和QDA模型预测指数涨跌
1 引言 机器学习(Machine Learning)是人工智能(AI)的重要组成部分,目前已广泛应用于数据挖掘.自然语言处理.信用卡欺诈检测.证券市场分析等领域.量化投资作为机器学习在投资领域内最典 ...
- 模型预测结果校准——Isotonic regression
模型预测结果校准--Isotonic regression 方法简介: Isotonic Regression: the method used by Zadrozny and Elkan (2002 ...
- 天气预报 :天气数据集爬取 + 可视化 + 13种模型预测
前几天一直在研究 Python 爬虫技术,只为从互联网上获取数据集. 本文就是利用前几天学到的爬虫知识使用 Python 爬取天气数据集,并做的一期讨论日期与最低气温能是否是最高气温的影响因素,进而判 ...
- 人口预测和阻尼-增长模型_使用分类模型预测利率-第3部分
人口预测和阻尼-增长模型 This is the final article of the series " Predicting Interest Rate with Classifica ...
- 人口预测和阻尼-增长模型_使用分类模型预测利率-第2部分
人口预测和阻尼-增长模型 We are back! This post is a continuation of the series "Predicting Interest Rate w ...
最新文章
- PNAS | 理解单个神经元在深度神经网络中的作用
- 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1078:求分数序列和
- 用Hystrix保护您的应用程序
- tnsnames.ora配置未生效_1分钟了解网络交换机的6种命令配置模式
- 使用Python+pillow绘制矩阵盖尔圆
- java中userservice是什么,【图片】求助大神~~我在Reaml中注入userService对象启动tomcat就报错【java吧】_百度贴吧...
- Angular4.X 介绍
- java 遍历 List 的六种方式 学习笔记
- php两张图片合成,php多张图片合成一张的方法及案例
- 几种最常见的网站盈利模式分析
- Spark Streaming源码解读之No Receivers彻底思考
- PCA主元分析方法描述
- 群响黄宝书:淘宝客历史沿革和新崛起的淘宝高手分享
- 高级转录组调控分析和R语言数据可视化第十三期 (线上/线下同时开课)
- 使用SPSS进行曲线估算分析
- 网页在线即时翻译- -
- 如何关闭win10防火墙_Win技巧 | 如何关闭防火墙
- 1w存银行一年多少利息_100万存银行,一年利息有多少?
- 数学分析讲义习题解答:(三:第二部分)
- Decenber 2004 (再见了我的2004猴年)
热门文章
- 华光昱能光知识-细说MPO光纤跳线那些事
- iPhone12或再引领轻薄时尚风潮,半斤机将被抛弃
- Es,N0,EsN0,EbN0,SNR关系详解
- 7-2 Binomial Queue
- 导入导出软件测试点,导入导出问题-TestCenter测试管理工具常见问题-SPASVO泽众软件测试网...
- Android 贝塞尔曲线的魅力
- Xilinx SRIO_gen2关于时钟的问题
- Excel 预习阶段Day1
- 超立方体(n方体)Qn:递推式 和 性质
- 自然语言处理-003NLP定义以及歧义性-学习笔记