147

MolFormer 论文精读:十亿级 SMILES 预训练带来了什么

MolFormer 用十亿级 SMILES 预训练,也暴露了规模化的边际收益问题。这篇讲清它的技术创新与规模的真实价值。

MolFormer(IBM,Ross 等,Nature Machine Intelligence 2022)在约 11 亿个 SMILES 上做预训练——规模远超此前的工作。它的技术创新扎实,但结果也再次显示:在分子任务上,规模的边际收益比 NLP 中小得多

两个技术创新

# 创新一:【线性注意力】
#
#   标准注意力的复杂度是 O(n²)
#   → 序列长时显存与计算爆炸
#
#   线性注意力用核函数近似,复杂度降到 O(n)
#   → 使得在十亿级数据上训练可行
#
#   代价:
#     表达能力略有损失
#     但对 SMILES 这类相对短的序列,影响不大
#
# 创新二:【旋转位置编码(RoPE)】
#
#   传统的绝对位置编码:
#     每个位置有一个固定的编码向量
#     → 模型学到「第 5 个 token 是什么」
#
#   RoPE:
#     通过旋转把位置信息编码进 query 和 key
#     → 注意力分数天然依赖【相对位置】
#
#   对 SMILES 为什么重要:
#     同一个分子的不同 SMILES 写法中,
#     原子的【绝对位置】完全不同,
#     但【相对关系】保持
#     → 相对位置编码对 SMILES 的多写法问题更稳健
#
#   这是一个有化学动机的技术选择,不是盲目照搬

# 训练规模:
#   数据:PubChem(约 1.11 亿)+ ZINC(约 10 亿)
#   模型:约 4400 万参数(【不算大】)
#   → 数据规模大,模型规模适中

规模的真实收益

对比 结果
MolFormer vs ChemBERTa 有提升,但幅度不算大
MolFormer vs 图神经网络 各有胜负,任务相关
MolFormer vs ECFP 基线 在部分任务上仍无显著优势
10 亿数据 vs 1 亿数据 边际收益明显递减

「11 亿 SMILES 换来的提升,远小于 NLP 中同等数据增长带来的提升」——这是这篇论文最值得注意的信息。

为什么分子任务的规模收益小

# 原因一:【下游数据集太小】
#   预训练模型的容量再大,
#   微调时只有 1000 个样本,用不上
#   → 【瓶颈在下游,不在预训练】
#
# 原因二:【SMILES 的信息量有限且已被指纹捕捉】
#   ECFP 直接枚举所有子结构,
#   已经是对分子结构相当完整的编码
#   → 预训练能提供的「额外信息」空间小
#
# 原因三:【化学空间的「语义」比语言简单】
#   自然语言中,同一个词在不同语境下含义不同
#   → 需要大量数据学习语境
#   化学中,一个官能团的性质相对固定
#   → 不需要那么多数据
#
# 原因四:【任务本身的噪声上限】
#   实验数据有测定误差、批次差异、
#   不同实验室的体系差异
#   → 【模型性能有天花板,与模型无关】
#   → 很多基准可能已经接近这个天花板
#
# 【推论】:
#   在分子性质预测上继续堆规模,
#   收益可能有限
#   → 更有价值的方向:
#     - 提高数据质量与一致性
#     - 更好的归纳偏置(见 146)
#     - 引入三维/结构信息(见 142)
#     - 主动学习减少数据需求(见 165)

使用

# MolFormer 权重在 HuggingFace 上
from transformers import AutoModel, AutoTokenizer
import torch

model_name = "ibm/MoLFormer-XL-both-10pct"
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
model = AutoModel.from_pretrained(model_name, trust_remote_code=True,
                                  deterministic_eval=True).eval()

def embed(smiles_list, batch_size=64):
    out = []
    for i in range(0, len(smiles_list), batch_size):
        batch = smiles_list[i:i+batch_size]
        enc = tokenizer(batch, padding=True, truncation=True,
                        return_tensors="pt")
        with torch.no_grad():
            res = model(**enc)
        out.append(res.pooler_output)
    return torch.cat(out).numpy()

X = embed(["CCO", "c1ccccc1", "CC(=O)Nc1ccc(O)cc1"])
print(X.shape)

# 用于下游任务
from sklearn.ensemble import GradientBoostingRegressor
model_gb = GradientBoostingRegressor().fit(X_train, y_train)

# 【推荐的实践】:
#   把 MolFormer 表示与 ECFP、RDKit 描述符【拼接】
#   一起喂给 LightGBM
#   → 通常比单独用任何一种好
#   → 成本低(表示只需算一次)

import numpy as np
X_combined = np.hstack([
    embed(smiles_list),           # MolFormer 表示
    ecfp_features(smiles_list),   # ECFP
    rdkit_descriptors(smiles_list),  # 全局描述符
])

选择表示的务实框架

# 一个可以直接照做的决策流程:
#
# 第 1 步:建立基线(半天)
#   ECFP(2048, r=2) + RDKit 描述符 + LightGBM
#   骨架划分,5 个种子
#   → 记录均值 ± 标准差
#
# 第 2 步:判断数据规模
#   < 500 样本   → 基线可能已是最优;考虑数据增强
#   500~5000    → 试预训练表示(冻结)+ 树模型
#   > 5000      → 试 Chemprop、微调预训练模型
#
# 第 3 步:只有显著超越才采用
#   「显著」= 提升 > 2 倍种子间标准差
#
# 第 4 步:计入部署成本
#   基线:CPU、毫秒级、一个文件
#   预训练模型:GPU、百毫秒级、数百 MB
#   → 提升 1% 值得这个代价吗?
#
# 第 5 步:【关注数据而非模型】
#   多数情况下,投入到数据清洗、
#   标注一致性、增加样本上的时间,
#   回报高于换模型(见 046)
#
# 这个框架适用于绝大多数分子性质预测项目

MolFormer 的持久价值

  • 线性注意力 + RoPE 的组合被后续工作采用:技术上的贡献是实在的;
  • 提供了大规模预训练的可用权重:省去了社区重复训练的成本;
  • 诚实地报告了规模的边际收益:这个负面结果对领域的价值不低于正面结果;
  • 它的表示适合作为特征拼接的一部分,而非替代其它表示。

关键要点

  • RoPE 相对位置编码对 SMILES 的多写法问题更稳健——这是有化学动机的技术选择;
  • 11 亿 SMILES 带来的提升远小于 NLP 中同等规模增长
  • 瓶颈在下游数据量与实验噪声天花板,不在预训练规模
  • 更有价值的方向是数据质量、归纳偏置、三维信息与主动学习。

延伸资源