把分子结构、蛋白序列、文本描述、组学数据放进同一个模型,听起来很有吸引力。但多模态的第一个问题不是「怎么融合」,而是「这些模态描述的是同一件事吗」——对齐问题解决不好,融合只会引入噪声。
对齐的三个层面
| 层面 | 问题 | 典型陷阱 |
|---|---|---|
| 实体对齐 | 不同数据源说的是同一个分子/蛋白吗 | 盐型、互变异构体、亚型、剪接变体 |
| 条件对齐 | 测量条件一致吗 | 不同细胞系、不同浓度、不同时间点 |
| 语义对齐 | 不同模态的「相同」含义一致吗 | 文本中的「有效」与实验中的 IC50 |
实体对齐的具体问题
# 分子侧:
# 同一个「化合物」可能是:
# - 游离碱 vs 盐酸盐(分子量不同)
# - 不同的互变异构体
# - 消旋体 vs 单一对映体
# - 不同的水合物/溶剂化物
# → 【必须先标准化】(见 046)
#
# 标识符的坑:
# - CAS 号可能对应盐型
# - InChIKey 的第一层块忽略立体化学
# - 数据库 ID 之间的映射不完全
#
# 蛋白侧:
# - UniProt ID vs 基因名 vs PDB 链
# - 同一基因的不同剪接变体
# - 物种(人 vs 小鼠的同源蛋白)
# - 翻译后修饰状态
# → 【「EGFR」在不同数据库中可能指不同的东西】
#
# 组学侧:
# - 探针 ID vs 基因 ID 的映射(一对多)
# - 不同平台的基因命名
# - 批次效应
#
# 【实践建议】:
# 建立一个明确的实体解析层,
# 记录每个映射的来源与置信度
# → 【这个「不性感」的工作决定了整个项目的质量】
from rdkit import Chem
from rdkit.Chem.MolStandardize import rdMolStandardize
def standardize_for_matching(smiles):
"""用于跨数据源匹配的标准化"""
mol = Chem.MolFromSmiles(smiles)
if mol is None:
return None
mol = rdMolStandardize.Cleanup(mol)
mol = rdMolStandardize.FragmentParent(mol) # 去掉盐/溶剂
mol = rdMolStandardize.Uncharger().uncharge(mol)
mol = rdMolStandardize.TautomerEnumerator().Canonicalize(mol)
return Chem.MolToInchiKey(mol)
# 【注意】:
# FragmentParent 会去掉抗衡离子 —— 这通常是对的
# 但如果盐型影响你关心的性质(如溶解度),
# 就不能这样处理
# → 【标准化策略必须与任务匹配】
条件对齐:最容易被忽略的问题
- 转录组数据的细胞类型:A549 细胞中的表达与患者肿瘤组织中的表达是两回事;
- 处理条件:药物处理的浓度、时间点不同,转录组响应完全不同;
- 活性数据的测定体系:酶活实验与细胞活性实验的 IC50 不可直接比较;
- 结构数据的状态:apo 结构与 holo 结构、不同的构象状态;
- 后果:模型可能学到的是「数据来源的特征」而非真实的生物学关系(这与 ADMET 数据的问题同源,见 156《AI ADMET 预测模型》);
- 应对:把条件作为显式的输入特征,或分层建模,而非假装它们不存在。
融合策略
# 三种基本策略
#
# 1) 【早期融合】
# 在输入层就把各模态拼在一起
# 优点:能建模细粒度的跨模态交互
# 缺点:要求模态严格对齐;某个模态缺失时难处理
#
# 2) 【晚期融合】
# 各模态独立编码/预测,最后合并结果
# 优点:
# - 【可以处理模态缺失】
# - 各模态可独立训练与调试
# - 能看出每个模态的贡献
# 缺点:无法建模跨模态的细粒度交互
# → 【实践中常常是更好的起点】
#
# 3) 【中间融合 / 交叉注意力】
# 各模态先独立编码,中间层做交互
# → AF3、Boltz 的做法(见 113、121)
# → 平衡了两者
#
# 【实践建议的顺序】:
#
# 第 1 步:单模态基线
# 每个模态单独建模,看各自能达到什么水平
# → 【这是判断融合是否有价值的前提】
#
# 第 2 步:晚期融合
# 简单地把各模态的预测加权平均或堆叠
# → 如果这就能提升,说明模态确实互补
# → 如果不能提升,深度融合大概率也不行
#
# 第 3 步:只在有明确收益时做深度融合
#
# 【常见的错误路径】:
# 直接上复杂的多模态架构 →
# 效果不如单模态 →
# 不知道问题出在对齐、融合还是数据
模态缺失:真实数据的常态
# 现实:很少有分子同时具备所有模态的数据
#
# 有 SMILES 的:100%
# 有三维构象的:可以算,但质量不一
# 有共晶结构的:极少数
# 有转录组响应的:只有做过实验的
# 有文本描述的:只有已发表的
#
# 处理方式:
#
# 1) 【只用交集】
# 简单,但数据量可能锐减
# → 且交集可能有偏(研究充分的分子)
#
# 2) 【掩码/占位符】
# 缺失的模态用特殊标记
# → 模型学会「没有这个模态时怎么办」
#
# 3) 【模态 dropout 训练】
# 训练时随机丢弃某些模态
# → 【让模型对缺失稳健】
# → 这是很实用的技巧
#
# 4) 【分层模型】
# 先用通用模态做基础预测,
# 有额外模态时做修正
#
# 【必做的检查】:
# 有完整模态的样本,与缺失模态的样本,
# 在其它方面是否有系统性差异?
# → 【如果有,那么「多模态更好」的结论
# 可能只是「有更多数据的分子更好预测」】
评估多模态模型的要点
| 检查项 | 为什么 |
|---|---|
| 单模态基线 | 必须——不然不知道融合是否有价值 |
| 逐模态消融 | 去掉每个模态看性能下降多少 |
| 模态置换测试 | 把某模态的数据打乱,性能是否下降?不下降说明它没被用 |
| 模态缺失下的表现 | 实际部署时会缺失 |
| 样本子集的一致性 | 只在有完整模态的样本上比较 |
| 计算成本 | 多模态成本高得多 |
「模态置换测试」是最有判别力的检查:把某个模态的数据随机打乱(打破它与标签的对应关系),如果模型性能几乎不变,说明这个模态实际上没有被使用——而论文可能仍然宣称「融合了 N 种模态」。
关键要点
- 对齐问题先于融合问题:实体、条件、语义三个层面都要处理;
- 条件对齐最容易被忽略——不同细胞系、浓度、时间点的数据不可直接混用;
- 先做单模态基线与晚期融合,晚期融合无收益则深度融合大概率也无收益;
- 模态置换测试能揭示某个模态是否真的被模型使用。
延伸资源
- 大语言模型:163《大语言模型与药物发现》;DTI 模型:157《AI DTI 预测模型》;ADMET:156《AI ADMET 预测模型》;
- 分子标准化:046《分子标准化》;AlphaFold3:113《AlphaFold3 论文精读》;Benchmark 陷阱:169《Benchmark 陷阱》。