自律的なタンパク質設計のためのマルチモーダル基盤:セリンプロテアーゼの活性部位を維持した100個の新規配列を生成する
パート02(タンパク質埋め込み)とパート11(構造/親和性予測)では、基盤モデルが天然タンパク質をどれだけ理解しているかを見てきました。しかし、本当に興味深い疑問はこれです。これらのモデルは、自然界に存在しない、完全に新しいタンパク質を最初からコード化できるでしょうか?EvolutionaryScaleのESM3(2024年)は、配列、構造、機能のモダリティを単一のトランスフォーマーで学習し、任意のモダリティの条件付き生成を可能にする、大規模なタンパク質基盤モデルの最初期の実例です。このパートでは、その機能を活用するための実用的なパイプラインを構築します。具体的には、セリンプロテアーゼの触媒三つ組(Ser195-His57-Asp102、キモトリプシン番号)を固定し、残りの配列を新しい方法で自律的に設計します。30%未満の配列類似性を持つ、完全に新しい100個のセリンプロテアーゼ候補を生成し、AF2/Boltzでそれらの3D構造を検証することで、プロセスを完了させます。
📚 推奨される事前知識(強く推奨されます)
このパートは、AI x 生物学の高度なコースの頂点です。このパートに入る前に、以下のDryBenchのパートを完了することを強くお勧めします。
- DryBench ai-native #3 Transformers and Embeddings
- DryBench ai-native #12 PyTorch Basics
- DryBench ai-native #13 HuggingFace and Commercial APIs
事前知識を完了していない場合、このパートの実用的なコードを理解することが難しくなります。なぜなら、このパートでは、マルチモーダル・トランスフォーマー、マスク付き言語モデルのトレーニング、大規模なPyTorchモデル管理の原理について再説明することなく進むからです。
DryBenchコースで学んだこと
DryBench ai-native #3では、トランスフォーマー埋め込みがドメインやモダリティに関係なくスケーラブルであることを学びました。#12では、大規模なテンソル、GPUメモリ、およびPyTorchを使用した混合精度最適化の基本を学び、#13では、HuggingFaceが、事前学習済みのモデルの標準的なロードと推論APIを提供することを学びました。
ESM3は、これらの3つの原理がタンパク質ドメインでピークに達したケーススタディです。配列トークン、離散的な構造トークン(3Diアルファベットに類似)、および機能ドメイントークンを、単一の統合された語彙に配置し、トランスフォーマーをトレーニングして、マスクされた言語モデルのスタイルで、任意の場所および任意のモダリティでトークンを予測させます。その結果は驚くべきものです。特定の活性部位構造を固定し、残りの配列を生成したり、所望の機能(例えば、蛍光、触媒、結合)を条件として、自律的に新しい配列をコード化することができます。このパートでは、その能力を実用的な酵素設計パイプラインに変換します。
困難な問題を定義する
実用的なシナリオ:新規セリンプロテアーゼの自律的な設計
セリンプロテアーゼは、タンパク質を分解する酵素であり、キモトリプシン、トリプシン、エラスターゼが代表的な例です。一般的な触媒メカニズム:Ser195のヒドロキシル基が求核剤であり、His57はプロトンを移動させる一般的な塩基であり、Asp102はHis57を安定化させます。この三角形は、活性のために完璧な3D配置を維持する必要があります。
私たちの目標:
- 天然のセリンプロテアーゼとの配列類似度が30%未満(真に新しい)。
- Ser-His-Asp触媒三つ組の3D座標を維持する(AF2予測RMSD ≤ 2 Å)。
- 100個の候補を自律的に生成する(約30〜60分)。
- 自己整合性(ESM3生成 → AF2予測 → 活性部位の再現)の成功率を40%以上にする。
- 上位5つの候補を、活性部位予測(Rosetta、MD)を使用して再検証する(オプション)。
De Novoタンパク質設計のスペクトル
- Rosetta(2003年以降): 物理学に基づいたタンパク質設計、確立された標準。
- RFdiffusion(Baker Lab 2023): 拡散モデルを使用してバックボーンを生成します。その後の配列設計には、ProteinMPNN [1] を使用します。
- ProteinMPNN(Baker Lab 2022): バックボーンから配列への再設計の標準 [2]。
- RFdiffusion + ProteinMPNN + AF2: 最新の標準パイプライン(バックボーン → 配列 → 検証)。
- Chroma(2024年、Baker Lab): 拡散ベース、全原子 [3]。
- ESM3(2024): 最初の大規模なマルチモーダル基盤。条件付き生成を統合します [4]。
- Boltz-2(パート11): 予測に特化しており、設計には制限があります。
- リガンド条件付き設計: RFdiffusion-Motif、Chroma-Ligand。
このパートでは、ESM3条件付き生成(主要なパート)+ AF2/Boltz検証 + RFdiffusion + ProteinMPNNアンサンブル比較(拡張)を使用します。
このパートの目標指標
- キモトリプシンPDB(1AB9、4CHAなど)から、触媒三つ組の3D座標を抽出する。
- ESM3条件付き生成を使用して100個の配列を生成する(ターゲット長200〜250残基)。
- 多様性フィルターを適用する(ペアワイズ同一性 ≤ 70%)。
- 天然配列との類似性をチェックする(UniProt Swiss-Prot BLASTまたはESM埋め込み)→30%未満の類似性を持つもののみを保持する。
- AF2/Boltzを使用して構造を予測する→活性部位RMSD ≤ 2 Åの再現率を40%以上にする。
- 平均pLDDT ≥ 70(構造の信頼性)。
ツールスタックとインフラストラクチャ要件
| ツール | 役割 | ライセンス |
|---|---|---|
ESM3 (esm3-sm-open-v1 1.4B) | 3トラック条件付き生成 | 学術利用はオープン、商用利用は別途契約 |
| ESM3 large (オープンウェイト、非商用) | 代替となる大規模モデル | EvolutionaryScaleライセンス |
| RFdiffusion + ProteinMPNN | アンサンブル比較 | 学術利用はオープン |
| Boltz-2 (Part 11) | 生成された配列の構造を生成および検証 | MIT |
| AlphaFold2 (または ColabFold) | 代替となる構造検証 | Apache 2.0 |
| Biopython · PyMOL | 配列/構造の操作と可視化 | Biopythonライセンス · LGPL |
| BLAST · Foldseek | 類似の自然配列/構造の検索 | 学術利用はオープン |
| PyTorch | バックエンド | BSD |
インフラストラクチャ要件:
- ESM3 1.4B 小規模オープンウェイト: 16〜24GB以上のVRAMを備えたサーバーGPU。FP16では約4GBのVRAM。
- ESM3 large (98B、プライベート): 学術API経由でのみアクセス可能。
- RFdiffusion: 24〜48GBのVRAMを備えたデータセンターGPU。
- AF2/Boltz検証: Part 11を参照(ハイエンドのコンシューマーGPUまたは24〜48GBのVRAMを備えたデータセンターGPU)。
- 大規模なバッチ生成と検証: 80GB以上のVRAMを備えたデータセンターワークステーション(通常はアクセス不可、クラウドでのオンデマンド利用を推奨)。
- RAM 32GB以上。
学習者向けの推定再現コスト: ローカルGPUを使用する場合、APIコストは0です。100個の配列を生成し、AF2/Boltzで検証するには、約4〜8時間かかります(24〜48GBのVRAM GPUを使用)。
実用的なパイプラインの実装
全体的な流れ:
ステップ1:活性部位の定義・ESM3制約の準備
キモトリプシン(PDB 4CHA、5CHA、1AB9など)から、触媒三連残基の3次元座標を抽出します。
from dataclasses import dataclassfrom pathlib import Path
import torchimport numpy as npfrom Bio.PDB import PDBParser
@dataclassclass ActiveSiteConstraint: """活性部位制約を定義します。""" site_name: str # 例:"serine_protease_triad" residue_positions: list[int] # 生成された配列における活性部位残基の位置(0ベース) residue_types: list[str] # 各位置のアミノ酸(例:["S", "H", "D"]) coordinates_backbone: np.ndarray # (N_residues、4、3):N、CA、C、O座標 ideal_distances: dict[tuple[int, int], float] # 活性部位残基間の理想的な距離(Å)
AA_3TO1 = { "ALA": "A", "ARG": "R", "ASN": "N", "ASP": "D", "CYS": "C", "GLN": "Q", "GLU": "E", "GLY": "G", "HIS": "H", "ILE": "I", "LEU": "L", "LYS": "K", "MET": "M", "PHE": "F", "PRO": "P", "SER": "S", "THR": "T", "TRP": "W", "TYR": "Y", "VAL": "V",}
def load_catalytic_triad_from_pdb( pdb_path: Path, triad_selection: list[tuple[str, int, str]], # [(chain, resid, expected_aa)] site_name: str = "serine_protease_triad",) -> ActiveSiteConstraint: """PDBファイルから触媒三連の座標を抽出します。
キモトリプシンの例(4CHA):[("A", 195, "S"), ("A", 57, "H"), ("A", 102, "D")] """ parser = PDBParser(QUIET=True) structure = parser.get_structure("target", str(pdb_path))
residue_types = [] coordinates = [] positions = [] for i, (chain_id, resid, expected_aa) in enumerate(triad_selection): try: chain = structure[0][chain_id] residue = chain[resid] except KeyError: raise ValueError(f"PDBが見つかりません: {chain_id}:{resid}") aa = AA_3TO1.get(residue.get_resname().upper(), "X") if aa != expected_aa: raise ValueError(f"活性部位{chain_id}:{resid}のアミノ酸が一致しません: 期待値は{expected_aa}、実際は{aa}") residue_types.append(aa) coords = np.array([ residue["N"].get_coord(), residue["CA"].get_coord(), residue["C"].get_coord(), residue["O"].get_coord(), ]) coordinates.append(coords) positions.append(i)
coordinates_arr = np.stack(coordinates, axis=0)
# 活性部位残基間の理想的な距離(キモトリプシンの測定に基づく) ca_positions = coordinates_arr[:, 1, :] # CAのみ ideal_dist = {} for i in range(len(triad_selection)): for j in range(i + 1, len(triad_selection)): d = float(np.linalg.norm(ca_positions[i] - ca_positions[j])) ideal_dist[(i, j)] = d
return ActiveSiteConstraint( site_name=site_name, residue_positions=positions, residue_types=residue_types, coordinates_backbone=coordinates_arr, ideal_distances=ideal_dist, )
# 例:キモトリプシンの触媒三連CHYMOTRYPSIN_TRIAD_4CHA = [ ("A", 57, "H"), # His57(ヒスチジン塩基) ("A", 102, "D"), # Asp102(アスパラギン酸安定化剤) ("A", 195, "S"), # Ser195(セリン求核剤)]ステップ2:ESM3条件付き生成
ESM3 SDKを使用すると、配列/構造/機能トラックに対してマスクを指定し、反復的にマスクを解除できます。
from esm.models.esm3 import ESM3from esm.sdk.api import ESMProtein, GenerationConfig
class ESM3Designer: """ESM3ベースのタンパク質設計。"""
def __init__(self, device: str = "cuda", model_name: str = "esm3-sm-open-v1"): self.device = device self.model = ESM3.from_pretrained(model_name).to(device).eval() self.model_name = model_name
@torch.no_grad() def design_with_active_site( self, constraint: ActiveSiteConstraint, target_length: int = 245, # キモトリプシンと同様の長さ num_samples: int = 100, temperature: float = 0.7, seed: int | None = None, ) -> list[dict]: """活性部位制約を維持しながら、新しい配列を生成します。
戻り値:[{sequence、seed、active_site_preserved:bool}] """ if seed is not None: torch.manual_seed(seed) np.random.seed(seed)
generated = [] for i in range(num_samples): # 初期タンパク質:配列はマスクされ、活性部位残基の位置は固定 seq_list = ["_"] * target_length
# 活性部位の位置(ターゲット長に任意に配置し、たとえば中央に配置) triad_positions = self._distribute_triad_positions( target_length, len(constraint.residue_positions), ) for pos, aa in zip(triad_positions, constraint.residue_types): seq_list[pos] = aa initial_sequence = "".join(seq_list)
protein = ESMProtein(sequence=initial_sequence)
# ESM3反復デコード config = GenerationConfig( track="sequence", num_steps=max(target_length // 4, 20), temperature=temperature, ) try: result = self.model.generate(protein, config) # 事後チェックで、活性部位残基が実際に維持されていることを確認します preserved = all( result.sequence[pos] == aa for pos, aa in zip(triad_positions, constraint.residue_types) ) generated.append({ "sequence": result.sequence, "seed": (seed or 0) + i, "triad_positions": triad_positions, "active_site_preserved": preserved, "length": len(result.sequence), }) except Exception as e: print(f"[{i}] 生成に失敗しました: {e}")
return generated
def _distribute_triad_positions( self, target_length: int, n_triad: int, spread_ratio: float = 0.4, ) -> list[int]: """活性部位残基をターゲット長に沿って均等に配置します。
実際のキモトリプシンでは、位置は57、102、195であり、245残基中、それぞれ21%、42%、80%です。 新しい設計では、同様の相対的な位置を維持します。 """ chymo_ref = [57, 102, 195] chymo_length = 245 positions = [ int(target_length * (p / chymo_length)) for p in chymo_ref[:n_triad] ] return positionsステップ3:多様性フィルター
ペアごとの同一性閾値を使用して生成された配列をフィルタリングし、多様性を確保します。
def compute_pairwise_identity(seq_a: str, seq_b: str) -> float: """長さが等しい場合は、位置ごとに比較を実行します。それ以外の場合は、アライメントを実行します。""" if len(seq_a) == len(seq_b): matches = sum(1 for a, b in zip(seq_a, seq_b) if a == b) return matches / len(seq_a) # 長さが異なる場合は、グローバルアライメントを実行します from Bio import pairwise2 aln = pairwise2.align.globalxx(seq_a, seq_b, one_alignment_only=True)[0] return aln.score / max(len(seq_a), len(seq_b))
def diversity_filter( sequences: list[str], max_pairwise_identity: float = 0.7,) -> list[str]: """貪欲なフィルター:すでに選択された配列との同一性が低い配列のみを保持します。""" kept = [] for seq in sequences: keep = True for existing in kept: if compute_pairwise_identity(seq, existing) > max_pairwise_identity: keep = False break if keep: kept.append(seq) return keptステップ4:自然配列の類似性チェック
BLASTまたはESM埋め込み+FAISSを使用して、自然配列との類似性をチェックします。
def blast_against_swissprot( query_seq: str, swissprot_fasta_path: Path, e_threshold: float = 1e-5,) -> list[dict]: """自然配列に対してBLASTを使用して類似性検索を実行します。
実際には、ローカルBLASTデータベースを使用します(makeblastdb + blastp)。 """ import subprocess import tempfile
with tempfile.NamedTemporaryFile(mode="w", suffix=".fasta", delete=False) as query_f: query_f.write(f">query\n{query_seq}\n") query_path = query_f.name
try: result = subprocess.run( ["blastp", "-query", query_path, "-db", str(swissprot_fasta_path), "-outfmt", "6 qseqid sseqid pident evalue bitscore", "-evalue", str(e_threshold), "-max_target_seqs", "5"], capture_output=True, text=True, check=True, ) hits = [] for line in result.stdout.strip().split("\n"): if not line: continue fields = line.split("\t") hits.append({ "subject": fields[1], "identity": float(fields[2]), "e_value": float(fields[3]), "bit_score": float(fields[4]), }) return hits except (subprocess.CalledProcessError, FileNotFoundError): return []
def natural_similarity_check( seq: str, max_identity: float = 30.0, # %) -> tuple[bool, float]: """配列が、自然配列と比較して新規であるかどうかをチェックします(同一性≤max_identity)。
戻り値:(is_novel、max_identity_found) """ hits = blast_against_swissprot(seq, Path("/path/to/swissprot.fasta")) if not hits: return True, 0.0 max_id = max(h["identity"] for h in hits) return max_id < max_identity, max_idステップ5:AF2/Boltz構造の検証
生成された配列の3次元構造をAF2またはBoltz-2(論文11)を使用して予測し、元の必要な活性部位座標へのRMSDを比較します。
import subprocessimport yaml
def predict_structure_boltz(sequence: str, output_dir: Path, seq_id: str) -> Path: """論文11のBoltz-2パイプラインを使用して構造を予測します。""" yaml_content = { "version": 1, "sequences": [{"protein": {"id": "A", "sequence": sequence}}], } output_dir.mkdir(parents=True, exist_ok=True) yaml_path = output_dir / f"{seq_id}.yaml" with open(yaml_path, "w") as f: yaml.safe_dump(yaml_content, f)
try: subprocess.run([ "boltz", "predict", str(yaml_path), "--out_dir", str(output_dir), "--use_msa_server", ], check=True, capture_output=True) except subprocess.CalledProcessError as e: raise RuntimeError(f"Boltz-2 failed for {seq_id}: {e.stderr.decode()[:500]}")
return output_dir / seq_id / f"{seq_id}_model_0.pdb"
def kabsch_rmsd(coords_a: np.ndarray, coords_b: np.ndarray) -> float: """Kabschアライメント後のRMSDを計算します。""" a = coords_a - coords_a.mean(axis=0) b = coords_b - coords_b.mean(axis=0) h = a.T @ b u, _, vt = np.linalg.svd(h) d = np.sign(np.linalg.det(vt.T @ u.T)) correction = np.eye(3) correction[2, 2] = d r = vt.T @ correction @ u.T a_aligned = a @ r.T return float(np.sqrt(np.mean(np.sum((a_aligned - b) ** 2, axis=1))))
def check_active_site_recovery( predicted_pdb: Path, triad_positions: list[int], original_constraint: ActiveSiteConstraint, rmsd_threshold: float = 2.0,) -> tuple[bool, float, float]: """予測された構造が活性部位を回復しているかどうかをチェックします。
戻り値:(recovered、rmsd、mean_plddt) """ parser = PDBParser(QUIET=True) structure = parser.get_structure("predicted", str(predicted_pdb)) residues_list = list(structure.get_residues())
predicted_coords = [] plddt_values = [] for pos in triad_positions: if pos >= len(residues_list): return False, float("inf"), 0.0 residue = residues_list[pos] try: coords = np.array([ residue["N"].get_coord(), residue["CA"].get_coord(), residue["C"].get_coord(), residue["O"].get_coord(), ]) except KeyError: return False, float("inf"), 0.0 predicted_coords.append(coords) # pLDDTはCA原子のBファクターに格納されます(AF2/Boltzの慣習) plddt_values.append(float(residue["CA"].get_bfactor()))
predicted_arr = np.stack(predicted_coords, axis=0).reshape(-1, 3) reference_arr = original_constraint.coordinates_backbone.reshape(-1, 3) rmsd = kabsch_rmsd(predicted_arr, reference_arr) mean_plddt = float(np.mean(plddt_values)) return rmsd < rmsd_threshold, rmsd, mean_plddtステップ6:統合・候補のランキング
from dataclasses import asdictimport pandas as pd
@dataclassclass DesignCandidate: sequence: str length: int seed: int active_site_preserved_in_seq: bool triad_positions: list[int] pdb_path: str | None active_site_rmsd: float plddt_active_site: float natural_identity_max: float novelty_score: float composite_score: float
def full_design_pipeline( catalytic_pdb: Path, triad_selection: list[tuple[str, int, str]], target_length: int, output_dir: Path, num_samples: int = 100, device: str = "cuda",) -> pd.DataFrame: """活性部位→新しい配列の生成→多様性・新規性・検証→ランキング。""" output_dir.mkdir(parents=True, exist_ok=True)
print("[1/6] 活性部位制約の読み込み") constraint = load_catalytic_triad_from_pdb(catalytic_pdb, triad_selection) print(f" triad: {constraint.residue_types}、distances: {constraint.ideal_distances}")
print("[2/6] ESM3条件付き生成") designer = ESM3Designer(device=device) generated = designer.design_with_active_site( constraint, target_length, num_samples, temperature=0.7, seed=42, ) preserved = [g for g in generated if g["active_site_preserved"]] print(f" 生成された配列:{len(generated)}、活性部位が保持された配列:{len(preserved)}")
print("[3/6] 多様性フィルター") preserved_seqs = [g["sequence"] for g in preserved] diverse_seqs = diversity_filter(preserved_seqs, max_pairwise_identity=0.7) diverse = [g for g in preserved if g["sequence"] in diverse_seqs] print(f" 多様性フィルタリング後:{len(diverse)}")
print("[4/6] 自然配列の新規性チェック") novel_candidates = [] for g in diverse: is_novel, max_id = natural_similarity_check(g["sequence"]) g["natural_identity_max"] = max_id g["novelty_score"] = 1.0 - (max_id / 100.0) if is_novel: novel_candidates.append(g) print(f" 新規(同一性≤30%):{len(novel_candidates)}")
print(f"[5/6] Boltz-2構造の検証({len(novel_candidates)}個の配列)") candidates_verified = [] for i, g in enumerate(novel_candidates): seq_id = f"design_{g['seed']}" try: pdb = predict_structure_boltz(g["sequence"], output_dir / "structures", seq_id) recovered, rmsd, plddt = check_active_site_recovery( pdb, g["triad_positions"], constraint, ) candidates_verified.append(DesignCandidate( sequence=g["sequence"], length=g["length"], seed=g["seed"], active_site_preserved_in_seq=g["active_site_preserved"], triad_positions=g["triad_positions"], pdb_path=str(pdb), active_site_rmsd=rmsd, plddt_active_site=plddt, natural_identity_max=g["natural_identity_max"], novelty_score=g["novelty_score"], composite_score=0.0, # 後で計算します )) except Exception as e: print(f" [{i}] {seq_id}で失敗しました:{e}")
print("[6/6] 複合的なランキング・CSV保存") if not candidates_verified: return pd.DataFrame()
df = pd.DataFrame([asdict(c) for c in candidates_verified]) # 複合スコア:pLDDT(40%)+活性部位RMSD(40%)+新規性(20%) df["composite_score"] = ( df["plddt_active_site"] / 100 * 0.4 + (1 - df["active_site_rmsd"].clip(0, 5) / 5.0) * 0.4 + df["novelty_score"] * 0.2 ) df = df.sort_values("composite_score", ascending=False) df.to_csv(output_dir / "design_candidates.csv", index=False) print(f" 上位5つの複合スコア:{df.head(5)['composite_score'].tolist()}") return df
# 例:(キモトリプシンの触媒三連→100個の新しいセリンプロテアーゼ)# result = full_design_pipeline(# catalytic_pdb=Path("./4CHA.pdb"),# triad_selection=CHYMOTRYPSIN_TRIAD_4CHA,# target_length=245,# output_dir=Path("./serine_protease_design"),# num_samples=100,# )ステップ7:RFdiffusion + ProteinMPNNアンサンブルの比較(オプションの拡張)
同じ活性部位制約をBaker Labの標準パイプラインで実行し、結果を比較します。
def run_rfdiffusion_motif( active_site_pdb: Path, triad_residues: list[int], output_dir: Path, num_designs: int = 100,) -> list[Path]: """RFdiffusionモチーフスカフォールディング。
触媒三連をモチーフとして固定し、残りの骨格を生成します。 実際には、RosettaCommons RFdiffusion GitHubの例を参照してください。 """ # 概念的なスタブ:RFdiffusion CLIを呼び出します # subprocess.run(["python", "run_inference.py", ...]) return [] # 実装時に完了
def run_proteinmpnn( backbone_pdb: Path, output_dir: Path, num_sequences: int = 10,) -> list[str]: """ProteinMPNNを使用して、骨格に配列を配置します。
# subprocess.run(["python", "protein_mpnn_run.py", ...]) return []
## パフォーマンス、コスト、および既知の失敗事例
### パフォーマンスの参考(公開されているベンチマークの引用)
| アプローチ | ベンチマーク(自己整合性 AF2 RMSD ≤ 2Å) | 新規性 | 参考文献 ||------|:-------------------------------------:|:-------:|------|| Rosetta酵素設計 | 20~30% | 低 | Baker Lab 2003+ || ProteinMPNN単独(既存の骨格の再設計) | 40~50% | 低~中 | Dauparas et al., Science 2022 [2] || RFdiffusion + ProteinMPNN + AF2 | 60~70% | 中~高 | Watson et al., Nature 2023 [1] || ESM3条件付き生成 | 40~55%(推定) | 中~高 | Hayes et al., bioRxiv 2024 [4] || Chroma(Baker Lab 全原子モデル) | 65~75% | 中~高 | Ingraham et al., Nature 2023 [3] || RFdiffusion + ProteinMPNN + Boltz-2検証 | ~65~72%(11個のアンサンブル) | 中~高 | コミュニティベンチマーク |
**実用的な観察:** RFdiffusion + ProteinMPNN + AF2 は、骨格を最初に設計するためのゴールドスタンダードです。ESM3は、条件付きの柔軟性(機能、配列、または構造に関する任意の条件)において優れています。アンサンブルアプローチが最も良い結果をもたらします。
### 学習者が再現するための推定コスト
- APIコスト:0(完全にローカル)。- 100個の配列を生成:ESM3 1.4Bを基に、16~24GB VRAM GPU上で30分から1時間かかります。- 100個の配列をBoltz-2で検証:11個のパイプラインのアンサンブルを基に、2~4時間かかります。- UniProt/Swissprotをローカルにダウンロードおよびインデックス:約500MB、1~2時間。
### 5つの既知の失敗事例(コミュニティと論文から収集)
1. **生成された配列で高いpLDDTスコアを示しますが、活性部位の再構築には失敗します。** 症状:AF2/Boltzによって予測されたpLDDTは80以上ですが、活性部位残基の配置が正しくありません。 原因:pLDDTはグローバルな信頼度スコアであり、残基の特定の3D配置とは異なります。特にループ領域では、pLDDTは高いままであっても柔軟性がある場合があります。 緩和策:(a)活性部位残基のpLDDTを個別にチェックします(この章のステップ5)、(b)予測された構造における活性部位のRMSDを必ずチェックします、(c)MDシミュレーション(OpenMM、GROMACS)で安定性を再検証します、(d)複数のシードで生成を繰り返し、コンセンサスを作成します。 参考文献:RFdiffusionとAF2の自己整合性に関する議論[1]。
2. **生成された配列は自然配列に類似しすぎており、本当に新しいものではありません。** 症状:生成された配列をUniProtに対してBLAST検索すると、40%を超える同一性を持つ複数のヒットが表示されます。 原因:基盤モデルは、トレーニングに使用された自然配列の分布を超えて進化することができません。 緩和策:(a)厳密な多様性フィルターを適用します(この章のステップ3)、(b)生成後にUniProt類似性フィルターを適用します(この章のステップ4)、(c)温度(0.9以上)を上げてサンプリングの多様性を高めます、(d)補助損失を使用して、より低い類似性を強制します。 参考文献:いくつかのde novo設計論文における議論[3][4]。
3. **実際の測定では、目的の機能(触媒活性または蛍光)がありません。** 症状:3D構造は、必要な条件を完全に再現しています。実験的な発現と精製の後、実際の活性は0です。 原因:活性には、活性部位残基の配置だけでなく、全体のフォールディング安定性、ダイナミクス、およびわずかな側鎖配置が必要です。タンパク質のフォールディングと発現の収量も、別の問題です。 緩和策:(a)MDシミュレーションとRosetta酵素設計を使用して、活性予測を強化します、(b)上位の候補で複数の並行実験を実行します、(c)ハイスループットスクリーニング(酵母またはファージディスプレイ)を自動化します、(d)実験測定で安定性タグと蛍光レポーターを使用します。 参考文献:Watson et al.のRFdiffusion論文における実験的検証に関する議論[1]。
4. **活性部位残基のみが維持されますが、配向は正しくありません。** 症状:Ser195、His57、Asp102が配列に存在しますが、3D空間では、触媒配列(SerヒドロキシルがHisと水素結合を形成)は存在しません。 原因:ESM3は、残基の同一性を維持するだけであり、側鎖の回転異性体または3Dの相対的な位置を最適化しません。 緩和策:(a)ESM3の構造トラックに、バックボーンと側鎖の制約を組み合わせて注入します、(b)Rosetta酵素設計を使用して、側鎖を後処理して最適化します、(c)CA-CA距離と活性部位の二面角を検証します(この章のステップ1のideal_distancesをチェックします)、(d)MDFFまたはMDshapingでダイナミクスを検証します。 参考文献:ESM3論文[4]における議論。Rosetta酵素設計チュートリアル。
5. **ESM3の商用ライセンスの制限。** 症状:EvolutionaryScale ESM3 large(98B)モデルでは、商用利用のために個別の契約が必要です。小規模(1.4B)モデルはオープンソースですが、主に学術利用を目的としています。 原因:EvolutionaryScaleポリシーと、以前のMeta ESM2とは異なるライセンス。 緩和策:(a)学術プロジェクトでは、オープンウェイトの1.4Bモデルを使用します、(b)商用プロジェクトでは、ライセンスについて問い合わせるか、代替手段(RFdiffusion + ProteinMPNNの組み合わせ)を使用します、(c)カスタムのファインチューニングを実行する際に、ライセンス条項を再確認します。 参考文献:EvolutionaryScale ESMライセンス[10]。
## 拡張されたアイデア
- **複合設計:** 単一のタンパク質ではなく、タンパク質-タンパク質インターフェースを設計します(第11章のBoltz-2に関連)。- **抗体設計:** CDRループの条件付き生成を使用して抗体を設計します(RFantibodyおよびIgLMを参照)。- **基質を持つde novo酵素:** 特定の基質結合部位のドッキングを、条件付き制約として利用します(第8章を参照)。- **環状ペプチド:** N-C結合制約を持つ、安定した環状ペプチドを自律的に設計します。- **多目的最適化:** 活性、安定性(熱安定性、凝集耐性)、および溶解度を同時に最適化します。- **蛍光タンパク質設計:** GFPクロモフォア(Ser65-Tyr66-Gly67)三つ組を維持しながら、新しい蛍光タンパク質を設計します。
## 次の章
- 第11章: `structure-affinity-boltz`: 生成されたタンパク質の配位子結合を予測します。- 第12章: `single-cell-perturbation`: 生成されたタンパク質が細胞内で発現された場合の応答を、in silicoでシミュレーションします。- 第7章: `drug-target-gnn`: 新規プロテアーゼに対する潜在的な阻害剤をGNNでスコアリングします。- 第14章: `bio-mcp-agent`: タンパク質設計をMCPツールとして公開し、エージェントによる自律的な実験設計を可能にします。
## 参考文献
1. Watson JL, Juergens D, Bennett NR, et al. "De novo design of protein structure and function with RFdiffusion." Nature 2023. `https://www.nature.com/articles/s41586-023-06415-8`2. Dauparas J, Anishchenko I, Bennett N, et al. "Robust deep learning-based protein sequence design using ProteinMPNN." Science 2022. `https://www.science.org/doi/10.1126/science.add2187`3. Ingraham J, Baranov M, Costello Z, et al. "Illuminating protein space with a programmable generative model (Chroma)." Nature 2023.4. Hayes T, Rao R, Akin H, et al. "Simulating 500 million years of evolution with a language model (ESM3)." bioRxiv 2024. `https://www.biorxiv.org/content/10.1101/2024.07.01.600583v1`5. EvolutionaryScale ESM GitHub: `https://github.com/evolutionaryscale/esm`6. RFdiffusion GitHub: `https://github.com/RosettaCommons/RFdiffusion`7. ProteinMPNN GitHub: `https://github.com/dauparas/ProteinMPNN`8. AlphaFold2 (DeepMind): `https://github.com/google-deepmind/alphafold`9. ColabFold: `https://github.com/sokrypton/ColabFold`10. EvolutionaryScale ESM License: `https://www.evolutionaryscale.ai/` · GitHub LICENSE11. Chroma (Baker Lab): `https://github.com/RosettaCommons/chroma`12. Baker Lab comprehensive: `https://www.bakerlab.org/`13. pyrosetta: `https://www.pyrosetta.org/`14. PyMOL open-source: `https://github.com/schrodinger/pymol-open-source`15. Boltz GitHub (第11章を参照): `https://github.com/jwohlwend/boltz`16. Biopython: `https://biopython.org/`17. Foldseek (構造類似性検索): `https://github.com/steineggerlab/foldseek`18. UniProt (天然配列検索): `https://www.uniprot.org/`19. RCSB PDB (キモトリプシン4CHAなど): `https://www.rcsb.org/`20. RosettaCommons酵素設計チュートリアル: `https://www.rosettacommons.org/docs/latest/application_documentation/design/enzyme-design`