Download code/speaker_v2/models.py from laion/tyger-speaker-predictor: direct link, hf CLI and curl.
- Browser
- Download file 2.76 kB
-
https://huggingface.co/laion/tyger-speaker-predictor/resolve/main/code/speaker_v2/models.py
- Command line
-
hf download hf://laion/tyger-speaker-predictor/code/speaker_v2/models.py
-
curl -L -o models.py https://huggingface.co/laion/tyger-speaker-predictor/resolve/main/code/speaker_v2/models.py
2.76 kB
| """Small causal Nemotron-L15 -> ECAPA-192 predictors; no ASR/teacher weights.""" | |
| from __future__ import annotations | |
| import torch | |
| from torch import nn | |
| from torch.nn import functional as F | |
| class SpeakerPredictor(nn.Module): | |
| def __init__(self, architecture="gru", width=128, input_dim=1024, output_dim=192, centered=False): | |
| super().__init__() | |
| self.architecture = architecture | |
| self.width = width | |
| self.centered = centered | |
| self.norm = nn.LayerNorm(input_dim) | |
| if architecture == "mlp": | |
| self.encoder = nn.Sequential(nn.Linear(input_dim * 2, width), nn.GELU(), | |
| nn.Linear(width, width), nn.GELU()) | |
| elif architecture == "gru": | |
| self.project = nn.Sequential(nn.Linear(input_dim, width), nn.GELU()) | |
| self.encoder = nn.GRU(width, width, batch_first=True) | |
| elif architecture == "tcn": | |
| self.project = nn.Sequential(nn.Linear(input_dim, width), nn.GELU()) | |
| self.encoder = nn.ModuleList([ | |
| nn.Sequential(nn.Conv1d(width, width, 3, groups=width, dilation=d), | |
| nn.GELU(), nn.Conv1d(width, width, 1), nn.GELU()) | |
| for d in (1, 2, 4)]) | |
| else: | |
| raise ValueError(architecture) | |
| self.embedding = nn.Linear(width, output_dim) | |
| self.activity = nn.Linear(width, 3) # speech / silence / ambiguous overlap | |
| self.register_buffer("teacher_mean",torch.zeros(output_dim)) | |
| self.register_buffer("teacher_radius",torch.ones(())) | |
| def forward(self, features, lengths=None): | |
| x = self.norm(features) | |
| if self.architecture == "mlp": | |
| h = self.encoder(torch.cat([x.mean(1), x.std(1, unbiased=False)], -1)) | |
| elif self.architecture == "gru": | |
| h, _ = self.encoder(self.project(x)) | |
| h = h[:, -1] | |
| else: | |
| h = self.project(x).transpose(1, 2) | |
| for dilation, layer in zip((1, 2, 4), self.encoder): | |
| h = h + layer(F.pad(h, (2 * dilation, 0))) | |
| h = h[:, :, -1] | |
| direction = F.normalize(self.embedding(h),dim=-1) | |
| embedding = F.normalize(self.teacher_mean+self.teacher_radius*direction,dim=-1) if self.centered else direction | |
| return embedding, self.activity(h) | |
| def load_state(model, state): | |
| """Compatibility with the first uncentered pilot checkpoints.""" | |
| missing, unexpected = model.load_state_dict(state,strict=False) | |
| if unexpected or set(missing)-{"teacher_mean","teacher_radius"}: | |
| raise ValueError(f"Unexpected checkpoint mismatch: missing={missing}, unexpected={unexpected}") | |
| def parameter_count(model): | |
| return sum(p.numel() for p in model.parameters() if p.requires_grad) | |