--- license: apache-2.0 language: - as - bn - en - gu - hi - kn - ml - mr - or - pa - ta - te library_name: mlx pipeline_tag: text-to-speech base_model: maya-research/maya2-native tags: - mlx - apple-silicon - text-to-speech - tts - indic - multilingual - mimi - 8-bit --- # Maya 2 Native for MLX (dynamic 8-bit) An Apple Silicon (MLX) port of [Maya 2 Native](https://huggingface.co/maya-research/maya2-native) by Maya Research: streaming text-to-speech for 11 Indic languages and English, with 20 built-in voices. It runs with no PyTorch and no CUDA, faster than real time on an M5. - **Ported line by line** from the [official code](https://github.com/MayaResearch/maya2-native) (commit `c6b3768`): the backbone, the depth decoder, the Mimi decoder, the sampler with its stop rules and guards, the official random-number stream, text splitting, prompts and the tokenizer. - **Proven against the official model** before quantizing: at the official 16-bit precision the port gives the same codes, stops and audio (within one int16 step) as the official code on every test request (strict gates, fp32), and the same accuracy at its own precision (production gates). - **Dynamic 8-bit weights** (`models/maya2-8bit`, in the spirit of Unsloth's dynamic quants): every tensor's sensitivity was measured against the official model; the outliers and the sensitive depth decoder stay 16-bit, the rest is 8-bit. 3.57 GB, with a sampling shift about 1.2× the official 16-bit model's own rounding noise in all 12 languages. (A plain 8-bit set, every weight 8-bit, was measured too and left out: up to 7× the official noise.) Independent port; not an official Maya Research release. See `NOTICE.md`. ## Quickstart Requirements: an Apple Silicon Mac, Python 3.11, about 6 GB of free memory. ```bash hf download zero0303/maya2-mlx-dynamic-8bit --local-dir maya2-mlx cd maya2-mlx uv venv --python 3.11 .venv VIRTUAL_ENV=$PWD/.venv uv pip install "mlx==0.32.4" numpy "tokenizers==0.22.2" .venv/bin/python -I speak.py "A heap keeps its smallest item at the top." --voice Malini --seed 7 -o heap.wav .venv/bin/python -I speak.py --voices ``` From Python: ```python import sys; sys.path.insert(0, "maya2-mlx") from maya2_mlx import Maya2 tts = Maya2() # models/maya2-8bit wav = tts.generate("नमस्ते, आप कैसे हैं?", lang="hi", voice="Vaidehi", seed=11) # float32, 24 kHz, in [-1, 1] for pcm in tts.stream("Long text ...", lang="en", voice="Anirban"): # int16 chunks as they are made ... ``` `generate` / `stream` follow the official `Maya3TTS` API: `lang`, `voice` (a built-in name, case-insensitive, or `None` for the plain voice), `seed`, `temperature`, `top_k`, `top_p`, `repetition_penalty` (the codebook-0 sampler), `max_frames`, `normalize` (the bundled text normaliser: digits, currency, dates, URLs). Long text is split into ~20-second pieces with 0.15 s gaps, as in the official engine. The same seed gives the same audio. ## Voices | Voice | | | Description | Trained languages | |---|---|---|---|---| | Ahana | female | young | bright, youthful | 11 | | Vaidehi | female | adult | calm, gentle | 11 | | Malini | female | mature | steady narrator | 11 | | Charvi | female | young | energetic, upbeat | 11 | | Jahnavi | female | adult | warm, friendly | 10 (not pa) | | Anirban | male | adult | steady narrator | 11 | | Nakul | male | young | bright, youthful | 11 | | Vasant | male | mature | steady narrator | 10 (not pa) | | Siddhant | male | adult | clear, professional | 11 | | Satvik | male | young | warm, friendly | 11 | | Abhay, Akshat, Shaunak | male | adult / young | natural conversational | en, hi | | Nivedita, Tanushree | female | adult | natural conversational | en, hi | | Ishwari, Vrinda | female | adult / young | natural conversational | hi | | Ritvik | male | adult | natural conversational | hi | | Sreekar | male | adult | natural conversational | en, hi, te | | Kayal | female | adult | natural conversational | en, ta | "11" = bn, en, gu, hi, kn, ml, mr, or, pa, ta, te. Other languages work cross-lingually (Assamese for every voice). ## Speed and quality Measured on an M5 (24 GB), the same 23.4 s English paragraph, and the parity gates against the official model (plain 8-bit and 16-bit for comparison; only the dynamic 8-bit is in this repository): | | **Dynamic 8-bit** (this repository) | Plain 8-bit | 16-bit | |---|---|---|---| | Download | 3.57 GB | 2.93 GB | 5.24 GB | | Peak memory | 5.8 GB | 4.2 GB | 8.2 GB | | Time for 23.4 s of speech | 18.4 s (1.27× real time) | 15.5 s (1.5×) | 20.6 s (1.14×) | | Sampling shift vs exact, 12 languages (official 16-bit noise = 1×) | ~1.2× (0.6–2×) | ~3.5× (1.5–7×) | 1× | | Depth decoder (fine sound detail) | exact, as the official | 1.6–2.8% error; decisions change beyond near-ties | exact | | Parity gates vs the official model | 101/101 | 86/101 | 101/101 | ## Files | File (`models/maya2-8bit/`) | Size | Contents | |---|---|---| | `backbone-main.safetensors` | 460 MB | token embeddings (8-bit), final norm, cb0 head, RoPE tables | | `backbone-layers-00/07/14/21.safetensors` | 4 × 396-407 MB | 28 Qwen3-shaped layers, linears 8-bit (layers 2 and 27 down-projection kept 16-bit) | | `depth.safetensors` | 1.10 GB (16-bit) | depth decoder | | `audio_in.safetensors` | 151 MB | feedback table, 8-bit | | `mimi.safetensors` | 230 MB | Kyutai Mimi decoder, fp32 | | `anchor.safetensors` | 2.3 MB | speaker anchor, bf16 | | `tokenizer.json`, `voices.json`, `meta.json`, `quant.json` | 16 MB | tokenizer, voices, source checksums, quantization recipe | | **total** | **3.57 GB** | | Code: `maya2_mlx/` (the port), `maya3/` and `configs/` (official files, unchanged), `speak.py`. The parity tests against the official model, the export and quantization scripts and the 16-bit MLX export are not part of this repository; their results are summarised below. ## How it was checked | | Result | |---|---| | Tokenizer | 546/546 prompts identical to the official (12 languages × 13 voices, Devanagari edge cases) | | Strict gates (fp32, CPU and GPU) | 92/92 each: identical sampler decisions and codes on every frame, same free-running requests (37 s / 3 pieces included) | | Production gates (16-bit) | 101/101: as accurate as the official bf16 (error ratio 1.02); depth flips only at near-ties, as the official's own fp32-vs-fp16 | | Dynamic 8-bit | 101/101 against the official model; sampling shift 1.2× the 16-bit floor | | Reviews | two independent code reviews against the official source; one hidden issue found and fixed (the official engine builds RoPE from bf16 frequencies) | ## Not included Voice cloning (ECAPA speaker encoder, Mimi encoder), emotion-tag evaluation, multi-request batching and the HTTP server. One request at a time. ## Licenses and credit Maya 2 Native weights and code © Maya Research, Apache-2.0 (`LICENSE`). Kyutai Mimi © Kyutai, CC BY 4.0 (decoder only, re-laid out for MLX). Qwen3 architecture, Apache-2.0. Details and the original citation: `NOTICE.md`. Use the voices responsibly: disclose synthetic speech, no impersonation (see the [original model card](https://huggingface.co/maya-research/maya2-native#intended-use-and-responsible-deployment)).