### Installation - Step 1 Source: https://github.com/anton-bushuiev/ppiformer/blob/main/README.md Clone the repository and install the environment. ```bash conda create -n ppiformer python==3.10 -y conda activate ppiformer git clone https://github.com/anton-bushuiev/PPIformer && pip install -e PPIformer ``` -------------------------------- ### Installation - Step 2 (Optional) Source: https://github.com/anton-bushuiev/ppiformer/blob/main/README.md Adapt PyTorch to your system, for example, installing PyTorch for ROCm. ```bash pip install -U torch --index-url https://download.pytorch.org/whl/rocm6.0 ``` -------------------------------- ### Installation - Step 3 (Optional) Source: https://github.com/anton-bushuiev/ppiformer/blob/main/README.md Clone and install PPIRef and mutils packages locally to download necessary data. ```bash git clone https://github.com/anton-bushuiev/PPIRef && pip install -e PPIRef git clone https://github.com/anton-bushuiev/mutils && pip install -e mutils ``` -------------------------------- ### Installation Source: https://github.com/anton-bushuiev/ppiformer/blob/main/scripts/README.md Commands to set up the development environment for PPIformer, including installing dependencies and PyTorch. ```bash # Create environment conda create -n ppiformer_dev python=3.9.17 conda activate ppiformer_dev # Install dependencies used for development pip install -e git+https://github.com/anton-bushuiev/PPIRef.git#egg=ppiref pip install --no-deps -e git+https://github.com/anton-bushuiev/mutils.git#egg=mutils pip install git+https://github.com/anton-bushuiev/equiformer-pytorch.git@512dd15350d541804540514a713ac690649ea6a0 conda env update --file conda-environment.yaml # Install PyTorch (please adapt the version suffix to your system, rocm5.2 is for AMD GPUs) pip install -U torch==1.13.1+rocm5.2 --index-url https://download.pytorch.org/whl/rocm5.2 # Install PPIformer code pip install --no-deps -e ../ ``` -------------------------------- ### Install biovec Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb Instructions to install the 'biovec' package, which is a dependency for certain Graphein submodules. ```bash pip install graphein[extras] ``` -------------------------------- ### Running Unit Tests Source: https://github.com/anton-bushuiev/ppiformer/blob/main/tests/README.md Commands to install pytest and run the unit tests. ```bash pip install pytest pytest . ``` -------------------------------- ### Installation instructions for missing dependencies Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb This snippet shows the warnings generated by Graphein when certain submodules require additional dependencies. It also provides the commands to install these dependencies, either via pip or conda. ```text [01/24/24 14:41:17] WARNING To use the Graphein submodule embeddings.py:44 graphein.protein.features.sequence .embeddings, you need to install: biovec biovec cannot be installed via conda Alternatively, you can install graphein with the extras: pip install graphein[extras] [01/24/24 14:41:17] WARNING To use the Graphein submodule embeddings.py:44 graphein.protein.features.sequence .embeddings, you need to install: biovec biovec cannot be installed via conda Alternatively, you can install graphein with the extras: pip install graphein[extras] [01/24/24 14:41:17] WARNING To use the Graphein submodule embeddings.py:44 graphein.protein.features.sequence .embeddings, you need to install: biovec biovec cannot be installed via conda Alternatively, you can install graphein with the extras: pip install graphein[extras] [01/24/24 14:41:17] WARNING To use the Graphein submodule embeddings.py:44 graphein.protein.features.sequence .embeddings, you need to install: biovec biovec cannot be installed via conda Alternatively, you can install graphein with the extras: pip install graphein[extras] [01/24/24 14:41:17] WARNING To use the Graphein submodule embeddings.py:44 graphein.protein.features.sequence .embeddings, you need to install: biovec biovec cannot be installed via conda Alternatively, you can install graphein with the extras: pip install graphein[extras] [01/24/24 14:41:18] WARNING To use the Graphein submodule visualisation.py:35 graphein.protein.visualisation, you need to install: pytorch3d To do so, use the following command: conda install -c pytorch3d pytorch3d WARNING To use the Graphein submodule meshes.py:29 graphein.protein.meshes, you need to install: pytorch3d To do so, use the following command: ``` -------------------------------- ### Data Preparation Progress Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb Example output showing the progress of data preparation processes. ```text Process 52240 preparing data: 100%|██████████| 1/1 [00:00<00:00, 1.65it/s]] Process 52238 preparing data: 100%|██████████| 22/22 [00:05<00:00, 3.85it/s] Process 52239 preparing data: 100%|██████████| 22/22 [00:06<00:00, 3.59it/s] Process 52237 preparing data: 100%|██████████| 22/22 [00:07<00:00, 3.06it/s] Process 52236 preparing data: 100%|██████████| 22/22 [00:08<00:00, 2.70it/s] ``` -------------------------------- ### Example Output from Data Preparation Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb This output shows the progress of data preparation processes, indicating successful completion. ```text Process 52227 preparing data: 100%|██████████| 1/1 [00:00<00:00, 1.57it/s]] Process 52225 preparing data: 100%|██████████| 22/22 [00:05<00:00, 3.77it/s] Process 52226 preparing data: 100%|██████████| 22/22 [00:06<00:00, 3.50it/s] Process 52224 preparing data: 100%|██████████| 22/22 [00:07<00:00, 3.00it/s] ``` -------------------------------- ### Install pytorch3d Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb Instructions to install the 'pytorch3d' package using conda, which is required for Graphein visualization and mesh functionalities. ```bash conda install -c pytorch3d pytorch3d ``` -------------------------------- ### Custom Library Dependencies Source: https://github.com/anton-bushuiev/ppiformer/blob/main/requirements.txt These are custom libraries, mutils and PPIRef, installed from specific GitHub repositories. ```text mutils @ git+https://github.com/anton-bushuiev/mutils.git@main ppiref @ git+https://github.com/anton-bushuiev/PPIRef.git@main ``` -------------------------------- ### Data Loading Progress Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb Example output showing the progress of data preparation for multiple processes. ```text Process 52209 preparing data: 100%|██████████| 29/29 [00:07<00:00, 3.64it/s] Process 52210 preparing data: 100%|██████████| 29/29 [00:08<00:00, 3.55it/s] Process 52212 preparing data: 100%|██████████| 29/29 [00:08<00:00, 3.44it/s] Process 52211 preparing data: 100%|██████████| 29/29 [00:08<00:00, 3.33it/s] ``` -------------------------------- ### Install py3Dmol Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb Installs the py3Dmol library, which is used for molecular visualization. ```python !pip install py3Dmol ``` -------------------------------- ### Dataset Loading Output Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb Example output indicating the successful loading of a dataset. ```text skempi2_iclr24_split,2 loaded: PPIInMemoryDataset(89, n_muts=1858) PPIInMemoryDataset(89, n_muts=1858) ``` -------------------------------- ### Graphein Data Loading Output Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb Example output from Graphein data loading process. ```text Process 52196 preparing data: 100%|██████████| 29/29 [00:07<00:00, 3.64it/s] Process 52197 preparing data: 100%|██████████| 29/29 [00:08<00:00, 3.56it/s] Process 52199 preparing data: 100%|██████████| 29/29 [00:08<00:00, 3.44it/s] Process 52198 preparing data: 100%|██████████| 29/29 [00:08<00:00, 3.30it/s] Done! ``` -------------------------------- ### Embed PPI Source: https://github.com/anton-bushuiev/ppiformer/blob/main/README.md Example of how to load a pre-trained PPIformer model and obtain PPI embeddings from a PDB file. ```python # Load the pre-trained model device = 'cuda' if torch.cuda.is_available() else 'cpu' model = PPIformer.load_from_checkpoint(PPIFORMER_WEIGHTS_DIR / 'masked_modeling.ckpt', map_location=torch.device('cpu')) model = model.to(device).eval() # Specify input ppi_path = PPIFORMER_TEST_DATA_DIR / '1bui_A_C.pdb' # PDB or PPIRef file (see https://ppiref.readthedocs.io/en/latest/extracting_ppis.html) # Embed (get the final type-0 features). Here, 128-dimensional embedding for each of 124 amino acids in the PPI embedding = embed(model, ppi_path) embedding.shape > torch.Size([124, 128]) ``` -------------------------------- ### Biovec Dependency Warning Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb Warning message indicating that 'biovec' is required for Graphein's sequence embeddings submodule and cannot be installed via conda, suggesting 'pip install graphein[extras]' as an alternative. ```text [01/24/24 14:41:05] WARNING To use the Graphein submodule embeddings.py:44 graphein.protein.features.sequence .embeddings, you need to install: biovec biovec cannot be installed via conda Alternatively, you can install graphein with the extras: pip install graphein[extras] [01/24/24 14:41:05] WARNING To use the Graphein submodule embeddings.py:44 graphein.protein.features.sequence .embeddings, you need to install: biovec biovec cannot be installed via conda Alternatively, you can install graphein with the extras: pip install graphein[extras] [01/24/24 14:41:05] WARNING To use the Graphein submodule embeddings.py:44 graphein.protein.features.sequence .embeddings, you need to install: biovec biovec cannot be installed via conda Alternatively, you can install graphein with the extras: pip install graphein[extras] [01/24/24 14:41:05] WARNING To use the Graphein submodule embeddings.py:44 graphein.protein.features.sequence .embeddings, you need to install: biovec biovec cannot be installed via conda Alternatively, you can install graphein with the extras: pip install graphein[extras] [01/24/24 14:41:05] WARNING To use the Graphein submodule embeddings.py:44 graphein.protein.features.sequence .embeddings, you need to install: biovec biovec cannot be installed via conda Alternatively, you can install ``` -------------------------------- ### Attention Subtraction Example Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb This snippet shows how to extract a specific slice from an attention tensor. ```python attn_sub = attn[:, 0, 0, :, 0, :, :, :] ``` -------------------------------- ### Getting Indices of Mutated Residues Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb This code snippet extracts the indices from the 'ppi_df' DataFrame where the 'mutated' column is true. It converts these indices to a PyTorch tensor. ```python idx_mutated = torch.from_numpy(ppi_df.index[ppi_df['mutated']].to_numpy()) idx_mutated ``` -------------------------------- ### Predict DDG and Attention Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb This code snippet shows how to call the predict_ddg function to get DDG values and attention scores. ```python ddg, attn = predict_ddg(models, ppi_path, muts, return_attn=True) ddg ``` -------------------------------- ### Download model weights Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_readme.ipynb Downloads the pre-trained weights for the PPIformer model from Zenodo. ```python # Download the weights download_from_zenodo('weights.zip') ``` -------------------------------- ### Debug Pre-training Locally Source: https://github.com/anton-bushuiev/ppiformer/blob/main/scripts/README.md Command to debug pre-training locally with EGNN on CPU. ```bash python3 run.py experiment=debug_pretraining ``` -------------------------------- ### Training Dependencies Source: https://github.com/anton-bushuiev/ppiformer/blob/main/requirements.txt These are the dependencies required for training, including Weights & Biases (wandb) and Hydra for configuration management. ```text wandb hydra-core hydra-submitit-launcher ``` -------------------------------- ### Download Pre-trained Checkpoint Source: https://github.com/anton-bushuiev/ppiformer/blob/main/scripts/README.md Python code to download the pre-trained model checkpoint from Zenodo. ```python from ppiformer.utils.api import download_from_zenodo download_from_zenodo('weights.zip') ``` -------------------------------- ### Project Dependencies Source: https://github.com/anton-bushuiev/ppiformer/blob/main/requirements.txt This snippet lists the core dependencies for the PPIfomer project, including PyTorch, PyTorch Geometric, PyTorch Lightning, and Graphein. ```text torch==2.1.* cmake torch_geometric==2.3.1 pytorch_lightning==2.0.8 graphein==1.7.6 ``` -------------------------------- ### Pre-training Command Source: https://github.com/anton-bushuiev/ppiformer/blob/main/scripts/README.md Command to run the pre-training experiment for PPIformer using Hydra for configuration. ```bash HYDRA_FULL_ERROR=1 python3 run.py \ trainer.accelerator=gpu \ trainer.devices=8 \ job_key="${job_key}" \ project_name=PRETRAINING \ run_name='pre_training_iclr24' \ experiment=pretraining \ model.optimizer.lr=0.0005 \ train_dataloader.batch_size=2 \ val_dataloader.batch_size=2 \ trainer.accumulate_grad_batches=16 \ train_dataloader.dataset=\'ppiref_10A_filtered_clustered_03,whole\' \ trainer.val_check_interval=0.1 \ train_dataloader._transform.masked_modeling.mask_ratio=0.5 \ train_dataloader._transform.masked_modeling.mask_sum=null \ train_dataloader._transform.masked_modeling.bert=true \ train_dataloader._transform.masked_modeling.same_chain=true \ val_dataloader._transform.masked_modeling.mask_ratio=0.5 \ val_dataloader._transform.masked_modeling.mask_sum=null \ val_dataloader._transform.masked_modeling.bert=true \ val_dataloader._transform.masked_modeling.same_chain=true \ val_dataloader.dataset=\'skempi2_iclr24_split,0+1+2\' \ model.label_smoothing=0.05 \ model.class_weights=true \ model.encoder.depth=8 \ model.encoder.heads=2 \ model.encoder.num_neighbors=10 \ tags=null ``` -------------------------------- ### Downloading Preprocessed Data Source: https://github.com/anton-bushuiev/ppiformer/blob/main/scripts/README.md Python code to download pre-processed dataset cache from Zenodo. ```python from ppiformer.utils.api import download_from_zenodo download_from_zenodo('.pyg_dataset_cache.zip') ``` -------------------------------- ### Data Transformation and Loading Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb This code demonstrates applying pre-transformations (PDBToPyGPretransform, DDGLabelPretransform) to a PDB file and printing the resulting data object. ```python from PPIformer.data.transforms import Compose, PDBToPyGPretransform, DDGLabelPretransform from PPIformer.data.utils import plot_data from PPIformer.data.constants import PPIFORMER_TEST_DATA_DIR transform = Compose([ PDBToPyGPretransform(), DDGLabelPretransform() ]) data = transform(PPIFORMER_TEST_DATA_DIR / '1bui_A_C.pdb') print(data) plot_data(data) ``` -------------------------------- ### Import necessary libraries Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_readme.ipynb Imports core libraries and specific modules from the PPIformer package. ```python %load_ext autoreload %autoreload 2 import torch from ppiformer.tasks.node import DDGPPIformer from ppiformer.model.ppiformer import PPIformer from ppiformer.utils.api import download_from_zenodo, predict_ddg, embed from ppiformer.definitions import PPIFORMER_WEIGHTS_DIR, PPIFORMER_TEST_DATA_DIR ``` -------------------------------- ### Dataloader with Preprocessing Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb This code iterates through different splits of the skempi2 dataset, creating dataloaders with specified pre-transformations and printing the dataset object for each split. ```python from PPIformer.data.dataloader import get_dataloader for i in range(3): dataloader = get_dataloader( f'skempi2_iclr24_split,{i}', pretransform=[PDBToPyGPretransform(), DDGLabelPretransform()], transform=[], fresh=True, ) dataset = dataloader.dataset print(dataset) ``` -------------------------------- ### Fine-tuning Command Source: https://github.com/anton-bushuiev/ppiformer/blob/main/scripts/README.md Command to run the fine-tuning experiment on the ddG regression task. ```bash HYDRA_FULL_ERROR=1 python3 run.py \ trainer.accelerator=gpu \ trainer.devices=8 \ job_key="${job_key}" \ run_name='fine_tuning_iclr24' \ experiment=ddg_regression \ project_name=DDG_REGRESSION \ train_dataloader.dataset=\'skempi2_iclr24_split,0+1\' \ train_dataloader.fresh=false \ train_dataloader.dataset_max_workers=16 \ train_dataloader._pretransform.ddg_label.df=null \ val_dataloader.dataset=\'skempi2_iclr24_split,2\' \ val_dataloader.fresh=false \ val_dataloader.dataset_max_workers=16 \ val_dataloader._pretransform.ddg_label.df=null \ model.optimizer.lr=0.0003 \ model.checkpoint_path=\'../weights/masked_modeling.ckpt\' \ model.kind=masked_marginals \ model.encoder.heads=2 \ model.encoder.depth=8 \ train_dataloader.batch_size=1 \ val_dataloader.batch_size=1 \ trainer.accumulate_grad_batches=32 \ trainer.val_check_interval=1.0 \ trainer.check_val_every_n_epoch=5 \ train_dataloader._pretransform.ddg_label.strict_wt=True \ cv=true \ tags=null ``` -------------------------------- ### Autoreload Extension Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb Loads the autoreload extension for interactive development. ```python %load_ext autoreload %autoreload 2 ``` -------------------------------- ### Inference - Download weights Source: https://github.com/anton-bushuiev/ppiformer/blob/main/README.md Download the pre-trained weights for PPIformer. ```python import torch from ppiformer.tasks.node import DDGPPIformer from ppiformer.utils.api import download_from_zenodo, predict_ddg, embed from ppiformer.definitions import PPIFORMER_WEIGHTS_DIR, PPIFORMER_TEST_DATA_DIR # Download the weights download_from_zenodo('weights.zip') ``` -------------------------------- ### Import Libraries Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb Imports necessary libraries for data manipulation, modeling, and visualization. ```python import tempfile from pathlib import Path from io import StringIO import copy import numpy as np import pandas as pd import torch import hydra from omegaconf import OmegaConf import matplotlib.pyplot as plt import seaborn as sns from biopandas.pdb import PandasPdb from colour import Color from mutils.mutations import Mutation from ppiformer.tasks.node import DDGPPIformer from ppiformer.data.loader import get_dataloader from ppiformer.definitions import PPIFORMER_WEIGHTS_DIR, PPIFORMER_ROOT_DIR, PPIFORMER_TEST_DATA_DIR from mutils.definitions import MUTILS_DATA_DIR from ppiref.definitions import PPIREF_DATA_DIR from ppiformer.utils.api import predict_ddg from ppiref.extraction import PPIExtractor from ppiref.utils.ppi import PPIPath from ppiformer.utils.torch import fill_diagonal from ppiref.utils.residue import Residue ``` -------------------------------- ### Prepare PDB and Extract PPI Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb Sets up PDB file path, partners, mutations, and extracts PPI data using PPIExtractor. ```python # pdb_path = '../../sak/data/Jan-Mican-6-Nov-2023/1bui-sak-wt.pdb' # extractor.extract(pdb_path, partners=['A', 'B']) # sak is A pdb_path = Path('../../sak/data/Jan-Mican-6-Nov-2023/1bui-sak-wt-ternary-foranton.pdb') pdb_path = PPIFORMER_TEST_DATA_DIR / '1bui_A_C.pdb' partners = ['A', 'C'] # muts = ['MA12I'] # 'IA114T', 'MA12I,IA114T' # muts = ['MC26I', 'MC26I', 'MC26I', 'MC26I'] # muts = ['SA2G,FA33G'] muts = ['SC16G,FC47G'] # Extract PPI into temp dir ppi_dir_temo_obj = tempfile.TemporaryDirectory() ppi_dir = Path(ppi_dir_temo_obj.name) extractor = PPIExtractor(out_dir=ppi_dir, nest_out_dir=True, join=True, radius=10.0) extractor.extract(pdb_path, partners=partners) # sak is A ppi_path = PPIPath.construct(ppi_dir, pdb_path.stem, partners) ``` -------------------------------- ### Debug Ratio-based Masked Modeling Source: https://github.com/anton-bushuiev/ppiformer/blob/main/scripts/README.md Command to debug ratio-based masked modeling. ```bash python3 run.py experiment=debug_pretraining \ train_dataloader._transform.masked_modeling.mask_ratio=0.2 \ train_dataloader._transform.masked_modeling.mask_sum=null \ val_dataloader._transform.masked_modeling.mask_ratio=0.2 \ val_dataloader._transform.masked_modeling.mask_sum=null ``` -------------------------------- ### Load models from checkpoint Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/test.ipynb Loads pre-trained PPIformer models for DDG regression from checkpoint files. ```python download_from_zenodo('weights.zip') TEST_MODEL_NAME = 'ppiformer' checkpoints_dir = PPIFORMER_WEIGHTS_DIR / 'ddg_regression' checkpoint_paths = list(checkpoints_dir.glob('*.ckpt')) device = 'cpu' models = [DDGPPIformer.load_from_checkpoint(PPIFORMER_WEIGHTS_DIR / f'ddg_regression/{i}.ckpt', map_location=torch.device(device)).eval() for i in range(3)] ``` -------------------------------- ### Dataset Loaded Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb Output indicating the successful loading of a PPI dataset. ```text skempi2_iclr24_split,1 loaded: PPIInMemoryDataset(116, n_muts=1868) PPIInMemoryDataset(116, n_muts=1868) ``` -------------------------------- ### Change Training ddG Labels Source: https://github.com/anton-bushuiev/ppiformer/blob/main/scripts/README.md Command to change training ddG labels. ```bash HYDRA_FULL_ERROR=1 python3 run.py \ experiment=debug_ddg_regression \ train_dataloader.fresh=true \ train_dataloader._pretransform.ddg_label.strict_wt=False \ train_dataloader._pretransform.ddg_label.df=\'/Users/anton/dev/mutils/data/SKEMPI2/augmentations/skempi_v2_permute_reverse.csv\' ``` -------------------------------- ### Import Statements Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb Imports necessary libraries and modules for PPIFormer data handling and processing. ```python import warnings import graphein from torch_geometric.transforms import Compose from ppiformer.data.dataset import PPIInMemoryDataset from ppiformer.data.loader import get_dataloader from ppiformer.data.transforms import * from ppiformer.data.visualization import plot_data from ppiformer.definitions import * ``` -------------------------------- ### Submit Run to Slurm Source: https://github.com/anton-bushuiev/ppiformer/blob/main/scripts/README.md Command to submit the run.py script to a Slurm job scheduler. ```bash cd jobs ./submit_run_slurm.sh 24:00 ``` -------------------------------- ### Forked Equiformer Dependency Source: https://github.com/anton-bushuiev/ppiformer/blob/main/requirements.txt This dependency is a forked version of equiformer-pytorch from a specific GitHub repository and branch, likely to incorporate attention coefficients. ```text equiformer-pytorch @ git+https://github.com/anton-bushuiev/equiformer-pytorch.git@main ``` -------------------------------- ### Load Models Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb Loads pre-trained DDG regression models. ```python # Load weights models = [ DDGPPIformer.load_from_checkpoint(PPIFORMER_WEIGHTS_DIR / f'ddg_regression/{i}.ckpt', map_location=torch.device('cpu')).eval() for i in range(3) ] ``` -------------------------------- ### SKEMPI v2.0 test set Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/test.ipynb This code snippet downloads the SKEMPI v2.0 dataset, processes it, and makes predictions for all PPIs. ```python download_from_zenodo_ppiref('skempi2.zip') ppis_paths_test = read_fold('skempi2_iclr24_split', 'test') df_ddg = load_SKEMPI2()[0] df_test = [] for ppi_path in tqdm(ppis_paths_test, desc='Making predictions for all PPIs'): pdb_id = path_to_pdb_id(ppi_path) ppi_id = path_to_ppi_id(ppi_path) df_ppi = df_ddg[(df_ddg['PDB Id'] == pdb_id)] ppi_id = df_ppi['#Pdb'].iloc[0] muts = df_ppi['Mutation(s)_cleaned'].to_list() ddg = df_ppi['ddG'].to_list() ddg_pred = predict_ddg(models, ppi_path, muts, impute=True) for m, d, d_pred in zip(muts, ddg, ddg_pred): df_test.append({ 'complex': ppi_id, 'mutstr': m, 'ddG': d, 'ddG_pred': d_pred.item() }) df_test = pd.DataFrame(df_test) df_test.to_csv(MUTILS_DATA_DIR / f'SKEMPI2/predictions_test/results_{TEST_MODEL_NAME}.csv', index=False) ``` -------------------------------- ### Embedding (Feature Extraction) Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_readme.ipynb Loads a pre-trained PPIformer model and uses it to generate embeddings (type-0 features) for a given PDB file. ```python # Load the pre-trained model device = 'cuda' if torch.cuda.is_available() else 'cpu' model = PPIformer.load_from_checkpoint(PPIFORMER_WEIGHTS_DIR / 'masked_modeling.ckpt', map_location=torch.device('cpu')) model = model.to(device).eval() # Specify input ppi_path = PPIFORMER_TEST_DATA_DIR / '1bui_A_C.pdb' # PDB or PPIRef file (see https://ppiref.readthedocs.io/en/latest/extracting_ppis.html) # Embed (get the final type-0 features) h = embed(model, ppi_path) h.shape ``` -------------------------------- ### DDG Prediction Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_readme.ipynb Loads an ensemble of fine-tuned DDG prediction models, specifies an input PDB file and mutations, and predicts the change in Gibbs Free Energy (DDG). ```python # Load the ensamble of fine-tuned models device = 'cuda' if torch.cuda.is_available() else 'cpu' models = [DDGPPIformer.load_from_checkpoint(PPIFORMER_WEIGHTS_DIR / f'ddg_regression/{i}.ckpt', map_location=torch.device('cpu')).eval() for i in range(3)] models = [model.to(device) for model in models] # Specify input ppi_path = PPIFORMER_TEST_DATA_DIR / '1bui_A_C.pdb' # PDB or PPIRef file (see https://ppiref.readthedocs.io/en/latest/extracting_ppis.html) muts = ['SC16A', 'FC47A', 'SC16A,FC47A'] # List of single- or multi-point mutations # Predict ddg = predict_ddg(models, ppi_path, muts) ddg ``` -------------------------------- ### Apply BERT Masking Source: https://github.com/anton-bushuiev/ppiformer/blob/main/scripts/README.md Command to apply BERT masking. ```bash HYDRA_FULL_ERROR=1 python3 run.py \ experiment=debug_pretraining \ train_dataloader._transform.masked_modeling.bert=true \ val_dataloader._transform.masked_modeling.bert=true ``` -------------------------------- ### Load Autoreload Extension Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb Loads the autoreload extension for interactive development. ```python %load_ext autoreload %autoreload 2 ``` -------------------------------- ### Processing Indicator Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb A simple text output indicating that a process is underway. ```text Processing... ``` -------------------------------- ### Precision at K function Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/test.ipynb Calculates the precision at a given rank k. ```python def precision_at_k(ranks, classes, k): # claess are bool df = pd.DataFrame({'ranks': ranks, 'classes': classes}) df = df.nsmallest(k, 'ranks') return df['classes'].mean() ``` -------------------------------- ### SKEMPI Benchmark Function Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/test.ipynb This Python function calculates and displays performance metrics (Spearman, Pearson, Precision, Recall, ROC AUC, PR AUC, MAE, RMSE) for various prediction methods on the SKEMPI dataset. It iterates through different protein complexes, calculates metrics for each method, and then aggregates and displays the results. ```python IMPUTE_VAL = 0.691834179286864 def test_skempi(pred_dir: Path): # Read test 'Protein 1' -> PDB codes mapping with open(MUTILS_DATA_DIR / 'SKEMPI2/test_protein1_to_pdbs.json') as file: p1_to_pdbs = json.load(file) # Calculate per-PPI performance for all methods all_dfs_ppi = [] for p1, pdbs in p1_to_pdbs.items(): df_ppi = [] for path in pred_dir.glob('*.csv'): name = path.stem # Read PPI df for a method df = pd.read_csv(path) df = df[df['complex'].apply(lambda c: c in pdbs)] df = df.fillna(IMPUTE_VAL) df['Method'] = name df['Protein 1'] = p1 # Add metrics pred = df['ddG_pred'] < 0 real = df['ddG'] < 0 metrics = { 'Method': name, 'Spearman': df['ddG'].corr(df['ddG_pred'], method='spearman'), 'Pearson': df['ddG'].corr(df['ddG_pred'], method='pearson'), 'Precision': precision_score(real, pred, zero_division=0), 'Recall': recall_score(real, pred, zero_division=0), 'ROC AUC': roc_auc_score(real, -df['ddG_pred']) if len(df) and real.nunique() > 1 else np.nan, 'PR AUC': average_precision_score(real, -df['ddG_pred']) if len(df) and real.nunique() > 1 else np.nan, 'MAE': (df['ddG'] - df['ddG_pred']).abs().mean(), 'RMSE': math.sqrt((df['ddG'] - df['ddG_pred']).pow(2).mean()) } if metrics is not None: df_ppi.append(metrics) # Print PPI performance df_ppi = pd.DataFrame(df_ppi).set_index('Method') print(f'Protein 1: {p1} ({pdbs})') display((df_ppi[['Spearman', 'Precision', 'Recall']])) all_dfs_ppi.append(df_ppi) # Print overall performance print('Overall') display(pd.concat(all_dfs_ppi).round(2).reset_index().groupby(by='Method').mean()) test_skempi(MUTILS_DATA_DIR / 'SKEMPI2/predictions_test') ``` -------------------------------- ### Benchmark Sak Function Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/test.ipynb This Python function calculates and displays performance metrics for different prediction methods against a set of stabilizing mutations. ```python def test_sak(pred_dir: Path): stabilizing_muts = df_label[df_label['Activity enhancement']]['Mutation(s)'].tolist() sel_stabilizing_muts = df_label[df_label['2x activity enhancement']]['Mutation(s)'].tolist() # Calculate performance of each method df_overall = [] df_test = [] for path in pred_dir.glob('*.csv'): df = pd.read_csv(path) if 'rank' not in df.columns: df['rank'] = df['ddG_pred'].rank() / len(df) metrics = {} metrics['name'] = path.stem for k in [1, 4, 8]: metrics[f'P@{k}'] = precision_at_k(df['rank'], df['mutstr'].isin(stabilizing_muts), k) metrics['Mean rank'] = df[df['mutstr'].isin(stabilizing_muts)]['rank'].mean() dct = df[df['mutstr'].isin(sel_stabilizing_muts)][['mutstr', 'rank']].set_index('mutstr').T.to_dict() dct = df[df['mutstr'].isin(sel_stabilizing_muts)][['mutstr', 'rank']].set_index('mutstr').T.to_dict() dct = {k: v['rank'] for k, v in dct.items()} dct['Method'] = path.stem df_overall.append(dct) df_test.append(metrics) # Calculate overall performance df_overall = pd.DataFrame(df_overall).set_index('Method') display((100*df_overall).round(2)) df_test = pd.DataFrame(df_test).set_index('name') display((100*df_test).round(3)) test_sak(MUTILS_DATA_DIR / 'SAK/predictions_test') ``` -------------------------------- ### Test Shan2022 function Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/test.ipynb Tests the performance of different methods against stabilizing mutations. ```python def test_shan2022(pred_dir: Path): stabilizing_muts = ['TH31W', 'AH53F', 'NH57L', 'RH103M', 'LH104F'] # Calculate performance of each method df_overall = [] df_test = [] for path in pred_dir.glob('*.csv'): df = pd.read_csv(path) if 'rank' not in df.columns: df['rank'] = df['ddG_pred'].rank() / len(df) metrics = {} metrics['name'] = path.stem for k in [1, 25, 49]: metrics[f'P@{k}'] = precision_at_k(df['rank'], df['ddG'] < 0, k) metrics['Mean rank'] = df[df['mutstr'].isin(stabilizing_muts)]['rank'].mean() dct = df[df['mutstr'].isin(stabilizing_muts)][['mutstr', 'rank']].set_index('mutstr').T.to_dict() dct = df[df['mutstr'].isin(stabilizing_muts)][['mutstr', 'rank']].set_index('mutstr').T.to_dict() dct = {k: v['rank'] for k, v in dct.items()} dct['Method'] = path.stem df_overall.append(dct) df_test.append(metrics) # Calculate overall performance df_overall = pd.DataFrame(df_overall).set_index('Method') display((100*df_overall).round(2)) df_test = pd.DataFrame(df_test).set_index('name') display((100*df_test).round(3)) test_shan2022(MUTILS_DATA_DIR / '7FAE/predictions_test') ``` -------------------------------- ### Prediction and Saving Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/test.ipynb This code snippet predicts ddG values for a given PPI and saves the results to a CSV file. ```python ppi_path = MUTILS_DATA_DIR / '7FAE/7FAE-RBD-Fv_A_H_L.pdb' df_label = pd.read_csv(MUTILS_DATA_DIR / '7FAE/shan2022_covid_SKEMPI_format.csv') muts = df_label['Mutation(s)_cleaned'].tolist() ddg_pred = predict_ddg(models, ppi_path, muts, impute=True) df_test = pd.DataFrame({ 'complex': len(muts) * ['7FAE'], 'mutstr': muts, 'ddG_pred': ddg_pred.tolist(), 'ddG': df_label['ddG'].tolist() }) df_test.to_csv(MUTILS_DATA_DIR / f'7FAE/predictions_test/results_{TEST_MODEL_NAME}.csv', index=False) ``` -------------------------------- ### Silence Graphein Warnings Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_dataloader.ipynb This code snippet silences specific warnings from the Graphein library to clean up the output. ```python import graphein import warnings graphein.verbose(enabled=False) warnings.filterwarnings("ignore", message=".*The default value of regex will change.*") ``` -------------------------------- ### Remove Edge Features for Equiformer Source: https://github.com/anton-bushuiev/ppiformer/blob/main/scripts/README.md Command to remove edge features for Equiformer. ```bash HYDRA_FULL_ERROR=1 python3 run.py \ experiment=debug_ddg_regression \ model/encoder=equiformer \ model.pre_encoder_transform_kwargs.intra_inter_edge_features=false \ model.encoder.num_edge_tokens=null \ model.encoder.edge_dim=null ``` -------------------------------- ### Citation Source: https://github.com/anton-bushuiev/ppiformer/blob/main/README.md BibTeX entry for citing the PPIformer paper. ```bibtex @article{ bushuiev2024learning, title={Learning to design protein-protein interactions with enhanced generalization}, author={Anton Bushuiev and Roman Bushuiev and Petr Kouba and Anatolii Filkin and Marketa Gabrielova and Michal Gabriel and Jiri Sedlar and Tomas Pluskal and Jiri Damborsky and Stanislav Mazurenko and Josef Sivic}, booktitle={The Twelfth International Conference on Learning Representations}, year={2024} } ``` -------------------------------- ### Inference - Predict ddG for a PPI upon mutation Source: https://github.com/anton-bushuiev/ppiformer/blob/main/README.md Load the ensemble of fine-tuned models and predict binding energy changes (ddG) for a given protein-protein interaction (PPI) upon mutation. ```python # Load the ensamble of fine-tuned models device = 'cuda' if torch.cuda.is_available() else 'cpu' models = [DDGPPIformer.load_from_checkpoint(PPIFORMER_WEIGHTS_DIR / f'ddg_regression/{i}.ckpt', map_location=torch.device('cpu')).eval() for i in range(3)] models = [model.to(device) for model in models] # Specify input ppi_path = PPIFORMER_TEST_DATA_DIR / '1bui_A_C.pdb' # PDB or PPIRef file (see https://ppiref.readthedocs.io/en/latest/extracting_ppis.html) muts = ['SC16A', 'FC47A', 'SC16A,FC47A'] # List of single- or multi-point mutations # Predict ddg = predict_ddg(models, ppi_path, muts) ddg > tensor([-0.3708, 1.5188, 1.1482]) ``` -------------------------------- ### Displaying DataFrame Rows Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb This code snippet displays the first 10 rows of a pandas DataFrame named 'ppi_df'. The output shows a tabular representation of protein interaction data, including columns like 'record_name', 'atom_number', 'atom_name', 'residue_name', 'chain_id', 'residue_number', and various coordinate and B-factor values. ```python ppi_df.iloc[5:15] ``` -------------------------------- ### Read Molecular File Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb Reads a molecular file and returns its content as a string, with specific replacements for atom names. ```python import py3Dmol def read_mol(molpath): # https://huggingface.co/spaces/huhlim/cg2all/blob/main/app.py with open(molpath, "r") as fp: lines = fp.readlines() mol = "" for l in lines: mol += l # mol = mol.replace("OT1", "O ") mol = mol.replace("OT2", "OXT") return mol ``` -------------------------------- ### Visualize Attention Matrix Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb This code snippet visualizes a slice of the attention tensor as a matrix. ```python plt.matshow(attn[0, 0, 0, 0, 0, 0, :, :]) ``` -------------------------------- ### Visualize attention matrices for each head, layer, and degree Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb This code iterates through different layers, degrees, and attention heads to visualize the attention matrices. Each matrix represents the attention distribution for a specific combination of these parameters. ```python i_model = 0 i_mut = 0 i_batch = 0 for i_layer in range(attn.shape[3]): for i_degree in range(attn.shape[4]): for i_head in range(attn.shape[5]): plt.matshow(attn[i_model, i_mut, i_batch, i_layer, i_degree, i_head, :, :]) plt.title(f'Layer {i_layer}, Degree {i_degree}, Head {i_head}') plt.show() ``` -------------------------------- ### Assign colors to chains and visualize PPI with py3Dmol Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb This snippet assigns unique colors to protein chains based on their attention scores and visualizes the protein structure using py3Dmol. It highlights mutated residues in red and adjusts stick colors and radii based on attention values. Finally, it sets cartoon styles and renders the visualization. ```python # Assign colors to chains # TODO Sample for > 3 chains chains = ppi_df['chain_id'].unique() colors = [Color(c) for c in ['LimeGreen', 'HotPink', 'RoyalBlue']] chain_to_color = dict(zip(chains, colors)) chain_to_color # Init py3Dmol ppi_py3dmol = read_mol(pdb_path) view = py3Dmol.view(width=1000, height=1000) view.addModelsAsFrames(ppi_py3dmol) view.setStyle({'model': 0}, {'ray_opaque_background': 'off'}, {"stick": {'color": 'lightgrey', 'opacity': 0.5}}) view.setBackgroundColor('00cccccc') # Sticks # TODO Insertions for i, row in ppi_df.iterrows(): color = copy.deepcopy(chain_to_color[row['chain_id']]) color.saturation = row['attn'] color = color.hex_l if row['mutated']: view.addStyle({'chain': row['chain_id'], 'resi': str(row['residue_number'])}, {'stick': {'color': 'red', 'radius': 0.2, 'opacity': 1.0}}) else: view.addStyle({'chain': row['chain_id'], 'resi': str(row['residue_number'])}, {'stick': {'color': color, 'radius': row['attn'] / 5, 'opacity': row['attn']}}) # Cartoon for chain in chains: view.addStyle({'chain': chain}, {'cartoon': {'color': chain_to_color[chain].hex_l, 'opacity': 0.6}}) view.zoomTo() view.write_html('py3dmol_tmp.html') view.show() ``` -------------------------------- ### Load and Process PDB Data Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb This code snippet loads PDB data using PandasPdb, processes it to extract CA atoms, and adds an 'id' column. ```python ppi_df = PandasPdb().read_pdb(ppi_path).df['ATOM'] ppi_df = ppi_df.groupby(list(Residue._fields)).apply(lambda df: df[df['atom_name'] == 'CA'].iloc[0]).reset_index(drop=True) ppi_df['id'] = ppi_df.apply(lambda row: ':'.join([row['residue_name'], row['chain_id'], str(row['residue_number']), row['insertion']]), axis=1) ppi_df['id'] = ppi_df['id'].apply(lambda x: x[:-1] if x[-1] == ':' else x) ppi_df ``` -------------------------------- ### Display attention per token values Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb Displays the calculated attention scores per token. ```python attns_per_token ``` -------------------------------- ### Calculate attention per token Source: https://github.com/anton-bushuiev/ppiformer/blob/main/notebooks/demo_ddg.ipynb This code snippet calculates the attention scores for each token, normalizes them, and adds a small epsilon to avoid division by zero. ```python attn_sub = fill_diagonal(attn_sub.clone(), 1e-10) attn_mutated = attn_sub[..., idx_mutated, :] attns_per_token = torch.sum(attn_mutated, dim=(0, 1, 2, 3)) attns_per_token = (attns_per_token - attns_per_token.min()) / (attns_per_token.max() - attns_per_token.min()) attns_per_token += 1e-10 ```