6.2 推理透明化:可解释性 GNN


6.2 推理透明化:可解释性 GNN

本节摘要:图上的可解释性回答"模型的结论由哪部分图证据支撑"——子图解释方法学习边与特征的软掩码,圈出决定性证据集合;注意力权重只能算线索而非证据;保真度指标量化"抽掉解释后结论崩不崩、只留解释时结论稳不稳"。本节覆盖事后解释、内置解释、生成式解释这些路线与风控场景的落地形态。

一纸监管函

金融监管的函件写得很克制:模型可以参与授信决策,但被拒客户有权知道理由,且理由必须来自该客户自身的案子,不能是"模型整体统计"。这纸函件终结了"黑箱也能上线"的侥幸。图模型的解释难题比表格模型更棘手:表格模型的理由落在特征上(收入、负债率),图模型的理由还可能落在结构上——"你被拒是因为你的担保圈里有失信节点",这种结构性理由连表述都需要设计。本节把可解释性当作正式的建模需求来处理,承接第三章 GAT 留下的伏笔(注意力权重是"看起来像解释"的东西),给出真正可用的解释框架与验收指标。

三条解释路线

事后解释不改动模型:训练完成后,对单个预测寻找"最小但充分的证据子图"。代表性做法是把边与特征的选择松弛为连续掩码,优化目标是"掩码后的子图输出尽量接近原输出",学到的掩码权重就是证据的重要性排序——GNNExplainer 是这条路线的经典。内置解释把解释能力设计进结构:注意力机制天然产出逐边权重,可解释图卷积在聚合时显式保留"哪些邻居贡献了什么"的通路。生成式解释反向构造样本:生成"能被模型稳定判为某类的最小图",用样例本身当解释——XGNN 论文用它同时满足"解释"与"模型诊断"(生成出的样例若违反常识,说明模型学到了伪规律)。三条路线的适用场景不同:监管审计要事后解释(对已有决策追责),实时风控偏好内置解释(权重顺手取出),模型调试则生成式最直观。

注意力的申诉与局限

注意力权重的申诉理由很充分:逐边可得、无需二次训练、风控同事一看就懂"模型盯的是哪条关系"。但把它直接当证据提交有两个风险。其一,权重高不等于因果贡献大——多头注意力的不同头可能互相抵消或放大,单边权重脱离整体路径没有意义。其二,注意力可能只反映训练分布的相关性而非决策依据,对抗样本甚至可以"注意力不变、结论翻转"。稳妥的用法是把注意力当初步线索,再用子图解释方法做交叉验证:两套方法指向同一证据集合,置信度才够提交。第三章 GAT 一节的"盯防热力图",在严谨场合应当配一份掩码解释作旁证。

# 子图证据的直觉实验:逐边测量"抽掉这条边,结论变多少" import torch import torch.nn.functional as F from torch_geometric.datasets import KarateClub from torch_geometric.nn import GCNConv data = KarateClub()[0] class Net(torch.nn.Module): def __init__(self): super().__init__() self.c1 = GCNConv(data.num_features, 8) self.c2 = GCNConv(8, 4) def forward(self, x, ei): return self.c2(F.relu(self.c1(x, ei)), ei) net = Net() opt = torch.optim.Adam(net.parameters(), lr=0.05) for _ in range(80): # 快速训练一个可用模型 opt.zero_grad() F.cross_entropy(net(data.x, data.edge_index)[data.train_mask], data.y[data.train_mask]).backward() opt.step() net.eval() with torch.no_grad(): base = net(data.x, data.edge_index).argmax(1) target = 0 # 待解释的节点 ei = data.edge_index related = (ei[0] == target) | (ei[1] == target) idxs = related.nonzero().flatten().tolist() influence = [] with torch.no_grad(): for i in idxs: # 逐边删除法(小图可用,大图用掩码松弛) keep = torch.ones(ei.size(1), dtype=torch.bool); keep[i] = False new_pred = net(data.x, ei[:, keep])[target].argmax().item() influence.append((int(i), int(base[target]), int(new_pred))) changed = [e for e in influence if e[2] != e[1]] print(f"与目标相关的边 {len(idxs)} 条,删掉后翻转结论的 {len(changed)} 条:", changed) # 翻转集合=决定性证据子图的候选——真实框架用连续掩码+优化,避免逐边组合爆炸

逐边删除法是"证据归因"的最朴素形态,它直接体现保真度的思想:证据的资格由"抽掉后结论是否改变"来检验。大图上逐边删除太贵,这就是掩码松弛优化存在的意义——把"选哪些边"变成可微的连续问题一次性求解。

验收指标:解释也要考试

解释本身需要质量指标,行业常用保真度双指标。必要性保真:把解释指出的证据从图中移除,模型对该样本的输出应显著改变——改变幅度越大,解释越"必要"(抽掉它结论就崩,说明它真是依据)。充分性保真:只保留解释指出的证据、其余全部遮蔽,模型输出应与原始输出接近——越接近,解释越"充分"(光靠这些证据就能得出同结论)。两指标一消一长,配合对比度(不同类别解释的差异度)与稀疏度(解释子图的大小),构成解释质量的四维体检。工程落地时还须加人审环节:解释子图转成自然语言陈述("三跳内与失信账户共同担保"),由业务同事评估"这个理由拿去给客户解释是否站得住"。

# 保真度双指标的计算骨架(接上文模型) import torch @torch.no_grad() def fidelity(model, x, ei, target, keep_idx): """keep_idx: 解释指定的证据边集合""" base_out = model(x, ei)[target] base_cls = base_out.argmax().item() mask = torch.zeros(ei.size(1), dtype=torch.bool); mask[keep_idx] = True # 必要性:抽掉证据边 → 输出应大变 out_wo = model(x, ei[:, ~mask])[target] nec = (base_out.softmax(-1) - out_wo.softmax(-1))[base_cls].item() # 充分性:只留证据边 → 输出应接近原始 out_only = model(x, ei[:, mask])[target] suf = 1 - abs(base_out.softmax(-1)[base_cls] - out_only.softmax(-1)[base_cls].item()) return nec, suf top_edges = [i for i, *_ in sorted(influence, key=lambda e: -e[2])][:2] or idxs[:2] nec, suf = fidelity(net, data.x, data.edge_index, 0, top_edges) print(f"必要性保真 {nec:+.4f}(绝对值越大越必要)|充分性保真 {suf:.4f}(越接近一越充分)")

落地形态与边界

风控场景的落地形态通常是"解释报告":对每个被拒客户,自动生成证据子图(哪些账户、哪类关系、何种模式),转写为业务语言,附保真度数值存档备审。要坦率承认边界:事后解释描述的是"模型此刻的决策依据",不保证该依据在统计意义上公平(偏见问题在第七章);解释子图里可能包含其他客户的信息,隐私约束(谁能看到谁的担保圈)必须在展示层解决。可解释性不是模型缺陷的遮羞布,而是把模型决策放进可审计轨道的基础设施。

⚠️ 常见坑:把显著性热图当因果证明。所有事后解释方法刻画的是"相关性贡献",用它做追责依据时,务必配合业务规则的因果校验。

本节要点

  • 三条路线:事后掩码解释、内置注意力通路、生成式反例,分别服务审计、实时、调试。
  • 注意力是线索不是证据:单边权重脱离整体无意义,严谨场合需子图解释交叉验证。
  • 保真度双指标:必要性看"抽掉崩不崩"、充分性看"只留稳不稳",加稀疏度与对比度构成体检。
  • 落地要人审:解释子图须转译为业务语言并评估隐私边界。

透明化诉求之后,下一桩悬案是彻底的"无米之炊"——零标注预算下如何让模型从数据自身学到表示。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U