机器学习在化学中的工程路线:实验—模拟—模型与多目标分子设计闭环 简介Machine Learning in Chemistry now and in the future.pdf 是 Jon Paul Janet阿斯利康生物医药研发部的一份英文演示文稿面向化学、材料与药物研发方向的研究者以及希望进入这一交叉领域的学生帮助他们建立机器学习在化学中应用的整体认知框架。内容按引言、案例、应用、结论四部分展开引言以 2018 年 CASP13 蛋白质折叠预测竞赛和 2020 年 CASP14 的结果为线索说明算法进步、大数据集与高性能算力如何共同推动化学领域的机器学习实践案例部分讨论阿斯利康在多目标分子设计中的落地经验涉及活性、毒性与靶标结合能力的预测应用章节覆盖分子三维结构预测、材料组合筛选与性能优化、反应可能性与产物预测、数据驱动的实验条件选择等场景结论展望反应机理预测、催化剂效率提升与新型药物、功能材料开发。压缩包共 1 个文件即单份 41.44MB 的 PDF篇幅约 24 页便于直接翻阅、批注与裁剪成组会分享素材。目前已有 222 人学习下载。1. 化学领域有一种说法机器学习进入实验室首先改变的不是论文而是排期表。合成一个目标分子要按周计算跑一次电子结构计算要按小时计算而一个训练好的模型给上亿个候选分子打分要按秒计算。这份《Machine Learning in Chemistry now and in the future》的讲义整篇都建立在这条成本时间轴上。它没有堆砌公式而是用一张三列对照图讲清“实验—模拟—模型”各自该回答什么问题再拿一个多目标分子设计的研发场景当案例把闭环拆成能落地执行的四个步骤。它适合三类人做药物化学、材料筛选但不知道从哪接模型的实验侧工程师手里有几十万条化合物数据、模型指标好看却没人使用的算法侧同学以及要判断这个方向值不值得投入人力和算力的技术负责人。讲义本身不是教程更像一张路线图价值在于帮你把“要不要上 ML”这个模糊问题换成“哪一步该交给模型”的具体问题。2. 先读懂“实验—模拟—模型”三列时间轴机器学习在化学里省掉的到底是什么2.1 三档耗时不能看成 benchmark它是分工依据讲义开场讲了一个蛋白质折叠盲测的故事一支首次参赛的队伍在一个不提供模板信息的类别里拿下了绝大多数题目第二名只捡到剩下的几道第二年再参赛几乎清场评测的发起人甚至说这个问题“某种意义上已经解决了”。这个故事容易看得很兴奋但它真正的用处是把一个抽象论断落地当数据规模、算力、模型结构同时到位时一个过去只能靠实验硬啃的问题会突然变成“可算”的问题。作者紧接着转述了一句流传很广的话不是机器取代化学家而是用机器的化学家取代不用机器的。这句在转述里常被当口号但讲义自己的注解很克制——真正的变化是所有科研工作者都在产生数据而机器学习提供了一种把数据变成可复用资产的路径。这个注解值得留意它把讨论从“AI 会不会替代人”拉回到“你手上的数据有没有被二次利用”。真正撑起全篇的是那张三列图左边实验中间模拟右边模型标注的量级分别是天到周、小时、秒。这三个数量级不是精确测量是示意但它决定了后面所有方法论的走向——什么该算、什么该做、什么该交给模型猜。通路单次耗时量级可并行度主要误差来源适合回答的问题实验天周极低受限于人、样品、仪器操作误差、批次效应、生物学噪声这个假设在真实体系里成不成立量子化学/分子模拟小时高可排队跑泛函与基组、溶剂模型、构象采样机理成立吗能垒差多少训练好的模型秒极高几乎无成本训练集覆盖面、标签噪声、外推这一万个候选里先挑哪几十个提示三列图的正确用法是自上而下做减法。先用实验定义问题边界再用模拟生成一批可信标签最后才让模型去做大规模筛选。反过来先训模型再找问题九成会变成一篇没有人接的论文。我给组里做成本盘点时一般按五步走做完基本能判断该不该上模型第一步列出你最近三个月真正卡住的五个问题写清楚每个问题现在靠什么手段回答第二步为每个问题填上三列耗时实验那列要算上排队和失败重做第三步标出哪些问题已经有超过两千条带标签的历史数据没有的当场划掉第四步算一笔账——模型把候选从十万缩到一百能省下多少次实验这个数字比任何 AUC 都更能说服人第五步把省不下来的问题写在最上面那是你的下一步数据采集计划。这套动作听起来像管理其实决定的是技术选型。因为模型能省的成本上限等于“被筛掉的候选数 × 单次实验成本”如果这个乘积不够大做再多模型优化也只是自娱自乐。2.2 化学空间规模达到 O(10^60)枚举失效之后方法学只能改变讲义里还有一个数字被反复提到可能的小分子有机化学空间大约是 10 的 60 次方量级。这个数字常被当成修辞但它带来的是一连串非常实际的技术后果——任何形式的全量枚举都不可能任何形式的“先建库再全筛”都只是在这个空间里取了一个极小的切片。一旦可枚举性消失方法学就必须换挡。传统的高通量筛选是“库里有什么就筛什么”虚拟筛选把库从百万扩到十亿但本质还是枚举而机器学习的意义在于它可以在不枚举的前提下给出一个近似排序让你把有限的实验预算花在排序靠前的区域再把实验结果回填修正下一轮的排序。这就是闭环也是讲义为什么把多目标分子设计单独拎出来当案例。这里有个很容易被忽略的细节10^60 和“可合成的类药空间”不是一个概念。通常说的虚拟库一个机构能管理的规模在 10^8 到 10^9 之间一次对接打分按每分子 0.1 到 1 秒算十亿级跑完就是几十万核时。所以真正的瓶颈不是“空间太大”而是“打分太贵”和“合成太难”——这两点恰好是模型和生成式方法各自的切入点。参数上要盯住三个数候选池规模决定算力预算、单次打分的成本决定能不能迭代多轮、每轮可执行的实验批次数决定闭环转几圈。这三个数一旦定下来用什么模型、要不要上主动学习基本就没有悬念了。2.3 把讲义的成本表换成你自己的数字讲义给的是通用框架落到具体项目必须换成本组的数字。做法不复杂但需要诚实先把你手里的“打分器”列出来——可能是对接打分、可能是某个开源预测模型、也可能就是资深化学家的经验排序——然后给每个打分器标三个属性单次成本、覆盖范围、已知失效场景。接下来做一次小规模对照实验从历史项目里挑 200 个已经做过实验的化合物用每个打分器排一遍序看 top 20 命中率。这一步花不了两天但它能告诉你哪个打分器值得放在闭环里当“廉价初筛”哪个只能当参考。我见过太多项目跳过这步直接上模型最后发现模型的排序能力和组里老师傅的直觉差不多闭环跑了一年也没多命中几个。还有一个参数经常被忽略淘汰阈值。闭环的价值不在“选出最好的”而在“快速淘汰明显不行的”。把淘汰线的位置调高一点、每轮多砍掉一半候选往往比把预测精度从 0.8 提到 0.85 更省实验费。3. 三条方法线怎么对应到化学卷积、Transformer、图卷积的选型表3.1 分子天然是图并不天然是图片讲义把计算机视觉的卷积网络、自然语言处理的 Transformer、以及处理通用图数据的图卷积并排放在同一页这个排版本身就是观点化学问题不是某一类模型的专属领地而是三类结构假设在化学里的投影。卷积网络的假设是局部性和平移不变性。分子确实有局部性官能团、片段但没有天然的栅格——除非你把三维构象渲染成体素或者把二维结构画成图再转成像素。这条路的代价很具体分辨率和计算量直接挂钩而且分子在空间里的旋转会让像素表示发生剧变除非额外加数据增强。早些年把分子画成图再喂 CNN 的做法能跑出结果但更多是因为任务简单不是因为表示合理。图卷积的假设更贴分子原子是节点化学键是边消息沿着键传递。这个表示天然满足置换不变原子编号换了结果不变、天然支持变长不同分子原子数不同而且可以把键级、芳香性、电荷、手性当作边特征和节点特征塞进去。代价也有图卷积的感受野受层数限制层数堆多了会出现过平滑远距离的电子效应抓不住。我一般的判断标准是如果任务的答案主要取决于局部子结构毒性预警、溶解度、反应性位点图卷积极具竞争力如果任务依赖全局形状或三维构象结合构象、蛋白-配体亲和力要么上三维几何网络要么老老实实做构象采样。3.2 把 SMILES 当语言Transformer 的用武之地与代价把分子写成字符串这条思路讲义归到自然语言处理那条线上。SMILES 确实像一句话字符是词子结构是短语分子是句子。于是 Transformer 那一套——预训练、掩码建模、序列到序列——可以整体搬过来反应预测、逆合成、分子生成这几类任务因此受益明显。代价同样明确而且都是踩过才知道的。第一SMILES 不唯一同一个分子可以写出多种合法字符串模型会把它们当成不同样本解决办法是随机化 SMILES 做数据增强或者统一用规范化写法但两者不能混着来。第二字符级表示对长程依赖不友好一个大环或长链在序列上被拉得很开注意力要跨很远才能连上。第三也是最容易被忽略的生成出来的字符串不一定化学合法必须加一步合法性校验否则你会得到一堆看起来像分子、实际价键错乱的东西。选型上我的经验是分任务看如果你的输入本来就是序列反应物到产物的映射Transformer 几乎是默认解如果输入是单个分子的性质预测图表示通常更省数据如果两者都要常见做法是图编码器加序列解码器的混合结构而不是硬选一边。3.3 五种任务对三种表示的对照任务推荐表示常见方法族最容易翻车的地方类药性/毒性分类分子图 或 指纹图卷积、梯度提升树正负样本极不平衡AUC 好看但召回极低溶解度/logP 回归分子图 描述符图卷积 手工特征拼接标签来自不同实验条件未做批次校正反应产率预测反应式序列Transformer 编码训练集偏向高产率反应低产率区间几乎无样本逆合成路线产物序列序列到序列只评估单步准确率忽略整条路线的可执行性三维构象生成原子坐标 图几何网络、扩散模型只比对能量不比对构象多样性注意这张表最右边一列比中间两列重要。方法族选错通常只是效果差一点翻车点没处理结果会直接不可用而且指标上看不出来。3.4 从一份结构文件到可训练图张量六个参数定生死具体落地时不管你用哪个框架把一份结构文件转成能训练的批数据都要经过同一组决策参数定错就直接白训。第一个是最大原子数。按你的数据集分布取 95 分位超出的截断或丢弃不要用全局最大值否则填充会吃掉大量显存。第二个是节点特征维度常见组合是原子类型独热、度数、形式电荷、杂化状态、是否在环上、手性标记加起来通常落在 30 到 80 维之间。第三个是边特征至少要有键级和是否芳香做立体化学的再加构型标记。第四个是填充与掩码必须在聚合时把填充节点的贡献屏蔽掉这一步漏了模型会学到“零向量代表碳”这种错误规律。第五个是批内分子数图网络对小分子的显存占用主要取决于总节点数而不是分子个数按总边数来控制批大小更稳。第六个是标准化方式回归任务的标签必须用训练集统计量做标准化且统计量要存下来供推理复用。这六个参数里我见过翻车最多的是第四个和第六个。掩码没做验证集指标照样能看因为填充比例在训练和验证里差不多标准化用了全量数据线下指标虚高上线一塌糊涂。这两个都不是模型问题是数据流水线问题。4. 多目标分子设计案例把“性质—特征—实验”闭环拆成四步4.1 加权求和的上限案例为什么一定要用 Pareto讲义把多目标设计放在案例位置是有意的。单目标优化好写也好讲但真实药物化学从来没有单目标活性要高、选择性要好、代谢要稳、毒性要低、合成要容易这五件事经常互相打架。用一个加权和把它们揉成一个分数最大的问题是权重没法解释——你跟我说 0.3 的活性权重加 0.2 的毒性权重是从哪来的说不清。第二个问题是加权和只能找到帕累托前沿的凸包部分非凸区域的最优解会被直接漏掉。Pareto 的思路是不预设权重先找出所有“不被任何其他解全面碾压”的候选形成前沿再交给人做决策。这一步的价值在于把一个数学问题变回一个化学判断前沿上这几个分子哪个更容易合成哪个毒性数据更可信这些是模型给不了的。实操上还要一个补充手段desirability 函数。给每个指标设一个可接受区间和一个理想值超出可接受区间直接判零落在中间按平滑曲线插值。它比加权和好解释因为它把“底线”显式写出来了。我一般会同时跑 Pareto 和 desirability两边选出来的交集通常是这一轮最值得合成的。4.2 闭环四步与每一步的失败信号步骤输入输出失败信号训练替代模型历史化合物 实验标签预测值 不确定度交叉验证很好但外部测试集掉十几个点采集函数排序虚拟库 预测分布每个候选的采集分数分数几乎全由某一维主导其他维不起作用批次选择采集分数 结构相似度几十个待合成分子选出来全是同一个骨架合成部门直接拒实验回填新测数据更新后的训练集回填数据与历史数据的实验条件不一致第一步的关键不是把模型训到多准而是让模型知道自己有多不确定。一个只会给点预测的模型放进闭环等于闭着眼睛迭代。常见做法是集成几个不同初始化的模型用预测方差当不确定度或者用高斯过程直接给分布深度模型上还可以用 MC dropout 做近似。第二步的采集函数常见有三种上置信界预测值加不确定度权重、期望改进相对当前最优的期望提升、汤普森采样按后验采样一次再取最大。前两个偏利用第三个偏探索。如果虚拟库很大而实验预算极小我一般会调高探索权重宁可牺牲一点短期命中率也要保证不被困在已有骨架附近。第三步是批次选择也是最容易被做糙的一步。逐点取 top-k 会导致选出来的分子高度相似合成部门看到十个同系物会直接把单子退回来。4.3 批次选择一个可以照着改的脚本import numpy as np from rdkit import Chem, DataStructs from rdkit.Chem import AllChem def pareto_mask(scores): scores: (n, k)所有指标已统一为越大越好返回非支配解的布尔掩码 n scores.shape[0] keep np.ones(n, dtypebool) for i in range(n): # 存在任一解在所有维度不劣于 i、且至少一维严格更优则 i 被支配 dominated np.all(scores scores[i], axis1) np.any(scores scores[i], axis1) if dominated.any(): keep[i] False return keep def greedy_pick(pred, smiles, batch32, lam0.6, radius2, nbits2048): pred: (n, k) 归一化后的预测值lam 越大越偏性能越小越偏多样性 fps [AllChem.GetMorganFingerprintAsBitVect(Chem.MolFromSmiles(s), radius, nBitsnbits) for s in smiles] chosen [int(np.argmax(pred.sum(axis1)))] # 首个子用最简单的标量化和起步 while len(chosen) batch: rest [i for i in range(len(smiles)) if i not in chosen] perf pred[rest].sum(axis1) perf perf / (np.abs(perf).max() 1e-9) # 归一化避免量纲压过多样性项 div np.array([ 1 - max(DataStructs.BulkTanimotoSimilarity(fps[i], [fps[j] for j in chosen])) for i in rest ]) score lam * perf (1 - lam) * div chosen.append(rest[int(np.argmax(score))]) return chosen这段代码解决的是“从预测结果里挑一批而不是挑一个”。pareto_mask用来做前置过滤把明显被支配的候选砍掉减少后续计算量greedy_pick用贪心方式逐步挑每次在“性能好”和“离已选分子远”之间做加权。参数上有几个地方值得调。lam是核心0.6 是我在中等规模库上的常用起点如果合成部门反馈“还是太像”往下调到 0.4如果反馈“挑的东西性能太差”往上走到 0.8。radius和nbits决定指纹的粒度半径 2、2048 位对应常见的 ECFP4 级别改成半径 1 会更关注局部官能团改成半径 3 会把更大的子结构纳入相似性判断库小的时候建议先用半径 2。batch要和合成产能对齐产能是每周 20 个就别一次挑 200 个多轮小批比一轮大批更容易纠错。真正需要改的是pred的来源。脚本里假设每列都是“越大越好”的归一化预测值实际项目里至少有一列是不确定度理性做法是把不确定度单独拿出来做加权比如按上置信界的形式合成一列再进选择器。批量贪心的复杂度是 O(batch × n)十万级库跑一次在分钟量级够用。4.4 模型可信度三条线切分、适用域、校准闭环能转起来的前提是模型在新数据上仍然可信而这件事在化学数据上尤其难因为样本之间不是独立的——同一系列化合物共享骨架共享合成路线甚至共享测量批次。第一条线是切分方式。随机切分会让同骨架分子同时出现在训练和测试里指标虚高是常态。做先导化合物优化这类任务至少要按骨架切分更严格的做法是按时间切分用早期项目数据训用后期项目数据测这才模拟了真实使用场景。第二条线是适用域。模型对训练集里没见过的化学空间没有发言权但它的输出不会自己标注“我在瞎猜”。常见做法是用指纹相似度做阈值判断新分子与训练集最近邻的 Tanimoto 低于某个值就直接标记为外推不进入决策也有用集成方差或距离度量的各有取舍但必须有一条。第三条线是校准。分类任务只看 AUC 是不够的AUC 只关心排序不关心概率是否可信。闭环里需要用概率做阈值决策比如“毒性概率低于 0.2 才进下一轮”就必须看校准曲线和 Brier 分数发现系统性高估或低估时用 Platt scaling 或等渗回归修一遍。5. 避坑与排查这类闭环项目最容易出问题的五个地方5.1 换用骨架切分后指标明显下降现象模型在随机切分的测试集上 R² 有 0.85换成按骨架切分后掉到 0.6 出头团队开始怀疑模型不行了。原因不是模型变了是评估方式变诚实了。同一骨架的分子在结构上高度相似模型只要记住骨架就能给出不错的预测随机切分把这种“记忆”当成了泛化能力。化学数据集的这种内部相关性远比图像数据集严重。解决把骨架切分作为默认评估口径写进项目模板随机切分的结果只在早期探索阶段参考。同时补一份时间切分的对照结果两套口径一起看。如果骨架切分后确实掉得厉害说明特征或模型容量不足以跨越骨架迁移这时候该做的是补数据多样性而不是继续调超参。5.2 线上预测整体偏移线下却复现不出来现象模型部署后第一批预测的分布和历史数据对不上人工检查发现有些数值明显不合理但在本地用同样的模型跑同样的输入结果又是对的。原因数据流水线不一致。最常见的是标准化统计量——训练时用训练集均值方差推理时用了当批数据的均值方差其次是特征计算版本不同比如描述符库升级后某个描述符的定义变了或者芳香性判定规则改了。解决把预处理参数和特征计算版本一起打包进模型产物推理时只允许加载这份快照不允许现场重算统计量。上线前做一次“冻结输入回放”拿一百条训练数据走完整推理链路输出必须和训练时的记录逐条对齐差一位都算失败。5.3 分类指标好看实际筛出来的全是阴性现象毒性分类模型 AUC 0.92看着很漂亮但按 0.5 阈值筛出来的候选实验验证的阳性率不到 10%。原因正负样本极度不平衡负样本占 95% 以上时AUC 依然会很高因为它衡量的是排序而排序在极端不平衡下很容易被大量负样本撑起来。真正该看的是 PR 曲线和不同阈值下的召回。解决把评估指标换成 PR-AUC 加固定召回下的精确率并且按业务需求选阈值——如果一轮只能合成 50 个就按 top 50 的精确率来评估而不是看全局阈值。另外对正样本做重采样或类别加权时要在验证集上重新校准概率否则阈值会整体偏移。5.4 把外推当内插模型给出的结果看似合理却不可靠现象虚拟库里有一批结构很新奇的候选模型给出的预测值落在合理区间团队据此排了合成优先级结果实验做出来偏差极大。原因模型对训练集覆盖范围之外的分子的预测本质上是由网络结构的外推行为决定的跟化学规律关系不大。它不会报错只会给你一个数。解决在打分环节前面加一道适用域过滤。用指纹最近邻相似度做粗筛阈值可以按历史数据的分布标定——比如取训练集内部交叉验证时“最近邻相似度”的 5 分位作为下限。超出的候选不直接丢弃标成“待评估”让人来判断别让模型替人做决定。这条规则听着保守但它省下的是真金白银的实验费。5.5 多轮迭代后候选高度雷同现象闭环跑了三四轮每轮选出来的分子越来越像骨架几乎是同一个合成部门开始抱怨没有新意。原因采集函数过度利用。模型在自己熟悉的区域预测值高不确定度低于是每一轮都往同一个坑里挖。加上批次选择没做多样性约束问题会被放大。解决两条一起上。采集函数里显式加入不确定度项把探索权重调高批次选择用前面那套贪心加相似度惩罚或者直接做聚类后按簇分配名额。还有一条经验每轮留出 10% 到 20% 的名额给“模型不看好但化学上说得通”的分子这批数据的价值往往比多合成十个高分候选更大。6. 把讲义当路线图三步读法与一份自检清单这份讲义信息密度不低但它的组织方式决定了不能从头顺着读到尾。我自己的读法是三步。第一步只看那张三列时间轴和方法映射的两页先给自己手上的问题定位它属于“实验太贵需要预筛”还是“模拟太慢需要替代”还是“数据太多需要归纳”。定位错了后面所有技术选择都会偏。第二步精读案例部分重点看它怎么把多目标拆开、怎么处理批次选择。这部分是全篇唯一给了完整闭环的地方也是最能直接抄结构的地方。读的时候拿自己项目的数据对照着填一遍填不下去的地方就是你的缺口。第三步回头再看结论部分。讲义对未来的判断是偏保守的算法会继续进步数据会继续积累但真正的瓶颈会从“模型能不能算”转移到“数据质量够不够”和“实验能不能跟上迭代速度”。这个判断我认同因为它和我这几年的实际体感一致——卡住项目的从来不是模型结构是标签。下面这份清单可以贴着项目走一遍每一条都能用一个短脚本验证。其中骨架重叠检查最值得写成固定动作from rdkit import Chem from rdkit.Chem.Scaffolds import MurckoScaffold def scaffold_of(smi): mol Chem.MolFromSmiles(smi) if mol is None: return None return MurckoScaffold.MurckoScaffoldSmiles(molmol, includeChiralityFalse) train_smiles, test_smiles [...], [...] # 换成你自己的切分结果 tr {s for s in (scaffold_of(x) for x in train_smiles) if s} te {s for s in (scaffold_of(x) for x in test_smiles) if s} overlap tr te print(f训练集骨架 {len(tr)} 个测试集 {len(te)} 个 f重叠 {len(overlap)} 个占测试集 {len(overlap)/max(len(te), 1):.1%})MurckoScaffoldSmiles取的是去掉侧链后的环系骨架includeChiralityFalse表示忽略手性做粗粒度泄漏检查时不需要区分对映体。判断标准很简单重叠骨架占测试集超过 20%说明切分基本还是随机的指标不能用落在 5% 到 20% 之间要结合任务看先导优化场景可以接受全新骨架的活性预测就不能接受。检查项通过标准不通过时先改什么骨架重叠测试集重叠骨架 5%切分脚本不是模型预处理快照推理链路可逐条复现训练输出流水线不是模型适用域有明确阈值外推样本有标记打分前置过滤器概率校准Brier 分数与校准曲线可接受后处理校准层批次多样性单批平均相似度低于阈值选择器的多样性项有一次我图省事直接拿随机切分的模型去排合成优先级第一批做了二十个命中两个团队对模型的信任度直接掉到冰点后面花了三个月才把信心重建回来。从那以后我每次交付前都强制走一遍骨架重叠检查和适用域过滤两个数不出来就不让模型进决策链。希望这份讲义和这套检查动作能帮你少走一遍我走过的弯路把有限的合成预算花在真正值得做的分子上。本文还有配套的精品资源点击获取