Download models.py from bxding/RC1: direct link, hf CLI and curl.
- Browser
- Download file 2.56 kB
-
https://huggingface.co/bxding/RC1/resolve/main/models.py
- Command line
-
hf download hf://bxding/RC1/models.py
-
curl -L -o models.py https://huggingface.co/bxding/RC1/resolve/main/models.py
2.56 kB
| """Small pretrained models for independent tiles and continuous grids.""" | |
| import timm | |
| from torch import nn | |
| BACKBONE = "mobilenetv4_conv_medium.e250_r384_in12k_ft_in1k" | |
| class GridModel(nn.Module): | |
| def __init__(self, tiles, classes, pretrained=True, backbone=BACKBONE): | |
| super().__init__() | |
| if tiles not in (9, 16): | |
| raise ValueError("Grid size must be 9 or 16 tiles") | |
| self.tiles = tiles | |
| if tiles == 9: | |
| self.backbone = timm.create_model(backbone, pretrained=pretrained) | |
| self.backbone.reset_classifier(0) | |
| channels = self.backbone.head_hidden_size | |
| self.head = nn.Linear(channels, classes) | |
| else: | |
| # The stride-16 stage: 448 px input gives a 28x28 map, 7x7 per cell. | |
| stage = ( | |
| timm.create_model(backbone, features_only=True).feature_info.reduction().index(16) | |
| ) | |
| self.backbone = timm.create_model( | |
| backbone, pretrained=pretrained, features_only=True, out_indices=(stage,) | |
| ) | |
| channels = self.backbone.feature_info.channels()[0] | |
| self.head = nn.Sequential( | |
| nn.Conv2d(channels, 128, 3, padding=1), | |
| nn.ReLU(), | |
| nn.Conv2d(128, classes, 1), | |
| # Max, not mean: any part of the target selects the cell. | |
| nn.AdaptiveMaxPool2d((4, 4)), | |
| ) | |
| def forward(self, images): | |
| features = self.backbone(images) | |
| return self.head(features if self.tiles == 9 else features[0]) | |
| def freeze_backbone(self, frozen): | |
| for parameter in self.backbone.parameters(): | |
| parameter.requires_grad_(not frozen) | |
| def select_target(logits, targets): | |
| """Only the requested target is supervised; other targets are unknown.""" | |
| import torch | |
| return logits[torch.arange(logits.shape[0], device=logits.device), targets] | |
| def transfer_backbone(model, state): | |
| """Copy matching backbone weights, e.g. from a tile classifier into the 4x4 feature extractor.""" | |
| source = {k.removeprefix("backbone."): v for k, v in state.items() if k.startswith("backbone.")} | |
| target = model.backbone.state_dict() | |
| matched = {k: v for k, v in source.items() if k in target and target[k].shape == v.shape} | |
| missing = sorted(set(target) - set(matched)) | |
| if missing: | |
| raise ValueError( | |
| f"Backbone weights missing for {len(missing)} parameters, e.g. {missing[:3]}" | |
| ) | |
| model.backbone.load_state_dict(matched) | |
| return len(matched) | |