4. 分子模态特征工程

分子模态建模的第一步不是搭网络,而是把化学结构翻译成模型能读的数值对象。同一批分子,用 SMILES 字符串、分子指纹、描述符向量还是分子图来表示,会直接决定后续模型能学到什么、学不到什么。本节围绕四条表示路线展开:分子图构建、原子与键特征、指纹与描述符、以及图神经网络的输入张量组织方式,并给出可复现的构建流程与示例参数。

一、从化学结构到分子图

分子图把分子抽象为 G = (V, E):节点 V 是重原子(通常为 C、N、O、S、P、卤素等),边 E 是化学键。构建流程一般从 SMILES 或 SDF 出发,经 RDKit 解析得到原子与键对象,再显式补氢、指定芳香性判定方式,最后导出节点特征矩阵 X ∈ R^(N×d_v)、边索引 E_idx ∈ Z^(2×M) 与边特征 E_attr ∈ R^(M×d_e)。其中 N 为原子数,M 为有向边数(无向边通常展开为两条有向边)。

关键约定必须提前固定,否则不同批次数据无法对齐:是否显式加氢(AddHs)、是否使用芳香性感知(SanitizeMol)、是否保留手性、是否把盐和多组分体系拆分为最大片段。工程上常用 MolFromSmiles(smi) 后接 Chem.AddHs,再以 Chem.GetAdjacencyMatrix 或遍历 mol.GetBonds() 生成边表。对于含金属配位、互变异构或电荷离域的分子,建议单独标记并在数据集中记录处理策略,避免训练与推理阶段不一致。

二、原子与键特征的设计

节点特征通常包含:原子类型(one-hot 或可学习嵌入)、度、形式电荷、杂化方式(SP/SP2/SP3)、是否在环内、是否芳香、手性标签、氢原子数、以及可选的原子质量或电负性。边特征包含:键类型(单/双/三/芳香)、是否共轭、是否在环内、键立体化学(E/Z 或顺反)。这些特征大多为类别型,实践中常做 one-hot 拼接,得到 d_v 约 30~40 维、d_e 约 6~10 维的向量。

一个常见误区是只给节点特征、不给边特征。对于反应预测、键级变化或构象敏感任务,键类型与共轭信息往往是决定性输入。若使用 torch_geometric,可用 Data(x=..., edge_index=..., edge_attr=...) 组织;若使用 DGL,则对应 dgl.graph 加 ndata/edata。特征维度需在数据集层面统计并固定,缺失类别用全零或专用 unknown 位补齐。

三、指纹与描述符:全局向量的两条路线

指纹把整个分子压成定长或稀疏位向量,强调子结构存在性。Morgan/ECFP 是最常用的圆形指纹:以每个原子为起点,按半径 r 迭代聚合邻居标识,再哈希到固定长度。示例参数可取 radius=2、nBits=2048,得到 2048 位 0/1 向量;若用 count 版本则记录出现次数。MACCS 键给出 166 位预定义子结构,适合快速相似性检索。指纹的优点是计算快、可解释到子结构,缺点是丢失拓扑连接细节与三维信息。

描述符走的是另一条路:用少量连续数值概括理化性质,如分子量、LogP、TPSA、氢键供体/受体数、可旋转键数、环数、芳香环数、形式电荷总和、QED、SAscore 等。RDKit 的 Descriptors 与 Crippen.MolLogP 可直接计算。描述符维度低、物理意义明确,适合与指纹拼接成混合特征,也常作为图模型的全局读出补充。使用时必须做缺失值处理与标准化(如 z-score),并注意 LogP、TPSA 等量纲差异较大,未标准化会主导距离度量。

四、图神经网络输入表示的组织

GNN 输入不是单个矩阵,而是一组按 batch 拼接的张量。以 PyTorch Geometric 为例,一个 batch 会把多个分子图拼成一张大图,用 batch 向量标记每个节点属于哪个分子,再通过 global_mean_pool 或 global_add_pool 得到图级表示。节点特征 x 形状为 [总节点数, d_v],边索引 edge_index 形状为 [2, 总边数],边特征 edge_attr 形状为 [总边数, d_e]。若同时使用指纹或描述符,可在读出后与图级向量拼接,形成多模态输入。

下面给出一个可直接参考的构建示例,展示从 SMILES 到 GNN 输入的完整链路与关键参数:

from rdkit import Chem
from rdkit.Chem import Descriptors, Crippen, rdMolDescriptors
from rdkit.Chem import AllChem
import numpy as np

def mol_to_graph(smi, radius=2, n_bits=2048):
    mol = Chem.MolFromSmiles(smi)
    mol = Chem.AddHs(mol)                      # 显式加氢
    atoms, bonds = [], []
    for a in mol.GetAtoms():
        atoms.append([
            a.GetAtomicNum(), a.GetDegree(), a.GetFormalCharge(),
            int(a.GetIsAromatic()), a.GetTotalNumHs(),
            int(a.GetHybridization())
        ])
    for b in mol.GetBonds():
        bonds.append([
            b.GetBeginAtomIdx(), b.GetEndAtomIdx(),
            int(b.GetBondTypeAsDouble()), int(b.GetIsAromatic()),
            int(b.GetIsConjugated())
        ])
    fp = AllChem.GetMorganFingerprintAsBitVect(mol, radius, nBits=n_bits)
    desc = [
        Descriptors.MolWt(mol), Crippen.MolLogP(mol),
        rdMolDescriptors.CalcTPSA(mol),
        rdMolDescriptors.CalcNumHBD(mol),
        rdMolDescriptors.CalcNumHBA(mol),
        rdMolDescriptors.CalcNumRotatableBonds(mol)
    ]
    return np.array(atoms), np.array(bonds), np.array(fp), np.array(desc)

该函数返回节点特征、边表、2048 位 Morgan 指纹与 6 维描述符。实际训练时,节点特征需按类别做 one-hot 或嵌入,描述符需标准化,指纹可直接作为图级辅助输入。若分子含手性中心,还应补充手性标签位;若任务涉及三维构象,则需额外生成坐标并引入距离或角度特征。

分子模态特征工程:从 SMILES 到 GNN 输入张量 输入 SMILES / SDF RDKit 解析 AddHs / Sanitize 分子图构建 节点 V / 边 E X, edge_index, edge_attr 指纹 Morgan r=2, 2048 bit MACCS 166 bit 描述符 MW, LogP, TPSA HBD, HBA, RotB GNN 输入张量 x: [N, d_v] edge_index: [2, M] edge_attr: [M, d_e] batch / fp / desc 关键约定与检查点 • 是否显式加氢、芳香性判定、手性保留、盐/多组分拆分策略需在数据集层面统一 • 节点特征 d_v ≈ 30–40 维,边特征 d_e ≈ 6–10 维;类别型特征做 one-hot 或嵌入 • 描述符需标准化;指纹与图级读出拼接时注意维度对齐与缺失位补齐

五、四条路线的取舍与组合

指纹与描述符适合快速基线、相似性检索和低数据场景,计算成本低、可解释性强;分子图适合需要感知拓扑、键级变化和局部环境的任务,如性质预测、反应产率预测、ADMET 建模。实际工程中更常见的是组合:图分支学习局部结构,指纹分支提供子结构先验,描述符分支补充全局理化约束,三者在读出层拼接后送入 MLP。组合时要注意各分支的归一化与维度平衡,避免某一分支因数值范围过大而主导梯度。

建议在数据集构建阶段就固定特征版本号,把原子特征列表、边特征列表、指纹参数、描述符清单写入元数据文件。这样当模型效果波动时,可以快速定位是数据表示变化还是模型结构变化导致的。
不要在不同阶段混用加氢与不加氢的分子对象。加氢后原子数会显著增加,若训练用加氢图、推理用不加氢图,节点索引与边表将完全错位,模型输出不可信。

总结来看,分子模态特征工程的核心是“先定约定、再定特征、最后定张量组织”。分子图给出拓扑骨架,原子与键特征填充局部语义,指纹与描述符提供全局视角,GNN 输入表示则把这些对象组织成可批量训练的张量。四者不是互斥选项,而是同一表示空间里可组合的层次。把每一步的输入、参数与输出显式记录下来,后续的多模态融合与消融实验才有可靠基础。