大家好,我是Ai学习的老章
偶尔推点老本行相关文章——机器学习系列
作者 Tobias Pitters [1] 。Tobias 是 shap 项目维护者,现任可解释人工智能初创公司 CloudExplain [2] 工程师。
机器学习面试准备路线图(2025版) 机器学习模型的可解释性算法汇总!
SHAP 是最广泛使用的模型可解释性库之一,这有其充分理由——它让解释复杂模型变得直观甚至美观。我自 2023 年 10 月开始参与 SHAP 开发,并于 2024 年 1 月成为维护者。在此期间,我贡献了许多改进和修复,至今仍热爱其底层数学的强大、易于集成的特性以及惊艳的可视化效果(我认为这正是 SHAP 最初如此受欢迎的重要原因)。
但作为维护者也意味着要直面系统崩溃、运行迟缓或用户遭遇挫折的环节。经过一年半时间,我整理出一份亟待改进的痛点清单——既为了项目健康发展,也为了所有使用者。
1. 解释过程可能变得缓慢 在笔记本环境中处理数千条观测数据时一切正常,你可以自由选择最适合的解释器。但一旦涉及更多特征和更大样本量,速度就会急剧下降。对于具有数十万条观测数据的大型模型,解释过程可能耗时数小时。
这种缓慢部分源于 SHAP 值计算方式的固有特性,但更多是由实现选择导致的,比如有限的并行化和大量纯 Python 循环。最近我们合并了一个将部分循环转移到 Cython 的修复方案,使 KernelExplainer 的速度提升了约 5%(参见 这个 PR [3] 或 这个 PR [4] )。我认为仍有很大改进空间,只是我们尚未将其列为优先事项。
2. DeepExplainer 的困扰 DeepExplainer 原本是解释 TensorFlow 或 PyTorch 模型的自然选择,它采用 DeepLIFT 风格逐层反向传播重要性值。遗憾的是,从 TensorFlow 2.4 版本开始,这一过程变得异常困难。许多神经网络层在内部由乘法、激活函数和加法等基础运算组合而成。过去我们只需重写这些底层运算的反向传播逻辑,就能自动适用于 LSTM 等高层结构,无需额外工作即可为各类层计算 SHAP 值。但随着 TensorFlow 转向即时执行模式并隐藏这些内部实现,这条捷径已然失效。如今我们必须为每个需要支持的层单独实现定制逻辑。
这导致 LayerNorm 等标准化层以及 LSTM、Attention 层等复杂结构不再受 DeepExplainer 支持。
3. TreeExplainer——速度快但难以修改
树模型在表格数据预测任务中仍被广泛使用且表现优异。幸运的是,SHAP 值可以通过解析方法从树模型中计算得出,而我们的实现由于采用 C 语言而具有极高的运行效率。但遗憾的是,目前团队缺乏精通 C 语言的维护者,且这部分代码年代久远难以修改。我们还遇到过内存错误——这种因内存处理不当引发的底层问题,所幸已被社区修复。我怀疑仍存在其他潜在问题,因此希望能通过用 Rust 重写代码或寻找专人接管这部分代码库,使其进入更易维护的状态。在与可解释 AI 专家讨论 Rust 实施方案时,我们一致认为这是可行的改进方向:既能借助 Rust 的内存安全设计避免问题,又能保持与当前版本相近的性能表现。
另外,您知道吗?我们其实有 TreeExplainer 的 GPU 版本 [5] 。遗憾的是,目前仅支持通过源码安装(克隆代码库后运行 pip install -e .)且需配备 GPU 设备。我理想中的方案是提供额外安装标记(pip install shap[gpu])或预编译的 GPU 轮包(pip install shap-gpu)。虽然需要升级构建基础设施,但其他软件包的成功案例证明这完全可行。
4. 因上游包导致测试失败和代码损坏 SHAP 支持众多机器学习框架——包括 scikit-learn、TensorFlow、PyTorch、LightGBM、XGBoost、CatBoost、transformers 库中的部分文本模型,甚至 NGBoost 模型。这意味着我们必须与所有框架保持兼容,并通过测试确保这一点。但问题在于,支持如此多软件包的同时还要兼顾多个 Python 版本,导致我们的 CI 流水线(自动化测试与集成工作流)经常失败。
每当这些库中的任何内容发生变化,都可能导致我们的代码失效。粗略估计,我花费在 SHAP 上约 30%的时间都用于修复上游变更。这些问题往往晦涩难懂且难以调试。例如,我们曾遇到测试套件在 Python 3.10 上失败,但在 Python 3.11 及更高版本上却运行正常。失败的测试与 transformers 代码相关。经过数小时调试后发现,我们必须将流水线专门升级到 Python 3.10.12 版本,因为 transformers 开始使用了一个仅在 Python 3.10.12 中向后移植的警告过滤参数(3.10.0-3.10.11 版本均未提供)。这种在补丁版本中添加功能的做法并不常见,让我们措手不及(参见 Python 发布说明 [6] )。 针对这种情况的解决方案并不多,我们可以改进日志记录、添加类型提示,但仍会有大量问题无法覆盖。
5. 绘图问题
我喜爱 SHAP 的图表功能,相信这是它成功的重要因素之一。其多样性令人印象深刻,几乎无可挑剔——除了那些缺失但难以添加到遗留绘图代码库中的功能。说到"遗留",我确实是这个意思——有些绘图函数在内部就是如此命名的,比如 这里 [7] ,或 这里 [8] ,还有那个 waterfall_legacy 函数 [9] (这个函数现在已不建议使用)。
若能清理这些代码并简化通常超过 300 行的单个绘图函数就太好了。此外,部分图表是用 JavaScript 生成的,这本身没问题,但这些代码相当陈旧且难以测试。我也希望能重写这部分代码 。 但这需要更全面的绘图测试。我们确实已有相关测试,但图表仍是代码库中测试覆盖最薄弱的部分。如果有完善的测试,我们不仅能修复一些错误,还能扩展绘图功能,让用户获得更多控制权,比如调整调色板、间距和高度等参数。
6. 其他问题 一些较小的杂项问题或缺失功能:
JAX 是一个用于构建深度学习网络的库,可与 PyTorch 或 TensorFlow 相媲美,只是采用了更函数式的编程方法。它正在快速发展,我很想在 Deep-和 GradientExplainer 中支持它。不过在开发大型新功能之前,我们还有许多更紧迫的问题需要解决,这些新功能本身就会带来各种问题。 作为维护者,我最讨厌 SHAP 的 6 件事之一就是缺乏完善的类型标注——这个功能在其他库中让我受益匪浅。对我们而言这是双重困境:一方面自然是时间不足难以实现,另一方面我们许多函数具有高度多态性,允许接收多种不同类型的输入,这也使得类型提示对用户而言变得难以阅读。 我真的很希望实现夜间构建,并支持 科学 Python 社区 [10] 提出的其他功能,比如按需懒加载代码。 乐观的前景
我不想显得悲观或让你觉得这是听天由命的放弃,我相信并致力于让这个软件包不断完善,许多贡献者也同样如此。诚实地面对并承认当前的不足是第一步,但看到 SHAP 带来的价值,就让人觉得值得持续投入。当出现一个 PR 解决了我们长期存在的问题,甚至是我们未曾意识到的问题,或是为 SHAP 构建了全新功能时,我都感到欣喜。看到这如何将人们凝聚在一起,推动事物向前发展,真是太好了。我也热爱这个软件包帮助解释了黑盒机器学习算法,将可解释 AI 带入主流,推动更广泛的机器学习应用,并支持我们更深入地理解复杂算法的工作原理。它让我深入探索可解释 AI,并接触了以前从未涉足的编码领域。
原文:# 作为维护者,我讨厌 SHAP 的 6 个方面 https://mindfulmodeler.substack.com/p/6-things-i-hate-about-shap-as-a-maintainer?utm_source=post-email-title&publication_id=1078760&post_id=173436591&utm_campaign=email-post-title&isFreemail=true&r=u9e1n&triedRedirect=true&utm_medium=email
[1] Tobias Pitters: https://github.com/CloseChoice
[2] CloudExplain: https://www.cloudexplain.eu/
[3] 这个 PR: https://github.com/shap/shap/pull/3944
[4] 这个 PR:
https://github.com/shap/shap/pull/3983
[5] TreeExplainer 的 GPU 版本: https://github.com/shap/shap/blob/master/shap/explainers/_gpu_tree.py
[6] Python 发布说明: https://www.python.org/downloads/release/python-31012/
[7] 这里: https://github.com/shap/shap/blob/8bcd29f3f49d1315411892417ab59cb7c1227151/shap/ init .py#L49 -L50
[8] 这里:
https://github.com/shap/shap/blob/8bcd29f3f49d1315411892417ab59cb7c1227151/shap/ init .py#L61
[9] waterfall_legacy 函数: https://github.com/shap/shap/blob/8bcd29f3f49d1315411892417ab59cb7c1227151/shap/plots/_waterfall.py#L376
[10] 科学 Python 社区: https://scientific-python.org/specs/