Download src/face_backbones.py from loveyudi/data_minning: direct link, hf CLI and curl.
- Browser
- Download file 4.3 kB
-
https://huggingface.co/loveyudi/data_minning/resolve/main/src/face_backbones.py
- Command line
-
hf download hf://loveyudi/data_minning/src/face_backbones.py
-
curl -L -o face_backbones.py https://huggingface.co/loveyudi/data_minning/resolve/main/src/face_backbones.py
4.3 kB
| """Backbone builders for scratch face-recognition experiments.""" | |
| from __future__ import annotations | |
| from collections.abc import Sequence | |
| import torch | |
| from facenet_pytorch import InceptionResnetV1 | |
| from torch import nn | |
| class Flatten(nn.Module): | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| return x.view(x.size(0), -1) | |
| class IRBlock(nn.Module): | |
| def __init__(self, in_channels: int, out_channels: int, stride: int): | |
| super().__init__() | |
| self.residual = nn.Sequential( | |
| nn.BatchNorm2d(in_channels), | |
| nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False), | |
| nn.BatchNorm2d(out_channels), | |
| nn.PReLU(out_channels), | |
| nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False), | |
| nn.BatchNorm2d(out_channels), | |
| ) | |
| if in_channels == out_channels and stride == 1: | |
| self.shortcut = nn.Identity() | |
| else: | |
| self.shortcut = nn.Sequential( | |
| nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False), | |
| nn.BatchNorm2d(out_channels), | |
| ) | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| return self.residual(x) + self.shortcut(x) | |
| class IRResNet(nn.Module): | |
| """InsightFace-style IR-ResNet for 112x112 face crops.""" | |
| def __init__(self, layers: Sequence[int], embedding_size: int = 512, dropout: float = 0.4): | |
| super().__init__() | |
| self.input_layer = nn.Sequential( | |
| nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False), | |
| nn.BatchNorm2d(64), | |
| nn.PReLU(64), | |
| ) | |
| self.body = nn.Sequential( | |
| self._make_stage(64, 64, layers[0], stride=2), | |
| self._make_stage(64, 128, layers[1], stride=2), | |
| self._make_stage(128, 256, layers[2], stride=2), | |
| self._make_stage(256, 512, layers[3], stride=2), | |
| ) | |
| self.output_layer = nn.Sequential( | |
| nn.BatchNorm2d(512), | |
| nn.Dropout(dropout), | |
| Flatten(), | |
| nn.Linear(512 * 7 * 7, embedding_size), | |
| nn.BatchNorm1d(embedding_size), | |
| ) | |
| self._init_weights() | |
| def _make_stage(self, in_channels: int, out_channels: int, blocks: int, stride: int) -> nn.Sequential: | |
| layers = [IRBlock(in_channels, out_channels, stride)] | |
| for _ in range(1, blocks): | |
| layers.append(IRBlock(out_channels, out_channels, 1)) | |
| return nn.Sequential(*layers) | |
| def _init_weights(self) -> None: | |
| for module in self.modules(): | |
| if isinstance(module, nn.Conv2d): | |
| nn.init.kaiming_normal_(module.weight, mode="fan_out", nonlinearity="relu") | |
| elif isinstance(module, (nn.BatchNorm1d, nn.BatchNorm2d)): | |
| nn.init.ones_(module.weight) | |
| nn.init.zeros_(module.bias) | |
| elif isinstance(module, nn.Linear): | |
| nn.init.xavier_uniform_(module.weight) | |
| nn.init.zeros_(module.bias) | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| x = self.input_layer(x) | |
| x = self.body(x) | |
| return self.output_layer(x) | |
| def canonical_backbone_name(name: str) -> str: | |
| normalized = name.lower().replace("-", "_") | |
| aliases = { | |
| "inceptionresnetv1": "inception_resnet_v1", | |
| "inception_resnet": "inception_resnet_v1", | |
| "inception_resnet_v1": "inception_resnet_v1", | |
| "ir18": "ir_resnet18", | |
| "ir_resnet18": "ir_resnet18", | |
| "ir34": "ir_resnet34", | |
| "ir_resnet34": "ir_resnet34", | |
| } | |
| if normalized not in aliases: | |
| raise ValueError(f"Unsupported backbone: {name}") | |
| return aliases[normalized] | |
| def build_backbone(name: str, pretrained_model: str | None = None) -> tuple[nn.Module, int, str]: | |
| canonical = canonical_backbone_name(name) | |
| if canonical == "inception_resnet_v1": | |
| model = InceptionResnetV1(pretrained=pretrained_model, classify=False) | |
| elif canonical == "ir_resnet18": | |
| model = IRResNet([2, 2, 2, 2]) | |
| elif canonical == "ir_resnet34": | |
| model = IRResNet([3, 4, 6, 3]) | |
| else: | |
| raise ValueError(f"Unsupported backbone: {name}") | |
| return model, 512, canonical | |