Download src/models/base_model.py from readylab/VizRef: direct link, hf CLI and curl.
- Browser
- Download file 3.46 kB
-
https://huggingface.co/spaces/readylab/VizRef/resolve/main/src/models/base_model.py
- Command line
-
hf download hf://spaces/readylab/VizRef/src/models/base_model.py
-
curl -L -o base_model.py https://huggingface.co/spaces/readylab/VizRef/resolve/main/src/models/base_model.py
3.46 kB
| import torch | |
| import torch.nn as nn | |
| from abc import ABC, abstractmethod | |
| from typing import Dict, Tuple, Optional, List | |
| class BaseModel(nn.Module, ABC): | |
| """Abstract base class for all models""" | |
| def __init__(self, num_classes: int = 5): | |
| super().__init__() | |
| self.num_classes = num_classes | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| """Forward pass""" | |
| pass | |
| def get_features(self, x: torch.Tensor) -> torch.Tensor: | |
| """Extract feature representations""" | |
| pass | |
| def freeze_backbone(self, freeze_ratio: float = 0.5) -> None: | |
| """Freeze early layers of the model""" | |
| pass | |
| def unfreeze_all(self) -> None: | |
| """Unfreeze all layers""" | |
| for param in self.parameters(): | |
| param.requires_grad = True | |
| class ModelWithFeatures(BaseModel): | |
| """Wrapper to add feature extraction to any model""" | |
| def __init__(self, base_model: nn.Module, feature_layer: str = None, num_classes: int = 5): | |
| super().__init__(num_classes) | |
| self.base_model = base_model | |
| self.feature_layer = feature_layer | |
| self.features = None | |
| if feature_layer: | |
| self._register_hook() | |
| def _register_hook(self): | |
| """Register forward hook to extract features""" | |
| def hook(module, input, output): | |
| self.features = output.detach() | |
| # Find the layer | |
| for name, module in self.base_model.named_modules(): | |
| if name == self.feature_layer: | |
| module.register_forward_hook(hook) | |
| break | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| """Forward pass""" | |
| return self.base_model(x) | |
| def get_features(self, x: torch.Tensor) -> torch.Tensor: | |
| """Extract features before final classification layer""" | |
| # Forward pass to populate features | |
| _ = self.forward(x) | |
| return self.features if self.features is not None else x | |
| def freeze_backbone(self, freeze_ratio: float = 0.5) -> None: | |
| """Freeze early layers""" | |
| all_params = list(self.base_model.named_parameters()) | |
| num_to_freeze = int(len(all_params) * freeze_ratio) | |
| for i, (name, param) in enumerate(all_params): | |
| if i < num_to_freeze: | |
| param.requires_grad = False | |
| class EnsembleModel(BaseModel): | |
| """Ensemble multiple models for better performance""" | |
| def __init__(self, models: List[nn.Module], weights: Optional[List[float]] = None): | |
| super().__init__() | |
| self.models = nn.ModuleList(models) | |
| if weights is None: | |
| weights = [1.0 / len(models)] * len(models) | |
| self.weights = torch.tensor(weights) | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| """Average predictions from all models""" | |
| outputs = [] | |
| for model in self.models: | |
| outputs.append(model(x)) | |
| # Weighted average | |
| stacked = torch.stack(outputs, dim=0) | |
| weights = self.weights.to(x.device).view(-1, 1, 1) | |
| return (stacked * weights).sum(dim=0) | |
| def get_features(self, x: torch.Tensor) -> torch.Tensor: | |
| """Get concatenated features from all models""" | |
| features = [] | |
| for model in self.models: | |
| if hasattr(model, 'get_features'): | |
| features.append(model.get_features(x)) | |
| return torch.cat(features, dim=1) if features else x |