3.1 自引用嵌入字符串SELFIES在分子生成式 AI 领域表示学习Representation Learning的瓶颈长期以来集中在语法脆弱性问题上。传统SMILESSimplified Molecular-Input Line-Entry System表示法虽然简洁但其上下文敏感文法导致随机变异或模型生成的字符串大多无效——随机突变后的有效性仅为9.9%。为解决这一根本性问题Krenn 等人于 2020 年提出了SELFIESSelf-Referencing Embedded Strings这是首个保证 100% 鲁棒性的分子字符串表示法。3.1.1 100% 有效性分子表示SELFIES 的核心创新在于将分子图映射为一种上下文无关文法Context-Free Grammar, CFG配合自引用函数的形式语言。与 SMILES 的上下文敏感语法不同SELFIES 确保无论符号如何组合、变异或生成每个字符串都对应一个化学上有效的分子图。从信息论视角看SELFIES 重新定义了分子表示的语义空间$$\forall s \in \Sigma_{SELFIES}^*, \exists! G \in \mathcal{G}_{chem} : \text{decode}(s) G$$其中 $\Sigma_{SELFIES}$ 是 SELFIES 字母表$\mathcal{G}_{chem}$ 是有效化学图空间。这一性质使得生成模型可以在整个隐空间中自由探索而无需担心无效区域的“陷阱”——实验表明基于 SELFIES 的 VAE 在隐空间中每一点都能解码出有效分子而 SMILES-based VAE 存在大量无效区域死区。在分子生成任务中这一特性带来了数量级的性能提升基于 SELFIES 的 GAN 生成78.9%的多样有效分子而 SMILES-based GAN 仅为18.6%。更重要的是SELFIES 允许模型内部记忆存储两个数量级更多的多样化分子结构。图1VAE隐空间有效性对比左SMILES存在大量无效区域红色右SELFIES保证100%有效性全绿3.1.1.1 SELFIES 语法自引用机制与分支/环的局部编码规则SELFIES 的语法体系建立在增强型上下文无关文法之上通过引入状态机和自引用函数将化学约束价键规则编码到文法产生式中。核心文法结构SELFIES 采用 Chomsky 类型-2上下文无关文法定义为四元组 $G (V, \Sigma, R, S)$非终结符$V \{X_0, X_1, \dots, X_r, N\}$其中 $X_i$ 表示当前原子的剩余价态可形成 $i$ 个键$N$ 为数值参数。终结符$\Sigma$包含原子符号、分支符号、环符号。产生式规则$R$基于当前状态 $X_i$ 和输入符号 $s_j$ 的转换规则。起始符号$S$初始状态 $X_0$。自引用函数syntactic validity 的保障分支函数$B(N, X_i)$当解析器遇到分支符号[BranchX]时函数递归地启动一个新的文法推导使用后续 $N$ 个符号在状态 $X_i$ 下构建子图。完成推导后将子图连接到当前顶点$$B(N, X_i) \to \text{derive}(s_{i1}, \dots, s_{iN}) \hookrightarrow v_{current}$$环函数$R(N)$建立当前顶点与第 $(N1)$ 个最近推导顶点之间的边。这通过维护一个环闭合队列lazy evaluation 策略实现。局部编码规则十六进制索引系统SELFIES 采用十六进制编码显式指定分支和环的长度分支长度计算若分支符号后跟随索引符号 $c_1, \dots, c_k$则分支包含的符号数 $N$ 为$$N 1 \sum_{i1}^{k} 16^{i-1} \cdot c_i$$环闭合编码环符号[RingX]同样使用十六进制索引指向回溯 $N1$ 步的顶点。这种显式长度编码消除了 SMILES 中环闭合数字冲突的问题。价态约束的状态机SELFIES 通过状态机跟踪原子剩余价态确保不生成超价结构当状态为 $X_i$剩余 $i$ 个键位时请求键级 $\beta$ 会被自动调整为 $\min(i, d(\beta))$防止价态违规。例如在碳原子价态 4已形成 3 个键状态 $X_1$后若请求双键[C]系统会自动降级为单键局部编码规则十六进制索引系统SELFIES 采用十六进制编码显式指定分支和环的长度分支长度计算若分支符号后跟随索引符号 $c_1, \dots, c_k$则分支包含的符号数 $N$ 为$$N 1 \sum_{i1}^{k} 16^{i-1} \cdot c_i$$环闭合编码环符号[RingX]同样使用十六进制索引指向回溯 $N1$ 步的顶点。这种显式长度编码消除了 SMILES 中环闭合数字冲突的问题。价态约束的状态机SELFIES 通过状态机跟踪原子剩余价态确保不生成超价结构当状态为 $X_i$剩余 $i$ 个键位时请求键级 $\beta$ 会被自动调整为 $\min(i, d(\beta))$防止价态违规。例如在碳原子价态 4已形成 3 个键状态 $X_1$后若请求双键[C]系统会自动降级为单键[C]。3.1.1.2 与 SMILES 的互操作kekulization 处理与立体化学支持Kekulization芳香性处理SELFIES 内部不直接支持芳香性原子符号。当encoder()接收含芳香符号的 SMILES如c1ccccc1时首先执行凯库勒化Kekulization将其转换为显式的交替单双键输入 SMILES:c1ccccc1(苯)Kekulization:C1CCCCC1输出 SELFIES:[C][C][C][C][C][C][Ring1][Branch1]立体化学支持手性中心使用和标记如[CH1]。SELFIES 确保属性顺序标准化[Bond][Isotope][Element][Chirality][H-count][Charge]。环立体化学通过扩展环符号[/RingX]和[\RingX]支持跨环键的 $E/Z$ 构型。3.1.1.3 自定义化学约束超价物种与特殊原子类型的规则定义语义约束机制通过set_semantic_constraints()用户可以定义规则向量 $\Lambda_i$针对每种原子类型 $T_i$ 指定最大价态 $D_i \max\text{deg}(T_i)$允许的键型单键、双键、三键电荷范围Python# 示例定义超价硫S6 import selfies as sf custom_constraints sf.get_semantic_constraints() custom_constraints[S] 6 sf.set_semantic_constraints(custom_constraints)特殊原子类型支持金属有机化合物Fe, Co, Ni 等过渡金属的配位键表示。同位素标记如[13CH1]。自由基与部分电荷通过[CH01]等符号表示。非标准价态如五价碳碳正离子或超价磷。与 SMILES 的互操作边界当前 SELFIES 不支持某些 SMILES 特性通配符*、四键$、反应箭头和聚合标记。对于这些情况encoder()会抛出异常以确保转换的可靠性。代码示例完整的SELFIES编解码与约束自定义 SELFIES分子表示完整示例 包括基础编解码、分支/环解析、自定义约束、立体化学处理 import selfies as sf from rdkit import Chem from rdkit.Chem import Draw # 1. 基础编解码100%有效性保证 print( * 60) print(3.1.1 100%有效性分子表示) print( * 60) benzene_smiles c1ccccc1 benzene_selfies sf.encoder(benzene_smiles) print(f苯SMILES: {benzene_smiles}) print(f苯SELFIES: {benzene_selfies}) # 输出: [C][C][C][C][C][C][Ring1][Branch1] # 解码回SMILESkekulized形式 decoded_smiles sf.decoder(benzene_selfies) print(f解码Kekulized: {decoded_smiles}) # 输出: C1CCCCC1 # 2. 自引用机制分支与环的局部编码 print(\n * 60) print(3.1.1.1 自引用机制与局部编码) print( * 60) # 复杂分子对乙酰氨基酚Paracetamol # 包含苯环、酰胺基和羟基 paracetamol_smiles CC(O)Nc1ccc(O)cc1 paracetamol_selfies sf.encoder(paracetamol_smiles) print(f对乙酰氨基酚 SELFIES:\n{paracetamol_selfies}) # [C][C][Branch1][C][O][N][C][C][C][C][Branch1][Branch1][C][C][Ring1][Branch1][O] # 分析结构 # [C][C] - 乙酰基起始 # [Branch1][C][O] - 分支1羰基CO # [N] - 酰胺氮 # [C][C][C][C]... - 苯环主干 # [Ring1][Branch1] - 环闭合指向1步前的原子带双键分支 # 3. 立体化学支持 print(\n * 60) print(3.1.1.2 立体化学与Kekulization) print( * 60) # 手性分子(R)-乳酸 lactic_acid_smiles C[CH](O)C(O)O lactic_acid_selfies sf.encoder(lactic_acid_smiles) print(f乳酸含手性SELFIES: {lactic_acid_selfies}) # 包含手性标记: [CH1] 或 [CH1] # 解码验证 mol Chem.MolFromSmiles(sf.decoder(lactic_acid_selfies)) print(f手性中心数量: {Chem.FindMolChiralCenters(mol).__len__()}) # 4. 自定义化学约束 print(\n * 60) print(3.1.1.3 自定义化学约束) print( * 60) # 默认约束硫最大价态为2如H2S try: sulfuric_acid OS(O)(O)O sf.encoder(sulfuric_acid) # 可能失败或警告 except Exception as e: print(f默认约束下编码失败: {e}) # 自定义约束允许超价硫6价 constraints sf.get_semantic_constraints() constraints[S] 6 # 硫可形成6个键 sf.set_semantic_constraints(constraints) selfies_sulfuric sf.encoder(sulfuric_acid) print(f硫酸超价SSELFIES: {selfies_sulfuric}) # 成功编码: [O][S][Branch1][C][O][Branch1][C][O][Branch1][C][O][O] # 5. 鲁棒性验证随机变异测试 print(\n * 60) print(鲁棒性验证随机变异) print( * 60) import random def random_mutate(selfies_string, num_mutations1): 随机变异SELFIES字符串 symbols list(sf.split_selfies(selfies_string)) alphabet list(sf.get_semantic_robust_alphabet()) for _ in range(num_mutations): idx random.randint(0, len(symbols) - 1) symbols[idx] random.choice(alphabet) return .join(symbols) # 测试对乙醇进行10次随机单点变异 ethanol_selfies sf.encoder(CCO) print(f原始乙醇 SELFIES: {ethanol_selfies}) valid_count 0 for i in range(10): mutated random_mutate(ethanol_selfies, 1) try: # SELFIES保证任何变异都产生有效分子 decoded sf.decoder(mutated) mol Chem.MolFromSmiles(decoded) if mol is not None: valid_count 1 print(f变异{i1}: {mutated} - {decoded} (有效)) except Exception as e: print(f变异{i1}: 无效 - {e}) print(f\n有效性率: {valid_count}/10 (理论上应为10/10)) # 对比SMILES随机变异通常只有~10%有效性技术总结SELFIES通过形式文法理论与化学语义约束的深度融合解决了分子生成AI中的有效性瓶颈100%鲁棒性通过上下文无关文法配合自引用函数确保任何符号组合都对应有效分子图局部编码分支和环使用十六进制索引显式编码长度避免SMILES的上下文依赖问题互操作性通过kekulization处理芳香性完整支持立体化学实现与SMILES的双向无损转换可扩展性自定义约束机制支持超价物种、金属有机化合物等特殊化学领域这些特性使SELFIES成为现代分子语言模型如ChemBERTa、MOLGEN、PolyBART的首选表示法在药物发现、材料设计和聚合物信息学中展现出显著优