Spaces:
Running
Running
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| import timm | |
| class FishClassifier(nn.Module): | |
| def __init__(self, architecture: str, num_classes: int, pretrained: bool = True, dropout: float = 0.3): | |
| super().__init__() | |
| self.backbone = timm.create_model(architecture, pretrained=pretrained, num_classes=0) | |
| feat_dim = self.backbone.num_features | |
| self.head = nn.Sequential( | |
| nn.Dropout(dropout), | |
| nn.Linear(feat_dim, 512), | |
| nn.ReLU(), | |
| nn.Dropout(dropout * 0.5), | |
| nn.Linear(512, num_classes), | |
| ) | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| return self.head(self.backbone(x)) | |
| def embed(self, x: torch.Tensor) -> torch.Tensor: | |
| """L2-normalized embedding — use for similarity search.""" | |
| return F.normalize(self.backbone(x), dim=1) | |
| def build_model(config: dict) -> FishClassifier: | |
| return FishClassifier( | |
| architecture=config["model"]["architecture"], | |
| num_classes=config["model"]["num_classes"], | |
| pretrained=config["model"]["pretrained"], | |
| dropout=config["model"]["dropout"], | |
| ) | |