🫘
MolSnapperの動作確認
分子生成系のAIも面白そうだなと思い、とりあえず最近の報告を実装・動作確認してみた。
今回はこちらの報告。 MolSnapper
githubはこちら。 MolSnapper(github)

本記事では、MolSnapper リポジトリをローカルで動かし、PDB ID: 4AG8 のタンパク質・リガンド複合体について
- データ準備
- 前処理(クリーニング & ポケット抽出)
- 分子サンプリング
- 評価スコアリング
- 上位候補の抽出&SDF マージ(Similarity / QED順)
という一連の流れを、コマンド/スクリプト例つきでまとめます。
1. 環境構築
# MolSnapper リポジトリをクローン
mkdir /usr/local/apps
cd /usr/local/apps
git clone https://github.com/oxpig/MolSnapper.git
cd MolSnapper
# Conda 環境作成
conda env create -f env.yml
conda activate MolSnapper
必要モジュール:
- Python 3.9.18
- PyTorch 2.0.1 + CUDA 11.7
- PyTorch Geometric 2.3.1
- RDKit 2022.03.5
- Biopython 1.83
- pdb-tools ≥2.0 など
2. 生データの準備
# 作業ディレクトリ作成
mkdir -p ~/molsnapper/4AG8_test
cd ~/molsnapper/4AG8_test
# PDB (4AG8) をダウンロード
wget -O 4AG8.pdb https://files.rcsb.org/download/4AG8.pdb
# リガンド三文字コードを確認 (例: LIG)
grep '^HETATM' 4AG8.pdb | awk '{print $4}' | sort | uniq
# リガンドモデル SDF をダウンロード
mkdir -p ligands
wget -O ligands/4AG8_0.sdf https://files.rcsb.org/ligands/download/LIG_model.sdf
構成例:
~/molsnapper/4AG8_test/
├── 4AG8.pdb
└── ligands/
└── 4AG8_0.sdf
3. 前処理(クリーニング&分割→ポケット抽出)
3.1 クリーニング & ATOM/HETATM 分割
python scripts/clean_and_split.py \
--in-dir ~/molsnapper/4AG8_test \
--proteins-dir ~/molsnapper/4AG8_test/proteins \
--ligands-dir ~/molsnapper/4AG8_test/ligands
出力例:
proteins/4AG8_protein.pdb
ligands/4AG8_0.sdf
3.2 ポケット.pkl 生成
python scripts/prepare_single_complex.py \
--root_dir ~/molsnapper/4AG8_test \
--ligand_filename ligands/4AG8_0.sdf \
--protein_filename proteins/4AG8_protein.pdb \
--out_pockets_path ~/molsnapper/4AG8_test/processed_pocket_4AG8.pkl
4. 分子サンプリング
mkdir -p ~/molsnapper/4AG8_test/outputs
python scripts/sample_single_pocket.py \
--outdir ~/molsnapper/4AG8_test/outputs \
--config configs/sample/sample_MolDiff.yml \
--device cuda:0 \
--batch_size 0 \
--pocket_path ~/molsnapper/4AG8_test/processed_pocket_4AG8.pkl \
--sdf_path ~/molsnapper/4AG8_test/ligands/4AG8_0.sdf \
--use_pharma False \
--clash_rate 0.1
生成結果はサブディレクトリ内に
0.sdf, 1.sdf, …, *_shifted.sdf
として出力されます。
5. 評価スコアリング
mkdir -p ~/molsnapper/4AG8_test/outputs/eval
python scripts/evaluate.py \
~/molsnapper/4AG8_test/outputs/sample_MolDiff_*_SDF \
--protein_path ~/molsnapper/4AG8_test/4AG8.pdb \
--reflig_path ~/molsnapper/4AG8_test/ligands/4AG8_0.sdf \
--save_path ~/molsnapper/4AG8_test/outputs/eval
出力:
~/molsnapper/4AG8_test/outputs/eval/eval_all.pt
→ 下記で results.csv に変換
cd ~/molsnapper/4AG8_test/outputs/eval
python - << 'EOF'
import torch, pandas as pd
data = torch.load('eval_all.pt')
df = pd.DataFrame(data)
chem = pd.json_normalize(df['chem_results'])
df2 = pd.concat([df.drop(columns=['chem_results']), chem], axis=1)
df2['sample'] = df2.index
df2.to_csv('results.csv', index=False)
print(df2.head())
EOF
6. 上位候補抽出&SDFマージ
6.1 Similarity 順トップ5
# ID を取得
cd ~/molsnapper/4AG8_test/outputs/eval
ids=$(python - << 'EOF'
import pandas as pd
df = pd.read_csv('results.csv')
print(" ".join(df.sort_values('similarity', ascending=False).head(5)['sample'].astype(str)))
EOF
)
# マージ
merged=~/molsnapper/4AG8_test/outputs/top5_sim_shifted.sdf
> "$merged"
for id in $ids; do
cat ~/molsnapper/4AG8_test/outputs/sample_MolDiff_*_SDF/${id}_shifted.sdf \
>> "$merged"
echo '$$$$' >> "$merged"
done
# 確認
grep -c '^\$\$\$\$$' "$merged" # => 5
6.2 QED 順トップ5
# ID を取得
cd ~/molsnapper/4AG8_test/outputs/eval
ids=$(python - << 'EOF'
import pandas as pd
df = pd.read_csv('results.csv')
print(" ".join(df.sort_values('qed', ascending=False).head(5)['sample'].astype(str)))
EOF
)
# マージ
merged=~/molsnapper/4AG8_test/outputs/top5_qed_shifted.sdf
> "$merged"
for id in $ids; do
cat ~/molsnapper/4AG8_test/outputs/sample_MolDiff_*_SDF/${id}_shifted.sdf \
>> "$merged"
echo '$$$$' >> "$merged"
done
# 確認
grep -c '^\$\$\$\$$' "$merged" # => 5
7. PyMOL で可視化
PyMOLでひと通りloadして生成した構造を見てみます。
pymol
# 受容体
load ~/molsnapper/4AG8_test/4AG8.pdb, receptor
# 入力構造
load ~/molsnapper/4AG8_test/ligands/4AG8_0.sdf, ligand
# Similarity 順トップ5
load ~/molsnapper/4AG8_test/outputs/top5_sim_shifted.sdf, sim_candidates
# QED 順トップ5
load ~/molsnapper/4AG8_test/outputs/top5_qed_shifted.sdf, qed_candidates
実施の途中で気がついたんですが、あくまで入力した分子構造をポケットの中の範囲で変換する方法論だったらしく、全くのde novoっていう感じではありませんでした。
pocket2molやDiffSBDDっていうのは低分子の入力なしに分子構造を生成できるっぽいので、次回はそちらにチャレンジしたいです。
Discussion