SaProt / scripts /dataset /saprot /saprot_regression_dataset.py
anzhi2710gmailcom's picture
Upload folder using huggingface_hub
3b99abb verified
Raw
History Blame Contribute Delete
3.08 kB
import torch
import json
import random
from ..data_interface import register_dataset
from transformers import EsmTokenizer
from ..lmdb_dataset import *
from ..lmdb_dataset import *
from scripts.utils.others import setup_seed
@register_dataset
class SaprotRegressionDataset(LMDBDataset):
def __init__(self,
tokenizer: str,
max_length: int = 1024,
min_clip: [float, float] = None,
mix_max_norm: [float, float] = None,
mask_struc_ratio: float = None,
plddt_threshold: float = None,
**kwargs):
"""
Args:
tokenizer: ESM tokenizer
max_length: Maximum length of the sequence
min_clip: [given_value, clip_value]
Set the fitness value to a fixed value if it is less than a given value
mix_max_norm: [min_norm, max_norm]
Normalize the fitness value to [0, 1] by min-max normalization
mask_struc_ratio: Ratio of masked structure tokens, replace structure tokens with "#"
plddt_threshold: If not None, mask structure tokens with pLDDT < threshold
**kwargs:
"""
super().__init__(**kwargs)
self.tokenizer = EsmTokenizer.from_pretrained(tokenizer)
self.max_length = max_length
self.min_clip = min_clip
self.mix_max_norm = mix_max_norm
self.mask_struc_ratio = mask_struc_ratio
self.plddt_threshold = plddt_threshold
def __getitem__(self, index):
entry = json.loads(self._get(index))
seq = entry['seq']
# Mask structure tokens
if self.mask_struc_ratio is not None:
tokens = self.tokenizer.tokenize(seq)
mask_candi = [i for i, t in enumerate(tokens) if t[-1] != "#"]
# Randomly shuffle the mask candidates and set seed to ensure mask is consistent
setup_seed(20000812)
random.shuffle(mask_candi)
# Mask first n structure tokens
mask_num = int(len(mask_candi) * self.mask_struc_ratio)
for i in range(mask_num):
idx = mask_candi[i]
tokens[idx] = tokens[idx][:-1] + "#"
seq = "".join(tokens)
# Mask structure tokens with pLDDT < threshold
if self.plddt_threshold is not None:
plddt = entry["plddt"]
tokens = self.tokenizer.tokenize(seq)
seq = ""
for token, score in zip(tokens, plddt):
if score < self.plddt_threshold:
seq += token[:-1] + "#"
else:
seq += token
tokens = self.tokenizer.tokenize(seq)[:self.max_length]
seq = " ".join(tokens)
if self.min_clip is not None:
given_min, clip_value = self.min_clip
if entry['fitness'] < given_min:
entry['fitness'] = clip_value
if self.mix_max_norm is not None:
min_norm, max_norm = self.mix_max_norm
entry['fitness'] = (entry['fitness'] - min_norm) / (max_norm - min_norm)
label = entry['fitness']
return seq, label
def __len__(self):
return int(self._get("length"))
def collate_fn(self, batch):
seqs, labels = tuple(zip(*batch))
labels = torch.tensor(labels)
labels = {"labels": labels}
encoder_info = self.tokenizer.batch_encode_plus(seqs, return_tensors='pt', padding=True)
inputs = {"inputs": encoder_info}
return inputs, labels