为什么需要可解释

两点考虑

  1. 若模型完全黑箱, 会有信任风险, 虽然 Performance 不错, 但难以放心地投用到业务中.
  2. 增强模型洞察, 辅助模型与特征的迭代.

本文主角是 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}CFS​1​.

直观例子

参考[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 问题.
怎么去用复杂度更低的计算方法去近似它呢?

  1. Shapley sampling values, 见参考 [8].
  2. Kernal Shap method, 见参考[4], 下文也会展开.

SHAP 库介绍

SHapley Additive exPlanation, 是一个py 三方库, 依据 合作博弈论 领域 中的 shapley value 思想, 对模型的单个预测作解释.

它把特征比作博弈问题中的玩家, 模型预测比喻玩家合作之后的收益, 于是再次解读这个公式:

  • F, 所有特征的集合
  • i, 待评估贡献的单个特征
  • S, 剩下特征组成集合的所有可能的子集
  • f, 待解释的黑盒模型
  • xSx_SxS​, 表示一次预测时传入的特征组合为集合S.

名字中的 additive 怎么理解

SHAP 是一类 additive feature attribution (满足可加性的特征归因) 方法. 该类方法更好地满足三大可解释性质:

  1. 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​ϕi​xi′​(1)
    各 feature value 的加和 = 该 sample 的 model output
  2. missingness
    xi′=0⇒ϕi=0(2)x_i'=0 \Rightarrow \phi_i=0 \tag 2xi′​=0⇒ϕi​=0(2)
    缺失值的 feature attribution value = 0
  3. 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框架不同, 具体干活的又分为 TFDeepPyTorchDeep.

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=log⁡2nh=\log_2nh=log2​n
根据上述算法, 要送入模型预测的样本数, 为一个公比为4的等比数列, 根据前n项和公式 Sn=a1∗1−qn1−qSn=a_1*\frac{1-q^n}{1-q}Sn=a1​∗1−q1−qn​, 树高h就是这里的项数n,
代入得 Sh=1−4log⁡2n1−4S_h=\frac{1-4^{\log_2n}}{1-4}Sh​=1−41−4log2​n​, 对分子部分作变换:
(22)log⁡2n=22log⁡2n=2log⁡2n2=n2(2^2)^{\log_2n} = 2^{2{\log_2n}} = 2^{\log_2n^2}=n^2(22)log2​n=22log2​n=2log2​n2=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 文件自行打开.

参考

  1. github, shap
  2. 代码例子, Sentiment Analysis with Logistic Regression
  3. 代码例子, deepexplainer
  4. shap 三方包的论文, a-unified-approach-to-interpreting-model-predictions.pdf
  5. 划分树, 联盟划分, owen 计算等, Mutual information-based group explainers with coalition structure
    for machine learning model explanations
  6. 知乎文章, 关于Shapley Value(夏普利值)的公式
  7. shap库 文档, Brute Force Kernel SHAP
  8. 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库 对模型预测作解释相关推荐

  1. R语言基于自定义函数构建xgboost模型并使用LIME解释器进行模型预测结果解释:基于训练数据以及模型构建LIME解释器解释一个iris数据样本的预测结果、LIME解释器进行模型预测结果解释并可视化

    R语言基于自定义函数构建xgboost模型并使用LIME解释器进行模型预测结果解释:基于训练数据以及模型构建LIME解释器解释一个iris数据样本的预测结果.LIME解释器进行模型预测结果解释并可视化 ...

  2. R语言基于自定义函数构建xgboost模型并使用LIME解释器进行模型预测结果解释:基于训练数据以及模型构建LIME解释器解释多个iris数据样本的预测结果、使用LIME解释器进行模型预测结果解释

    R语言基于自定义函数构建xgboost模型并使用LIME解释器进行模型预测结果解释:基于训练数据以及模型构建LIME解释器解释多个iris数据样本的预测结果.使用LIME解释器进行模型预测结果解释并可 ...

  3. Paper:《A Unified Approach to Interpreting Model Predictions—解释模型预测的统一方法》论文解读与翻译

    Paper:<A Unified Approach to Interpreting Model  Predictions-解释模型预测的统一方法>论文解读与翻译 导读:2017年11月25 ...

  4. python机器学习库sklearn——模型评估

    全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 各类模型评估详细意思参考:https://blog.csdn.net/luanpeng825485697/article/detail ...

  5. 程序员教你如何用 13 种模型预测天气预报 | 原力计划

    作者 | 荣仔!最靓的仔! 责编 | 王晓曼 出品 | CSDN博客 天气数据集爬取   爬取思路: 确定目标(目标网站:大同历史天气预报 2020年5月份) 请求网页(第三方库 requests) ...

  6. 【手把手教你】使用Logistic回归、LDA和QDA模型预测指数涨跌

    1 引言 机器学习(Machine Learning)是人工智能(AI)的重要组成部分,目前已广泛应用于数据挖掘.自然语言处理.信用卡欺诈检测.证券市场分析等领域.量化投资作为机器学习在投资领域内最典 ...

  7. 模型预测结果校准——Isotonic regression

    模型预测结果校准--Isotonic regression 方法简介: Isotonic Regression: the method used by Zadrozny and Elkan (2002 ...

  8. 天气预报 :天气数据集爬取 + 可视化 + 13种模型预测

    前几天一直在研究 Python 爬虫技术,只为从互联网上获取数据集. 本文就是利用前几天学到的爬虫知识使用 Python 爬取天气数据集,并做的一期讨论日期与最低气温能是否是最高气温的影响因素,进而判 ...

  9. 人口预测和阻尼-增长模型_使用分类模型预测利率-第3部分

    人口预测和阻尼-增长模型 This is the final article of the series " Predicting Interest Rate with Classifica ...

  10. 人口预测和阻尼-增长模型_使用分类模型预测利率-第2部分

    人口预测和阻尼-增长模型 We are back! This post is a continuation of the series "Predicting Interest Rate w ...

最新文章

  1. PNAS | 理解单个神经元在深度神经网络中的作用
  2. 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1078:求分数序列和
  3. 用Hystrix保护您的应用程序
  4. tnsnames.ora配置未生效_1分钟了解网络交换机的6种命令配置模式
  5. 使用Python+pillow绘制矩阵盖尔圆
  6. java中userservice是什么,【图片】求助大神~~我在Reaml中注入userService对象启动tomcat就报错【java吧】_百度贴吧...
  7. Angular4.X 介绍
  8. java 遍历 List 的六种方式 学习笔记
  9. php两张图片合成,php多张图片合成一张的方法及案例
  10. 几种最常见的网站盈利模式分析
  11. Spark Streaming源码解读之No Receivers彻底思考
  12. PCA主元分析方法描述
  13. 群响黄宝书:淘宝客历史沿革和新崛起的淘宝高手分享
  14. 高级转录组调控分析和R语言数据可视化第十三期 (线上/线下同时开课)
  15. 使用SPSS进行曲线估算分析
  16. 网页在线即时翻译- -
  17. 如何关闭win10防火墙_Win技巧 | 如何关闭防火墙
  18. 1w存银行一年多少利息_100万存银行,一年利息有多少?
  19. 数学分析讲义习题解答:(三:第二部分)
  20. Decenber 2004 (再见了我的2004猴年)

热门文章

  1. 华光昱能光知识-细说MPO光纤跳线那些事
  2. iPhone12或再引领轻薄时尚风潮,半斤机将被抛弃
  3. Es,N0,EsN0,EbN0,SNR关系详解
  4. 7-2 Binomial Queue
  5. 导入导出软件测试点,导入导出问题-TestCenter测试管理工具常见问题-SPASVO泽众软件测试网...
  6. Android 贝塞尔曲线的魅力
  7. Xilinx SRIO_gen2关于时钟的问题
  8. Excel 预习阶段Day1
  9. 超立方体(n方体)Qn:递推式 和 性质
  10. 自然语言处理-003NLP定义以及歧义性-学习笔记