Text-to-Speech
Transformers
Safetensors
Kabyle
agbalu_speech
feature-extraction
kabyle
taqbaylit
berber
amazigh
speech-synthesis
voice-cloning
cross-lingual-voice-cloning
expressive-speech
low-resource
custom_code
Instructions to use agbalu/Matoub-4B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use agbalu/Matoub-4B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-to-speech", model="agbalu/Matoub-4B", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("agbalu/Matoub-4B", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
Download adaptation.py from agbalu/Matoub-4B: direct link, hf CLI and curl.
- Browser
- Download file 5.02 kB
-
https://huggingface.co/agbalu/Matoub-4B/resolve/main/adaptation.py
- Command line
-
hf download hf://agbalu/Matoub-4B/adaptation.py
-
curl -L -o adaptation.py https://huggingface.co/agbalu/Matoub-4B/resolve/main/adaptation.py
5.02 kB
| """Adapt only the selected decoder projections with rank-32 LoRA.""" | |
| from __future__ import annotations | |
| import math | |
| from collections.abc import Iterator, Mapping | |
| from contextlib import contextmanager | |
| from typing import Final | |
| import torch | |
| from torch import Tensor, nn | |
| from torch.nn import functional | |
| from .backbone import Generator | |
| PROJECTIONS: Final = frozenset(('q_proj', 'k_proj', 'v_proj', 'o_proj', 'gate_proj', 'up_proj', 'down_proj')) | |
| RANK: Final = 32 | |
| SCALE: Final = 2.0 | |
| class AdaptedLinear(nn.Module): | |
| def __init__(self, original: nn.Linear) -> None: | |
| super().__init__() | |
| self.original = original | |
| self.original.requires_grad_(False) | |
| self.factor_a = nn.Parameter(torch.empty(RANK, original.in_features, dtype=torch.float32, device=original.weight.device)) | |
| self.factor_b = nn.Parameter(torch.zeros(original.out_features, RANK, dtype=torch.float32, device=original.weight.device)) | |
| nn.init.kaiming_uniform_(self.factor_a, a=math.sqrt(5)) | |
| self.is_enabled = True | |
| self.inference_scale = 1.0 | |
| def forward(self, inputs: Tensor) -> Tensor: | |
| output: Tensor = self.original(inputs) | |
| if not self.is_enabled: | |
| return output | |
| adapted = functional.linear(functional.linear(inputs.to(self.factor_a.dtype), self.factor_a), self.factor_b) | |
| return output + (adapted * (SCALE * self.inference_scale)).to(output.dtype) | |
| def merged_weight(self) -> Tensor: | |
| delta = self.factor_b.float() @ self.factor_a.float() * (SCALE * self.inference_scale) | |
| return (self.original.weight.float() + delta).to(self.original.weight.dtype) | |
| def inject_adapter(model: Generator) -> tuple[str, ...]: | |
| model.requires_grad_(False) | |
| selected: list[str] = [] | |
| for name, layer in tuple(model.named_modules()): | |
| if isinstance(layer, nn.Linear) and name.rsplit('.', 1)[-1] in PROJECTIONS: | |
| parent_name, attribute = name.rsplit('.', 1) | |
| model.get_submodule(parent_name).set_submodule(attribute, AdaptedLinear(layer)) | |
| selected.append(name) | |
| expected = model.geometry.layers * len(PROJECTIONS) | |
| trainable = sum((parameter.numel() for parameter in model.parameters() if parameter.requires_grad)) | |
| if len(selected) != expected or trainable != model.geometry.adapter_parameters: | |
| message = f'adapter contract failed: projections={len(selected)}/{expected}' | |
| message += f', parameters={trainable}/{model.geometry.adapter_parameters}' | |
| raise ValueError(message) | |
| return tuple(selected) | |
| def adapter_state(model: Generator) -> dict[str, Tensor]: | |
| return {name: parameter.detach().cpu().clone() for name, parameter in model.named_parameters() if parameter.requires_grad} | |
| def restore_adapter(model: Generator, state: Mapping[str, Tensor]) -> None: | |
| expected = {name: parameter for name, parameter in model.named_parameters() if parameter.requires_grad} | |
| if set(state) != set(expected): | |
| message = f'adapter keys mismatch: missing={set(expected) - set(state)}' | |
| message += f', extra={set(state) - set(expected)}' | |
| raise ValueError(message) | |
| with torch.no_grad(): | |
| for name, parameter in expected.items(): | |
| tensor = state[name] | |
| if tensor.shape != parameter.shape or not bool(torch.isfinite(tensor).all().item()): | |
| message = f'invalid adapter tensor {name}: shape={tensor.shape}' | |
| message += f', expected={parameter.shape}' | |
| raise ValueError(message) | |
| parameter.copy_(tensor) | |
| def merge_adapter(model: Generator) -> None: | |
| for name, layer in tuple(model.named_modules()): | |
| if isinstance(layer, AdaptedLinear): | |
| with torch.no_grad(): | |
| layer.original.weight.copy_(layer.merged_weight()) | |
| parent, attribute = name.rsplit('.', 1) | |
| model.get_submodule(parent).set_submodule(attribute, layer.original) | |
| def disabled_adapter(model: Generator) -> Iterator[None]: | |
| layers = [(layer, layer.is_enabled) for layer in model.modules() if isinstance(layer, AdaptedLinear)] | |
| try: | |
| for layer, _ in layers: | |
| layer.is_enabled = False | |
| yield | |
| finally: | |
| for layer, previous in layers: | |
| layer.is_enabled = previous | |
| def scaled_adapter(model: Generator, multiplier: float) -> Iterator[None]: | |
| if not math.isfinite(multiplier) or multiplier < 0: | |
| message = f'adapter multiplier must be finite and nonnegative, got {multiplier!r}' | |
| raise ValueError(message) | |
| layers = [(layer, layer.inference_scale) for layer in model.modules() if isinstance(layer, AdaptedLinear)] | |
| if not layers and multiplier != 1: | |
| message = 'adapter scaling requires unmerged adapter weights' | |
| raise ValueError(message) | |
| try: | |
| for layer, _ in layers: | |
| layer.inference_scale = multiplier | |
| yield | |
| finally: | |
| for layer, previous in layers: | |
| layer.inference_scale = previous | |