Automatic Speech Recognition
Transformers
asr
speaker-diarization
timestamps
quantization
low-bit
arm
on-device
Instructions to use yongyizang/TinyMOSS-Diarize with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use yongyizang/TinyMOSS-Diarize with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("automatic-speech-recognition", model="yongyizang/TinyMOSS-Diarize")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("yongyizang/TinyMOSS-Diarize", device_map="auto") - Notebooks
- Google Colab
- Kaggle
| """Core Sherry 3:4 ternary fake quantization and Arenas scheduling.""" | |
| from __future__ import annotations | |
| import math | |
| from typing import Any | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| def _validate_quant_shape(weight: torch.Tensor, group_size: int) -> None: | |
| """Validate constraints that the original implementation left to reshapes.""" | |
| if weight.ndim != 2: | |
| raise ValueError(f"Sherry only supports 2-D linear weights, got {weight.ndim}-D") | |
| if not weight.is_floating_point(): | |
| raise ValueError("Sherry fake quantization requires a floating-point weight") | |
| if not isinstance(group_size, int) or group_size <= 0: | |
| raise ValueError("group_size must be a positive integer") | |
| if group_size % 4: | |
| raise ValueError("group_size must be divisible by the 3:4 block width (4)") | |
| if weight.shape[1] % group_size: | |
| raise ValueError( | |
| f"in_features ({weight.shape[1]}) must be divisible by group_size ({group_size}); " | |
| "groups may not cross output-channel rows" | |
| ) | |
| class _NMQuantizeSTE(torch.autograd.Function): | |
| """Autograd implementation whose backward is the unmodified identity STE.""" | |
| def forward(ctx: Any, weight: torch.Tensor, group_size: int) -> torch.Tensor: | |
| del ctx | |
| _validate_quant_shape(weight, group_size) | |
| original_shape = weight.shape | |
| blocks = weight.reshape(original_shape[0], original_shape[1] // 4, 4) | |
| survivor_indices = blocks.abs().topk(k=3, dim=-1).indices | |
| mask = torch.zeros_like(blocks, dtype=torch.bool) | |
| mask.scatter_(-1, survivor_indices, True) | |
| sparse = blocks.masked_fill(~mask, 0).reshape(-1, group_size) | |
| # The original accumulates in the latent dtype (often bf16). Sherry notes | |
| # identify that as a precision bug, so accumulation is deliberately fp32. | |
| scale = sparse.float().abs().sum(dim=-1, keepdim=True) / (group_size * 3 / 4) | |
| signs = sparse.sign().float() | |
| quantized = (signs * scale).reshape(original_shape) | |
| return quantized.to(dtype=weight.dtype) | |
| def backward(ctx: Any, grad_output: torch.Tensor) -> tuple[torch.Tensor, None]: | |
| del ctx | |
| # Unlike mask-aware pruning estimators, the original Sherry rule passes | |
| # gradients through pruned lanes too. Preserve that pure STE exactly. | |
| return grad_output, None | |
| def nm_quantize(weight: torch.Tensor, group_size: int = 128) -> torch.Tensor: | |
| """Fake-quantize a linear weight with dynamic 3:4 sparsity and ternary scales. | |
| Every consecutive four input lanes retains the three largest magnitudes. A | |
| group shares ``delta = abs(nonzero).mean()`` and survivors become ``+/-delta``. | |
| Differences from AngelSlim Sherry: the public API contains only live | |
| arguments, validates row-local grouping, and computes scale reductions in | |
| fp32. Its backward remains the original, unclipped, mask-free STE. | |
| """ | |
| return _NMQuantizeSTE.apply(weight, group_size) | |
| class SherryLinear(nn.Linear): | |
| """``nn.Linear``-compatible Sherry layer with an externally driven residual. | |
| Differences from AngelSlim ``Arenas``: ``eps`` is a persistent buffer, no | |
| forward counter exists, schedule constants are not hard-coded, the typo in | |
| the terminal branch is removed with that branch, and the master parameters | |
| remain fp32. The bias is added once rather than once per parallel path. | |
| """ | |
| def __init__( | |
| self, | |
| in_features: int, | |
| out_features: int, | |
| bias: bool = True, | |
| *, | |
| group_size: int = 128, | |
| device: torch.device | str | None = None, | |
| ) -> None: | |
| if in_features % group_size: | |
| raise ValueError( | |
| f"in_features ({in_features}) must be divisible by group_size ({group_size})" | |
| ) | |
| super().__init__( | |
| in_features, | |
| out_features, | |
| bias=bias, | |
| device=device, | |
| dtype=torch.float32, | |
| ) | |
| self.group_size = group_size | |
| self.register_buffer("eps", torch.tensor(0.0, dtype=torch.float32)) | |
| # Cached host float so forward can skip the residual path without | |
| # synchronizing on ``self.eps.item()`` every call. | |
| self._eps_py = 0.0 | |
| def set_eps(self, value: float | torch.Tensor) -> None: | |
| """Update the residual coefficient buffer and its host-side cache.""" | |
| eps = float(value.item() if isinstance(value, torch.Tensor) else value) | |
| self.eps.fill_(eps) | |
| self._eps_py = eps | |
| def _load_from_state_dict( | |
| self, | |
| state_dict: dict[str, torch.Tensor], | |
| prefix: str, | |
| local_metadata: dict[str, Any], | |
| strict: bool, | |
| missing_keys: list[str], | |
| unexpected_keys: list[str], | |
| error_msgs: list[str], | |
| ) -> None: | |
| """Accept native Linear checkpoints while still persisting ``eps``. | |
| AngelSlim's Python ``eps`` never appeared in checkpoints. Here it is a | |
| buffer, but treating an absent epsilon as zero preserves strict loading | |
| compatibility with existing native ``nn.Linear`` state dictionaries. | |
| """ | |
| eps_key = prefix + "eps" | |
| if eps_key not in state_dict: | |
| state_dict[eps_key] = self.eps.detach().clone() | |
| super()._load_from_state_dict( | |
| state_dict, | |
| prefix, | |
| local_metadata, | |
| strict, | |
| missing_keys, | |
| unexpected_keys, | |
| error_msgs, | |
| ) | |
| self._eps_py = float(self.eps.detach().item()) | |
| def from_linear(cls, linear: nn.Linear, *, group_size: int = 128) -> "SherryLinear": | |
| """Copy a native linear into an fp32-master Sherry layer. | |
| Unlike the original model-construction path, this wrapper works on any | |
| already-created Transformers model and upgrades bf16/fp16 weights to the | |
| fp32 latent master representation required for stable QAT. | |
| """ | |
| converted = cls( | |
| linear.in_features, | |
| linear.out_features, | |
| bias=linear.bias is not None, | |
| group_size=group_size, | |
| device=linear.weight.device, | |
| ) | |
| with torch.no_grad(): | |
| converted.weight.copy_(linear.weight.detach().float()) | |
| if linear.bias is not None and converted.bias is not None: | |
| converted.bias.copy_(linear.bias.detach().float()) | |
| converted.weight.requires_grad_(linear.weight.requires_grad) | |
| if linear.bias is not None and converted.bias is not None: | |
| converted.bias.requires_grad_(linear.bias.requires_grad) | |
| converted.train(linear.training) | |
| return converted | |
| def forward(self, input: torch.Tensor) -> torch.Tensor: | |
| """Apply quantized and annealed full-precision paths. | |
| AngelSlim mutates its schedule on every forward (including checkpoint | |
| recomputation). This implementation only reads the ``eps`` buffer; an | |
| :class:`ArenasScheduler` must update it once per optimizer step. | |
| When ``eps`` is zero the full-precision residual matmul is skipped. | |
| """ | |
| quantized_weight = nm_quantize(self.weight, self.group_size).to(input.dtype) | |
| output = F.linear(input, quantized_weight, None) | |
| if self._eps_py != 0.0: | |
| master_for_compute = self.weight.to(input.dtype) | |
| output = output + self.eps.to(input.dtype) * F.linear( | |
| input, master_for_compute, None | |
| ) | |
| if self.bias is not None: | |
| output = output + self.bias.to(input.dtype) | |
| return output | |
| class ArenasScheduler: | |
| """Optimizer-step scheduler for the additive Arenas residual coefficient. | |
| ``eps`` rises linearly from zero to one during warmup and then decays to zero. | |
| The scheduler is intentionally external: unlike AngelSlim's forward-local | |
| counter, gradient accumulation and activation checkpointing cannot advance it | |
| accidentally. Layer ``eps`` values persist in model checkpoints. | |
| """ | |
| def __init__( | |
| self, | |
| total_steps: int, | |
| warmup_frac: float = 0.1, | |
| schedule: str = "cosine", | |
| ) -> None: | |
| if not isinstance(total_steps, int) or total_steps < 2: | |
| raise ValueError("total_steps must be an integer of at least 2") | |
| if not 0.0 < warmup_frac < 1.0: | |
| raise ValueError("warmup_frac must be strictly between 0 and 1") | |
| if schedule not in {"cosine", "linear"}: | |
| raise ValueError("schedule must be 'cosine' or 'linear'") | |
| self.total_steps = total_steps | |
| self.warmup_frac = float(warmup_frac) | |
| self.schedule = schedule | |
| self.warmup_steps = min(total_steps - 1, max(1, int(total_steps * warmup_frac))) | |
| self.current_step = 0 | |
| def eps(self) -> float: | |
| """Return epsilon at the current optimizer step.""" | |
| step = min(self.current_step, self.total_steps) | |
| if step <= self.warmup_steps: | |
| return step / self.warmup_steps | |
| progress = (step - self.warmup_steps) / (self.total_steps - self.warmup_steps) | |
| if self.schedule == "linear": | |
| return max(0.0, 1.0 - progress) | |
| return 0.5 * (1.0 + math.cos(math.pi * progress)) | |
| def step(self) -> float: | |
| """Advance exactly one optimizer step and return the new epsilon.""" | |
| self.current_step = min(self.current_step + 1, self.total_steps) | |
| return self.eps | |
| def set_eps(self, model: nn.Module) -> list[str]: | |
| """Write the current epsilon to every Sherry layer and return its names. | |
| This replaces AngelSlim's non-resumable Python scalar mutation. Call it | |
| after ``optimizer.step()`` (and after :meth:`step`) so one scheduler tick | |
| always corresponds to one optimizer update. | |
| """ | |
| updated: list[str] = [] | |
| for name, module in model.named_modules(): | |
| if isinstance(module, SherryLinear): | |
| module.set_eps(self.eps) | |
| updated.append(name) | |
| return updated | |
| def state_dict(self) -> dict[str, int | float | str]: | |
| """Serialize external progress; layer epsilon itself is model-persistent.""" | |
| return { | |
| "total_steps": self.total_steps, | |
| "warmup_frac": self.warmup_frac, | |
| "schedule": self.schedule, | |
| "current_step": self.current_step, | |
| } | |
| def load_state_dict(self, state: dict[str, int | float | str]) -> None: | |
| """Restore progress after validating immutable schedule parameters.""" | |
| expected = (self.total_steps, self.warmup_frac, self.schedule) | |
| found = (state["total_steps"], state["warmup_frac"], state["schedule"]) | |
| if found != expected: | |
| raise ValueError(f"scheduler configuration mismatch: expected {expected}, got {found}") | |
| step = int(state["current_step"]) | |
| if not 0 <= step <= self.total_steps: | |
| raise ValueError("invalid current_step in scheduler state") | |
| self.current_step = step | |