Instructions to use aruntemme/maya2-native-mlx with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use aruntemme/maya2-native-mlx with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] hf download aruntemme/maya2-native-mlx --local-dir maya2-native-mlx
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
Maya-2 Native on MLX (Apple Silicon)
An unofficial MLX port of the inference code for maya-research/maya2-native,
the open-weight Indic + English text-to-speech model by Maya Research. All credit for the model
goes to them. This repo contains code only: it loads the official weights from maya-research/maya2-native as they
are, with no conversion step and no re-upload.
The official release needs Linux and an NVIDIA GPU (CUDA graphs, Triton kernels). This port runs it natively on a Mac's GPU, one stream at a time. Every component was checked against the original PyTorch model (see Parity).
Listen
Generated on an M4 Max with this port (default exact mode):
| Language | Voice | Sample |
|---|---|---|
| English | Siddhant | |
| Hindi | Ritvik | |
| Tamil | Abhay | |
| Telugu | Nivedita |
Install
Needs macOS on Apple Silicon and Python 3.10–3.12.
python -m venv .venv && source .venv/bin/activate
pip install "maya2-mlx @ git+https://huggingface.co/aruntemme/maya2-native-mlx"
This also installs the official maya3 package from GitHub, pinned to the commit the parity checks were run against.
The release's text normaliser, prompt packer, voices and guards are reused from it. The weights (~5 GB), the Mimi
codec and the ECAPA speaker encoder download from Hugging Face on first use.
Use
import soundfile as sf
from maya2_mlx.tts import Maya2MLX
tts = Maya2MLX.from_pretrained() # exact port: bf16 backbone, fp16 depth decoder
wav = tts.generate("வணக்கம், எப்படி இருக்கீங்க?", lang="ta", voice="Kayal", normalize=True)
sf.write("speech.wav", wav, 24000)
# stream 80 ms int16 PCM frames as they are generated
for chunk in tts.stream("Your order has shipped.", lang="en", voice="Siddhant", normalize=True):
...
# clone a voice across languages (get the speaker's permission first)
tts.register_voice("my_voice", ref_audio="reference.wav", ref_text="<exact transcript>", lang="en")
wav = tts.generate("नमस्ते, आप कैसे हैं?", lang="hi", voice="my_voice", normalize=True)
- Same API as the official Python interface:
generate()andstream()take the same keyword arguments asmaya3.Maya3TTS:seed,temperature,top_k,top_p,repetition_penalty,max_frames,ref_audio/ref_text/ref_lang,return_info. - Voices: all 20 named voices from the release are available.
- Cloning: the reference clip is encoded once with the PyTorch Mimi encoder and ECAPA on CPU. Generation itself runs on MLX.
- Fast mode:
Maya2MLX.from_pretrained(backbone_bits=8, depth_dtype="bf16"), an opt-in trade-off measured below.
Speed (M4 Max, 36 GB)
| Time to make 1 s of audio | Time to first audio | Peak memory | |
|---|---|---|---|
Official PyTorch engine on MPS (with patches/maya2-mps.patch) |
0.94 s | 120 ms | – |
| This port, exact (default) | 0.41 s | 60 ms | 6.1 GB |
| This port, fast (8-bit backbone + bf16 depth) | 0.30 s | 50 ms | 4.5 GB |
Load plus warmup takes about 3.5 s.
Intelligibility
Character error rate when Whisper large-v3-turbo transcribes the output (one sample per clip; lower is better):
| en | hi | ta | te | bn | kn | mr | clone en→hi | |
|---|---|---|---|---|---|---|---|---|
| Official PyTorch engine | 0.00 | 0.15 | 0.00 | 0.13 | 0.20 | 0.13 | 0.27 | 0.07 |
| This port, exact | 0.00 | 0.03 | 0.00 | 0.07 | 0.17 | 0.09 | 0.14 | 0.07 |
| This port, fast | 0.00 | 0.06 | 0.04 | 0.07 | 0.22 | 0.20 | 0.11 | 0.07 |
With a single sample per language, read these as "the same quality". Most remaining errors are Whisper's spelling of Indic scripts.
Parity with the PyTorch model
Each component was compared with the original code on identical inputs, using real model states rather than random
ones. The raw output is in parity/results.txt.
| Component | Result |
|---|---|
| Prompt embeddings | 97–99% bit-identical; the rest differ by 1 bf16 ulp |
| Backbone (Qwen3-1.7B) hidden state | error at or below PyTorch's own bf16 noise; same cb0 argmax in all cases; cb0 KL ≤ 2e-3 |
| Depth decoder, 31 levels | logit error vs fp32 1.4e-3 (PyTorch fp16 itself: 1.3e-3); greedy codes 95–97% equal to the engine's |
| Mimi streaming decoder | 122 dB SNR vs the engine's decoder (fp32 rounding) |
| Fast-mode costs | 8-bit backbone: cb0 KL 4.5e-3; bf16 depth: 8× the fp16 logit error; 4-bit backbone rejected (KL 0.32) |
The parity scripts need the original PyTorch engine to run on a Mac. Its CUDA-graph decoders need the small patch in
patches/maya2-mps.patch, which also lets the official engine run on Apple's MPS
backend. Apply it to a checkout of MayaResearch/maya2-native at the pinned commit, install that checkout, then run:
PYTHONPATH=parity:. python parity/check_backbone.py # also check_depth.py, check_mimi.py, check_variants.py
How it maps to the original
| File | Mirrors |
|---|---|
maya2_mlx/backbone.py |
Qwen3 decoder with a preallocated KV cache (serve/fast_backbone.py) |
maya2_mlx/depth.py |
31-level depth decoder in one compiled graph per frame (serve/fast_depth.py) |
maya2_mlx/mimi.py |
streaming Mimi decoder built from the HF module tree (serve/fast_codec.py) |
maya2_mlx/prompt.py |
prompt packing via the release's own collate, plus compose_inputs |
maya2_mlx/tts.py |
the engine's per-seat loop: controlled stop, sampling, loop guard, voices |
Limits
- One stream at a time. The CUDA engine's continuous batching across many concurrent streams isn't ported.
- No HTTP / WebSocket server. The release's
maya3.serverdrives the PyTorch engine. - Seeds aren't portable. A seed reproduces audio within this port, but not the CUDA engine's audio, because the random number generators differ. The sampling distributions are the same.
- Where the time goes. About two thirds of each 80 ms frame goes to the depth decoder's small-matrix kernels across 31 dependent levels. The bf16 backbone step is at its memory-bandwidth floor.
License and credit
The code is Apache-2.0, like the original. It's derived from MayaResearch/maya2-native, and the model weights, voices and evaluation are Maya Research's. Please cite their release: maya-research/maya2-native.
This port is not affiliated with or endorsed by Maya Research.