164

多模态模型:结构、序列、文本和组学融合前先解决对齐问题

多模态模型融合结构、序列、文本与组学,但对齐问题必须先解决。这篇讲清对齐的含义、常见陷阱与务实做法。

把分子结构、蛋白序列、文本描述、组学数据放进同一个模型,听起来很有吸引力。但多模态的第一个问题不是「怎么融合」,而是「这些模态描述的是同一件事吗」——对齐问题解决不好,融合只会引入噪声。

对齐的三个层面

层面 问题 典型陷阱
实体对齐 不同数据源说的是同一个分子/蛋白吗 盐型、互变异构体、亚型、剪接变体
条件对齐 测量条件一致吗 不同细胞系、不同浓度、不同时间点
语义对齐 不同模态的「相同」含义一致吗 文本中的「有效」与实验中的 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 种模态」。

关键要点

  • 对齐问题先于融合问题:实体、条件、语义三个层面都要处理;
  • 条件对齐最容易被忽略——不同细胞系、浓度、时间点的数据不可直接混用;
  • 先做单模态基线与晚期融合,晚期融合无收益则深度融合大概率也无收益;
  • 模态置换测试能揭示某个模态是否真的被模型使用。

延伸资源