分子表示方法:SMILES、SELFIES、分子图
做AI药物研发这些年,我最常被问到的一个问题是:“给模型吃的分子到底是什么样子的?”
嗯,这确实是个好问题。你用Transformer生成分子序列,首先得让模型“认识”分子长啥样。说白了,我们需要一种计算机能理解、化学上又不丢信息的表示法。今天我们就聊聊三种主流方案:SMILES、SELFIES 和 分子图。
1. SMILES:最老牌,但也最“脆”
SMILES(Simplified Molecular Input Line Entry System)算是分子序列表示的老祖宗了。你把分子结构沿着一个路径走,遇到原子就写原子符号,遇到键就写键符号,最后得到一串字符串。
一个小例子:乙醇的SMILES是 CCO,苯是 c1ccccc1。
我第一次用SMILES训练Transformer时,踩了个大坑——语法错误。SMILES对环的闭合、分支括号匹配特别敏感,少写一个数字或者括号不匹配,整个序列就废了。
避坑指南:我遇到过一个开源数据集,里面大约有3%的SMILES是无效的。训练之前一定要用RDKit做一次合法性校验,否则模型会学到错误模式。
| 特性 | 说明 |
|---|---|
| 表示方式 | 一维线性字符串,原子顺序按路径遍历 |
| 优点 | 紧凑,直观,生态工具齐全(RDKit、Open Babel) |
| 缺点 | 非唯一性(一个分子有多个SMILES);对环和手性敏感;容易生成无效序列 |
我个人习惯用规范化(canonical)SMILES来做训练集,至少能保证每个分子只对应一个序列。但你如果直接让Transformer生成SMILES,大概率会得到一堆语法错误的产物。所以才有了SELFIES。
2. SELFIES:为生成而生
SELFIES(Self-Referencing Embedded Strings)是专门为了解决SMILES“脆”的问题被设计出来的。它的核心思想:每个符号都“知道自己该接什么”,所以无论你随机删改哪个符号,生成的序列总是合法的。
我的经验:在Transformer场景下,SELFIES的合法性几乎100%。你想想看,模型在推理时哪怕乱采样一个token,整个序列依然是一个有效分子表示——这太爽了。
SELFIES和SMILES的对应关系可以这样理解:
SMILES: CCO (乙醇)
SELFIES: [C][C][O] (每个原子都被方括号包裹)
SMILES: c1ccccc1 (苯)
SELFIES: [C][=C][C][=C][C][=C][Ring1][Branch1]
看出来了吗?SELFIES用 [Ring] 和 [Branch] 这样的“约束token”替代SMILES里的数字和括号,从而避免了歧义。我自己在几个生成任务里对比过,SELFIES的生成成功率比SMILES高了一截。
| 对比维度 | SMILES | SELFIES |
|---|---|---|
| 语法错误率(随机采样) | ~30% | <0.1% |
| 序列长度 | 较短 | 稍长(多了约束token) |
| Transformer适配程度 | 一般,需大量后处理 | 优秀,可直接用 |
| 生态可用性 | RDKit、自建词典 | selfies 库、rdkit2sdf |
3. 分子图:保留全部拓扑结构
无论是SMILES还是SELFIES,本质上都是把二维结构压扁成一维字符串。这会导致一个问题——结构信息丢失。比如一个手性中心,或者一个稠环的连接方式,字符串很难完美表达。
分子图(Molecular Graph)直接保留原子和键的关系。每个原子是一个节点,每条化学键是一条边。节点可以带特征(原子类型、电荷、手性等),边也可以带特征(键级、芳香性等)。
为什么需要图?Transformer处理的是序列,而图是更自然的分子表示。你如果做分子性质预测,用图的GNN通常比用序列的Transformer效果更好。但在生成任务里,我们需要把图编码成序列才能用Transformer解码——这就引出了一种混合方案。
我曾经在项目里尝试过直接让Transformer预测图的邻接矩阵。结果?嗯,计算量太大,而且模型很难收敛。后来还是回到序列表示,但用图的验证来做后处理。
总结:三种表示法怎么选?
| 表示法 | 适用场景 | 我的建议 |
|---|---|---|
| SMILES | 分子检索、数据库存储、传统QSAR | 经典但需谨慎,建议加后处理过滤 |
| SELFIES | 分子生成、Transformer训练、高熵采样 | 强烈推荐,尤其用Transformer时 |
| 分子图 | 性质预测、图神经网络、结构保留分析 | 如果要做生成+预测双模态,可以考虑图→序列→图 |
最后,咱们用一张图把这三者的关系理清楚:
好了,三种表示法的核心差异和选型建议就聊到这。下一部分我们会深入讲一下如何用Python把这些表示法互相转换,以及怎样构造一个干净的分子序列数据集。嗯,到时候我再分享几个经常踩到的坑。