Text-to-Speech
Safetensors
MLX
Zonos
mlx-audio
zonos2
tts
voice-cloning
quantized
4-bit precision
apple-silicon
Instructions to use amal-david/Zyphra-ZONOS2-4bit with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use amal-david/Zyphra-ZONOS2-4bit with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] huggingface-cli download --local-dir Zyphra-ZONOS2-4bit amal-david/Zyphra-ZONOS2-4bit
- Zonos
How to use amal-david/Zyphra-ZONOS2-4bit with Zonos:
# pip install git+https://github.com/Zyphra/Zonos.git import torchaudio from zonos.model import Zonos from zonos.conditioning import make_cond_dict model = Zonos.from_pretrained("amal-david/Zyphra-ZONOS2-4bit", device="cuda") wav, sr = torchaudio.load("speaker.wav") # 5-10s reference clip speaker = model.make_speaker_embedding(wav, sr) cond = make_cond_dict(text="Hello, world!", speaker=speaker, language="en-us") codes = model.generate(model.prepare_conditioning(cond)) audio = model.autoencoder.decode(codes)[0].cpu() torchaudio.save("sample.wav", audio, model.autoencoder.sampling_rate) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
| """Reproduce this mixed-precision quantization from the BF16 base. | |
| Recipe (verified to keep generation healthy — uniform 4-bit breaks EOS because | |
| 4-bit *attention* corrupts the model; the experts tolerate 4-bit fine): | |
| - 4-bit gs64 : MoE experts (SwitchGLU) <- 94.5% of weights, the bandwidth lever | |
| - 8-bit gs64 : attention wq/wo, token embeddings | |
| - bf16 : output head, MoE router, gater, per-head temp, RMSNorm, ChunkedLinear | |
| Run: | |
| pip install git+https://github.com/Amal-David/mlx-audio.git@zonos2-optimized | |
| python quantize.py --out Zyphra-ZONOS2-4bit | |
| """ | |
| from __future__ import annotations | |
| import argparse, json, shutil | |
| from pathlib import Path | |
| from mlx_audio.tts.utils import convert | |
| SRC = "mlx-community/Zyphra-ZONOS2" | |
| SKIP = ("router", "multi_output", "gater", "norm", "temp") | |
| def quant_predicate(path, module): | |
| if any(s in path for s in SKIP): | |
| return False | |
| if "experts" in path: | |
| return {"group_size": 64, "bits": 4} | |
| if "attention" in path: # wq/wo (gater already skipped); 4-bit here breaks EOS | |
| return {"group_size": 64, "bits": 8} | |
| if "embedders" in path: | |
| return {"group_size": 64, "bits": 8} | |
| return False # everything else stays bf16 | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--src", default=SRC) | |
| ap.add_argument("--out", default="Zyphra-ZONOS2-4bit") | |
| args = ap.parse_args() | |
| out = Path(args.out) | |
| if out.exists(): | |
| shutil.rmtree(out) | |
| convert(args.src, str(out), quantize=True, q_group_size=64, q_bits=4, q_mode="affine", | |
| quant_predicate=quant_predicate) | |
| # convert() copies the source bf16 shards in too; the loader globs *.safetensors, | |
| # so prune any shard not referenced by the quantized index. | |
| idx = json.load(open(out / "model.safetensors.index.json")) | |
| keep = set(idx["weight_map"].values()) | |
| for f in out.glob("*.safetensors"): | |
| if f.name not in keep: | |
| f.unlink() | |
| # ensure the speaker encoder (voice cloning) is present | |
| if not (out / "speaker_encoder").exists(): | |
| from huggingface_hub import snapshot_download | |
| src = Path(snapshot_download(args.src, allow_patterns=["speaker_encoder/*"])) | |
| shutil.copytree(src / "speaker_encoder", out / "speaker_encoder", dirs_exist_ok=True) | |
| sz = sum(f.stat().st_size for f in out.glob("*.safetensors")) / 1e9 | |
| print(f"done -> {out} ({sz:.2f} GB)") | |
| if __name__ == "__main__": | |
| main() | |