Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,8 @@ jobs:
run: |
python -m pytest --nbval notebooks/RFDiffusion.ipynb tests/rfdiffusion_output.py

- name: Run PLM-Interact
run: |
python -m pytest --nbval tests/PLM_prepare.py notebooks/PLM-interact.ipynb tests/PLM_output.py


Binary file added docs/images/tutorial/bwVisu_PLM_files.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/tutorial/bwVisu_PLM_input.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/tutorial/bwVisu_PLM_more_output.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/tutorial/bwVisu_PLM_output.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
88 changes: 88 additions & 0 deletions docs/tutorials/tutorial_PLM_bwVisu.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# PLM-Interact on bwVisu

Welcome to the PLM-interact Tutorial for bwVisu!

<a href="https://github.com/liudan111/PLM-interact" target="_blank" rel="noopener">PLM-interact</a> is an open-source protein language model that predicts whether two proteins can interact from their sequences. This tutorial will guide you through running PLM-interact on bwVisu. Please follow these steps carefully. Any feedback on the tutorial is welcome! Feel free to [contact us](../contact.md)!

### Step 1: Get access to bwVisu

To start, get access to bwVisu via bwForCluster Helix or SDS. For more information, visit

<a href="https://www.urz.uni-heidelberg.de/en/service-catalogue/software-and-applications/bwvisu" target="_blank" rel="noopener">https://www.urz.uni-heidelberg.de/en/service-catalogue/software-and-applications/bwvisu</a>

For technical questions regarding the high performance cluster, see <a href="https://bw-support.scc.kit.edu" target="_blank" rel="noopener">https://bw-support.scc.kit.edu</a>. Feel free to [contact us](../contact.md) for support.

### Step 2: Connect to bwVisu and Start Jupyter

Go to <a href="https://bwvisu.bwservices.uni-heidelberg.de/" target="_blank" rel="noopener">https://bwvisu.bwservices.uni-heidelberg.de/</a> and log in with your credentials and one-time password.

Choose Jupyter and start a new session. Now you can select the resources you need.

For the inference model in PLM-interact we need a GPU. A list of available GPUs and their specifications is available at <a href="https://wiki.bwhpc.de/e/Helix/Hardware#Compute_Nodes" target="_blank" rel="noopener">https://wiki.bwhpc.de/e/Helix/Hardware#Compute_Nodes</a>, or in the table below.

![Screenshot](../images/tutorial/Helix_GPU.png){:.invertable}
<!--Cant I link this directly?-->

The GPU is selected by "GPU Type". The memory of each GPU Type is specified in GPU Memory per GPU (GB). For this example we select one of the A40 GPUs. Larger jobs (= longer sequences, more chains) require more memory. To access these, it is suggested to run the job directly on the Helix cluster. Feel free to contact us, if you need assistance!

<!-- no need for kernel this time -->

![Screenshot](../images/tutorial/bwVisu_GPU.png){:.invertable}
<!--{: style="height:500px;width:750px"}-->

Click on "Launch". This will bring you to a new screen showing your interactive sessions. Wait for your session to be ready, then click on "Connect to Jupyter". This brings you into a JupyterLab environment.

### Step 3: Set a Working Directory and Upload Files

Now we need to define a working directory. These will contain all files necessary for the tutorial. A new directory can be created using folder icon on the top left of the file browser:

![Screenshot](../images/tutorial/bwVisu_newDir.png){: .invertable style="height:111px;width:444px"}


#### Input Sequences in `.csv` Format
PLM-interact reads the input sequence pairs from a `.csv` file. More information can be found <a href="https://github.com/liudan111/PLM-interact/tree/main#1-ppi-inference-with-multi-gpus" target="_blank" rel="noopener">here</a>. We also provide an example in our <a href="https://github.com/ssciwr/BioStructureHub/tree/main/references/PLM" target="_blank" rel="noopener">github</a>.

| query | text |
| -------- | ------- |
| {sequence1} | {sequence2} |

If you copy these from `.fasta` files, make sure that there are no spaces within the sequences.

Upload the PLM-interact notebook from our <a href="https://github.com/ssciwr/BioStructureHub/tree/main/notebooks" target="_blank" rel="noopener">github</a> and the `.csv` file by clicking on the upload button:

![Screenshot](../images/tutorial/bwVisu_upload.png){: .invertable style="height:111px;width:444px"}

After the upload, you can see the notebooks in the file browser on the left.

![Screenshot](../images/tutorial/bwVisu_PLM_files.png){: .invertable style="width:377px"}

### Step 4: Open the Notebook and Start the Calculation

Open `PLM_interact.ipynb` and execute the cells in the notebook to start your Boltzgen run!


#### Verify Input

Before starting your Boltz prediction you should see the following files in your working directory:

![Screenshot](../images/tutorial/bwVisu_PLM_input.png){:.invertable style="width:377px"}

#### Verify Output

In the output directory, there will be a `.csv` file with the output scores. For more information on the scoring, see the PLM-interact <a href="https://www.nature.com/articles/s41467-025-64512-w" target="_blank" rel="noopener">publication</a>.

![Screenshot](../images/tutorial/bwVisu_PLM_output.png){:.invertable style="width:377px"}

Note that the entries in the output `.csv` file are in the same order as the input sequence pairs. In the tutorial `.ipynb` we include a simple cell to merge the input sequences and output scores, if you prefer this:

![Screenshot](../images/tutorial/bwVisu_PLM_more_output.png){:.invertable style="width:377px"}

### References

<a href="https://www.nature.com/articles/s41467-025-64512-w" target="_blank" rel="noopener">https://www.nature.com/articles/s41467-025-64512-w</a>

<a href="https://github.com/liudan111/PLM-interact" target="_blank" rel="noopener">https://github.com/liudan111/PLM-interact</a>

<a href="https://huggingface.co/danliu1226/PLM-interact-650M-humanV11" target="_blank" rel="noopener">https://huggingface.co/danliu1226/PLM-interact-650M-humanV11</a>

<a href="https://huggingface.co/facebook/esm2_t33_650M_UR50D" target="_blank" rel="noopener">https://huggingface.co/facebook/esm2_t33_650M_UR50D</a>
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ nav:
- tutorials/tutorial_Boltz_bwVisu.md
- tutorials/tutorial_Boltzgen_bwVisu.md
- tutorials/tutorial_RFDiffusion_bwVisu.md
- tutorials/tutorial_PLM_bwVisu.md
- Contact: contact.md

extra_css:
Expand Down
189 changes: 189 additions & 0 deletions notebooks/PLM-interact.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "5b554a86-ff7e-453a-9e79-877f88bb3290",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"from pathlib import Path"
]
},
{
"cell_type": "markdown",
"id": "1e510275-e8e5-400b-bde1-c6b67007177f",
"metadata": {},
"source": [
"First we need to define where PLM_interact finds our input data and where the output files are written to. You can see these files in the file browser on the left. If you change these names, remember to change them in the analysis notebook as well.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4e09c3bd-e8ad-42c0-ada0-798eefbed072",
"metadata": {},
"outputs": [],
"source": [
"WORKING_DIR = Path.cwd() / \"PLM_interact\"\n",
"OUTPUT_DIR = WORKING_DIR / \"output\""
]
},
{
"cell_type": "markdown",
"id": "7b0c1ba2-55c2-44dc-86e6-1e950be264a8",
"metadata": {},
"source": [
"Next we need to upload our sequence pairs. A description of the `.csv` format can be found [here](https://github.com/liudan111/PLM-interact/tree/main#1-ppi-inference-with-multi-gpus). You also need to tell PLM-interact the length of the longest sequence."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f4e4a1ed-4ac8-46dd-8566-59eb6ac9312c",
"metadata": {},
"outputs": [],
"source": [
"list_of_sequence_pairs = WORKING_DIR / \"test.csv\"\n",
"max_length = 1520"
]
},
{
"cell_type": "markdown",
"id": "fe247cff-b189-4aa4-8270-00bed455be0f",
"metadata": {},
"source": [
"Now we can prepare a bash file that calls PLM-interact."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0af52ad0-7482-434d-88c1-d479cf1d68e9",
"metadata": {},
"outputs": [],
"source": [
"RUN_FILE = WORKING_DIR / \"run.sh\"\n",
"\n",
"run_file = f\"\"\"\n",
"#!/bin/bash\n",
"\n",
"module load devel/miniforge/24.9.2\n",
"conda activate /mnt/sds-hd/sd25g005/PLMinteract\n",
"\n",
"! torchrun --nproc_per_node=1 -m PLMinteract inference_PPI \\\\\n",
"--seed 2 \\\\\n",
"--batch_size_val 1 \\\\\n",
"--test_filepath {list_of_sequence_pairs} \\\\\n",
"--resume_from_checkpoint /mnt/sds-hd/sd25g005/PLMinteract/download_huggingface_folder/PLM-interact-650M-humanV11/pytorch_model.bin \\\\\n",
"--output_filepath {OUTPUT_DIR}/ \\\\\n",
"--offline_model_path /mnt/sds-hd/sd25g005/PLMinteract/download_huggingface_folder/offline/ \\\\\n",
"--model_name esm2_t33_650M_UR50D \\\\\n",
"--embedding_size 1280 --max_length {max_length}\n",
"\"\"\"\n",
"\n",
"with open(RUN_FILE, \"w\") as file:\n",
" file.write(run_file)"
]
},
{
"cell_type": "markdown",
"id": "ce271a31-601b-44da-897a-9ba5f2b2e17e",
"metadata": {},
"source": [
"Execute the cell below to start the PLM-interact:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "4a42c64e-0880-4a05-8d19-1d1bc59074bd",
"metadata": {
"scrolled": true,
"tags": [
"nbval-skip"
]
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Running file run.sh\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Be aware, overflowing tokens are not returned for the setting you have chosen, i.e. sequence pairs with the 'longest_first' truncation strategy. So the returned list will always be empty even if some tokens have been removed.\n"
]
},
{
"data": {
"text/plain": [
"256"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"os.system(f'echo \"Running file {RUN_FILE}\"')\n",
"os.system(f\"bash {RUN_FILE}\")"
]
},
{
"cell_type": "markdown",
"id": "2e0f40d5-349e-4289-bf73-45fc3b2ee1d1",
"metadata": {},
"source": [
"If you want to have your input sequences and the output scores in one `.csv` file, execute the following cells:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "b0e04a4c-3288-4458-a433-cd3d24ef1f14",
"metadata": {
"tags": [
"nbval-skip"
]
},
"outputs": [],
"source": [
"import pandas as pd\n",
"\n",
"input_csv = pd.read_csv(list_of_sequence_pairs)\n",
"output_csv = pd.read_csv(OUTPUT_DIR / \"pred_scores.csv\", header=None)\n",
"\n",
"results_csv = pd.merge(input_csv, output_csv, left_index=True, right_index=True)\n",

Check warning on line 163 in notebooks/PLM-interact.ipynb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Specify the "how", "on" and "validate" parameters of this merge.

See more on https://sonarcloud.io/project/issues?id=ssciwr_BioStructureHub&issues=AZ9rGNPoIc2FEvJ1hDvA&open=AZ9rGNPoIc2FEvJ1hDvA&pullRequest=41
"results_csv.to_csv(OUTPUT_DIR / \"pred_scores_w_sequences.csv\", index=False)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
15 changes: 15 additions & 0 deletions references/PLM/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

#!/bin/bash

module load devel/miniforge/24.9.2
conda activate /mnt/sds-hd/sd25g005/PLMinteract

! torchrun --nproc_per_node=1 -m PLMinteract inference_PPI \
--seed 2 \
--batch_size_val 1 \
--test_filepath PLM_interact/test.csv \
--resume_from_checkpoint /mnt/sds-hd/sd25g005/PLMinteract/download_huggingface_folder/PLM-interact-650M-humanV11/pytorch_model.bin \
--output_filepath PLM_interact/output/ \
--offline_model_path /mnt/sds-hd/sd25g005/PLMinteract/download_huggingface_folder/offline/ \
--model_name esm2_t33_650M_UR50D \
--embedding_size 1280 --max_length 1520
3 changes: 3 additions & 0 deletions references/PLM/test.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
query,text
MSAPTPLAEASQIPTIPALSPLTAKQSKGNFFSSNPISSFVVDTYKQLHSHRQSLELVNPGTVENLNKEVSRDVFLSQYFFTGLRADLNKAFSMNPAFQTSHTFSIGSQALPKYAFSALFANDNLFAQGNIDNDLSVSGRLNYGWDKKNISKVNLQISDGQPTMCQLEQDYQASDFSVNVKTLNPSFSEKGEFTGVAVASFLQSVTPQLALGLETLYSRTDGSAPGDAGVSYLTRYVSKKQDWIFSGQLQANGALIASLWRKVAQNVEAGIETTLQAGMVPITDPLMGTPIGIQPTVEGSTTIGAKYEYRQSVYRGTLDSNGKVACFLERKVLPTLSVLFCGEIDHFKNDTKIGCGLQFETAGNQELLMLQQGLDADGNPLQALPQL,MSFLPSFILSDESKERISKILTLTHNVAHYGWIPFVLYLGWAHTSNRPNFLNLLSPLPSV
MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAEDLQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN,MSFLPSFILSDESKERISKILTLTHNVAHYGWIPFVLYLGWAHTSNRPNFLNLLSPLPSV
24 changes: 24 additions & 0 deletions tests/PLM_output.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from pathlib import Path
from tests.utils import normalize_text_paths


REPO_ROOT = Path(__file__).resolve().parent.parent
OUTPUT_DIR = REPO_ROOT / "notebooks" / "PLM_interact"

output_sh = OUTPUT_DIR / "run.sh"
reference_sh = REPO_ROOT / "references" / "PLM" / "run.sh"

MARKER = "PLM_interact"


def test_run_sh_exists():
assert output_sh.exists(), f"{output_sh} was not created by the notebook"


def test_run_sh_content():
produced_text = normalize_text_paths(output_sh.read_text(), [MARKER])
expected_text = normalize_text_paths(reference_sh.read_text(), [MARKER])

assert produced_text == expected_text, (
f"Produced {output_sh} differs from reference"
)
15 changes: 15 additions & 0 deletions tests/PLM_prepare.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from pathlib import Path
from tests.utils import prepare_file

REPO_ROOT = Path(__file__).resolve().parent.parent


SRC_csv = REPO_ROOT / "references" / "PLM" / "test.csv"
DST_csv = REPO_ROOT / "notebooks" / "PLM_interact" / "test.csv"


def test_prepare_csv():
"""Ensure reference PLM input files are copied for prediction notebook."""
prepare_file(SRC_csv, DST_csv)

assert DST_csv.exists()
Empty file added tests/__init__.py
Empty file.
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"BOLTZGEN_WORKING_DIR": NOTEBOOKS_DIR / "protein_design_w_Boltzgen",
"RFDIFFUSION_WORKING_DIR": NOTEBOOKS_DIR / "protein_design_w_RFDiffusion",
"BINDCRAFT_WORKING_DIR": NOTEBOOKS_DIR / "protein_design_w_Bindcraft",
"PLM_INTERACT_WORKING_DIR": NOTEBOOKS_DIR / "PLM_interact",
}


Expand Down
Loading