Diffusion-Physics Hybrid Molecular Docking — Re-validation of SARS-CoV-2 Mpro Candidates with DiffDock-Glide
パート 07:GNN DTI予測は、上位のSARS-CoV-2 Mpro結合候補に対して、結合する可能性を示す確率スコアのみを提供します。実際の実験を行う前に、"どのように結合するか"の3D構造と、"どれだけ安定して結合するか"の物理学に基づいた根拠が必要です。AutoDock VinaやGlideなどの物理学に基づいたドッキングツールは、30年の実績があり、標準的なツールとして確立されていますが、広範な構造空間を徹底的に探索するため、計算時間がかかります。一方、DiffDockなどの拡散モデルは、数秒で複数の候補構造を生成できますが、物理的に衝突するような構造が生じやすいという欠点があります。本パートでは、両方の手法の長所を組み合わせたハイブリッドパイプライン、具体的にはDiffDock-Glide (2025)に焦点を当て、実用的な環境で、構造の正確性と計算速度の両方を実現することを目指します。
📚 推奨される事前知識 (強く推奨)
本パートは、AI × 生物学における高度で専門的なトピックです。本パートを開始する前に、DryBenchの以下の部分を最初に確認することをお勧めします。
事前知識を確認せずに進めると、本パートでは拡散モデルのノイズ除去の原理、SE(3)-equivariantグラフ、およびPyTorchにおける大規模なテンソル処理について再説明しないため、実践的なコードを理解することが難しくなります。
DryBenchで以前に学習したこと
DryBench ai-native #2では、確率分布を学習する生成モデルの原理を学び、#12では、PyTorchを使用して大規模なテンソルを操作し、混合精度最適化を行う方法を学びました。
拡散モデルは、ノイズからデータを段階的に再構築するトレーニング手法であり、画像、音声、ビデオの分野で大きな成功を収めています。しかし、リガンドドッキングは、やや異なる問題です。それは、ノイズからリガンドの3D座標を、ターゲットポケット内の正確な位置に"再構築"することを含みます。特に、SE(3)-equivariant(回転および並進対称性を保持する)ように設計することが重要です。DiffDock (2022)およびその後のいくつかのモデルは、このアイデアを改良してきました。しかし、拡散モデルの根本的な制限(物理法則を明示的に強制しない)は、実用的なアプリケーションにおいて、衝突や非現実的な形状として現れます。したがって、物理学に基づく再検証レイヤーは不可欠です。
難しい問題の定義
実用的なシナリオ:SARS-CoV-2 Mpro候補リガンドの再検証
パート07では、ドッキングによってスコアリングされた、承認された薬剤ライブラリからの上位20個の候補リガンドを再検証します。
- 入力: Mproの3D構造(PDB 6LU7、7BQYなど、いくつかのapoおよびholo構造)、20個の候補リガンドのSMILES。
- 出力: 各候補に対する上位3つの結合構造、各構造に対する結合エネルギー、衝突および幾何学的な妥当性、および最終的なアンサンブルスコア。
- 検証: 既知のMpro阻害剤(nirmatrelvir、ensitrelvir、N3など)、PDBbind Mproサブセットベンチマークとの一貫性。
- コスト: 1リガンドあたり60秒未満(DL 30秒 + 物理学による再検証30秒)。
ドッキングの基本的な要件
ターゲットタンパク質の3D構造と数千個のリガンドに対して:
- 結合構造の予測: 各リガンドがどのポケットに、どのような方向で結合するかを決定します。
- 結合親和性スコア: 構造の物理的および化学的な安定性を定量化します。
- 偽陽性フィルター: 非現実的な構造(衝突、誤ったポケット、歪んだ形状)を自動的に除去します。
- 処理速度: 1リガンドあたり数秒から数分。
既存のアプローチ
- AutoDock Vina (2010、いくつかの改訂版):無料およびオープンソース。標準的なドッキングツール。1分あたり1〜10個のリガンド [1]。
- Glide (Schrödinger):商用。精度レベルはSPからXPまで。業界標準。
- DiffDock (MIT 2022):拡散に基づく最初のSOTA。1リガンドあたり30秒、上位1の精度は38% [2]。
- DiffDock-L (MIT 2024):上位1の精度が43%に向上した拡張版。
- DiffDock-Pocket (2024):ポケット情報を利用して精度を向上させます。
- DiffDock-Glide (bioRxiv 2025):DL構造 + Glideによるハイブリッド最小化、上位1の精度は55%以上 [3]。
- RLDiff (2024、Oxford):強化学習によって誘導される拡散 [4]。
- Boltz-2 (パート11):ドッキングを含む統合予測ツール。本パートでは、ドッキングに特化したアプローチに焦点を当て、Boltz-2を補完します。
- PoseBusters (2024):ドッキング構造の妥当性を定量化するためのDLフレームワーク [5]。
本パートでは、DiffDock(またはDiffDock-Glide)による構造予測 + Vina / Glideによる再検証 + PoseBustersフィルターを組み合わせます。
本パートのターゲットメトリック
- 20個のMpro候補それぞれに対して、30分以内のウォールクロック時間で、上位3つの構造を生成します。
- PoseBustersの物理学フィルターを使用して、30%以上の衝突および非現実的な構造を除去します。
- アンサンブルスコア(DiffDockの信頼度 + Vinaスコア + 幾何学的な妥当性)を定量化します。
- 既知の阻害剤(nirmatrelvirなど)のトップ3ランキングを再現します。
- DUD-Eベンチマーク(活性化合物とデコイ化合物を区別する)で、ROC AUC 0.85以上を達成します。
必要なツールとインフラ
| ツール | 役割 | ライセンス |
|---|---|---|
| DiffDock (または DiffDock-L) | 拡散に基づくポーズ予測 | MIT |
| DiffDock-Glide (bioRxiv 2025 コード) | ハイブリッド最小化 | 個々の著者のライセンス |
| AutoDock Vina | 物理に基づいたドッキングと再検証 | Apache 2.0 |
| PoseBusters | ポーズの妥当性検証 | MIT |
| OpenBabel | ファイル形式の変換 (SMI、SDF、PDB、PDBQT) | GPL |
| RDKit | SMILES、3D座標、および正規化 | BSD-3-Clause |
| PyMOL (オープンソース版) | 可視化 | LGPL |
| MDAnalysis (オプション) | トラジェクトリー解析と後処理 | GPL |
| PDBFixer (OpenMMファミリー) | タンパク質の前処理 | LGPL |
| PDBbind / DUD-E / COVID Moonshot | ベンチマークデータセット | 学術利用は無料 |
インフラストラクチャ要件:
- 24〜48GB VRAMのデータセンターGPU(DiffDockおよびその後のバージョン、大きなリガンド、大きなポケットの場合)。
- ほとんどのタスクは、ハイエンドのコンシューマーGPU(RTX 4090 24GB)で実行できます。大規模な複合体には、データセンターGPUが必要です。
- VinaおよびGlideによる再検証:8コア以上のCPUを推奨(並列処理のため)。
- 16GB以上のRAM。
- ディスク容量:DiffDockの重み(約2GB)、PDBbind(約10GB)、DUD-E(約30GB)、およびさまざまなMpro PDBファイル(約100MB)。
学習者向けの推定コスト: ローカルGPUおよびCPUを使用する場合、APIコストは0です。100個のリガンドをスクリーニングするには、約30〜60分かかります。クラウドGPUを使用する場合は、時間単位の料金を参照してください。
パイプラインの実践的な実装
全体のフロー:
ステップ1:タンパク質の事前処理
ドッキングを行う前に、プロトン化状態の除去、水素の付加、水とイオンの除去、リガンドの除去を行うことが重要です。PDBFixerは標準的なツールです。
import subprocessfrom pathlib import Path
def prepare_protein(input_pdb: Path, output_pdb: Path, remove_hetatoms: bool = True) -> None: """PDBの事前処理:水、イオン、リガンドの除去 + Hの付加 + 部分電荷の保持。
実用的なオプション:pdb2pqr、PDBFixer、Schrödinger Protein Prep、UCSF ChimeraX。 """ from pdbfixer import PDBFixer from openmm.app import PDBFile fixer = PDBFixer(filename=str(input_pdb)) fixer.findMissingResidues() fixer.findMissingAtoms() fixer.addMissingAtoms() fixer.addMissingHydrogens(pH=7.4) if remove_hetatoms: fixer.removeHeterogens(keepWater=False) with open(output_pdb, "w") as f: PDBFile.writeFile(fixer.topology, fixer.positions, f)
def pdb_to_pdbqt(pdb_path: Path, pdbqt_path: Path) -> None: """AutoDock Vina用にPDBQT形式に変換(OpenBabel)。
-xr:剛体レセプター(側鎖の柔軟性を排除し、ドッキング速度を向上)。 -xh:Hを保持、-xn:Nアミド電荷、-xr r:剛体。 """ subprocess.run( ["obabel", str(pdb_path), "-O", str(pdbqt_path), "-xr"], check=True, capture_output=True, )
def identify_binding_site(pdb_path: Path, known_ligand_pdb: Path | None = None) -> tuple[float, float, float]: """ドッキングボックスの中心。既知のリガンドがある場合は、その中心を使用します。そうでない場合は、ポケット予測ツールを使用します。
Mpro 6LU7シナリオ:共結晶化された阻害剤の中心を使用します。 """ if known_ligand_pdb: # リガンド原子の座標の平均 from Bio.PDB import PDBParser parser = PDBParser(QUIET=True) structure = parser.get_structure("lig", str(known_ligand_pdb)) coords = [atom.get_coord() for atom in structure.get_atoms()] import numpy as np center = np.mean(coords, axis=0) return (float(center[0]), float(center[1]), float(center[2])) else: # fpocket、PocketFinderなどを使用します(ここでは概念的なスタブ)。 raise NotImplementedError("既知のリガンドがない場合は、fpocketを統合する必要があります")ステップ2:リガンドの3Dコンフォーマーを生成
from rdkit import Chemfrom rdkit.Chem import AllChem
def smiles_to_sdf(smiles: str, sdf_path: Path, num_conformers: int = 3) -> Path: """SMILES → 複数の3Dコンフォーマー → SDF。
複数のコンフォーマーは、DiffDockの多様性ヒントとして役立ちます(一部のアプローチでは、単一のコンフォーマーのみを使用します)。 """ mol = Chem.MolFromSmiles(smiles) if mol is None: raise ValueError(f"無効なSMILES:{smiles}") mol = Chem.AddHs(mol) # 複数のコンフォーマーを生成し、次にエネルギーを最小化します conf_ids = AllChem.EmbedMultipleConfs( mol, numConfs=num_conformers, params=AllChem.ETKDGv3(), ) for conf_id in conf_ids: try: AllChem.MMFFOptimizeMolecule(mol, confId=conf_id, maxIters=500) except Exception: pass writer = Chem.SDWriter(str(sdf_path)) for conf_id in conf_ids: writer.write(mol, confId=conf_id) writer.close() return sdf_pathステップ3:DiffDockポーズを生成
import subprocess
def run_diffdock( protein_pdb: Path, ligand_sdf: Path, output_dir: Path, num_poses: int = 20, num_inference_steps: int = 40, device: str = "cuda", use_pocket: bool = False, pocket_center: tuple[float, float, float] | None = None,) -> list[Path]: """DiffDockを実行 → 複数のポーズのSDFファイルを返します。
DiffDockリポジトリのinference.py CLIを呼び出します。 """ output_dir.mkdir(parents=True, exist_ok=True) cmd = [ "python", "-m", "inference", "--protein_path", str(protein_pdb), "--ligand", str(ligand_sdf), "--out_dir", str(output_dir), "--samples_per_complex", str(num_poses), "--inference_steps", str(num_inference_steps), "--batch_size", "10", ] if use_pocket and pocket_center: # DiffDock-Pocket拡張(座標ヒント) cmd += ["--pocket_center", ",".join(f"{c:.2f}" for c in pocket_center)] result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: print(f"DiffDock failed STDERR: {result.stderr[:500]}") raise RuntimeError("DiffDock execution failed") pose_files = sorted(output_dir.glob("complex_0/rank*.sdf")) return pose_filesステップ4:PoseBusters物理フィルタ
PoseBustersは、ドッキングポーズの物理的および化学的妥当性を定量的に評価する最近のフレームワークです[5]。
def validate_pose_with_posebusters( pose_sdf: Path, protein_pdb: Path,) -> dict: """PoseBustersでポーズの妥当性を検証します。
返り値:{ "passes_all_checks": bool, "checks": {チェック名:bool}, "critical_failures": [失敗したチェックのリスト], } """ try: from posebusters import PoseBusters buster = PoseBusters(config="dock") results = buster.bust( mol_pred=[pose_sdf], mol_cond=protein_pdb, ) # resultsはpandas DataFrame checks = results.iloc[0].to_dict() critical_failures = [k for k, v in checks.items() if v is False and "clash" in k.lower() or "geometry" in k.lower()] passes_all = all(v for v in checks.values() if isinstance(v, bool)) return { "passes_all_checks": passes_all, "checks": checks, "critical_failures": critical_failures, } except ImportError: # PoseBustersがインストールされていない場合は、単純な衝突チェックにフォールバックします return {"passes_all_checks": True, "checks": {}, "critical_failures": []}
import numpy as npfrom Bio.PDB import PDBParser, NeighborSearch
VDW_RADII = { "H": 1.20, "C": 1.70, "N": 1.55, "O": 1.52, "F": 1.47, "P": 1.80, "S": 1.80, "Cl": 1.75, "Br": 1.85, "I": 1.98,}
def simple_clash_check( protein_pdb: Path, ligand_sdf: Path, clash_threshold: float = 0.7, max_clash_count: int = 3,) -> bool: """衝突がある場合はTrueを返します(PoseBustersのフォールバック)。""" parser = PDBParser(QUIET=True) structure = parser.get_structure("protein", str(protein_pdb)) protein_atoms = list(structure.get_atoms()) ns = NeighborSearch(protein_atoms) mol = Chem.SDMolSupplier(str(ligand_sdf), removeHs=False)[0] if mol is None: return True conf = mol.GetConformer() clash_count = 0 for i, atom in enumerate(mol.GetAtoms()): pos = conf.GetAtomPosition(i) lig_vdw = VDW_RADII.get(atom.GetSymbol(), 1.7) nearby = ns.search([pos.x, pos.y, pos.z], 5.0) for prot_atom in nearby: prot_vdw = VDW_RADII.get(prot_atom.element, 1.7) distance = np.linalg.norm( np.array([pos.x, pos.y, pos.z]) - prot_atom.get_coord() ) if distance < (lig_vdw + prot_vdw) * clash_threshold: clash_count += 1 if clash_count > max_clash_count: return True return Falseステップ5:Vinaローカル最小化 + スコア算出
DiffDockポーズを初期座標として使用してVinaのローカル最適化を実行し、物理的に安定したポーズにポーズを改良し、スコアを取得します。
def vina_local_score( receptor_pdbqt: Path, ligand_pdbqt: Path, center: tuple[float, float, float], size: tuple[float, float, float] = (20, 20, 20), exhaustiveness: int = 1, # ローカル最適化なので、低めに設定 output_pdbqt: Path | None = None,) -> float: """Vinaローカル最適化 + スコア。exhaustiveness=1はローカル最小化用。
返り値:結合エネルギー(kcal/mol、小さいほど結合が強い)。 """ cmd = [ "vina", "--receptor", str(receptor_pdbqt), "--ligand", str(ligand_pdbqt), "--center_x", str(center[0]), "--center_y", str(center[1]), "--center_z", str(center[2]), "--size_x", str(size[0]), "--size_y", str(size[1]), "--size_z", str(size[2]), "--exhaustiveness", str(exhaustiveness), "--num_modes", "1", "--local_only", ] if output_pdbqt: cmd += ["--out", str(output_pdbqt)] result = subprocess.run(cmd, capture_output=True, text=True, check=False) # Vinaの出力から親和性を解析 for line in result.stdout.splitlines(): stripped = line.strip() if stripped.startswith("1 ") or stripped.startswith("1\t"): parts = stripped.split() try: return float(parts[1]) # kcal/mol except (IndexError, ValueError): pass return 0.0ステップ6:アンサンブルスコアリング
DiffDockの信頼度 + PoseBustersの妥当性 + Vinaスコアの重み付き組み合わせ。
from dataclasses import dataclass
@dataclassclass PoseResult: ligand_id: str pose_path: Path diffdock_confidence: float posebusters_passes: bool vina_score: float final_score: float metadata: dict
def ensemble_score( diffdock_conf: float, posebusters_passes: bool, vina_score: float, weight_dl: float = 0.3, weight_vina: float = 0.6, invalid_penalty: float = 5.0,) -> float: """アンサンブルスコア。小さいほど良好(Vinaスケール)。
DLスコアをVinaスケールに変換(-5.0は不確か、-8.0以下が強い結合)。 """ dl_component = -diffdock_conf * 3.0 combined = weight_vina * vina_score + weight_dl * dl_component if not posebusters_passes: combined += invalid_penalty # 物理的に非現実的なポーズに対するペナルティ return combined
def rank_ligand_poses( ligand_id: str, diffdock_poses: list[dict], # [{pose_path, confidence}] receptor_pdb: Path, receptor_pdbqt: Path, binding_center: tuple[float, float, float],) -> list[PoseResult]: """単一のリガンドの複数のポーズをVinaとPoseBustersで再検証し、アンサンブル化します。""" results = [] for pose in diffdock_poses: pose_pdbqt = pose["pose_path"].with_suffix(".pdbqt") try: subprocess.run( ["obabel", str(pose["pose_path"]), "-O", str(pose_pdbqt)], check=True, capture_output=True, ) except subprocess.CalledProcessError: continue vina_score = vina_local_score(receptor_pdbqt, pose_pdbqt, binding_center) pb_result = validate_pose_with_posebusters(pose["pose_path"], receptor_pdb) final = ensemble_score( pose["confidence"], pb_result["passes_all_checks"], vina_score, ) results.append(PoseResult( ligand_id=ligand_id, pose_path=pose["pose_path"], diffdock_confidence=pose["confidence"], posebusters_passes=pb_result["passes_all_checks"], vina_score=vina_score, final_score=final, metadata={ "posebusters_details": pb_result["checks"], "critical_failures": pb_result["critical_failures"], }, )) return sorted(results, key=lambda r: r.final_score)ステップ7:PyMOL自動レンダリング
パート11と同様のパターン。
def render_top_poses( receptor_pdb: Path, top_poses: list[PoseResult], output_dir: Path,) -> None: output_dir.mkdir(parents=True, exist_ok=True) for i, pose in enumerate(top_poses): script = f"""load {receptor_pdb}, receptorload {pose.pose_path}, ligandhide everythingshow cartoon, receptorshow sticks, ligandshow sticks, receptor within 5 of ligandcolor grey70, receptorcolor yellow, ligandzoom ligand, 5bg_color whiteray 1200, 900png {output_dir / f"{pose.ligand_id}_rank{i+1}.png"}, dpi=150quit""" script_path = output_dir / f"render_{pose.ligand_id}_{i}.pml" script_path.write_text(script) subprocess.run(["pymol", "-cq", str(script_path)], check=True, capture_output=True)ステップ8:統合パイプラインとMproシナリオの実行
import pandas as pd
def hybrid_docking_pipeline( protein_pdb: Path, known_ligand_pdb: Path | None, ligand_smiles_list: list[tuple[str, str]], # [(ligand_id, smiles)] work_dir: Path, top_k: int = 10, poses_per_ligand: int = 10, device: str = "cuda",) -> pd.DataFrame: """完全なハイブリッドドッキングスクリーニング。""" work_dir.mkdir(parents=True, exist_ok=True) print("[1/5] タンパク質の事前処理") prepared_pdb = work_dir / "protein_prepared.pdb" prepare_protein(protein_pdb, prepared_pdb) receptor_pdbqt = work_dir / "protein_prepared.pdbqt" pdb_to_pdbqt(prepared_pdb, receptor_pdbqt) binding_center = identify_binding_site(prepared_pdb, known_ligand_pdb) print(f" 結合中心:{binding_center}") all_results = [] for ligand_id, smiles in ligand_smiles_list: print(f"[2/5] {ligand_id} 3Dコンフォーマー + DiffDock") ligand_sdf = work_dir / "ligands" / f"{ligand_id}.sdf" try: smiles_to_sdf(smiles, ligand_sdf, num_conformers=3) pose_files = run_diffdock( prepared_pdb, ligand_sdf, work_dir / "diffdock" / ligand_id, num_poses=poses_per_ligand, device=device, ) except Exception as e: print(f" 失敗 ({ligand_id}):{e}") continue # DiffDockの信頼度は、ファイル名または別のメタデータにあるランク diffdock_poses = [ {"pose_path": p, "confidence": max(0.0, 1.0 - 0.05 * i)} # ランクが低いほど、信頼度が高い for i, p in enumerate(pose_files) ] print(f"[3/5] {ligand_id} PoseBusters + Vina再検証") ranked = rank_ligand_poses( ligand_id, diffdock_poses, prepared_pdb, receptor_pdbqt, binding_center, ) all_results.extend(ranked[:3]) # リガンドごとにトップ3 # 4. 全体ランキング all_results.sort(key=lambda r: r.final_score) df = pd.DataFrame([{ "ligand_id": r.ligand_id, "diffdock_conf": r.diffdock_confidence, "posebusters_pass": r.posebusters_passes, "vina_score": r.vina_score, "final_score": r.final_score, "critical_failures": ";".join(r.metadata["critical_failures"]), "pose_path": str(r.pose_path), } for r in all_results]) df.to_csv(work_dir / "docking_results.csv", index=False) print(f"[4/5] トップ-{top_k} PyMOLレンダリング") render_top_poses(prepared_pdb, all_results[:top_k], work_dir / "renders") print("[5/5] 完了") return df
# 例:SARS-CoV-2 Mproシナリオ# result_df = hybrid_docking_pipeline(# protein_pdb=Path("./6LU7.pdb"),# known_ligand_pdb=Path("./6LU7_ligand.pdb"), # 共結晶化されたN3阻害剤# ligand_smiles_list=[# ("nirmatrelvir", "CC1(C)C2CC1C(NC(=O)C1CCCN1C(=O)C(NC(=O)OC(C)(C)C)C(C)(C)C)C(=O)NC(C#N)CC2=O"),# ("ensitrelvir", "..."),# # パート07のトップ20の候補を追加# ],# work_dir=Path("./mpro_docking_output"),# )
## パフォーマンス、コスト、および既知の失敗事例
### パフォーマンスの参考(公開されたベンチマークの引用)
| モデル | ベンチマーク | Top-1 RMSD ≤ 2Å | PoseBusters 合格率 | 時間/ペア | 参照 ||------|------|:----------------:|:------------------:|:---------:|------|| AutoDock Vina | PDBbind core | 20~30% | 85~90% (物理ベースライン) | 分 | Trott & Olson 2010 [1] || Glide SP | PDBbind core | 35~40% | 90%+ | 秒~分 | Schrödinger || Glide XP | PDBbind core | 40~50% | 92%+ | 分 | Schrödinger || DiffDock | PDBbind core | 38% | 60~70% (物理の問題) | 30秒 GPU | Corso et al., ICLR 2023 [2] || DiffDock-L | PDBbind core | 43% | 65~75% | 30秒 GPU | Corso et al. 2024 || DiffDock-Pocket | PDBbind core | 45%+ | 70%+ | 40秒 GPU | 2024 || DiffDock-Glide | PDBbind core | 55~60% | 85%+ (Glideによる補正) | 60秒 GPU+CPU | Miller et al., bioRxiv 2025 [3] || RLDiff | PDBbind subset | ~50% | 78% | 40秒 GPU | Zhang et al. 2024 [4] || Boltz-2 (Part 11) | 同様のベンチマーク | 50%+ | 90%+ (物理を統合した設計) | 秒 GPU | MIT/Genentech 2025 |
### 学習者が再現するための推定コスト
- APIコスト:0(完全にローカル)。- 100個の配位子をスクリーニング:DiffDockは約30分(GPU)+ Vinaによる再検証は約30分(CPU、並列4~8コア)。- 20個のMpro候補をスクリーニング:15~30分。- DiffDockの重みをダウンロードするのに約2GB(初回実行時)。- Vina、OpenBabel、PoseBustersは無料。
### 5つの既知の失敗事例(コミュニティ/論文の収集)
1. **DiffDockのポーズにおける原子の衝突と非現実的な形状(PoseBusters 60%の失敗)** 症状:DiffDockのトップのポーズで、配位子の原子がタンパク質の原子と重なり(浸透)、結合角が歪み、芳香環が平面でなくなる。 原因:拡散モデルは、物理法則を明示的に強制しない。トレーニングの目的は、座標の再構築であり、幾何学的妥当性の個別の検証はない。 緩和策:(a)常にPoseBustersフィルターを使用する(このパートのステップ4)、(b)Vinaによる局所最適化で改良する、(c)複数のポーズをアンサンブル化して、有効なポーズを選択する、(d)物理を統合したDiffDock-Glideのような後続モデルを使用する、(e)物理を統合したトレーニングであるPart 11のBoltz-2に置き換える。 出典:Buttenschoen et al. "PoseBusters" Chem Sci 2024 [5]。
2. **誤ったポケットの選択(ブラインドドッキングと標的ドッキング)** 症状:DiffDockがブラインドモードで、既知のオルソステリック部位以外のポケットに配位子を配置する。 原因:DiffDockには、自動ポケット検索モードと明示的な指定モードの両方があり、ブラインドモードでは誤認が一般的である。 緩和策:(a)ポケットの座標を事前に指定する(このパートのidentify_binding_site)、(b)fpocketを使用して候補のポケットを事前に探索する、(c)DiffDock-Pocketを使用する、(d)既知の配位子が存在する場合は、その位置をシードとして使用する。 出典:DiffDock GitHub Issues [6]。
3. **DUD-Eベンチマークにおける既知のバイアス(活性分子とデコイのバイアス)** 症状:DUD-EではAUC > 0.9だが、実際の新しい創薬スクリーニングではパフォーマンスが大幅に低下する。 原因:DUD-Eのデコイは、特性の一致を使用して生成されるため、スコアリング関数は、活性分子とデコイ分子の間の物理化学的差異のみを学習する(実際の結合の識別がない)。 緩和策:(a)LIT-PCBAなどのバイアスのないベンチマークを使用する、(b)将来の実験的な検証を行う、(c)複数のベンチマークのアンサンブルを使用する、(d)COVID Moonshotなどの実世界のデータセットを使用する。 出典:Chen et al. "Hidden bias in the DUD-E dataset." PLoS ONE 2019 [7]。
4. **標的タンパク質の柔軟性を無視(剛体受容体)** 症状:ドッキングは剛体受容体を仮定するが、実際にはタンパク質は柔軟であり、特にループと側鎖の動きがある。 原因:ほとんどのVinaおよびDiffDockモデルは、デフォルトで剛体受容体モードを使用する。 緩和策:(a)MDシミュレーションを使用して複数のコンフォメーションを生成し、それぞれをドッキングする(アンサンブルドッキング)、(b)DiffDockを複数のapo/holo構造と並行して実行する、(c)商用のIFD(誘導適合ドッキング)ソフトウェアを使用する、(d)Boltz-2およびChai-1(Part 11)のような共同折り畳みアプローチを使用する。 出典:Amaro RE et al. "Ensemble Docking in Drug Discovery." Biophysical Journal 2018 [8]。
5. **配位子の立体化学と互変異性異性体を無視** 症状:SMILESで立体化学が指定されている場合でも、予測は複数の立体異性体のうちの1つをランダムに選択する。または、特定のpHで支配的でない互変異性異性体でドッキングが発生する。 原因:SMILESの標準化と3Dコンフォメーション生成の段階で情報が失われる。 緩和策:(a)`Chem.MolFromSmiles`でキラル性を保持する、(b)`MolStandardize`を使用して互変異性異性体を標準化する、(c)各立体異性体と互変異性異性体を個別にドッキングし、次にアンサンブル化する、(d)予測されたポーズのキラル性を事後検証する。 出典:RDKit MolStandardizeドキュメント [9]; Boltz Issues(立体化学)[6]。
## 拡張のアイデア
- **フラグメントベースのドッキング:**大きなライブラリをフラグメント(< 300 Da)に縮小してドッキングし、次にリンカーを設計する。- **アンサンブルドッキング:**複数のタンパク質コンフォメーション(MDシミュレーションまたはAlphaFoldの複数)のそれぞれをドッキングし、次に集約する。- **自由エネルギー計算の統合:**トップのドッキング候補をMM-GBSAまたはFEPで事後処理して、より正確な親和性を得る。- **デノボリンカー設計:**RFdiffusion(Part 13)でリンカーを生成し、ドッキングで検証する。- **アクティブラーニング+自動ドッキング:**予測の不確実性が高い配位子を特定し、実験的な検証を行い、再トレーニングする。- **アンサンブルBoltz-2 vs. DiffDock-Glide:**Part 11のBoltz-2の結果を比較し、アンサンブル化する。
## 次のパート
- Part 11 `structure-affinity-boltz`:ドッキングをBoltz-2と統合する(個別のドッキングパートを置き換える)。- Part 07 `drug-target-gnn`:GNN予測でドッキング候補を事前にフィルタリングする。- Part 12 `single-cell-perturbation`:トップのドッキング配位子の細胞応答をin silicoで予測する。- Part 14 `bio-mcp-agent`:ドッキングパイプラインをMCPツールとして公開する。
## 参考文献
1. Trott O, Olson AJ. "AutoDock Vina: Improving the speed and accuracy of docking." Journal of Computational Chemistry 2010. `https://onlinelibrary.wiley.com/doi/10.1002/jcc.21334`2. Corso G, Stärk H, Jing B, et al. "DiffDock: Diffusion Steps, Twists, and Turns for Molecular Docking." ICLR 2023. `https://arxiv.org/abs/2210.01776`3. Miller B, Corso G, et al. "DiffDock-Glide: a hybrid physics-based and data-driven approach to molecular docking." bioRxiv 2025. `https://www.biorxiv.org/content/10.1101/2025.06.02.657461v1`4. Oxford RLDiff GitHub: `https://github.com/oxpig/RLDiff`5. Buttenschoen M, Morris GM, Deane CM. "PoseBusters: AI-based docking methods fail to generate physically valid poses or generalise to novel sequences." Chemical Science 2024. `https://pubs.rsc.org/en/content/articlelanding/2024/sc/d3sc04185a`6. DiffDock GitHub Issues: `https://github.com/gcorso/DiffDock/issues`7. Chen L, Cruz A, Ramsey S, et al. "Hidden bias in the DUD-E dataset leads to misleading performance of deep learning in structure-based virtual screening." PLoS ONE 2019.8. Amaro RE et al. "Ensemble Docking in Drug Discovery." Biophysical Journal 2018.9. RDKit MolStandardize documentation: `https://www.rdkit.org/docs/source/rdkit.Chem.MolStandardize.html`10. Vina GitHub: `https://github.com/ccsb-scripps/AutoDock-Vina`11. OpenBabel: `http://openbabel.org/`12. RDKit: `https://www.rdkit.org/`13. PyMOL open-source: `https://github.com/schrodinger/pymol-open-source`14. PDBbind: `http://www.pdbbind.org.cn/`15. DUD-E: `http://dude.docking.org/`16. LIT-PCBA (バイアスがないベンチマーク): Tran-Nguyen VK et al. J Chem Inf Model 2020.17. PDBFixer (OpenMM ファミリー): `https://github.com/openmm/pdbfixer`18. PoseBusters GitHub: `https://github.com/maabuu/posebusters`19. COVID Moonshot consortium: `https://postera.ai/moonshot/`20. SARS-CoV-2 Mpro 構造 (PDB 6LU7 など): `https://www.rcsb.org/`