:自适应采样与工作流编排——HTMD 多 epoch 闭环)
AI增强构象采样教程15自适应采样与工作流编排——HTMD 多 epoch 闭环版本声明块工具/软件HTMDAcelleraPython 包htmd、moleculekit、jobqueues/LocalGPUQueue本地多 GPU 队列、AutoDock Vina经 HTMDdock()封装、OpenMM 8.x本篇作为 HTMD 体系构建与上游 MD 参考见正文。语言/环境Python 3.9GPU 并行队列基于jobqueues.localqueue.LocalGPUQueue。说明HTMD 原生 MD 抽样引擎为 ACEMDLocalGPUQueue默认调度 ACEMD 作业HTMD 对 OpenMM 引擎的支持取决于具体构建相关不确切之处一律标以官方文档为准。所有参数名来自官方 adaptive-configure / docking-poses 文档。一句话结论自适应采样adaptive sampling用AdaptiveMDhtmd.adaptive.adaptiverun把一次跑完拆成数十个 epoch 的闭环——每轮跑一批短模拟on-the-fly 用 MSM/聚类找欠采样的微观态再自动挑这些区域的帧作为下一轮起点配合LocalGPUQueue(ngpusN)让多 GPU 并行喂满显卡用systemPrepare(pH7.4)dock()把对接 pose 逐个转成可跑 MD 的体系amber.build(ionizeTrue, saltconc0.15)即可把第 14/12 篇的多起点真正变成会自我导航的采样舰队。〇、本篇要解决的认知问题为什么每个体系从头到尾一次跑完不是好策略多起点短模拟 聚类 选点的闭环好在哪HTMD 的自适应采样adaptive sampling到底怎么选出下一轮起点on-the-fly 的马尔可夫状态模型MSM和多 epoch 模拟战役simulation campaign分别指什么LocalGPUQueue这类队列怎么驱动多 GPU 并行和普通一条命令跑一条 MD的提交方式有何不同对接docking产出的多个 pose怎么变成可跑 MD 的多个多起点自适应采样的收益与风险各是什么起点挑选偏差为什么比采样不足更隐蔽一、机制解析1.1 反直觉起点一次跑完 vs 多段短跑第 01 篇就立了规矩构象采样conformational sampling慢是因为跨自由能垒FES 上的能量垒需要长时间。直觉上那就一条轨迹跑到看不到新状态为止——但在探索未知自由能景观FES时单条长轨迹是串行的它从出发盆地一路艰难爬坡大部分算力花在已经在采样的谷里打转。自适应采样adaptive sampling换了个思路跑一簇短轨迹每隔一段停下来回看数据找出哪些微观态被采得最稀、最欠采样下一段模拟就从这些区域的代表性帧重新出发。这样策略并行度算力去向对新状态的发现单条长轨迹无1 个起点大量花在已访问区域重采样靠运气翻越势垒多起点短模拟第 14 篇高多起点并行平均分配均匀但盲提高发现概率仍可能重复自适应采样闭环本篇高且有方向下一轮聚焦欠采样区间每轮根据前一轮数据选点稳定推进多起点是把鸡蛋分到多个篮子自适应采样则是先看哪个篮子最空再往那儿放鸡蛋。1.2 多 epoch 模拟战役与闭环图模拟战役simulation campaignsimulation campaign指一套由AdaptiveMD统一指挥的、跨很多轮的模拟计划每一轮叫一个epoch时代/轮次。每轮结束都会收集已完成轨迹 → 投影 聚类 建马尔可夫模型 → 挑欠采样态里的帧 → 写入下一轮输入目录 → 交给队列再跑。架构如下┌────────────────────────── 模拟战役.run() 阻塞直到 nepochs 或 KeyboardInterrupt │ 每轮 epoch: └────→ ① 收集已完成轨迹datapath/ ② projection 投影如 MetricSelfDistance: Cα contacts 或配体 RMSD ③ 聚类KCenter→ 按 TICA 降维后的宏观态 ④ 建/累计 MSM识别欠采样微观态 ⑤ 从这些态的代表帧挑出下一轮起点 ⑥ 写 inputpath/eNN/经 jobqueue 提交新短模拟跑在多个 GPU 上 │ └──→ 短模拟完成 → 回到 ① epoch 自增直到达到 nepochs关键输入模板generatorspath只在epoch 1播种从 epoch 2 起新模拟直接复制父模拟的输入目录只覆盖coorname默认input.coor与boxname默认input.xsc为所选起点帧。所以每轮起点都是真跑过的帧绝不凭空产生——这就是复用已有轨迹的直接体现。1.3 on-the-fly 的 MSM为什么它知道哪里欠采样马尔可夫状态模型Markov state modelMSM把构象空间按投影特征常用 TICA 慢特征离散为一组状态并估计状态间转移概率。自适应采样的欠采样判据就来自 MSM某微观态若统计量太少如被采样帧数低于阈值或转移不确定性大就会被标记为需要补充采样的目标。TICA 的作用是把高维投影降到少数慢特征ticadim3让聚类更贴近真正的慢过程——这与第 15 篇之前用到的元动力学 CV 思想一致找慢变量才能有意义地划分状态。1.4LocalGPUQueue把多 GPU变成队列资源单个短期模拟只占一块 GPU 的一小会儿逐个手动提交会让算力空闲。LocalGPUQueue(ngpusN)是一个本地作业队列你声明最多 N 块 GPUAdaptiveMD每轮产出新模拟时队列自动把作业调度到空闲的 GPU 上跑跑完即回收资源。它与 Slurm/LSF/PBS 队列接口一致app换一个类即可所以本地多 GPU 跑通的配置可无缝平移到集群。这才是第 19 篇多起点并行与性能的前奏。1.5 对接 pose 转 MD给战役准备可跑的多起点第 12/14 篇的对接触角(DiffDock/Vina)只是坐标进水盒、定质子化、配键都是离 MD 很远的活。HTMD 官方dock()docking-poses 指南直接封装 AutoDock Vina返回(poses, scores)再经systemPrepare(pH7.4)solvate(pad12)amber.build(ionizeTrue, saltconc0.15)逐个出完整体系——这正好是第 15 篇自适应采样的弹药库对接出的每个 pose 都可以作为一条独立 MD 轨迹的起点候选。1.6 收益与风险必须同时看懂收益一句话记忆资源聚焦高价值区间 轨迹复用已有轨迹不浪费每轮基于全线数据选点天然配合多 GPU 并行弹夹替换式推进明确定位哪块没采够比均匀撒点有方向。风险这两条常在真实项目里戳穿人的美梦起点挑选偏差selection biasMSM/聚类模型本身就是从已采样本学的若某一盆地从没进去过模型并不知道那里有东西——自适应会选择性地忽略从未到达的区域把算力继续投在已知谷的边界。对策是跳出一小撮探索模拟或与元动力学混杂。过度集中局部谷over-concentration, local traps欠采样判据若只看转移概率模型可能反复重新播种进入同一批边界态造成局部谷内假收敛。对策是监控每轮新探明的宏观态数量是否有增量无增量即应停止或换策略。这两条风险都需要监控而不是一次性配置故正式战役一定要看每轮的交易量新增态数、转移矩阵残差。二、完整代码与逐行剖析以下两段是自包含可执行骨架代码 A 做体系构建 对接 pose 转 MD 多起点即prepare代码 B 做AdaptiveMD 配置 LocalGPUQueue 并行 跑战役 产出。两段可串成一个战役脚本所有 API 名来自官方文档参数如有出入以你安装构建的官方文档为准。2.1 代码 Aprepare——构建体系并把对接 pose 转 MD 起点# -*- coding: utf-8 -*-HTMD 体系构建 对接 pose 转 MD 多起点第15篇 代码Afrommoleculekit.moleculeimportMoleculefrommoleculekit.tools.preparationimportsystemPreparefromhtmd.dockimportdock# 官方 dock() 封装 AutoDock Vinafromhtmd.builder.solvateimportsolvatefromhtmd.builderimportamberdefbuild_poses_to_md(protein_pdb,ligand_mol2,center_res,out_rootbuild,numposes12,box20.0):把蛋白配体对接出多个 pose并逐个建成可跑 MD 的完整体系。# --- 1. 读入受体/配体都必须是【单帧】否则 dock 直接抛 NameError ---protMolecule(protein_pdb)prot.dropFrames(keep0)# 只留第 0 帧共其只有一帧时无害ligMolecule(ligand_mol2)iflig.coords.shape[2]!1:# coords 第三轴是帧索引lig.dropFrames(keep0)# --- 2. 以口袋残基质心为 box 中心做对接extent 单位 Å ---poses,scoresdock(prot,lig,centerprot.getCenter(fresname{center_res}),extent[box,box,box],# 20 Å 是单口袋常用默认numposesnumposes)# Vina 上限 20超出静默截断# --- 3. 每个 pose → 完整模拟体系多起点弹药 ---built[]fori,poseinenumerate(poses):complex_molprot.copy()# 复制蛋白不污染 prot 本体complex_mol.append(pose)# 往蛋白里拼上该 pose 的配体prepared,_systemPrepare(complex_mol,pH7.4)# 先定质子化再加氢solvsolvate(prepared,pad12)# 加水盒pad 单位 Åamber.build(solv,outdirf{out_root}/pose_{i:02d},ionizeTrue,saltconc0.15)# 加中和离子 0.15 mol/Lbuilt.append(f{out_root}/pose_{i:02d})# scores[i] [affinity_kcal/mol, RMSD_lb, RMSD_ub]只用于排序不用于热力学returnposes,scores,builtif__name____main__:# 以你本地的核心蛋白 PDB 与配体 mol2 替换路径poses,scores,builtbuild_poses_to_md(protein.pdb,ligand.mol2,center_resPOCKET)fori,scoreinenumerate(scores):print(fpose{i:2d}: build{built[i]}faffinity{score[0]:6.2f}kcal/mol)# Vina 打分仅排名用逐行要点dropFrames(keep0)官方文档明确dock()要求蛋白与配体都是单帧多帧会抛NameError这是最常翻车的点。getCenter(resname ...)拿口袋残基质心当 box 中心避免整蛋白盲扫导致的打分漂移。systemPrepare在对接之后又做一次配体已在口袋里确保氢与质子化正确amber.build输出structure.prmtopstructure.pdb这正是后续AdaptiveMD每个 generator 目录需要的输入。2.2 代码 BAdaptiveMD 配置 LocalGPUQueue 多 GPU 并行 跑战役# -*- coding: utf-8 -*-HTMD AdaptiveMD 自适应采样战役第15篇 代码Bfromhtmd.adaptive.adaptiverunimportAdaptiveMD# 战役总指挥类fromhtmd.projections.ticaimportTICAfrommoleculekit.projections.metricdistanceimportMetricSelfDistancefromjobqueues.localqueueimportLocalGPUQueue# 本地多 GPU 作业队列fromhtmd.clustering.kcentersimportKCenter# 质心聚类选宏观态# --- 配置模拟器队列声明可用 GPU 数作业自动调度到空闲卡 ---appLocalGPUQueue(ngpus4)# 4 卡并行改为 Slurm/LSF/PBS 换对应 Queue 类# --- 实例化自适应运行 ---adAdaptiveMD()ad.appapp# 队列即模拟器/调度器ad.nmin2# 低水位在跑作业 ≤ 2 时才触发新 epochad.nmax4# 触发后补到最多 4 个并发作业ad.nepochs30# 到 30 轮即停或 CtrlC 安全中断ad.generatorspath./generators# epoch1 的输入模板目录完整可跑体系ad.inputpath./input# 每轮新模拟的输入目录input/eNN/ad.datapath./data# 已完成模拟的轨迹落盘处ad.filteredpath./filtered# 自动去水后的轨迹水剥离再聚类# --- 投影/聚类特征在这个低维特征空间里判断哪里欠采样 ---ad.projectionMetricSelfDistance(protein and name CA,metriccontacts)ad.clustmethodKCenter# 聚类算法类对象选宏观态ad.macronum4# 期望宏观态数量ad.ticadim3# TICA 慢特征降到 3 维ad.ticalag20# TICA 时间滞后帧数大体系可加大ad.run()# 阻塞直到 30 轮跑完或 KeyboardInterrupt逐行要点app LocalGPUQueue(ngpus4)这是多 GPU 并行的真正入口——AdaptiveMD每轮产出的新模拟不是手动run(OpenMM)而是交给此队列自动调度nmin/nmax控制舰队吞吐。generatorspath只播种 epoch 1epoch 2 起复制父模拟输入目录只换起点帧coorname/boxname所以每个 generator 必须是完整可运行的体系目录——这就是代码 A 的amber.build输出。projection每轮全部已完成轨迹上重算故特征别选太重如全部重原子自距离500 残基会拖慢每轮示例选 Cα contacts。KeyboardInterrupt安全ad.run()再次调用会按inputpath/e*/目录计数从上一完成 epoch 续跑——这就是工作流可重开的落地。选点发生在.run()内部clustering MSM 识别欠采样微观态 → 挑帧 → 写input/eNN/对用户透明。2.3 产出解读这就是下一轮选点 产出跑完后inputpath/e0*/是每一轮的输入目录datapath是所有轨迹filteredpath是去水后的可用轨迹。官方提供检查已完成战役的 how-toadaptive-inspect-run从datapath/重建父/子模拟依赖树parent/child 关系据此判断每个状态的抽样次数与收敛情况——这是判断该不该停的原始材料。三、常见报错与排查现象根因排查与修复dock()抛NameError蛋白或配体mol.coords不是单帧传入前对两者都dropFrames(keep0)检查是否误读了含多个 MODEL 的文件Vina 报格式怪异错误obabel缺失或转出坏 PDBQT先obabel --version确认在$PATHbabelexe参数指向真实路径ad.run()启动后无作业产出generatorspath里的体系目录不可直接运行确认目录内含完整可跑输入prmtop/pdb 等generators 只种 epoch 1缺了第一轮无从开始每轮极慢/内存暴涨projection特征过重每轮全程重算只投影 Cα 或主动用 TICAticadim降维skip抽帧再聚类跑了几轮后新态不再增加过度集中局部谷MSM 反复重播种同一批边界态混入少量探索模拟或用AdaptiveGoal引导监控每轮新增宏观态数无增量即停回调中断后 job 状态混乱未正确计数 epoch 就硬杀触发KeyboardInterrupt安全不要 kill -9重开ad.run()从input/e*/前缀继续四、动手练习练习 1构建产物断言运行代码 A配一个真实蛋白如已有 PDB与配体 mol2。判据built里每个pose_NN目录存在且含structure.prmtop与structure.pdbscores行数 numposes≤12打印的 affinity 均有数值且你可按大小排序Vina 打分仅排名用。若报NameError说明漏了dropFrames(keep0)。练习 2配置自检 dryrun运行代码 B但先设ad.dryrun True官方文档只测生成逻辑不真提交。判据程序不卡死、目录input/e1/被创建dryrun 下也走生成逻辑把nepochs改成 2 仍能正常退出。这是你做任何大型战役前必做的空战演练。练习 3真实小战役ad.nmin2, ad.nmax4, ad.nepochs54 卡或 1 卡真跑 5 轮。判据运行结束后datapath下轨迹数 ≥ad.nepochs每轮 ≥ nmin 条filteredpath里有去水轨迹能数出inputpath出现超过 1 个eNN目录——证明闭环真的推进了多轮而非只跑一批。观察每轮是否出现新宏观态官方 inspect how-to 判据无新增即触发风险 2 的反思。五、小结与下一篇预告本篇把多起点升级成闭环理解了为何一次跑完在探索未知 FES 时低效掌握了 HTMDAdaptiveMD的 on-the-fly MSM 选点机制与多 epoch 模拟战役用LocalGPUQueue(ngpusN)把多 GPU 并行落地并以dock()systemPrepareamber.build把对接 pose 转成可跑 MD 的多起点同时看清了自适应采样的收益复用轨迹、聚焦欠采样区与两大风险起点挑选偏差、过度集中局部谷。下一阶段我们把这些 API 再收进自己可控的插件框架里。第 16 篇预告《二次开发封装 AIMD 采样插件》将把第 12–15 篇的对接→体系→自适应/增强采样→分析整理成可复用、可重开、CI 友好的 mini 插件框架用参数化复用、日志保留与断点续跑让整套采样真正可工程化交付。本篇认知问题回显FAQQ1为什么每个体系一次跑完不是好策略A1单条长轨迹是串行且盲目大量算力花在已访问区域重采样自适应采样跑多段短模拟、每轮停在数据上重定向把算力引向欠采样的状态区间发现新构象更快。Q2HTMD 的自适应采样怎么选下一轮起点模拟战役又是什么A2AdaptiveMD每轮先生成轨迹投影聚类on-the-fly MSM识别欠采样微观态后挑其中代表性帧作下一轮起点模拟战役simulation campaign就是由这些 epoch 组成的、由ad.run()统一指挥的采集计划。Q3LocalGPUQueue 怎么实现多 GPU 并行和普通跑一条 MD 有何不同A3LocalGPUQueue(ngpusN)是本地作业队列声明可用卡数后把每轮新模拟自动调度到空闲 GPU跑完回收区别于手动一条条提交它是让AdaptiveMD按nmax弹夹式填充满、不设即空闲。Q4对接的多个 pose 怎么变成可跑 MD 的多起点A4用dock()拿(poses, scores)把蛋白复制后append(pose)逐帧、经systemPrepare(pH7.4)定质子化加氢、solvate(pad12)加水盒、amber.build(ionizeTrue)出 prmtop/pdb每个 pose 就是一个独立起点体系正可喂给generatorspath。Q5自适应采样的收益与风险各是什么凭什么起点挑选偏差更隐蔽A5收益在复用已有轨迹并聚焦欠采样区两大风险是起始挑选偏差MSM 从已采样本学从未到达的盆地会被选择性忽略与过度集中局部谷反复重播种同一批边界态。偏差不报错也不明显只见新态停止增长故必须监控每轮新增态数而非只看跑了多少轮。