| import torch |
| import torch.nn as nn |
| import numpy as np |
| from huggingface_hub import PyTorchModelHubMixin |
|
|
|
|
| class PISCOClassifier(nn.Module, PyTorchModelHubMixin): |
| def __init__(self, d: int, hidden: int = 512, threshold: float = 0.5, device="cpu"): |
| super().__init__() |
| self.net = nn.Sequential( |
| nn.Linear(d, hidden), nn.LayerNorm(hidden), nn.GELU(), nn.Dropout(0.3), |
| nn.Linear(hidden, hidden // 4), nn.GELU(), nn.Dropout(0.2), |
| nn.Linear(hidden // 4, 1), |
| ).to(device) |
| self.threshold = threshold |
| def forward(self, x): |
| return self.net(x).squeeze(-1) |
|
|
| @torch.inference_mode() |
| def predict_proba(self, X) -> np.ndarray: |
| self.eval() |
| x = self._as_tensor(X) |
| return torch.sigmoid(self.net(x)).cpu().numpy() |
|
|
| def predict(self, X, threshold: float | None = None) -> np.ndarray: |
| """Binary predictions. Uses stored threshold if not given.""" |
| t = threshold if threshold is not None else self.threshold |
| return (self.predict_proba(X) >= t).astype(int) |
|
|
| @staticmethod |
| def _as_tensor(X) -> torch.Tensor: |
| if isinstance(X, torch.Tensor): |
| return X.float() |
| return torch.tensor(np.asarray(X), dtype=torch.float32) |