Download Modules/predictor_duration_speaker_context.py from FashionFlora/SFlowTTS: direct link, hf CLI and curl.
- Browser
- Download file 9.95 kB
-
https://huggingface.co/FashionFlora/SFlowTTS/resolve/main/Modules/predictor_duration_speaker_context.py
- Command line
-
hf download hf://FashionFlora/SFlowTTS/Modules/predictor_duration_speaker_context.py
-
curl -L -o predictor_duration_speaker_context.py https://huggingface.co/FashionFlora/SFlowTTS/resolve/main/Modules/predictor_duration_speaker_context.py
9.95 kB
| # predictor_duration_speaker_context.py | |
| # ============================================================================== | |
| # Duration Predictor with Speaker ID + Context Window Conditioning | |
| # | |
| # Architecture: | |
| # - Text encoder (shared ConvNeXtV2TextEncoder from predictor_fsq_flow_convnext) | |
| # encodes the full context window (prev + curr + next concatenated) in one pass | |
| # - _extract_current_context_embeddings slices out only the current | |
| # sentence embeddings by token_start/end indices | |
| # - Stochastic Duration Predictor (Flow-based) with speaker conditioning | |
| # ============================================================================== | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| import math | |
| from typing import Optional | |
| from Modules.transforms import piecewise_rational_quadratic_transform | |
| # Import from meldataset | |
| from meldataset import SPOKEN_IDS | |
| # ============================================================================== | |
| # 1. UTILS & BASIC LAYERS | |
| # ============================================================================== | |
| def length_to_mask(lengths: torch.Tensor, max_len: Optional[int] = None) -> torch.Tensor: | |
| max_len = int(max_len or lengths.max().item()) | |
| rng = torch.arange(max_len, device=lengths.device).unsqueeze(0) | |
| mask = rng < lengths.unsqueeze(1) | |
| return mask | |
| # ============================================================================== | |
| # 2. SDP COMPONENTS (Flow Layers) | |
| # ============================================================================== | |
| class Flip(nn.Module): | |
| def forward(self, x, *args, reverse=False, **kwargs): | |
| x = torch.flip(x, [1]) | |
| if not reverse: | |
| logdet = torch.zeros(x.size(0)).to(dtype=x.dtype, device=x.device) | |
| return x, logdet | |
| else: | |
| return x | |
| class ElementwiseAffine(nn.Module): | |
| def __init__(self, channels): | |
| super().__init__() | |
| self.channels = channels | |
| self.m = nn.Parameter(torch.zeros(channels, 1)) | |
| self.logs = nn.Parameter(torch.zeros(channels, 1)) | |
| def forward(self, x, x_mask, reverse=False, **kwargs): | |
| if not reverse: | |
| y = self.m + torch.exp(self.logs) * x | |
| y = y * x_mask | |
| logdet = torch.sum(self.logs * x_mask, [1, 2]) | |
| return y, logdet | |
| else: | |
| x = (x - self.m) * torch.exp(-self.logs) * x_mask | |
| return x | |
| class Log(nn.Module): | |
| def forward(self, x, x_mask, reverse=False, **kwargs): | |
| if not reverse: | |
| y = torch.log(torch.clamp_min(x, 1e-5)) * x_mask | |
| logdet = torch.sum(-y, [1, 2]) | |
| return y, logdet | |
| else: | |
| x = torch.exp(x) * x_mask | |
| return x | |
| class LayerNorm(nn.Module): | |
| def __init__(self, channels, eps=1e-5): | |
| super().__init__() | |
| self.channels = channels | |
| self.eps = eps | |
| self.gamma = nn.Parameter(torch.ones(channels)) | |
| self.beta = nn.Parameter(torch.zeros(channels)) | |
| def forward(self, x): | |
| x = x.transpose(1, -1) | |
| x = F.layer_norm(x, (self.channels,), self.gamma, self.beta, self.eps) | |
| return x.transpose(1, -1) | |
| class DDSConv(nn.Module): | |
| def __init__(self, channels, kernel_size, n_layers, p_dropout=0.0): | |
| super().__init__() | |
| self.n_layers = n_layers | |
| self.drop = nn.Dropout(p_dropout) | |
| self.convs_sep = nn.ModuleList() | |
| self.linears = nn.ModuleList() | |
| self.norms_1 = nn.ModuleList() | |
| self.norms_2 = nn.ModuleList() | |
| for i in range(n_layers): | |
| dilation = kernel_size**i | |
| padding = (kernel_size * dilation - dilation) // 2 | |
| self.convs_sep.append(nn.Conv1d(channels, channels, kernel_size, groups=channels, dilation=dilation, padding=padding)) | |
| self.linears.append(nn.Linear(channels, channels)) | |
| self.norms_1.append(LayerNorm(channels)) | |
| self.norms_2.append(LayerNorm(channels)) | |
| def forward(self, x, x_mask, g=None): | |
| if g is not None: | |
| x = x + g | |
| for i in range(self.n_layers): | |
| y = self.convs_sep[i](x * x_mask) | |
| y = self.norms_1[i](y) | |
| y = F.gelu(y) | |
| y = self.linears[i](y.mT).mT | |
| y = self.norms_2[i](y) | |
| y = F.gelu(y) | |
| y = self.drop(y) | |
| x = x + y | |
| return x * x_mask | |
| class ConvFlow(nn.Module): | |
| def __init__(self, in_channels, filter_channels, kernel_size, n_layers, num_bins=16, tail_bound=5.0): | |
| super().__init__() | |
| self.filter_channels = filter_channels | |
| self.num_bins = num_bins | |
| self.tail_bound = tail_bound | |
| self.half_channels = in_channels // 2 | |
| self.pre = nn.Linear(self.half_channels, filter_channels) | |
| self.convs = DDSConv(filter_channels, kernel_size, n_layers, p_dropout=0.0) | |
| self.proj = nn.Linear(filter_channels, self.half_channels * (num_bins * 3 - 1)) | |
| def forward(self, x, x_mask, g=None, reverse=False): | |
| x0, x1 = torch.split(x, [self.half_channels] * 2, 1) | |
| h = self.pre(x0.mT).mT | |
| h = self.convs(h, x_mask, g=g) | |
| h = self.proj(h.mT).mT * x_mask | |
| b, c, t = x0.shape | |
| h = h.reshape(b, c, -1, t).permute(0, 1, 3, 2) | |
| unnormalized_widths = h[..., : self.num_bins] / math.sqrt(self.filter_channels) | |
| unnormalized_heights = h[..., self.num_bins : 2 * self.num_bins] / math.sqrt(self.filter_channels) | |
| unnormalized_derivatives = h[..., 2 * self.num_bins :] | |
| x1, logabsdet = piecewise_rational_quadratic_transform( | |
| x1, unnormalized_widths, unnormalized_heights, unnormalized_derivatives, | |
| inverse=reverse, tails="linear", tail_bound=self.tail_bound | |
| ) | |
| x = torch.cat([x0, x1], 1) * x_mask | |
| logdet = torch.sum(logabsdet * x_mask, [1, 2]) | |
| if not reverse: | |
| return x, logdet | |
| else: | |
| return x | |
| # ============================================================================== | |
| # 3. STOCHASTIC DURATION PREDICTOR WITH CONTEXT | |
| # ============================================================================== | |
| class StochasticDurationPredictorContext(nn.Module): | |
| """ | |
| Stochastic Duration Predictor with speaker + context conditioning. | |
| """ | |
| def __init__(self, in_channels, filter_channels, kernel_size, p_dropout, n_flows=4, | |
| speaker_emb_dim=256): | |
| super().__init__() | |
| self.log_flow = Log() | |
| self.flows = nn.ModuleList() | |
| self.flows.append(ElementwiseAffine(2)) | |
| for i in range(n_flows): | |
| self.flows.append(ConvFlow(2, filter_channels, kernel_size, n_layers=3)) | |
| self.flows.append(Flip()) | |
| self.pre = nn.Linear(in_channels, filter_channels) | |
| self.convs = DDSConv(filter_channels, kernel_size, n_layers=3, p_dropout=p_dropout) | |
| self.proj = nn.Linear(filter_channels, filter_channels) | |
| self.post_pre = nn.Linear(1, filter_channels) | |
| self.post_convs = DDSConv(filter_channels, kernel_size, n_layers=3, p_dropout=p_dropout) | |
| self.post_proj = nn.Linear(filter_channels, filter_channels) | |
| self.post_flows = nn.ModuleList() | |
| self.post_flows.append(ElementwiseAffine(2)) | |
| for i in range(4): | |
| self.post_flows.append(ConvFlow(2, filter_channels, kernel_size, n_layers=3)) | |
| self.post_flows.append(Flip()) | |
| # Speaker conditioning | |
| if speaker_emb_dim > 0: | |
| self.cond_speaker = nn.Linear(speaker_emb_dim, filter_channels) | |
| def forward(self, x, x_mask, w=None, g=None, reverse=False, noise_scale=1.0): | |
| """ | |
| Args: | |
| x: [B, C, T] text features | |
| x_mask: [B, 1, T] mask | |
| w: [B, 1, T] ground truth durations (training only) | |
| g: [B, speaker_emb_dim] speaker embedding | |
| reverse: inference mode | |
| noise_scale: sampling temperature | |
| """ | |
| x = self.pre(x.mT).mT | |
| # Add speaker conditioning | |
| if g is not None and hasattr(self, 'cond_speaker'): | |
| g_expanded = g.unsqueeze(-1).expand(-1, -1, x.size(2)) | |
| x = x + self.cond_speaker(g_expanded.mT).mT | |
| x = self.convs(x, x_mask) | |
| x = self.proj(x.mT).mT * x_mask | |
| if not reverse: | |
| # Training | |
| h_w = self.post_pre(w.mT).mT | |
| h_w = self.post_convs(h_w, x_mask) | |
| h_w = self.post_proj(h_w.mT).mT * x_mask | |
| e_q = torch.randn(w.size(0), 2, w.size(2)).to(device=x.device, dtype=x.dtype) * x_mask | |
| z_q = e_q | |
| logdet_tot_q = 0 | |
| for flow in self.post_flows: | |
| z_q, logdet_q = flow(z_q, x_mask, g=(x + h_w)) | |
| logdet_tot_q += logdet_q | |
| z_u, z1 = torch.split(z_q, [1, 1], 1) | |
| u = torch.sigmoid(z_u) * x_mask | |
| z0 = (w - u) * x_mask | |
| logdet_tot_q += torch.sum((F.logsigmoid(z_u) + F.logsigmoid(-z_u)) * x_mask, [1, 2]) | |
| logq = torch.sum(-0.5 * (math.log(2 * math.pi) + (e_q**2)) * x_mask, [1, 2]) - logdet_tot_q | |
| logdet_tot = 0 | |
| z0, logdet = self.log_flow(z0, x_mask) | |
| logdet_tot += logdet | |
| z = torch.cat([z0, z1], 1) | |
| for flow in self.flows: | |
| z, logdet = flow(z, x_mask, g=x, reverse=reverse) | |
| logdet_tot += logdet | |
| nll = torch.sum(0.5 * (math.log(2 * math.pi) + (z**2)) * x_mask, [1, 2]) - logdet_tot | |
| return nll + logq | |
| else: | |
| # Inference | |
| flows = list(reversed(self.flows)) | |
| flows = flows[:-2] + [flows[-1]] | |
| z = torch.randn(x.size(0), 2, x.size(2)).to(device=x.device, dtype=x.dtype) * noise_scale | |
| for flow in flows: | |
| z = flow(z, x_mask, g=x, reverse=reverse) | |
| z0, z1 = torch.split(z, [1, 1], 1) | |
| return z0 | |