Download wannabe_tokenizer/encoder.py from ManyOtherFunctions/Yue2-WannabeTokenizer: direct link, hf CLI and curl.
- Browser
- Download file 9.95 kB
-
https://huggingface.co/ManyOtherFunctions/Yue2-WannabeTokenizer/resolve/main/wannabe_tokenizer/encoder.py
- Command line
-
hf download hf://ManyOtherFunctions/Yue2-WannabeTokenizer/wannabe_tokenizer/encoder.py
-
curl -L -o encoder.py https://huggingface.co/ManyOtherFunctions/Yue2-WannabeTokenizer/resolve/main/wannabe_tokenizer/encoder.py
9.95 kB
| """Local PyTorch MERT2 encoder for the unified tokenizer checkpoint.""" | |
| from typing import Dict, Sequence | |
| import torch | |
| import torch.nn.functional as F | |
| from torch import nn | |
| from torchaudio.transforms import AmplitudeToDB, MelScale, Spectrogram | |
| SAMPLE_RATE = 24000 | |
| HOP = 960 | |
| class MelFrontend(nn.Module): | |
| def __init__(self, cfg: Dict): | |
| super().__init__() | |
| bins = cfg["num_mel_bins"] | |
| self.register_buffer("mel_mean", torch.zeros(bins)) | |
| self.register_buffer("mel_std", torch.ones(bins)) | |
| self.spectrogram = Spectrogram( | |
| n_fft=cfg["n_fft"], | |
| win_length=cfg["win_length"], | |
| hop_length=cfg["hop_length"], | |
| power=2.0, | |
| ) | |
| self.mel_scale = MelScale( | |
| n_mels=bins, | |
| sample_rate=cfg["sampling_rate"], | |
| n_stft=cfg["n_fft"] // 2 + 1, | |
| ) | |
| self.amplitude_to_db = AmplitudeToDB(stype="power", top_db=None) | |
| def forward(self, waveform: torch.Tensor) -> torch.Tensor: | |
| with torch.autocast(device_type=waveform.device.type, enabled=False): | |
| mel = self.amplitude_to_db(self.mel_scale(self.spectrogram(waveform.float()))) | |
| mel = mel[..., :-1].transpose(-1, -2) | |
| return (mel - self.mel_mean) / self.mel_std.clamp_min(1e-5) | |
| class Transpose(nn.Module): | |
| def forward(self, x): | |
| return x.transpose(1, 2) | |
| class GlobalResponseNorm(nn.Module): | |
| def __init__(self, dim: int): | |
| super().__init__() | |
| self.weight = nn.Parameter(torch.zeros(1, 1, dim)) | |
| self.bias = nn.Parameter(torch.zeros(1, 1, dim)) | |
| def forward(self, x): | |
| magnitude = torch.norm(x, p=2, dim=1, keepdim=True) | |
| return self.weight * (x * (magnitude / (magnitude.mean(dim=-1, keepdim=True) + 1e-6))) + self.bias + x | |
| class ConvNextLayer(nn.Module): | |
| def __init__(self, dim: int, eps: float): | |
| super().__init__() | |
| self.depthwise_block = nn.Sequential( | |
| Transpose(), | |
| nn.Conv1d(dim, dim, 7, padding=3, groups=dim), | |
| Transpose(), | |
| ) | |
| self.pointwise_block = nn.Sequential( | |
| nn.LayerNorm(dim, eps=eps), | |
| nn.Linear(dim, 4 * dim), | |
| nn.GELU(), | |
| GlobalResponseNorm(4 * dim), | |
| nn.Linear(4 * dim, dim), | |
| ) | |
| def forward(self, x): | |
| return x + self.pointwise_block(self.depthwise_block(x)) | |
| class ConvNextBlock(nn.Module): | |
| def __init__(self, cin: int, cout: int, stride: int, depth: int, eps: float): | |
| super().__init__() | |
| self.resampling_layer = ( | |
| nn.Sequential( | |
| nn.LayerNorm(cin, eps=eps), | |
| Transpose(), | |
| nn.Conv1d(cin, cout, 2, stride=stride), | |
| Transpose(), | |
| ) | |
| if cin != cout or stride > 1 | |
| else nn.Identity() | |
| ) | |
| self.convnext_layers = nn.Sequential(*[ConvNextLayer(cout, eps) for _ in range(depth)]) | |
| def forward(self, x): | |
| return self.convnext_layers(self.resampling_layer(x)) | |
| class RotaryEmbedding(nn.Module): | |
| def __init__(self, cfg: Dict): | |
| super().__init__() | |
| head_dim = cfg["hidden_size"] // cfg["num_attention_heads"] | |
| inv = 1.0 / ( | |
| cfg["rotary_embedding_base"] | |
| ** (torch.arange(0, head_dim, 2, dtype=torch.float32) / head_dim) | |
| ) | |
| self.register_buffer("inv_freq", inv, persistent=False) | |
| def forward(self, x): | |
| positions = torch.arange(x.shape[1], device=x.device, dtype=torch.float32) | |
| angles = torch.einsum("i,j->ij", positions, self.inv_freq.float()) | |
| angles = torch.cat((angles, angles), dim=-1)[None, :, None, :] | |
| return angles.cos().to(x.dtype), angles.sin().to(x.dtype) | |
| def rotate_half(x): | |
| first, second = x.chunk(2, dim=-1) | |
| return torch.cat((-second, first), dim=-1) | |
| class SelfAttention(nn.Module): | |
| def __init__(self, cfg: Dict, causal: bool): | |
| super().__init__() | |
| width = cfg["hidden_size"] | |
| self.num_heads = cfg["num_attention_heads"] | |
| self.head_dim = width // self.num_heads | |
| self.causal = causal | |
| self.query_proj = nn.Linear(width, width) | |
| self.key_proj = nn.Linear(width, width) | |
| self.value_proj = nn.Linear(width, width) | |
| self.out_proj = nn.Linear(width, width) | |
| def forward(self, x, rope): | |
| batch, frames, width = x.shape | |
| shape = (batch, frames, self.num_heads, self.head_dim) | |
| q, k, v = ( | |
| projection(x).reshape(shape) | |
| for projection in (self.query_proj, self.key_proj, self.value_proj) | |
| ) | |
| cos, sin = rope | |
| q = q * cos + rotate_half(q) * sin | |
| k = k * cos + rotate_half(k) * sin | |
| out = F.scaled_dot_product_attention( | |
| q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2), is_causal=self.causal | |
| ) | |
| return self.out_proj(out.transpose(1, 2).reshape(batch, frames, width)) | |
| class FeedForward(nn.Module): | |
| def __init__(self, cfg: Dict): | |
| super().__init__() | |
| self.w_1 = nn.Linear(cfg["hidden_size"], cfg["intermediate_size"]) | |
| self.w_2 = nn.Linear(cfg["intermediate_size"], cfg["hidden_size"]) | |
| def forward(self, x): | |
| return self.w_2(F.gelu(self.w_1(x))) | |
| class ConvolutionModule(nn.Module): | |
| def __init__(self, cfg: Dict): | |
| super().__init__() | |
| width = cfg["hidden_size"] | |
| kernel = cfg["conv_depthwise_kernel_size"] | |
| eps = cfg["layer_norm_eps"] | |
| self.layer_norm = nn.LayerNorm(width, eps=eps) | |
| self.conv_block = nn.Sequential( | |
| Transpose(), | |
| nn.Conv1d(width, 2 * width, 1, bias=False), | |
| nn.GLU(dim=1), | |
| nn.Conv1d( | |
| width, | |
| width, | |
| kernel, | |
| padding=(kernel - 1) // 2, | |
| groups=width, | |
| bias=False, | |
| ), | |
| nn.Sequential(Transpose(), nn.LayerNorm(width, eps=eps), Transpose()), | |
| nn.GELU(), | |
| nn.Conv1d(width, width, 1, bias=False), | |
| Transpose(), | |
| ) | |
| def forward(self, x): | |
| return self.conv_block(self.layer_norm(x)) | |
| class ConformerBlock(nn.Module): | |
| def __init__(self, cfg: Dict, causal: bool): | |
| super().__init__() | |
| width, eps = cfg["hidden_size"], cfg["layer_norm_eps"] | |
| self.ffn1_layer_norm = nn.LayerNorm(width, eps=eps) | |
| self.ffn1 = FeedForward(cfg) | |
| self.attn_layer_norm = nn.LayerNorm(width, eps=eps) | |
| self.attn = SelfAttention(cfg, causal) | |
| self.conv_module = ConvolutionModule(cfg) | |
| self.ffn2_layer_norm = nn.LayerNorm(width, eps=eps) | |
| self.ffn2 = FeedForward(cfg) | |
| self.final_layer_norm = nn.LayerNorm(width, eps=eps) | |
| def forward(self, x, rope): | |
| x = x + 0.5 * self.ffn1(self.ffn1_layer_norm(x)) | |
| x = self.attn(self.attn_layer_norm(x), rope) + x | |
| x = self.conv_module(x) + x | |
| x = x + 0.5 * self.ffn2(self.ffn2_layer_norm(x)) | |
| return self.final_layer_norm(x) | |
| class MERT2Encoder(nn.Module): | |
| """Mono 24 kHz waveform to 25 Hz Conformer block outputs.""" | |
| def __init__(self, cfg: Dict, causal: bool, layers: int): | |
| super().__init__() | |
| self.feature_extractor = MelFrontend(cfg) | |
| channels = [cfg["num_mel_bins"]] + list(cfg["subsampling_channels"]) | |
| self.subsampling_module = nn.Sequential( | |
| *[ | |
| ConvNextBlock( | |
| channels[i], | |
| channels[i + 1], | |
| (1, 2, 2)[i], | |
| cfg["subsampling_depths"][i], | |
| cfg["subsampling_layer_norm_eps"], | |
| ) | |
| for i in range(3) | |
| ] | |
| ) | |
| self.layers = nn.ModuleList([ConformerBlock(cfg, causal) for _ in range(layers)]) | |
| self.embed_positions = RotaryEmbedding(cfg) | |
| def forward(self, waveform: torch.Tensor, output: int) -> torch.Tensor: | |
| mel = self.feature_extractor(waveform) | |
| first = self.subsampling_module[0].convnext_layers[0].depthwise_block[1] | |
| x = self.subsampling_module(mel.to(first.weight.dtype)) | |
| rope = self.embed_positions(x) | |
| for index, layer in enumerate(self.layers): | |
| x = layer(x, rope) | |
| if index == output: | |
| return x | |
| raise ValueError(f"Requested encoder block {output}, but only {len(self.layers)} are present") | |
| def features(self, mono24: torch.Tensor, output: int, chunk: float = 0) -> torch.Tensor: | |
| """Return fp32 [frames, 1024] features, optionally in fixed-second pieces.""" | |
| if mono24.ndim != 1 or mono24.shape[0] < 1025: | |
| raise ValueError("The encoder needs at least 1025 mono samples at 24 kHz") | |
| with torch.autocast( | |
| device_type=mono24.device.type, | |
| dtype=torch.bfloat16, | |
| enabled=mono24.device.type == "cuda", | |
| ): | |
| if not chunk: | |
| return self(mono24[None], output)[0].float() | |
| samples = int(SAMPLE_RATE * chunk) | |
| pieces = [ | |
| piece | |
| for piece in (mono24[start : start + samples] for start in range(0, len(mono24), samples)) | |
| if len(piece) >= SAMPLE_RATE | |
| ] | |
| if not pieces: | |
| raise ValueError(f"Audio is shorter than the minimum one-second {chunk}-second chunk") | |
| full = [piece for piece in pieces if len(piece) == samples] | |
| groups = ([torch.stack(full)] if full else []) + [piece[None] for piece in pieces if len(piece) < samples] | |
| parts = [self(group, output) for group in groups] | |
| frames = int(round(len(mono24) / HOP)) | |
| joined = torch.cat([part.reshape(-1, part.shape[-1]) for part in parts]).float() | |
| return F.interpolate( | |
| joined.T[None], size=frames, mode="linear", align_corners=False | |
| )[0].T | |