CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
MLOps 入门/课时/可解释 AI
RawBlame
课时目录12 节

MLOps 入门

  1. 01MLOps 是什么
  2. 02数据工程基础
  3. 03版本控制与 DVC
  4. 04训练与实验跟踪
  5. 05MLflow 与血缘
  6. 06编排与调度
  7. 07CI/CD for ML
  8. 08容器化部署
  9. 09云原生 ML
  10. 10监控与可观测
  11. 11可解释 AI
  12. 12综合练习

可解释 AI

LIME/SHAP 与合规沟通。

25 分钟

可解释 AI

这一课你将能做到

  1. 用 SHAP 解释树模型:单条预测的贡献分解(waterfall)与全局特征重要性(beeswarm)
  2. 用 LIME 做「模型无关」的局部解释,并与 SHAP 结论对比
  3. 把数值解释翻译成业务语言,产出可归档的离线解释报告

为什么要学

「这个提交为什么被判成大概率超时?」——运营会问,出题人也会问。黑盒预测在需要信任与问责的场景(误判申诉、模型验收、合规审计)站不住脚。可解释性(XAI)就是把模型的判断依据翻译成人话的技术。

两个事实标准各有分工:SHAP 基于博弈论 Shapley 值,把预测拆成每个特征的「贡献额」,全局加和严格成立,树模型有极速实现;LIME 在预测点附近扰动采样、拟合局部线性代理模型,任何模型都能用但解释是近似的。人话:SHAP 是精确到分的账单,LIME 是「在附近问一圈」的民意调查。

先建立图像

单条预测的 SHAP 分解(waterfall 思路):
基准(全体平均超时概率)= 0.15
  + code_lines = 280      → +0.52   (代码很长,强烈推高)
  + problem_tle_hist = 0.4 → +0.30   (该题历史 TLE 率高)
  + loop_depth = 2         → -0.06   (循环不深,略微拉低)
  + lang_java = 1          → -0.01
  ────────────────────────
  最终预测 = 0.90          (每个特征贡献严格可加)

全局视角:对全部样本的 |SHAP| 求均值 → 哪些特征整体上最有话语权

跟着做

步骤 1:准备数据与已训练模型

pip install shap lime matplotlib
python src/train.py     # 训练并落盘 MLflow run(沿用第 4 课脚本)

步骤 2:SHAP 解释单条预测与全局

# src/explain_shap.py
import matplotlib
matplotlib.use("Agg")            # 无界面环境必须先设后端,否则画图报错
import pandas as pd
import shap
import joblib
from sklearn.model_selection import train_test_split

import sys; sys.path.insert(0, ".")
from src.train import load_data, FEATURES

model = joblib.load("models/timeout-v1.joblib")
df = load_data()
split = int(len(df) * 0.8)
X_te = df[FEATURES][split:]

explainer = shap.TreeExplainer(model)   # 树模型专用,秒级出结果
sv = explainer(X_te)

# ① 全局:哪些特征最有话语权
shap.plots.beeswarm(sv, max_display=8, show=False)
import matplotlib.pyplot as plt
plt.savefig("shap_beeswarm.png", bbox_inches="tight", dpi=150)

# ② 局部:第 0 号样本为什么被判超时
shap.plots.waterfall(sv[0], max_display=8, show=False)
plt.savefig("shap_waterfall.png", bbox_inches="tight", dpi=150)

# ③ 数值形式(报告/落库用):贡献值表
print(pd.DataFrame({
    "feature": FEATURES,
    "value": X_te.iloc[0].values,
    "shap": sv.values[0].round(3),
}).sort_values("shap", key=abs, ascending=False))
python src/explain_shap.py
# 看 shap_beeswarm.png:横轴是 SHAP 值,红色高值点落在哪边,特征就把预测推向哪边

步骤 3:LIME 局部解释与对比

# src/explain_lime.py
import numpy as np
import pandas as pd
import joblib
from lime.lime_tabular import LimeTabularExplainer

import sys; sys.path.insert(0, ".")
from src.train import load_data, FEATURES

model = joblib.load("models/timeout-v1.joblib")
df = load_data()
split = int(len(df) * 0.8)
X_tr, X_te = df[FEATURES][:split], df[FEATURES][split:]

explainer = LimeTabularExplainer(
    X_tr.values, feature_names=FEATURES,
    class_names=["normal", "timeout"], mode="classification",
    discretize_continuous=True)          # 把连续特征离散成规则更易读

exp = explainer.explain_instance(
    X_te.iloc[0].values, model.predict_proba, num_features=4)
for feat, weight in exp.as_list():
    print(f"{weight:+.3f}  {feat}")
exp.save_to_file("lime_report.html")
python src/explain_lime.py
# 输出示意:
# +0.28  code_lines > 195.5      (代码行数超阈值,推高超时概率)
# +0.19  0.35 < problem_tle_hist ≤ 0.45
# -0.05  loop_depth ≤ 2.0

步骤 4:翻译成业务语言

# src/report_one.py —— 给运营/出题人的解释话术生成器(示意)
# 读 shap 贡献值表,按 |shap| 排序取前 3:
# 「该提交被判为高超时风险(0.90),主要依据:
#   ① 代码长度 280 行,远高于全站平均,贡献最大;
#   ② 所属题目近期 TLE 率 40%,属于易超时题目;
#   ③ 循环深度仅 2 层,略微缓解了风险。」
# 同样的三句话可自动渲染进挑战申诉工单,人工复核时有据可依

讲清楚要点

  1. SHAP 的两个直觉:基准值是「什么都不知道时」的平均预测;每个特征的 SHAP 值是「把该特征纳入后预测移动了多少」,正推高风险、负推低风险,全部加总恰好等于预测值与基准之差。
  2. TreeExplainer 与 KernelExplainer 差一个数量级:树模型(XGBoost/LightGBM/sklearn 树)用 TreeExplainer 精确且快;任意黑盒只能 KernelExplainer,慢到只能采样少量样本。选模型时就该想到「以后要不要解释」。
  3. LIME 的本质是局部线性近似:在预测点附近扰动生成「伪样本」→ 拿原模型打分 → 拟合一个可读的线性/规则模型。它的解释是「这一片的行为」,不是全局规律,且受扰动策略影响不稳定。
  4. 解释的两大用途:对内——验收与排障(发现模型学到可疑特征,如「user_id 尾号越大越超时」这种泄漏信号);对外——申诉、合规、建立业务信任。判题超时误判申诉就是典型场景。
  5. 解释要离线做:SHAP/LIME 都不便宜,放到离线批处理(每日对抽检样本出报告、申诉工单触发的按需解释),不要阻塞毫秒级在线推理链路。

你可能会懵的地方

  • SHAP 值的正负和单位是什么? 与预测同单位。分类模型解释的是概率(或 logit,取决于实现),回归模型解释的就是预测值本身。explainer(X) 返回的 base_values + values.sum(axis=1) 应等于逐条预测,可用这步自检。
  • LIME 和 SHAP 对同一样本给出不同解释,谁对? 都是「对」的近似,但口径不同:SHAP 是满足可加性公理的精确贡献,LIME 是固定扰动策略下的局部近似,结论对超参敏感。工程约定:树模型以 SHAP 为准,LIME 用于给非树模型补位与交叉验证。
  • 深度学习模型怎么解释? 文本/图像用 SHAP 的 GradientExplainer/DeepExplainer 或注意力可视化、Grad-CAM;表格深度模型用 SHAP 采样实现。共同点是更慢更近似,更依赖抽样验证稳定性。
  • SHAP 排名能直接用来删特征吗? 能提供线索,不能直接执行。全局重要性低 ≠ 可删(可能对少数关键样本至关重要),且删特征要考虑业务口径与上游数据稳定性。正确流程:SHAP 定候选 → 特征消融实验验证 → 业务确认后下线。
  • 解释结果会被「对抗利用」吗? 会。若「代码行数 > 195 就显著推高超时概率」被公开,用户可以故意写短代码绕过预测。策略:解释只对内部与申诉工单开放,对外只暴露结论性话术。

错法对照

错法问题正解
把 SHAP 当因果解释贡献是「相关性归因」,非因果表述为「模型依据」而非「因为所以」
只看全局重要性不看单条关键个例的异常依据被平均掩盖全局定位 + waterfall 逐单复核
在线推理链路同步算 SHAP延迟从 5ms 涨到秒级离线批量出报告,线上只存预测
特征离散化阈值随数据变同一提交两次解释结论不同解释代码与阈值也进版本控制
用解释「自证模型正确」解释只能发现可疑,不能证明正确解释 + 消融实验 + 人工抽检三角验证

卡点急救

  1. 画图报错 "no display":脚本开头先 matplotlib.use("Agg") 再 import pyplot,配 show=False 后 savefig。
  2. TreeExplainer 不支持该模型:换 shap.KernelExplainer(model.predict_proba, X背景样本)(取几百条背景即可);或确认模型在 SHAP 支持列表内。
  3. LIME 输出的是区间规则不是原始特征名:discretize_continuous=True 把数值切成可读区间,属正常行为;要原始连续权重设为 False。

面试常问

  • 讲讲 SHAP 的原理。 Shapley 值来自合作博弈论:把「预测」看成各特征合作产出的收益,计算每个特征在所有可能「入场顺序」下带来的边际贡献的期望,满足可加性、对称性、零贡献等公理。树模型用 TreeShap 算法把指数级遍历降为多项式级,工程上可用。
  • LIME 和 SHAP 的区别与选型? SHAP:公理化、精确可加、树模型快,但任意模型慢;LIME:模型无关、输出可读规则,但局部近似、对扰动敏感、不稳定。选型:树模型默认 SHAP;黑盒(深度网络/外部模型)用 LIME 或 SHAP 采样实现;重要决策场景两者交叉验证。
  • 如何向业务方解释一条预测? 模板:「结论 + 前三依据(特征名+取值+方向)+ 不确定度」。禁止输出 SHAP 数值本身,翻译成「代码行数远高于平均」这类业务语言;同时主动说明「这是模型依据,不构成因果结论」。

自测三问

  1. waterfall 图里的 base value 是什么?SHAP 值如何加总回预测?
  2. LIME 为什么结论可能不稳定?它适合什么场景?
  3. 发现「user_id 尾号」SHAP 重要性异常高,说明什么?该怎么处理?

小结一句话

XAI 用 SHAP 的精确贡献分解与 LIME 的局部近似规则,把黑盒预测翻译成可审计、可沟通的依据,服务于排障、申诉与合规。

延伸

  • SHAP 官方文档——各 Explainer 的适用模型与图表示例。
  • LIME 官方文档——Tabular/Text/Image 三种解释器的用法。
  • 下一课:综合练习——把 11 节课的组件串成一条从数据到监控的完整流水线并交付。
加载本节练习…
← 上一课监控与可观测下一课 →综合练习