018

DiffDock 教程:扩散模型如何预测蛋白-配体结合姿势

DiffDock 用扩散模型做盲对接。这篇给出上手流程、参数选择与必需的后处理步骤。

DiffDock 的独特能力是盲对接——不需要指定口袋位置就能预测结合姿势。但它生成的姿势有相当比例通不过物理有效性检查,因此后处理是必需而非可选的。

安装与运行

# 推荐用官方的 conda 环境(依赖较复杂)
git clone https://github.com/gcorso/DiffDock.git
cd DiffDock
conda env create -f environment.yml
conda activate diffdock

# ---- 单个复合物 ----
python -m inference \
  --protein_path receptor.pdb \
  --ligand_description "CC(=O)Nc1ccc(O)cc1" \
  --out_dir results/ \
  --samples_per_complex 40 \
  --inference_steps 20

# ligand_description 可以是 SMILES 或 SDF 路径

# ---- 批量(用 CSV)----
# input.csv:
#   complex_name,protein_path,ligand_description,protein_sequence
#   cmpd1,rec.pdb,CC(=O)Nc1ccc(O)cc1,
#   cmpd2,rec.pdb,ligands/cmpd2.sdf,

python -m inference \
  --protein_ligand_csv input.csv \
  --out_dir results/ \
  --samples_per_complex 20

# ---- 输出 ----
# results/<complex_name>/
#   rank1_confidence-0.85.sdf
#   rank2_confidence-0.42.sdf
#   ...
# 【文件名中的数字是置信度分数】

# ---- 关键参数 ----
#   --samples_per_complex  生成候选数(10~40)
#     越多越可能包含正确姿势,但耗时线性增长
#   --inference_steps      去噪步数(默认 20)
#     增大可能提升质量
#   --actual_steps         实际执行的步数(可小于 inference_steps)

必需的后处理流程

# 【只用 rank1 而不做检查,是最常见的误用】

# ---- 第 1 步:物理有效性检查 ----
pip install posebusters

from posebusters import PoseBusters
import pandas as pd

buster = PoseBusters(config="dock")
df = buster.bust(["results/cmpd1/rank1.sdf"], None, "receptor.pdb")

# 检查项包括:
#   分子层面:SMILES 合法、键长键角、芳环平面性、
#            立体化学、内部空间冲突
#   复合物层面:与蛋白的空间冲突、是否在口袋内
#
# 【任何一项不通过 → 该姿势不应用于设计决策】

passed = df.iloc[0].all()
print("通过所有检查:", passed)

# ---- 第 2 步:局部优化修正 ----
# 对轻微不合理的姿势,用力场优化修正
smina -r receptor.pdb -l results/cmpd1/rank1.sdf \
      --minimize --minimize_iters 1000 -o rank1_min.sdf

# ---- 第 3 步:用经验打分作第二判据 ----
smina -r receptor.pdb -l rank1_min.sdf --score_only
# 【DiffDock 的置信度不是亲和力】
# → 需要独立的打分

# ---- 第 4 步:相互作用核对 ----
# 用 PLIP/ProLIF 检查是否复现关键相互作用(见 108、109)

# ---- 第 5 步:与传统方法比较 ----
# 与 Vina/GNINA 的结果比较一致性(见 346)

# ---- 完整的后处理脚本 ----
import glob
from rdkit import Chem
from posebusters import PoseBusters
import subprocess, re

def postprocess(complex_dir, receptor):
    buster = PoseBusters(config="dock")
    kept = []
    for path in sorted(glob.glob(f"{complex_dir}/rank*.sdf")):
        # 物理检查
        df = buster.bust([path], None, receptor)
        if not df.iloc[0].all():
            continue
        # 提取置信度
        m = re.search(r"confidence([-\d.]+)", path)
        conf = float(m.group(1)) if m else None
        # smina 重打分
        out = subprocess.run(
            ["smina", "-r", receptor, "-l", path, "--score_only"],
            capture_output=True, text=True).stdout
        aff = re.search(r"Affinity:\s+([-\d.]+)", out)
        kept.append({"path": path, "confidence": conf,
                     "smina_score": float(aff.group(1)) if aff else None})
    return kept

# 【判读】:
#   置信度高 + 通过物理检查 + smina 分数好 + 复现关键相互作用
#   → 才是可用的姿势

多次采样的一致性判断

# 【这是最实用的可信度判据】

import numpy as np
from rdkit import Chem
from rdkit.Chem import rdMolAlign
import glob

def sampling_consistency(complex_dir, top_k=10, threshold=2.0):
    """检查前 k 个姿势是否聚集在同一位置"""
    mols = []
    for path in sorted(glob.glob(f"{complex_dir}/rank*.sdf"))[:top_k]:
        m = Chem.SDMolSupplier(path)[0]
        if m:
            mols.append(Chem.RemoveHs(m))

    rmsds = []
    for i in range(len(mols)):
        for j in range(i + 1, len(mols)):
            try:
                rmsds.append(rdMolAlign.CalcRMS(mols[i], mols[j]))
            except Exception:
                continue
    if not rmsds:
        return None
    rmsds = np.array(rmsds)
    agree = (rmsds < threshold).mean()
    return {
        "median_rmsd": float(np.median(rmsds)),
        "agreement": float(agree),
        "verdict": ("高一致性,可信" if agree > 0.7 else
                    "中等,需进一步验证" if agree > 0.4 else
                    "【各说各话,不应据此决策】"),
    }

# 【判读逻辑】:
#   模型如果真的「知道」配体结合在哪,
#   多次采样应该聚集在同一位置
#   → 分散说明模型不确定

适用场景的判断

场景 DiffDock 是否合适
不知道口袋在哪 最合适——原生优势
探索可能的结合位点 合适,作为假设生成
与传统方法交叉验证 推荐——原理不同,一致性有意义
口袋已知的常规对接 优势不明显,Vina/GNINA 更成熟
大规模虚拟筛选 不适合——无可靠的亲和力信号
先导优化的细微排序 不适合
新颖靶点(与训练集差异大) 谨慎——泛化能力存疑

常见问题

  • 环境安装困难:依赖 PyTorch Geometric、e3nn 等,版本组合敏感。建议严格按官方 environment.yml,或用容器
  • 显存不足:大蛋白 + 多采样会占用较多显存,可减少 samples_per_complex
  • 置信度与实际质量不完全对应高置信度不保证物理合理,必须做 PoseBusters 检查;
  • 对大蛋白的处理:模型会先做口袋预测再对接,超大蛋白可能效果下降;
  • 配体的准备:SMILES 输入时的质子化态与立体化学要正确。

关键要点

  • 原生优势是盲对接;口袋已知时相对传统方法优势不明显;
  • 置信度不是亲和力,且高置信度不保证物理合理;
  • PoseBusters 检查 + smina 局部优化是必需的后处理,不是可选项;
  • 多次采样的一致性是最实用的可信度判据——分散就不该据此决策。

延伸资源