Spaces:
Running
Running
File size: 10,366 Bytes
6963cf4 9e29637 8bd6bbb 11bcc1a a28eeb5 11bcc1a e0408f3 6963cf4 8bd6bbb a6b7cf0 4ed9ef0 a6b7cf0 aae512c 6963cf4 a28eeb5 a6b7cf0 6963cf4 a6b7cf0 6963cf4 a6b7cf0 6963cf4 a6b7cf0 6963cf4 a6b7cf0 a2460df 6963cf4 a6b7cf0 6963cf4 a6b7cf0 6963cf4 a6b7cf0 6963cf4 a6b7cf0 6643342 a6b7cf0 6643342 a6b7cf0 6963cf4 6643342 6963cf4 11bcc1a 6963cf4 01ff8b6 a6b7cf0 01ff8b6 a6b7cf0 01ff8b6 a6b7cf0 01ff8b6 a6b7cf0 01ff8b6 a6b7cf0 01ff8b6 a6b7cf0 c5491c0 8bd6bbb c5491c0 8bd6bbb 11bcc1a 01ff8b6 e0408f3 a28eeb5 8bd6bbb a28eeb5 5dae6ce 11bcc1a a28eeb5 8bd6bbb 11bcc1a a28eeb5 a653779 11bcc1a 8bd6bbb 11bcc1a 8bd6bbb e0408f3 8bd6bbb c5491c0 e0408f3 c5491c0 e0408f3 8bd6bbb e0408f3 8bd6bbb e0408f3 c5491c0 e0408f3 8bd6bbb e4000f9 a6b7cf0 01ff8b6 8bd6bbb 01ff8b6 8bd6bbb 11bcc1a 01ff8b6 8bd6bbb 01ff8b6 8bd6bbb 01ff8b6 8bd6bbb 5dae6ce 01ff8b6 11bcc1a 088d0d1 01ff8b6 11bcc1a 5dae6ce 01ff8b6 a28eeb5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
import gradio as gr
from model_loader import load_model
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
import re
import numpy as np
import os
import pandas as pd
import copy
import transformers, datasets
from transformers import AutoTokenizer
from transformers import DataCollatorForTokenClassification
from datasets import Dataset
from scipy.special import expit
import requests
from gradio_molecule3d import Molecule3D
# Biopython imports
from Bio.PDB import PDBParser, Select, PDBIO
from Bio.PDB.DSSP import DSSP
from Bio.PDB import PDBList
from matplotlib import cm # For color mapping
from matplotlib.colors import Normalize
# Configuration
checkpoint = 'ThorbenF/prot_t5_xl_uniref50'
max_length = 1500
# Load model and move to device
model, tokenizer = load_model(checkpoint, max_length)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.to(device)
model.eval()
def is_valid_sequence_length(length: int) -> bool:
"""Check if sequence length is within valid range."""
return 100 <= length <= 1500
def is_nucleic_acid_chain(chain) -> bool:
"""Check if chain contains nucleic acids."""
nucleic_acids = {'A', 'C', 'G', 'T', 'U', 'DA', 'DC', 'DG', 'DT', 'DU', 'UNK'}
return any(residue.get_resname().strip() in nucleic_acids for residue in chain)
def extract_protein_sequence(pdb_path):
"""
Extract the longest protein sequence from a PDB file with improved logic
"""
parser = PDBParser(QUIET=1)
structure = parser.get_structure('protein', pdb_path)
# Comprehensive amino acid mapping
aa_dict = {
# Standard amino acids (20 canonical)
'ALA': 'A', 'CYS': 'C', 'ASP': 'D', 'GLU': 'E', 'PHE': 'F',
'GLY': 'G', 'HIS': 'H', 'ILE': 'I', 'LYS': 'K', 'LEU': 'L',
'MET': 'M', 'ASN': 'N', 'PRO': 'P', 'GLN': 'Q', 'ARG': 'R',
'SER': 'S', 'THR': 'T', 'VAL': 'V', 'TRP': 'W', 'TYR': 'Y',
# Modified amino acids and alternative names
'MSE': 'M', # Selenomethionine
'SEP': 'S', # Phosphoserine
'TPO': 'T', # Phosphothreonine
'CSO': 'C', # Hydroxylalanine
'PTR': 'Y', # Phosphotyrosine
'HYP': 'P', # Hydroxyproline
}
# Ligand and nucleic acid exclusion set
ligand_exclusion_set = {'HOH', 'WAT', 'DOD', 'SO4', 'PO4', 'GOL', 'ACT', 'EDO'}
# Find the longest protein chain
longest_sequence = ""
longest_chain = None
for model in structure:
for chain in model:
# Skip nucleic acid chains
if is_nucleic_acid_chain(chain):
continue
# Extract and convert sequence
sequence = ""
for residue in chain:
# Check if residue is a standard amino acid or a known modified amino acid
res_name = residue.get_resname().strip()
if res_name in aa_dict:
sequence += aa_dict[res_name]
# Check for valid length and update longest sequence
if (10 < len(sequence) < 1500 and
len(sequence) > len(longest_sequence)):
longest_sequence = sequence
longest_chain = chain
if not longest_sequence:
return None, None, pdb_path
# Save filtered PDB if needed
if longest_chain:
io = PDBIO()
io.set_structure(longest_chain.get_parent().get_parent())
filtered_pdb_path = pdb_path.replace('.pdb', '_filtered.pdb')
io.save(filtered_pdb_path)
return longest_sequence, longest_chain, filtered_pdb_path
return longest_sequence, longest_chain, pdb_path
def create_dataset(tokenizer, seqs, labels, checkpoint):
tokenized = tokenizer(seqs, max_length=max_length, padding=False, truncation=True)
dataset = Dataset.from_dict(tokenized)
# Adjust labels based on checkpoint
if ("esm" in checkpoint) or ("ProstT5" in checkpoint):
labels = [l[:max_length-2] for l in labels]
else:
labels = [l[:max_length-1] for l in labels]
dataset = dataset.add_column("labels", labels)
return dataset
def convert_predictions(input_logits):
all_probs = []
for logits in input_logits:
logits = logits.reshape(-1, 2)
probabilities_class1 = expit(logits[:, 1] - logits[:, 0])
all_probs.append(probabilities_class1)
return np.concatenate(all_probs)
def normalize_scores(scores):
min_score = np.min(scores)
max_score = np.max(scores)
return (scores - min_score) / (max_score - min_score) if max_score > min_score else scores
def predict_protein_sequence(test_one_letter_sequence):
# Sanitize input sequence
test_one_letter_sequence = test_one_letter_sequence.replace("O", "X") \
.replace("B", "X").replace("U", "X") \
.replace("Z", "X").replace("J", "X")
# Prepare sequence for different model types
if ("prot_t5" in checkpoint) or ("ProstT5" in checkpoint):
test_one_letter_sequence = " ".join(test_one_letter_sequence)
if "ProstT5" in checkpoint:
test_one_letter_sequence = "<AA2fold> " + test_one_letter_sequence
# Create dummy labels
dummy_labels = [np.zeros(len(test_one_letter_sequence))]
# Create dataset
test_dataset = create_dataset(tokenizer,
[test_one_letter_sequence],
dummy_labels,
checkpoint)
# Select appropriate data collator
data_collator = (DataCollatorForTokenClassification(tokenizer)
if "esm" not in checkpoint and "ProstT5" not in checkpoint
else DataCollatorForTokenClassification(tokenizer))
# Create data loader
test_loader = DataLoader(test_dataset, batch_size=1, collate_fn=data_collator)
# Predict
for batch in test_loader:
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
with torch.no_grad():
outputs = model(input_ids, attention_mask=attention_mask)
logits = outputs.logits.detach().cpu().numpy()
# Process logits
logits = logits[:, :-1] # Remove last element for prot_t5
logits = convert_predictions(logits)
# Normalize and format results
normalized_scores = normalize_scores(logits)
test_one_letter_sequence = test_one_letter_sequence.replace(" ", "")
return test_one_letter_sequence, normalized_scores
def fetch_pdb(pdb_id):
try:
# Create a directory to store PDB files if it doesn't exist
os.makedirs('pdb_files', exist_ok=True)
# Fetch the PDB structure from RCSB
pdb_url = f'https://files.rcsb.org/download/{pdb_id}.pdb'
pdb_path = f'pdb_files/{pdb_id}.pdb'
# Download the file
response = requests.get(pdb_url)
if response.status_code == 200:
with open(pdb_path, 'wb') as f:
f.write(response.content)
return pdb_path
else:
return None
except Exception as e:
print(f"Error fetching PDB: {e}")
return None
def score_to_color(score):
norm = Normalize(vmin=0, vmax=1) # Normalize scores between 0 and 1
color_map = cm.coolwarm # Directly use the colormap (e.g., 'cividis', 'coolwarm', etc.)
rgba = color_map(norm(score)) # Get RGBA values
hex_color = '#{:02x}{:02x}{:02x}'.format(int(rgba[0] * 255), int(rgba[1] * 255), int(rgba[2] * 255))
return hex_color
def process_pdb(pdb_id):
# Fetch PDB file
pdbl = PDBList()
pdb_path = pdbl.retrieve_pdb_file(pdb_id, pdir='pdb_files', file_format='pdb')
if not pdb_path or not os.path.exists(pdb_path):
return "Failed to fetch PDB file", None
# Extract protein sequence and chain
protein_sequence, chain, filtered_pdb_path = extract_protein_sequence(pdb_path)
if not protein_sequence:
return "No suitable protein sequence found", None
# Predict binding sites
sequence, normalized_scores = predict_protein_sequence(protein_sequence)
# Prepare result string
result_str = "\n".join([f"{aa}: {score:.2f}" for aa, score in zip(sequence, normalized_scores)])
# Prepare representations for Molecule3D
reps = [
{
"model": 0,
"chain": "",
"resname": "",
"style": "cartoon",
"color": "spectrum",
"residue_range": "",
"around": 0,
"byres": False,
"visible": True
}
]
# Add color-coded residues based on binding site scores
#for i, score in enumerate(normalized_scores):
# if score > 0.7: # You can adjust this threshold
# reps.append({
# "model": 0,
# "chain": chain.get_id(),
# "style": "stick",
# "color": score_to_color(score),
# "residue_range": f"{i+1}-{i+1}",
# "byres": True,
# "visible": True
# })
# Create Molecule3D with the PDB file and representations
molecule_viewer = Molecule3D(
reps=reps
)
return result_str, molecule_viewer
# Create Gradio interface
with gr.Blocks() as demo:
gr.Markdown("# Protein Binding Site Prediction")
with gr.Row():
with gr.Column():
pdb_input = gr.Textbox(
value="2IWI",
label="PDB ID",
placeholder="Enter PDB ID here..."
)
predict_btn = gr.Button("Predict Binding Sites")
with gr.Column():
predictions_output = gr.Textbox(
label="Binding Site Predictions"
)
molecule_output = Molecule3D(label="Protein Structure")
# Prediction logic
predict_btn.click(
process_pdb,
inputs=[pdb_input],
outputs=[predictions_output, molecule_output]
)
gr.Markdown("## Examples")
gr.Examples(
examples=[
["2IWI"],
["7RPZ"],
["3TJN"]
],
inputs=[pdb_input],
outputs=[predictions_output, molecule_output]
)
demo.launch() |