SELFIES(SELF-referencIng Embedded Strings)解决了 SMILES 在分子生成中的一个具体问题:随机生成或修改的 SMILES 常常是无效的分子,而 SELFIES 保证 100% 有效。
SMILES 在生成中的问题
# 【问题一:语法可能不合法】
# 随机改一个字符:
# "c1ccccc1" → "c1ccccc2" 环闭合不匹配 → 无效
# "CC(C)C" → "CC(C)C)" 括号不匹配 → 无效
#
# 【问题二:语法合法但化学不合法】
# "C(C)(C)(C)(C)C" 五价碳 → 化学上不可能
#
# 【后果】:
# 生成模型需要「学会」这些规则
# → 浪费模型容量
# → 生成的分子中相当比例无效
# → 【在隐空间中做优化时,很多点解码不出有效分子】(见 149)
#
# 【SELFIES 的解决方案】:
# 设计一套编码规则,使得
# 【任意的符号序列都能解码成有效分子】
#
# 核心机制:
# 1) 每个符号携带「派生规则」
# 2) 解码时维护一个状态(当前原子的剩余价键数)
# 3) 【如果某个符号会导致违规,就按规则替换成合法的】
# 4) 环闭合用【相对索引】而非绝对标号
# → 不会出现「闭合不匹配」
#
# → 结果:100% 有效性(这是数学上保证的,不是统计上的)
使用
pip install selfies
import selfies as sf
from rdkit import Chem
# 编码与解码
smiles = "CC(=O)Nc1ccc(O)cc1"
encoded = sf.encoder(smiles)
print(encoded)
# [C][C][=Branch1][C][=O][N][C][=C][C][=C][Branch1]...
decoded = sf.decoder(encoded)
print(decoded)
print(Chem.CanonSmiles(decoded) == Chem.CanonSmiles(smiles)) # True
# ---- 验证「任意序列都有效」----
import random
alphabet = list(sf.get_semantic_robust_alphabet())
random.seed(42)
valid_count = 0
for _ in range(1000):
length = random.randint(5, 20)
random_selfies = "".join(random.choices(alphabet, k=length))
smi = sf.decoder(random_selfies)
if Chem.MolFromSmiles(smi) is not None:
valid_count += 1
print(f"随机 SELFIES 的有效率: {valid_count/1000:.1%}") # 100%
# 【对比】:随机的 SMILES 字符序列几乎全部无效
# ---- 用于生成模型的词表 ----
dataset = ["CCO", "c1ccccc1", "CC(=O)Nc1ccc(O)cc1"]
selfies_list = [sf.encoder(s) for s in dataset]
alphabet = sf.get_alphabet_from_selfies(selfies_list)
alphabet.add("[nop]") # padding token
alphabet = sorted(alphabet)
symbol_to_idx = {s: i for i, s in enumerate(alphabet)}
# 转成整数序列
max_len = max(sf.len_selfies(s) for s in selfies_list)
for s in selfies_list:
label, one_hot = sf.selfies_to_encoding(
s, vocab_stoi=symbol_to_idx, pad_to_len=max_len)
print(label)
什么时候用 SELFIES
| 场景 | SELFIES 的价值 |
|---|---|
| 遗传算法的变异/交叉 | 高——随意修改都有效 |
| 隐空间优化 | 高——避免解码失败(见 149《MolMIM 论文精读》) |
| 从零训练生成模型 | 中——省去学语法的负担 |
| 强化学习生成 | 中(见 137《REINVENT 论文精读》) |
| 性质预测 | 低——有效性不是问题 |
| 数据存储与交换 | 低——SMILES 更通用可读 |
| 子结构搜索 | 低——用 SMARTS 更好 |
实际的局限
# 【局限一:有效不等于合理】
# SELFIES 保证「化学上可能存在」,
# 但【不保证】:
# - 分子稳定(可能极不稳定)
# - 可合成
# - 类药
# - 有意义
#
# → 【100% 有效性只解决了最低层次的问题】
# → 后续的过滤(性质、警示、可合成性)仍然必需
#
# 【局限二:序列变长】
# SELFIES 通常比对应的 SMILES 长
# → 序列模型的负担增加
# → 长程依赖更难学
#
# 【局限三:可读性差】
# SMILES 有经验的化学家能直接读
# SELFIES 基本不可读
# → 【调试与人工检查时不便】
#
# 【局限四:生态支持不如 SMILES】
# 多数工具、数据库用 SMILES
# → 需要来回转换
#
# 【局限五:局部性差】
# 修改 SELFIES 中的一个符号,
# 【可能导致后续结构大幅改变】
# (因为解码是有状态的)
# → 这对「小改动 = 小变化」的优化直觉不利
# → 在遗传算法中可能产生跳跃过大的变异
#
# 【近年的实践观察】:
# 随着生成模型能力提升,
# 直接用 SMILES 的有效率也能达到 95% 以上
# → 【SELFIES 的相对优势在缩小】
# → 但在遗传算法与隐空间优化中仍有明确价值
与其它表示的选择
# 【决策流程】
#
# 我要做什么?
#
# ├─ 性质预测
# │ → 【用 ECFP 指纹或分子图】(见 035、034)
# │ 字符串表示不是最优选择
# │
# ├─ 生成模型
# │ ├─ 需要保证有效性(GA、隐空间优化)
# │ │ → 【SELFIES】
# │ └─ 用序列模型自回归生成
# │ → SMILES 也可以(现代模型有效率已很高)
# │ + SMILES 增强(见 145)
# │
# ├─ 数据存储与交换
# │ → 【SMILES】(通用、可读)
# │ + InChIKey 作为唯一标识(见 033)
# │
# ├─ 子结构搜索
# │ → 【SMARTS】(见 031)
# │
# └─ 三维相关任务
# → 需要生成构象(见 049)
#
# 【一个务实的建议】:
# 不要为了用 SELFIES 而用
# 先确认「无效分子」真的是你的瓶颈
# → 如果生成的分子有效率已经 95%+,
# 换 SELFIES 的收益很小
关键要点
- 100% 有效性是数学上保证的,不是统计上的——任意符号序列都能解码成有效分子;
- 有效不等于合理——不保证稳定、可合成或类药,后续过滤仍必需;
- 真正有价值的场景是遗传算法的变异与隐空间优化;
- 局部性差:改一个符号可能导致后续结构大幅改变,不利于「小改动=小变化」的优化。
延伸资源
- SMILES:031《SMILES 入门》;分子生成模型:158《AI 分子生成模型》;MolMIM:149《MolMIM 论文精读》;
- REINVENT:137《REINVENT 论文精读》;GuacaMol:135《GuacaMol 论文精读》。