分子模型的「可解释性」常常停留在画一张原子高亮图的层面。但一张好看的热图,如果不能改变化学家的下一步行动,就没有创造价值。真正有用的解释必须可验证、可行动。
常见方法与可靠性
| 方法 | 原理 | 可靠性 |
|---|---|---|
| 特征重要性(树模型) | 分裂增益 | 较可靠但粒度粗 |
| SHAP | 合作博弈论的归因 | 理论基础好;计算贵 |
| LIME | 局部线性近似 | 不稳定 |
| 注意力权重 | 模型内部权重 | 不可靠——不是因果证据 |
| 梯度类(Grad-CAM 等) | 输出对输入的梯度 | 有噪声 |
| 遮蔽/消融 | 删掉某部分看预测变化 | 直接,较可信 |
| 匹配分子对(MMP) | 数据驱动的结构-活性关系 | 最可靠——基于真实实验 |
为什么注意力不是解释
# 三个理由:
#
# 1) 【注意力不唯一】
# 可以构造出很不同的注意力分布,
# 给出几乎相同的预测
# → 那么哪一个是「正确的解释」?
#
# 2) 【注意力不等于因果】
# 模型「看了」某个位置,
# 不代表这个位置在化学上重要
# → 可能只是计算路径的中间产物
#
# 3) 【缺乏验证】
# 多数论文只展示 2~3 个「看起来合理」的案例
# → 【人类在任何热图中都能找到模式】
# → 没有统计验证的解释不构成证据
#
# 【正确的验证方式】:
# 把解释与【已知的真实信息】比较:
# - 共晶结构中的实际相互作用(见 108)
# - MMP 分析得到的取代基贡献
# - 已知的代谢位点
# - 化学家标注的药效团
# 计算重合度,并与随机基线比较
#
# 【消融验证】:
# 把模型认为重要的部分改掉,
# 预测是否显著变化?
# → 【这是最直接的检验】
# → 而且这个检验很容易做,却常常被省略
SHAP:相对可靠的选择
import shap
import numpy as np
from rdkit import Chem
from rdkit.Chem import rdFingerprintGenerator, Draw
# 对树模型,TreeSHAP 是精确且快速的
gen = rdFingerprintGenerator.GetMorganGenerator(radius=2, fpSize=2048)
explainer = shap.TreeExplainer(lgbm_model)
shap_values = explainer.shap_values(X_test)
# 全局重要性
shap.summary_plot(shap_values, X_test, max_display=20)
# ---- 把 SHAP 值映射回分子原子(关键步骤)----
def atom_contributions(smiles, model, explainer, radius=2, n_bits=2048):
"""把指纹位的 SHAP 值归到原子上"""
mol = Chem.MolFromSmiles(smiles)
if mol is None:
return None
bit_info = {}
gen_local = rdFingerprintGenerator.GetMorganGenerator(
radius=radius, fpSize=n_bits)
ao = rdFingerprintGenerator.AdditionalOutput()
ao.AllocateBitInfoMap()
fp = gen_local.GetFingerprint(mol, additionalOutput=ao)
bit_info = ao.GetBitInfoMap()
sv = explainer.shap_values(np.array(fp).reshape(1, -1))[0]
contrib = np.zeros(mol.GetNumAtoms())
for bit, envs in bit_info.items():
if sv[bit] == 0:
continue
for center_atom, rad in envs:
# 该位对应的子结构包含哪些原子
if rad == 0:
atoms = [center_atom]
else:
env = Chem.FindAtomEnvironmentOfRadiusN(mol, rad, center_atom)
atoms = set()
for b in env:
bond = mol.GetBondWithIdx(b)
atoms.add(bond.GetBeginAtomIdx())
atoms.add(bond.GetEndAtomIdx())
atoms = list(atoms) or [center_atom]
for a in atoms:
contrib[a] += sv[bit] / len(atoms)
return contrib
# 可视化
contrib = atom_contributions("CC(=O)Nc1ccc(O)cc1", model, explainer)
mol = Chem.MolFromSmiles("CC(=O)Nc1ccc(O)cc1")
Draw.SimilarityMaps.GetSimilarityMapFromWeights(mol, list(contrib))
# 【解读注意】:
# 1) SHAP 值是【相对于基线(平均预测)】的贡献
# 2) 一个指纹位可能对应多个原子环境 —— 归因有任意性
# 3) 【相关不等于因果】:SHAP 反映的是模型的行为,
# 不是化学的真理
# 4) 【必须与 MMP 分析交叉验证】
匹配分子对:最可靠的「解释」
# MMP(Matched Molecular Pairs):
# 找出只差一个取代基的分子对,
# 统计这个变换对性质的影响
#
# 【为什么最可靠】:
# 它基于【真实的实验数据】,
# 而非模型的内部状态
# → 这不是「解释模型」,而是「解释数据」
# → 但对化学决策而言,后者才是真正需要的
from rdkit import Chem
from collections import defaultdict
import numpy as np
# 用 mmpdb 或 RDKit 的 rdMMPA 做片段化
from rdkit.Chem import rdMMPA
def find_mmps(df, smiles_col="smiles", value_col="pIC50"):
"""找出匹配分子对并统计变换的影响"""
frags = defaultdict(list)
for _, row in df.iterrows():
mol = Chem.MolFromSmiles(row[smiles_col])
if mol is None:
continue
for core, chains in rdMMPA.FragmentMol(mol, maxCuts=1):
if core:
frags[Chem.MolToSmiles(core)].append(
(Chem.MolToSmiles(chains), row[value_col]))
transforms = defaultdict(list)
for core, items in frags.items():
for i in range(len(items)):
for j in range(i + 1, len(items)):
a, va = items[i]
b, vb = items[j]
if a != b:
transforms[(a, b)].append(vb - va)
transforms[(b, a)].append(va - vb)
results = []
for (a, b), deltas in transforms.items():
if len(deltas) >= 5: # 【需要足够的样本才有统计意义】
results.append({
"from": a, "to": b, "n": len(deltas),
"median_delta": float(np.median(deltas)),
"std": float(np.std(deltas)),
})
return sorted(results, key=lambda r: -abs(r["median_delta"]))
# 【输出对化学家直接可用】:
# 「把甲基换成三氟甲基,在这个系列中
# 中位数提升 0.6 个 log 单位(n=12)」
# → 这是可以直接指导下一步合成的信息
什么样的解释才有价值
| 标准 | 说明 |
|---|---|
| 可行动 | 能指出「改哪里、怎么改」 |
| 可验证 | 能设计实验检验这个解释 |
| 与已知知识一致或有理由不一致 | 矛盾时应能给出说法 |
| 有统计支撑 | 不是精选的个案 |
| 粒度合适 | 到官能团/取代基级别,而非单个指纹位 |
| 诚实标注不确定性 | 解释本身也有不确定性 |
一个实用的检验:把解释拿给化学家看,问「这会改变你下一步做什么吗?」如果答案是「不会」,那么这个解释没有创造价值——不管它的图画得多好看。
关键要点
- 注意力权重不是因果证据——注意力不唯一,且多数论文只展示精选案例;
- 消融验证最直接:改掉模型认为重要的部分,预测是否显著变化;
- 匹配分子对最可靠——它解释的是数据而非模型,且输出直接可指导合成;
- 检验标准:「这会改变化学家下一步做什么吗?」答案是否定的,解释就没有价值。
延伸资源
- MolTrans:141《MolTrans 论文精读》;SAR:073《SAR 构效关系》;活性预测:155《AI 活性预测模型》;
- PLIP:108《PLIP》;Benchmark 陷阱:169《Benchmark 陷阱》。