Spaces:
Running on Zero
Running on Zero
Download bluemagpie/tslm.py from voidful/BlueMagpie-TTS-Demo: direct link, hf CLI and curl.
- Browser
- Download file 3.48 kB
-
https://huggingface.co/spaces/voidful/BlueMagpie-TTS-Demo/resolve/7e7df2a5f9ea6839a43a3ed880a32d7ecaea9176/bluemagpie/tslm.py
- Command line
-
hf download hf://spaces/voidful/BlueMagpie-TTS-Demo@7e7df2a5f9ea6839a43a3ed880a32d7ecaea9176/bluemagpie/tslm.py
-
curl -L -o tslm.py https://huggingface.co/spaces/voidful/BlueMagpie-TTS-Demo/resolve/7e7df2a5f9ea6839a43a3ed880a32d7ecaea9176/bluemagpie/tslm.py
3.48 kB
| """Barbet as the Text-Semantic LM (TSLM), with incremental decoding. | |
| VoxCPM2's generation loop decodes one latent patch at a time, so the TSLM needs | |
| a stateful single-step path. As of the open_formosa R2 architecture, Barbet | |
| ships exactly that: a real **Mamba2** mixer and a native ``BarbetCache`` holding | |
| - attention K/V states (rolling window for sliding-window layers), | |
| - the trailing ``d_conv - 1`` causal-conv inputs per Mamba layer, and | |
| - the Mamba2 selective-scan SSM state per Mamba layer. | |
| We delegate stepwise decoding to it rather than re-deriving a cache by hand: | |
| the selective-scan state cannot be reconstructed from a conv ring buffer alone, | |
| so the official cache is the only correct option (and it stays in lockstep with | |
| upstream). ``tests/test_step_equivalence.py`` asserts prefill + forward_step | |
| reproduces the full-sequence forward across all layer types. | |
| """ | |
| from __future__ import annotations | |
| from dataclasses import dataclass | |
| import torch | |
| from torch import nn | |
| from barbet import BarbetConfig, BarbetModel | |
| from barbet.modeling_barbet import BarbetCache | |
| class BarbetStepState: | |
| """Decoding state: Barbet's native hybrid cache (tracks position itself).""" | |
| cache: BarbetCache | |
| def pos(self) -> int: | |
| return self.cache.seen_tokens | |
| class BarbetTSLM(nn.Module): | |
| """Barbet backbone with embeddings, full forward, and cached stepwise decode.""" | |
| def __init__(self, config: BarbetConfig) -> None: | |
| super().__init__() | |
| self.config = config | |
| self.backbone = BarbetModel(config) | |
| def embed_tokens(self) -> nn.Embedding: | |
| return self.backbone.embed_tokens | |
| def hidden_size(self) -> int: | |
| return self.config.hidden_size | |
| def forward( | |
| self, | |
| inputs_embeds: torch.Tensor, | |
| attention_mask: torch.Tensor | None = None, | |
| ) -> torch.Tensor: | |
| """Full-sequence forward (training / teacher-forcing), no cache.""" | |
| out = self.backbone( | |
| inputs_embeds=inputs_embeds, | |
| attention_mask=attention_mask, | |
| use_cache=False, | |
| return_dict=True, | |
| ) | |
| return out.last_hidden_state | |
| # ------------------------------------------------------------------ # | |
| # Stepwise decoding (delegated to BarbetCache) | |
| # ------------------------------------------------------------------ # | |
| def prefill(self, inputs_embeds: torch.Tensor) -> tuple[torch.Tensor, BarbetStepState]: | |
| """Run the prompt and return (hidden_states, state) with a warm cache.""" | |
| cache = BarbetCache(self.config) | |
| out = self.backbone( | |
| inputs_embeds=inputs_embeds, | |
| past_key_values=cache, | |
| use_cache=True, | |
| return_dict=True, | |
| ) | |
| return out.last_hidden_state, BarbetStepState(cache=out.past_key_values or cache) | |
| def forward_step(self, x: torch.Tensor, state: BarbetStepState) -> torch.Tensor: | |
| """Decode one position. ``x``: [B, H] input embedding -> [B, H] hidden. | |
| The cache tracks the running position (``seen_tokens``), so RoPE offsets | |
| and the sliding-window / conv / SSM states advance automatically. | |
| """ | |
| out = self.backbone( | |
| inputs_embeds=x.unsqueeze(1), | |
| past_key_values=state.cache, | |
| use_cache=True, | |
| return_dict=True, | |
| ) | |
| return out.last_hidden_state[:, 0, :] | |