:用 --diffusion_samples 批量采样构象集合——多样性开关与 ensemble 起点)
AI增强构象采样教程3用 --diffusion_samples 批量采样构象集合——多样性开关与 ensemble 起点版本声明块工具/软件Boltz-2 v2.2.1boltz predict系列参数、Python 3.9环境沿用md23conda 环境需要 CUDA/GPU 才能并发跑多个构象。关键参数--diffusion_samples 5、--sampling_steps 200、--step_scale 1.638、--recycling_steps 3。目标产出第 04 篇起可直接用于多起点 MD 的构象集合ensemble。一句话结论boltz predict input.yaml --diffusion_samples 5会让 Boltz-2 在扩散去噪里用不同随机种子把同一个体系递归采出 5 个彼此不同、又都低能的 3D 构象落盘成model_0.cif~model_4.cif其中step_scale默认 1.638、sampling_steps默认 200、recycling_steps默认 3三个参数是多样性旋钮——采样步数越多越逼近稳构象step_scale 越大越早结束去噪但越偏离近乎低能构象而 recycling_steps 让每次去噪前反复精修共折叠——这 5 个 structure 就构成后续 MD 的多起点 ensemble多样性控制参数的边界行为以官方文档为准。〇、本篇要解决的认知问题--diffusion_samples 5到底做了什么为什么同一个输入能出多个不同构象step_scale1.638、sampling_steps200、recycling_steps3分别控制构象的什么性质怎么权衡多样性与质量5 个 model_* 输出文件长什么样怎么用脚本自动归类为什么这些多构象叫ensemble它与第 01 篇的多起点思想怎么衔接采样出一堆相似构象怎么办——是不是该先做去重一、机制解析1.1 同一个输入为什么能出多个构象入门篇锚点Boltz-2 是生成式模型不是确定性打分器这是多样性这件事的唯一来源。第 02 篇讲过 Boltz-2 靠扩散去噪产出结构。扩散生成的核心一个往返先把结构往噪声里推移再让网络逐步把它洗回来成干净坐标。如果每次洗回都用同一个确定性路径输出就总是同一个结构而 Boltz-2 在每一轮去噪里都引入随机性随机噪声、随机初始化、随机种子所以即便输入完全一致不同随机种子仍会收敛到结构相近但不完全相同的构象。--diffusion_samples N只是告诉它这一轮我采样多少个这样的去噪流程于是你得到 N 个构象。1.2 三个多样性旋钮它们各自调的是什么参数默认值含义调大 → 变什么step_scale1.638扩散去噪中噪声对数空间的一个缩放标度控制噪声注入的量越大 → 去噪过程更早熟/更少回退构象偏离理想低能态更多、多样性反而可能下降行为以官方文档为准sampling_steps200去噪迭代的步数每轮把噪声再洗回一点越大 → 路径更细、构象更收敛更高质量太大会慢recycling_steps3去噪开始前对共折叠坐标反复精修的次数常见开关默认回收越大 → 每次洗回前先把坐标校准一遍后接近稳定、构象更多样但更耗时三个一起决定你想要的 ensemble 是偏繁还是偏收敛新手一般先用默认step_scale 1.638 / sampling_steps 200 / recycling_steps 3再用--diffusion_samples 5拿第一版 ensemble若发现 5 个构象彼此几乎一样两两 RMSD 极小再微调这些旋钮。**这为什么对你重要**因为第 04~08 篇的多起点 MD 是把这些构象当不同初始坐标喂进去若 ensemble 内部高度重复多起点就等于白做——你是在用同样的结构重复跑。1.3 输出model_* 构象与 ensemble 归类--diffusion_samples N会把 N 个构象分别存成model_0.cif、model_1.cif、…每个还有对应的confidence_*.json与affinity_*.json。这些编号的 model 文件天然就是多起点集的第一层结构再往下你要按构象之间的相似度做去冗余第 13 篇讲初筛但做 MD 之前第一步只是简单地把它们分别取出来当作 N 个初始 structure。二、完整代码与逐行剖析2.1 代码一一次出 5 个构象bashconda activate md23# 用第 02 篇的 input.yaml一次采 5 个构象boltz predict input.yaml\--diffusion_samples5\--out_dir./boltz_ensemble\--use_gpu# 查看输出目录结构应看到 model_0.cif ~ model_4.cifls-R./boltz_ensemble|head-n30要点--diffusion_samples 5是核心其余直接沿用第 02 篇命令行。注意sampling_steps/step_scale/recycling_steps都有--前缀的同名 CLI 开关可覆盖默认值以 prediction.md 为准。2.2 代码二把输出按 model_* 归类 计算两两 RMSDPython先装一个轻量比对工具gemmi 也可做坐标读取再用 RDKit/gemmi 统计多样性# -*- coding: utf-8 -*-把 Boltz-2 的多个 model_*.cif 归类并估算构象多样性两两 RMSD。importos,globimportnumpyasnpimportgemmi out_dirboltz_ensemblecif_dirglob.glob(os.path.join(out_dir,predictions,*))[0]# 1) 找齐 N 个 model 文件model_0.cif 编号连续cifssorted(glob.glob(os.path.join(cif_dir,model_*.cif)))nlen(cifs)print(f找到{n}个构象:,[os.path.basename(c)forcincifs])defload_coords(path):用 gemmi 读 mmCIF返回按原子顺序的坐标数组 (N,3)。docgemmi.cif.read(path)blkdoc.sole_block()loopblk.find_mmcif_category(_atom_site).get_loop()xnp.array(loop.get_column(Cartn_x).data,dtypefloat)ynp.array(loop.get_column(Cartn_y).data,dtypefloat)znp.array(loop.get_column(Cartn_z).data,dtypefloat)returnnp.stack([x,y,z],axis1)# 2) 计算两两 RMSD仅用重原子且假定每个构象原子顺序一致coords[load_coords(c)forcincifs]refcoords[0]max_rmsd0.0fori,cainenumerate(coords):max_rmsdmax(max_rmsd,float(np.sqrt(np.mean(np.sum((ca-ref)**2,axis1)))))print(f相对 model_0 的最大 RMSD:{max_rmsd:.2f}Å)print(若该值 ~0.3 Å说明 ensemble 彼此几乎相同可调大多样性旋钮。)要点用glob(model_*.cif)自动归类所有构象这就是多起点集合的第一个可编程表示。两两 RMSD 是多样性的客观判据max_rmsd偏低 ensemble 冗余提示该调step_scale/sampling_steps。若原子顺序不完全一致构建 A 与构建 B 链序不同RMSD 前应先按残基再按原子对齐完整实现以官方/学术对齐工具为准。2.3 代码三抽出每个构象对应哪个亲和力建 ensemble 元数据表Python# -*- coding: utf-8 -*-把 affinity_*.json 与 model_*.cif 的编号对应起来生成可写的 ensemble 表。importglob,os,json,csv out_dirboltz_ensemblecif_dirglob.glob(os.path.join(out_dir,predictions,*))[0]rows[]forcifinsorted(glob.glob(os.path.join(cif_dir,model_*.cif))):idxos.path.basename(cif).split(_)[1].split(.)[0]# model_0.cif - 0baseos.path.join(cif_dir,fmodel_{idx})# 亲和力/置信度 json 通常在对应 model 的同目录命名以官方为准affglob.glob(base*affinity*)\ glob.glob(os.path.join(out_dir,f*model_{idx}*affinity*))ifaff:djson.load(open(aff[0],encodingutf-8))rows.append([base,d.get(affinity_pred_value,[None])[0]])else:rows.append([base,None])withopen(ensemble_table.csv,w,newline,encodingutf-8)asfh:wrcsv.writer(fh)wr.writerow([model,affinity_pred_value])wr.writerows(rows)print(已写出 ensemble_table.csv共,len(rows),行)要点把构象编号 → 亲和力分数固化到一张 CSV就是第 13 篇用亲和力挑选多起点的前置数据affinity_pred_value[0]取列表首个值具体结构以官方 JSON schema 为准。三、常见报错与排查现象根因排查与修复加了--diffusion_samples 5仍只出一个 structure参数名写错了或该版本默认定死单一构象用boltz predict --help查确切开关名官方可能用--diffusion_samples或--num_recycles等以文档为准5 个构象两两 RMSD 几乎为 0sampling_steps/step_scale让去噪过度收敛适当降低 sampling_steps、调高 step_scale 或改随机种子观察 RMSD 上升model_3.cif之类缺失编号不连续某次生成崩溃用glob(model_*.cif)而非硬编码编号数len(cifs) --diffusion_samples输出 JSON 字段名与教程不一致Boltz-2 版本字段有变打印list(json.keys())自查字段命名以官方 prediction.md 为准显存不足采样很多 model5 个模型并行占用高降到--diffusion_samples 2或用显存更小的批次四、动手练习练习 1批量采样用第 02 篇的 YAML 执行 2.1 命令。判据model_0.cif~model_4.cif共 5 个文件存在glob数到 5。练习 2多样性量化运行 2.2 脚本。判据打印出max_rmsd并确认它在 0.3~3 Å 之间太大了说明构象发散需检查质量太小了说明冗余。练习 3改旋钮把--sampling_steps从默认 200 降到 100 再采样一次运行 2.2 对比max_rmsd。判据步数减少后max_rmsd比默认时更大说明去噪收敛程度与多样性负相关数值确切差异以本机输出为准。五、小结与下一篇预告本篇把 Boltz-2 从单结构生成器升级成ensemble 生成器--diffusion_samples 5一次产出 5 个低能且彼此不同的构象step_scale(1.638)、sampling_steps(200)、recycling_steps(3)是控制多样性/质量平衡的三个旋钮我们用glob(model_*.cif)自动归类、用两两 RMSD 量化多样性并用 CSV 把构象与亲和力分数绑定成元数据表。这 5 个构象就是我们第 01 篇多起点思想的第一个实体形态。但坐标堆在那里Boltz-2 输出的 CIF 还带着共折叠的修饰残基、共价键与可能的缺失段直接喂给 MD 会死得很惨——结构得先洗干净。第 04 篇预告《从预测结构到 MD 的第一步》将教你用 PDBFixer 清洗/补全把 Boltz-2 的 CIF 转成可用的 PDB并在 OpenMM 里跑通第一个最小体系minimizer 或短程 mdrun正式建立从 ensemble 构象出发做多起点 MD的工程。本篇认知问题回显FAQQ1--diffusion_samples 5做了什么为什么能出多个构象A1它让 Boltz-2 用不同随机种子分别跑 5 次扩散去噪流程每次收敛到结构相近但不相同的构象落盘为model_0.cif~model_4.cif多样性来自生成式模型的噪声随机性。Q2step_scale/sampling_steps/recycling_steps 各控制什么A2sampling_steps是去噪迭代步数越大越收敛step_scale是噪声缩放标度调大有早熟风险recycling_steps是去噪前的共折叠精修次数三者共同决定构象的多样性与质量边界行为以官方为准。Q3怎么自动归类这些 model_* 文件A3用glob(model_*.cif)自动收集按文件名model_idx编号再配对读取对应confidence_*/affinity_*JSON输出成 CSV 元数据表。Q4为什么这些多构象叫 ensemble跟多起点怎么衔接A4ensemble 指彼此不同且都能低能的构象集合它正是第 01 篇多起点思想的实体形态后续 MD 把每个构象当作一个独立初始坐标来跑。Q5如果采样出相似构象怎么办A5先算两两 RMSDmax_rmsd 值过低如 0.3 Å说明冗余应降低 sampling_steps、调 step_scale 或换随机种子以增大多样性再做后处理去重第 13 篇讲初筛。