SaProt / model /saprot /saprot_regression_model.py
anzhi2710gmailcom's picture
Upload folder using huggingface_hub
3b99abb verified
Raw
History Blame Contribute Delete
3.58 kB
import torch.distributed as dist
import torchmetrics
import torch
from ..model_interface import register_model
from .base import SaprotBaseModel
@register_model
class SaprotRegressionModel(SaprotBaseModel):
def __init__(self, test_result_path: str = None, **kwargs):
"""
Args:
test_result_path: path to save test result
**kwargs: other arguments for SaprotBaseModel
"""
self.test_result_path = test_result_path
super().__init__(task="regression", **kwargs)
def initialize_metrics(self, stage):
return {f"{stage}_loss": torchmetrics.MeanSquaredError(),
f"{stage}_spearman": torchmetrics.SpearmanCorrCoef(),
f"{stage}_R2": torchmetrics.R2Score(),
f"{stage}_pearson": torchmetrics.PearsonCorrCoef()}
def forward(self, inputs, structure_info=None):
if structure_info:
# To be implemented
raise NotImplementedError
# If backbone is frozen, the embedding will be the average of all residues
if self.freeze_backbone:
repr = torch.stack(self.get_hidden_states(inputs, reduction="mean"))
x = self.model.classifier.dropout(repr)
x = self.model.classifier.dense(x)
x = torch.tanh(x)
x = self.model.classifier.dropout(x)
logits = self.model.classifier.out_proj(x).squeeze(dim=-1)
else:
logits = self.model(**inputs).logits.squeeze(dim=-1)
return logits
def loss_func(self, stage, outputs, labels):
fitness = labels['labels'].to(outputs)
loss = torch.nn.functional.mse_loss(outputs, fitness)
# Update metrics
for metric in self.metrics[stage].values():
# Training is on half precision, but metrics expect float to compute correctly.
metric.update(outputs.detach().float(), fitness.float())
if stage == "train":
# Skip calculating metrics if the batch size is 1
if fitness.shape[0] > 1:
log_dict = self.get_log_dict("train")
self.log_info(log_dict)
# Reset train metrics
self.reset_metrics("train")
return loss
def test_epoch_end(self, outputs):
if self.test_result_path is not None:
from torchmetrics.utilities.distributed import gather_all_tensors
preds = self.test_spearman.preds
preds[-1] = preds[-1].unsqueeze(dim=0) if preds[-1].shape == () else preds[-1]
preds = torch.cat(gather_all_tensors(torch.cat(preds, dim=0)))
targets = self.test_spearman.target
targets[-1] = targets[-1].unsqueeze(dim=0) if targets[-1].shape == () else targets[-1]
targets = torch.cat(gather_all_tensors(torch.cat(targets, dim=0)))
if dist.get_rank() == 0:
with open(self.test_result_path, 'w') as w:
w.write("pred\ttarget\n")
for pred, target in zip(preds, targets):
w.write(f"{pred.item()}\t{target.item()}\n")
log_dict = self.get_log_dict("test")
print(log_dict)
self.log_info(log_dict)
self.reset_metrics("test")
def validation_epoch_end(self, outputs):
log_dict = self.get_log_dict("valid")
self.log_info(log_dict)
self.reset_metrics("valid")
self.check_save_condition(log_dict["valid_loss"], mode="min")