李雷的贷款申请又被拒了。银行柜台只丢给他一句「综合评分不足」,仿佛他所有的努力都白费了。但他真正想知道的是:如果当初我多做了一件事,结果会不会不一样?——如果月收入再高一点?如果信用卡负债再少一点?如果工作年限再长一年?这就是典型的「反事实问题」。 AI 模型就像一位只看纸质材料的「审批官」:你把条件喂进去,它给你一个冷冰冰的判决。传统的 AI 解释工具,比如 SHAP、LIME,会告诉你判决书里哪一条贡献最大——「你的负债率把分数拉低了」,却不会告诉你怎么改才能翻案。而 DiCE(Diverse Counterfactual Explanations,多样反事实解释)做的,是把「人生重开」变成一份可执行的菜单:它一次性给出几个不同的「平行世界」,每个世界都只对你做了极小的改动,却都让审批官点了头。 在这篇文章里,我们跟着李雷一起拜访这位「人生重开顾问」:看它如何寻找最小改动、如何保证方案多样不重样、如何过滤掉「把年龄改小 5 岁」这种荒谬建议,以及如何用指标给解释打分。读完你会明白,让 AI 不只说「不」,还能说「怎样才行」,正是可解释 AI 最有温度的方向。

岗位关联

学会 DiCE,你能让 AI 从「只报忧」升级为「既报忧又指路」:把黑盒模型的拒绝,翻译成客户可执行的具体改动建议。这项能力在金融风控、招聘筛选、医疗决策等强解释需求场景中,是 AI 工程师最有说服力的加分项。

目录
  1. 可视化演示
  2. 概念与背景
  3. 核心思想
  4. 生成算法
  5. 多样调控
  6. 因果约束
  7. 评估指标
  8. 实践与挑战
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示DiCE生成多样化反事实解释的过程、多目标优化约束(距离+多样性+有效性)以及反事实质量评估维度,交互切换三种模式探索可解释AI方法。

本节配有交互动效(进入视口后自动加载,约 3KB)。

'+CAPS.mode1+'

概念与背景

李雷站在银行门口,攥着那张写着「综合评分不足」的回执,心里很不服气。他找到理财经理追问原因,得到的回答是「您的负债率偏高」。可负债率到底高到什么程度?哪一项改动最值钱?没有人告诉他。这位只给判决、不给建议的 AI 审批官,就是一个典型的「黑盒模型」——输入输出看得见,内部判断机制却像隔着一层磨砂玻璃。

早期的可解释 AI 主要做「特征归因」:像体检报告那样告诉你「胆固醇这一项扣了最多分」。这类解释回答了「为什么被拒」,却没有回答「怎么改才能获批」。于是研究者把目光投向了因果推理里的「反事实」概念——它研究的是遗憾句式:「如果当初……,现在会不会……?」在机器学习里,反事实解释把这句遗憾变成一道可计算的题:找到一组改动,让模型的判决翻转。

形式化地说,给定原始样本 x 和模型 f,反事实解释的目标是找到一个改动后的样本 x',让 f(x') 变成我们希望的结果,同时 x' 与 x 尽量相似。DiCE 的名字里带「Diverse」(多样),意味着它不是给一个标准答案,而是给一整套答案集。这就像你问「人生重开顾问」:不许你穿越回 18 岁重头再来,只许你在现有材料上做几处小修小改,然后告诉你——「这样改,审批官就会点头。」

于是,DiCE 就像一个「剧本导演」:他不允许你重新投胎,只允许你在现有剧本上改几行台词,然后保证改完的剧本能在大结局拿到「审批通过」的圆满收场。

事实:  f(x)=0  (拒绝),反事实:  f(x′)=1  (通过),x′≠x\displaystyle \text{事实:}\; f(x) = 0 \;(\text{拒绝}), \qquad \text{反事实:}\; f(x') = 1 \;(\text{通过}), \quad x' \neq x
这行公式是整个反事实解释的「宪法」:事实是被拒,反事实是通过,中间的桥梁是一份改动过的申请材料。
  1. f 与 x——审批官与原始材料f 是银行的 AI 审批模型,x 是李雷的原始申请材料(收入、负债、工龄、贷款金额等特征),f(x)=0 表示审批官给出「拒绝」判决。
    f(x)=0  (拒绝)f(x) = 0 \;(\text{拒绝})
  2. x' 与 f(x')=1——平行世界的材料x' 是一份改动后的申请材料,它能让审批官改口说「通过」(输出 1)。
    f(x′)=1  (通过)f(x') = 1 \;(\text{通过})
  3. x' ≠ x——改动必须真实发生反事实之所以叫「反」事实,是因为它描述的是一个编造但足够接近真实的替代场景,而不是把原始材料原样复述一遍。
    x′≠xx' \neq x

核心思想

李雷拿到了人生第一份「平行世界剧本」:月收入从 7000 涨到 12000。他高兴之余又犯了难——「涨收入哪是说涨就涨?有没有别的改法?」如果人生重开顾问只递过来一个剧本,那这顾问也太不贴心了。DiCE 的特殊之处恰恰在这里:它递过来的是一本「剧本集」,里面是好几条不同的路。

普通反事实解释只给一个答案,像只写了一个结局的导演;DiCE 坚持给出「多个结局」:收入高一点可以获批;还清一张信用卡、把负债率降下来也可以;把工作年限熬满三年同样可以。这些候选方案在特征层面彼此不同,但都能让模型输出翻转。这就是「多样候选集」的威力——它把解释从「一道单选题」变成了「一份选择题」。

为了实现这一点,DiCE 把反事实解释的质量拆成了三个目标,像三把尺子同时量一份解释:有效性(每个候选都必须真的让结果翻转)、贴近性(每个候选离原始样本越近越好,改动幅度小)、多样性(候选之间彼此尽量不同,给足选择空间)。三个目标放进同一个损失函数里互相博弈,谁都不能一家独大。

于是 DiCE 递给李雷的是一本《平行世界菜单》:一号剧本是加薪,二号剧本是还债,三号剧本是熬工龄。哪个他真做得到,就照抄哪个。解释这件事,从「宣布判决」变成了「给出出路」。

{x1′,…,xk′}=arg⁡min⁡x1′,…,xk′[  ∑i=1kℓ(f(xi′), y∗)+λ∑i=1kdist(xi′, x)−λdiv  div(x1′,…,xk′)  ]\displaystyle \{x_1', \dots, x_k'\} = \arg\min_{x_1', \dots, x_k'} \Big[\;\sum_{i=1}^{k} \ell\big(f(x_i'),\, y^{*}\big) + \lambda \sum_{i=1}^{k} \mathrm{dist}(x_i',\, x) - \lambda_{\mathrm{div}}\; \mathrm{div}(x_1', \dots, x_k')\;\Big]
这个公式是 DiCE 的「总调度台」:左边想的是「我要的不是一个答案,而是一组答案」,右边的三项分别管「管不管用」「改动大不大」「彼此像不像」。
  1. 候选集合 {x1',…,xk'}要一次性找 k 个平行世界(比如 k=4 个候选剧本),而不是只找一个答案。
    {x1′,…,xk′}\{x_1', \dots, x_k'\}
  2. 损失项 ℓ(f(xi'), y\)保证第 i 个候选让审批官判为「通过」(y\=1 是期望结果),这一项越小,说明候选越有效。
    ℓ(f(xi′), y∗)\ell\big(f(x_i'),\, y^{*}\big)
  3. 贴近项 λ·Σdist惩罚所有候选改得太远,让每个剧本都尽量「小改」,像要求续写小说不能把主角职业凭空换掉。
    λ∑i=1kdist(xi′, x)\lambda \sum_{i=1}^{k} \mathrm{dist}(x_i',\, x)
  4. 多样项 −λdiv·div减号表示「多样性越高损失越低」,鼓励候选之间互相远离,避免四个剧本长得一模一样。
    −λdiv  div(x1′,…,xk′)- \lambda_{\mathrm{div}}\; \mathrm{div}(x_1', \dots, x_k')
  5. λ 与 λdiv——两个旋钮λ 管「贴近度」权重,λdiv 管「多样度」权重;拧大哪个,优化器就更迁就哪个目标。
    λ,λdiv\lambda,\quad \lambda_{\mathrm{div}}

生成算法

这位「人生重开顾问」是怎么当场编出剧本的?李雷很好奇。顾问摊开一张地图:横轴是收入水平,纵轴是负债水平,地图上的每个点代表一份申请材料;中间那道「审批及格线」把地图切成两半——上半是拒绝区,下半是通过区。李雷现在站在拒绝区深处,他需要找一条最短的路,走到及格线的另一侧。

但计算机不会像人一样「目测找路」,它靠数学。DiCE 把「离及格线还差多少」和「改了多少」合并成一个损失函数,然后用梯度下降一步步挪。梯度下降的直觉很像在山谷里摸黑下坡:你看不见整座山,但只要每一步都往「坡度最陡的下坡方向」迈,最终总能走到谷底。这里的「谷底」就是「既能让审批官点头、又改动最小」的方案。

具体实现时,DiCE 对连续特征直接算梯度更新;对离散特征(如学历、婚姻状态)则用概率采样加「软」技巧(比如 Gumbel-Softmax)让梯度能流过去。由于损失曲面坑坑洼洼,算法还会从多个随机起点并行出发——就像顾问同时让好几个助手从地图不同位置开始探路,最后再汇总出最优的几份候选。

顾问在「人生地图」上小步快跑:每挪一寸就问一次「审批官现在会点头吗?改了多少?」,直到一只脚踏进通过区。这套「走一步、问一句」的笨功夫,就是梯度下降的真相。

xt+1′=xt′−η⋅∇x′[ ℓ(f(xt′),y∗)+λ  dist(xt′,x) ]\displaystyle x'_{t+1} = x'_{t} - \eta \cdot \nabla_{x'} \big[\, \ell(f(x'_t), y^{*}) + \lambda\; \mathrm{dist}(x'_t, x) \,\big]
这是一行「走一步」的更新式:每走一步,都要问一次「这个方向能不能让审批分更高、改动更少」,然后迈出一步,重复很多次。
  1. x'_{t+1} = x'_t新剧本等于旧剧本加上一步的修正量,t 表示第几步,像写小说改了一版又一版。
    xt+1′=xt′x'_{t+1} = x'_{t}
  2. η——学习率(步长)控制每步迈多大。步子太大容易一脚踩过「及格线」冲到荒郊野外,太小则走得太慢。
    η\eta
  3. ∇x'[·]——梯度方括号里是「目标损失」对 x' 的导数,像指南针一样指出「哪个方向能让审批分更高、改动更少」。
    ∇x′[ ℓ(f(xt′),y∗)+λ  dist(xt′,x) ]\nabla_{x'} \big[\, \ell(f(x'_t), y^{*}) + \lambda\; \mathrm{dist}(x'_t, x) \,\big]
  4. 负号——逆着梯度走梯度指向损失上升的方向,所以取反号才能让损失下降,相当于指南针指上山,我们偏要下山去。
    −η⋅∇x′- \eta \cdot \nabla_{x'}

多样调控

李雷在地图上发现了惊喜:同样的「获批」目标,门口竟然有四个不同的入口——有人从「加薪」方向进来,有人从「降负债」方向进来,有人从「清空消费贷」方向进来,还有人从「延长工龄」方向进来。顾问是怎么保证这些入口不重叠的呢?

你可能已经想到一个问题:既然目标都是「走到通过区」,算法会不会每次都抄最近的那条路,最后给出一模一样的四个剧本?DiCE 论文里专门设计了「多样性惩罚」来防止这种撞车。它借用了数学里「行列式点过程」(Determinantal Point Process,DPP)的思想:把候选之间的相似度编码成一个核矩阵 K,然后取 K 的行列式作为「铺得有多开」的度量。

为什么用行列式?直觉上,如果两个候选几乎一样,矩阵里对应的两行就高度相似,行列式会变得很小;候选之间差异越大,行列式越大。于是优化器在追求「有效」和「贴近」之外,还要额外把一个「行列式」做大——这就逼着它把候选们往互相远离的方向推。工程实践中也常用更朴素的替代:直接最大化候选两两之间的距离,效果类似但计算更便宜。

这就像四位司机要开进同一个地下车库,顾问强制要求他们走不同的入口——宁可某条路多绕两步,也要保证每一条路线都不同,让李雷拥有真正的选择权,而不是拿到四份一模一样的「加薪方案」。

div(x1′,…,xk′)=det⁡(K),Kij=11+dist(xi′, xj′)\displaystyle \mathrm{div}(x_1', \dots, x_k') = \det(K), \qquad K_{ij} = \frac{1}{1 + \mathrm{dist}(x_i',\, x_j')}
多样性得分 = 「候选相似度矩阵」的行列式。行列式越大,代表这几份剧本在特征空间里铺得越开,选择越丰富。
  1. K 核矩阵一个 k×k 对称矩阵,K_{ij} 表示第 i 个候选和第 j 个候选的相似度:距离越近,相似度越接近 1。
    Kij=11+dist(xi′, xj′)K_{ij} = \frac{1}{1 + \mathrm{dist}(x_i',\, x_j')}
  2. det(K)——行列式矩阵行列式的值能紧凑地反映「这组向量有多独立」。候选越像,行列式越小;候选越不同,行列式越大。
    det⁡(K)\det(K)
  3. 整体含义把「多样性得分」定义为 det(K) 塞进损失函数,优化器就会自动把候选往「彼此远离」的方向推,得到四个入口不重叠的剧本。
    div(x1′,…,xk′)=det⁡(K)\mathrm{div}(x_1', \dots, x_k') = \det(K)

因果约束

拿到四个剧本后,李雷哭笑不得:其中一版建议「把信用卡负债从 80% 降到 30%」,他咬咬牙能做到;可另一版建议「把年龄改小 5 岁」,这根本不可能;还有一版把「名下房产数」从 0 改成 1,可房子哪是说买就买的?顾问拍了拍脑袋:「是我考虑不周,这些凡人做不到的改动,我帮你过滤掉。」

这暴露了反事实解释在工程落地时最重要的一课:不是所有特征都允许随便改。年龄、出生城市、既往病史这类特征天生不可操纵;学历、职业可以改但代价很高;收入、负债这类相对可操作。如果不加约束,优化器会在数学上找到一个「完美但荒谬」的答案——因为它不懂现实世界的社会规则和物理规律。

DiCE 的工程化方案是引入「可操作特征集合」A 和因果图:集合 A 之外的特征在优化过程中锁死不动;因果图则负责防止出现「提高学历会让年龄自动变小」这种违反因果常识的联动漏洞。更进一步,每个可操作特征还带一个允许改动的范围,比如负债率只能降不能升、收入不能改成负数。这些约束把解空间从「所有平行世界」压缩到「现实可能世界」。

顾问在「人生地图」上贴了一圈「此处禁止施工」的胶带:不可改的特征画红线,可改的特征圈绿区。李雷再拿到的剧本,从此只包含他真能执行的改动——这才是「可行的人工智能建议」。

xj′={xj+δj,j∈A, δj∈rangejxj,j∉A\displaystyle x'_j = \begin{cases} x_j + \delta_j, & j \in \mathcal{A},\ \delta_j \in \mathrm{range}_j \\[4pt] x_j, & j \notin \mathcal{A} \end{cases}
一句话:能改的才让改,不能改的锁死,能改的也必须在合理范围内改。这是「平行世界菜单」能端上桌的最后一道质检。
  1. A——可操作特征集合只有落在集合 A 里的特征才允许改动,比如「收入」「信用卡数量」;A 之外的默认视为不可撼动。
    A\mathcal{A}
  2. δj——每个特征的改动量对可操作特征 j,允许加一个改动量 δj,但这个改动量必须落在这个特征的合理取值范围内(不能把负债改成负数)。
    xj+δj,δj∈rangejx_j + \delta_j,\quad \delta_j \in \mathrm{range}_j
  3. j ∉ A 时锁死年龄、种族、是否拥有房产等不可操作特征保持原值,不参与优化,从源头杜绝「把年龄改小 5 岁」的荒唐剧本。
    xj,j∉Ax_j, \quad j \notin \mathcal{A}
  4. 整体效果优化器只能在「现实允许改动的维度」上寻找平行世界,保证每一份剧本都真的可执行。
    x′=(x1′,…,xd′),满足上述逐维约束x' = (x'_1, \dots, x'_d), \quad \text{满足上述逐维约束}

评估指标

李雷把四个剧本拿给同事小张看,小张半信半疑:「你凭什么说这些剧本好?万一是顾问瞎编的呢?」顾问表示:给解释打分,得像给外卖评分一样讲究维度——口味(有效)、速度(贴近)、花样(多样)、分量(稀疏),缺一不可。

一篇可解释 AI 的论文如果只讲故事不量化,很难服众。DiCE 的作者给行业定下了一套评估「解释质量」的标准口径:有效性(Validity)、贴近度(Proximity)、多样性(Diversity),外加一个稀疏度(Sparsity)。有了这些指标,不同的反事实算法才能拉出来公平对打,业务方也能用数字向上汇报「这套解释系统到底靠不靠谱」。

具体来说:有效性计算候选集中能让模型结果翻转的比例,100% 说明每个剧本都管用;贴近度计算候选与原始样本的平均距离,距离越小说明改动越轻;多样性计算候选两两之间的平均距离,距离越大说明选择越丰富;稀疏度则统计每个候选动用了几个特征,改动特征越少,用户的执行成本就越低。这四个数字组合起来,基本就能判断一份解释是「花架子」还是「真有用」。

这就像给一份「人生重开菜单」打分:每道菜都得真能下咽(有效)、原材料别太离谱(贴近)、菜单上不能四道菜全是番茄炒蛋(多样)、每道菜的配料别超过三种(稀疏)。四项都达标,才算一份合格的解释。

Validity=1k∑i=1k1[ f(xi′)=y∗ ],Diversity=2k (k−1)∑i<jdist(xi′, xj′)\displaystyle \mathrm{Validity} = \frac{1}{k} \sum_{i=1}^{k} \mathbb{1}\big[\, f(x_i') = y^{*} \,\big], \qquad \mathrm{Diversity} = \frac{2}{k\,(k-1)} \sum_{i<j} \mathrm{dist}(x_i',\, x_j')
左边算「有多少剧本真的能翻盘」,右边算「剧本之间平均有多不一样」。两个数字,一个管质量底线,一个管选择空间。
  1. Validity——有效性逐个检查 k 个候选是否真的把结果翻转,用示性函数 1[·] 计数(真为 1,假为 0),除以 k 得到翻转比例。
    1[ f(xi′)=y∗ ]\mathbb{1}\big[\, f(x_i') = y^{*} \,\big]
  2. Diversity——多样度k 个候选两两配对共有 k(k−1)/2 对,累加每对的距离后取平均,衡量剧本彼此有多不一样。
    2k (k−1)∑i<jdist(xi′, xj′)\frac{2}{k\,(k-1)} \sum_{i<j} \mathrm{dist}(x_i',\, x_j')
  3. 配套指标贴近度取平均距离「越小越好」,稀疏度数一数每个候选改动了几个特征,「改动特征越少越容易执行」。
    Proximity=1k∑i=1kdist(xi′, x),Sparsity=1k∑i=1k∣{j:xij′≠xij}∣\mathrm{Proximity} = \frac{1}{k} \sum_{i=1}^{k} \mathrm{dist}(x_i',\, x), \qquad \mathrm{Sparsity} = \frac{1}{k} \sum_{i=1}^{k} \big|\{j : x'_{ij} \neq x_{ij}\}\big|

实践与挑战

李雷最终拿着「加薪剧本」鼓起勇气找老板谈了一次,成功了。他感慨:如果当初银行直接给出这么具体的建议,他早两年就能还清债务。但故事的另一面是:要把这位「人生重开顾问」从论文搬进生产系统,还有一长串现实难题。

最大的难题是:银行里真正的审批模型往往是「黑盒中的黑盒」——它们由多个模型集成、封装成内部 API,只给你预测结果,不给你梯度。而 DiCE 的梯度下降天然需要一个可微的函数 f,遇到不可微模型就只能用有限差分(数值梯度)或训练一个「代理模型」来近似,计算成本成倍上升。另一个痛点是高维数据:特征一多,「平行世界」的搜索空间指数膨胀,优化器很容易迷路;类别型特征、缺失值、硬性业务规则也都需要在工程上逐一处理。

好消息是,DiCE 已经有开源实现(如 Python 的 DiCE 库),支持 TensorFlow 和 PyTorch,也能对接任意 sklearn 风格的模型。社区围绕它生长出很多变体:加入因果约束的版本、面向时间序列的版本、面向医疗决策的版本。但万变不离其宗——核心永远是那句承诺:给用户一份「多样、贴近、可行」的 What-if 答案集。

「人生重开顾问」也有自己的瓶颈:进不了审批官的大脑深处(黑盒)、地图太大跑不动(高维)、有些规则是硬杠杠(约束)。但正因如此,能把顾问从实验室请进银行大厅的工程师,才格外值钱——他们让冷冰冰的拒绝多了一点「还能怎么办」的温度。

f^≈f,x′∗=arg⁡min⁡x′[ ℓ(f^(x′),y∗)+λ  dist(x′,x) ]s.t. x′∈C\displaystyle \hat{f} \approx f, \qquad x'^{*} = \arg\min_{x'} \Big[\, \ell\big(\hat{f}(x'), y^{*}\big) + \lambda\; \mathrm{dist}(x', x) \,\Big] \quad \text{s.t. } x' \in \mathcal{C}
当真正的审批官不让你「看脑子」时,就训练一个替身(代理模型)替你探路,最后在所有「现实中可行的剧本」里选最优。
  1. f̂ ≈ f——代理模型原模型 f 不可导,就训练一个可导且行为相近的替身 f̂(比如用梯度提升树的预测值拟合一个神经网络),保证梯度算得出来。
    f^≈f\hat{f} \approx f
  2. x'\*——最优反事实在代理模型上求解「最小改动、最贴近、可翻转」的剧本,得到最优候选。
    x′∗=arg⁡min⁡x′[ ℓ(f^(x′),y∗)+λ  dist(x′,x) ]x'^{*} = \arg\min_{x'} \Big[\, \ell\big(\hat{f}(x'), y^{*}\big) + \lambda\; \mathrm{dist}(x', x) \,\Big]
  3. s.t. x' ∈ C——可行性约束C 是可行性约束集合(可操作特征、取值范围、因果图规则),所有候选都必须在这个集合内,否则直接淘汰。
    s.t. x′∈C\text{s.t. } x' \in \mathcal{C}

AI 应用场景

信贷审批的「拒绝回执改造」

阶段:模型部署后的事后解释与客户沟通

解决的问题:传统拒绝回执只有一句「综合评分不足」,客服话术无法给出个性化建议,客户不知道从何改进,投诉率居高不下。用 DiCE 给每个被拒客户生成 3-5 个「最小改动」的平行世界剧本,客服照读便可执行,把「拒绝」变成「改进指南」。

具体案例:某消费金融公司把 DiCE 接入贷后客服系统:当模型拒绝申请时,系统自动输出多个反事实建议,并按「改动成本从低到高」排序推送给客服。实测客户按建议调整后,3 个月内再次申请获批率显著提升,客户投诉量明显下降。

招聘筛选的「落选改进建议」

阶段:招聘筛选模型的解释与候选人反馈

解决的问题:简历被 AI 筛掉的候选人往往一头雾水,不知道从哪个方向提升。传统做法是统一模板的拒绝邮件,候选人体验差。DiCE 可以为每份落选简历生成个性化建议,如「补充 3 年以上项目经验」或「在简历中突出 Python/Spark 技能」。

具体案例:某互联网公司的 HR 筛选系统对落选简历批量运行 DiCE,把生成的解释写进感谢信。候选人满意度大幅提升,部分候选人有针对性地补充技能后再次投递,进入面试环节的比例上升。

Python 演示

python60 行
import numpy as np  class LoanModel:    """用逻辑回归模拟银行的AI审批官"""     def __init__(self, weights, bias):        self.weights = np.array(weights, dtype=float)        self.bias = float(bias)     def approve_score(self, x):        z = np.dot(self.weights, x) + self.bias        return 1.0 / (1.0 + np.exp(-z))     def is_approved(self, x, threshold=0.62):        return self.approve_score(x) >= threshold  model = LoanModel(weights=[2.0, -1.5, 1.2, -0.9], bias=-1.2)feature_names = ["收入", "负债", "工龄", "贷款额"]x0 = np.array([0.42, 0.78, 0.35, 0.72])  # 李雷: 收入低, 负债高, 工龄短  def total_loss(x, y_target=1.0, lam=0.6):    pred = model.approve_score(x)    return (pred - y_target) ** 2 + lam * np.sum((x - x0) ** 2)  def numerical_gradient(x, h=1e-3):    grad = np.zeros_like(x)    for i in range(len(x)):        xp = x.copy()        xp[i] += h        xm = x.copy()        xm[i] -= h        grad[i] = (total_loss(xp) - total_loss(xm)) / (2.0 * h)    return grad  def generate_counterfactuals(n_candidates=4, lr=0.18, steps=120, seed=7):    rng = np.random.default_rng(seed)    results = []    for _ in range(n_candidates):        x = x0 + rng.normal(0, 0.35, size=x0.shape)  # 随机起点 = 不同平行世界        for _ in range(steps):            x = x - lr * numerical_gradient(x)        results.append(x)    return results  def main():    print("原始申请是否获批:", model.is_approved(x0))    print("\nDiCE 生成的多样反事实解释(平行世界):")    for i, x in enumerate(generate_counterfactuals(), 1):        changed = [feature_names[j] for j in range(len(x)) if abs(x[j] - x0[j]) > 0.05]        print("  剧本%d: 审批分=%.3f, 改动特征=%s" % (i, model.approve_score(x), changed))  if __name__ == "__main__":    main()
目的:用数值梯度模拟 DiCE 的核心流程——为「被拒」的贷款申请人生成多个多样化的「平行世界」方案,每个方案都尽量小改动且能让模型翻转为「获批」。
  1. class LoanModel:用类封装银行 AI 审批官,内部是带 sigmoid 的逻辑回归,输入四维特征,输出 0~1 的审批分。
  2. return 1.0 / (1.0 + np.exp(-z))sigmoid 函数把加权求和值压缩到 0~1,作为「审批通过的概率」。
  3. x0 = np.array([0.42, 0.78, 0.35, 0.72])李雷的原始材料:收入低、负债高、工龄短、贷款多,保证初始被拒。
  4. return (pred - y_target) ** 2 + lam * np.sum((x - x0) ** 2)损失函数由「结果偏差」和「改动幅度」两部分组成,对应有效性与贴近度。
  5. grad[i] = (total_loss(xp) - total_loss(xm)) / (2.0 * h)有限差分法近似梯度:只依赖模型的输入输出,黑盒也能求导。
  6. x = x0 + rng.normal(0, 0.35, size=x0.shape)不同的随机起点对应不同的初始扰动,是「多样平行世界」的来源。
  7. x = x - lr * numerical_gradient(x)梯度下降更新:逆着梯度方向小步走,逐步逼近「获批且改动小」的方案。

常见误区

误区「DiCE 和 SHAP、LIME 都是解释 AI 的,不都是说哪些特征重要吗?我学一个就够了。」

正解两者回答的是不同问题。特征归因回答「为什么被拒」——哪个特征把分数拉低了,像体检报告告诉你「胆固醇超标」;反事实解释回答「怎么改才能获批」——像医生开处方「每天走一万步、减盐」,并且 DiCE 会一次性给你三张不同处方。一个指向病因,一个指向出路,二者是互补关系,不能互相替代。

为何常见:两者都顶着「可解释 AI」的帽子,输出也在讲输入特征,初学者很容易把它们打包成同一类工具。

误区「反事实解释不就是找到改动最小的那个方案吗?给一个不就行了,给多了反而乱。」

正解单一方案常常代价高昂或不可行——比如最优解是「年收入翻倍」,对普通人等于废话。DiCE 的核心价值恰恰是「多样」:给出多个候选,用户才能在其中挑一个自己真正做得到的方案。就像一位被裁程序员收到「读研、转行、自学接私活」三条路,他才能结合现状做选择。

为何常见:传统优化思维默认「最优解只有一个」,忽略了现实中不同用户的执行可行性完全不同。

误区「DiCE 靠梯度下降生成反事实,而梯度下降需要导数,黑盒模型又不给我导数,所以 DiCE 只能用在白盒模型上。」

正解DiCE 是模型无关的。即使 f 不可导,也可以用有限差分(数值梯度)——只需要增加减少一点点输入、观察输出的变化,就能估出梯度方向;更省事的做法是训练一个可导的代理模型替身。黑盒只是让求解更贵、更慢,并不会让 DiCE 完全失效。

为何常见:「梯度下降需要导数」这个先入为主的印象,让很多人以为拿不到模型内部结构就等于无法优化。

误区「DiCE 输出的反事实方案是算法精心算出来的,肯定是合理可执行的,我直接照着改准没错。」

正解基础版 DiCE 并不自动保证因果合理性,它可能给出「把年龄改小 5 岁」「同时提高学历又降低年龄」这类联动矛盾建议。工程落地时必须额外加上可操作特征集合、取值范围约束和因果图,才能过滤掉荒谬剧本。论文里的 demo 和生产线上的版本,中间隔着大量工程工作。

为何常见:论文示例里的特征都经过精心挑选,而真实数据里低质量特征比比皆是,用户拿到剧本容易盲目照做。

面试题

Q1. DiCE 中的「D」代表什么设计思想?

单选题 · easy

  • A.数据的多样性
  • B.解释的多样性← 正确答案
  • C.模型的深度
  • D.距离的度量

答案:B。DiCE 全称 Diverse Counterfactual Explanations,核心创新就是一次性给出多个不同的反事实候选,让用户有选择空间。数据增强、模型深度、距离度量虽然都与机器学习相关,但都不是「D」的真实含义。

Q2. 反事实解释回答的核心问题是什么?

单选题 · easy

  • A.模型为何做出预测
  • B.哪些特征最重要
  • C.如何改动才能翻盘← 正确答案
  • D.数据质量有多差

答案:C。反事实解释解决的是 What-if 问题:把哪些特征改成多少,模型结果会从拒绝翻转为通过。A、B 属于特征归因的范畴,D 属于数据质量分析,与反事实解释的核心目标无关。

Q3. 在 DiCE 的目标函数中,多样性项前面使用减号的作用是什么?

单选题 · mid

  • A.使优化轻易失效
  • B.惩罚相近的候选← 正确答案
  • C.让候选挤作一团
  • D.减少计算开销

答案:B。目标函数是「有效性 + 贴近度 − 多样性」,减号表示多样性越高、损失越低,从而鼓励候选彼此远离。A 恰好相反,C 是减号要避免的结果,D 与数学形式无关。

Q4. 下列哪些属于 DiCE 生成反事实时应考虑的约束?(选择两项)

多选题 · mid

  • A.可操作特征集合← 正确答案
  • B.特征取值范围← 正确答案
  • C.模型参数量
  • D.训练集的大小

答案:AB。可操作特征集合决定「哪些特征能改」,取值范围决定「每个特征能改多少」,两者共同确保剧本可执行。模型参数量、训练集大小属于模型训练阶段的考量,与解释生成无关。

Q5. 当目标模型 f 不可导(黑盒)时,常用的替代方案是什么?

单选题 · mid

  • A.调用随机猜测
  • B.有限差分求梯度← 正确答案
  • C.删除并重训模型
  • D.输出随机候选集

答案:B。有限差分(数值梯度)只依赖模型输入输出,通过扰动输入观察输出变化来估计梯度方向,是黑盒优化的常用手段。A、D 不是求解方案,C 不现实也不必要。

Q6. DiCE 的多样性损失主要基于哪种数学工具?

单选题 · hard

  • A.矩阵的行列式← 正确答案
  • B.傅里叶变换系数
  • C.概率分布的熵
  • D.余弦相似度均值

答案:A。DiCE 借用行列式点过程(DPP),把候选相似度编码成核矩阵,再取其行列式作为多样性得分:候选差异越大,行列式越大。傅里叶、熵、余弦相似度都不是论文中用到的核心工具。

Q7. 在 DiCE 中,同时增大 λ 并减小 λdiv,最可能造成什么结果?

单选题 · hard

  • A.候选更近且更相似← 正确答案
  • B.候选更远更多样
  • C.候选保持原样
  • D.目标函数变为零

答案:A。λ 控制贴近度权重,增大它会让候选更贴近原始样本;λdiv 控制多样性权重,减小它会让候选更容易「撞车」。因此最直接的结果是候选距离更小且彼此更相似。C 过于绝对,D 不现实。

Q8. 下列哪些是评估反事实解释质量的常用指标?(选择两项)

多选题 · hard

  • A.有效性(翻转率)← 正确答案
  • B.贴近度(距离)← 正确答案
  • C.模型的 AUC
  • D.数据的覆盖率

答案:AB。评估解释质量看「是否真能翻盘」(有效性)、「离原样本多近」(贴近度)以及「候选之间多大差异」(多样度)。AUC 用来评估分类模型本身,覆盖率是推荐/聚类领域的指标,与解释质量无直接关系。

Q9. 反事实解释(如 DiCE)与特征归因(如 SHAP)最主要的区别是什么?

单选题 · easy

  • A.前者给建议后者释因← 正确答案
  • B.前者只能用于树模型
  • C.后者无需训练数据
  • D.两者作用完全一致

答案:A。特征归因回答「为什么」——哪些特征贡献最大;反事实解释回答「怎么改」——改成什么值能翻盘。DiCE 是模型无关的,SHAP 也需要数据,B、C、D 均为错误说法。

Q10. 关于 DiCE 的适用限制,下列描述正确的有哪些?(选择两项)

多选题 · mid

  • A.高维数据求解开销大← 正确答案
  • B.可能给出不可行建议← 正确答案
  • C.只支持连续型特征
  • D.必须白盒模型才能用

答案:AB。高维数据下搜索空间指数膨胀,求解开销大;基础版不加因果约束时确实可能输出「改年龄」这类荒谬建议。DiCE 可以通过概率采样处理类别型特征,且黑盒模型也能用代理或数值梯度求解,因此 C、D 错误。