Inference runtime for ZONOS3-Mini, Zyphra's multilingual text-to-speech model: HTTP servers that serve the Zonos Voice Studio, an in-browser WebGPU build and an offline Python API. Model details are in About ZONOS3-Mini.
Blog post · Weights · Run in your browser (no install) · Zyphra Cloud · ZTTS2-Eval
| Machine | Backend | Setup |
|---|---|---|
| Linux x86_64 with an NVIDIA GPU (tested on H100) | CUDA server on Mini-SGLang (servers/sgl) |
below |
| Apple Silicon Mac | MLX server (servers/mlx) |
below; details in servers/mlx/README.md |
| CPU, CUDA, Metal or Vulkan, no Python at runtime | C++/ggml server and CLI (servers/ggml) |
servers/ggml/README.md |
| A browser with WebGPU, no server | In-browser server (servers/web, the studio's ?api=web) |
nothing to install: run it in your browser; to build it, servers/web/README.md |
Every server implements the same HTTP API and serves the same studio.
- uv; the project pins Python 3.12.
- ggml server: a Rust toolchain (rustup, stable). Its CMake build compiles the text normalizer's C library from the zyphra-textnorm submodule with cargo; the Python servers install the same normalizer's wheel from PyPI.
- The weights come from the public Hugging Face repo
Zyphra/ZONOS3-Mini; no token is needed.- CUDA server: the PyTorch weights (
lm/,autoencoder/,speaker_encoders/, about 9 GB with the default decoder), downloaded into the Hugging Face cache on first use. - MLX, ggml and in-browser servers: the
gguf/andweb/folders.
- CUDA server: the PyTorch weights (
- CUDA server: the CUDA 12.8 toolkit (
CUDA_HOME, default/usr/local/cuda-12.8).
git clone --recurse-submodules git@github.com:Zyphra/ZONOS3.git
cd ZONOS3
uv sync --locked --all-packages # Linux with an NVIDIA GPU
uv sync --locked --package zonos3-mlx # Apple SiliconIn an existing checkout, git submodule update --init third_party/fusealign-multilingual fetches the FuseAlign
aligner; the ggml server also needs servers/ggml/ggml and the text normalizer, third_party/zyphra-textnorm.
# Linux with an NVIDIA GPU: the release LM on 127.0.0.1:1919
servers/sgl/scripts/serve.sh
# Apple Silicon: fetch the GGUF files once (servers/ggml/gguf/), then serve on 127.0.0.1:1919
hf download Zyphra/ZONOS3-Mini --include 'gguf/*' --local-dir servers/ggml
servers/mlx/scripts/serve.shThe first CUDA start JIT-compiles kernels, which takes several minutes. Ports, voices, steering and other settings are in Server configuration.
Open http://127.0.0.1:1919/ and pick an app: Zonos Voice Studio (/studio) or the lightweight voice-cloning
page /lite (pick, upload, record or load a voice embedding, then speak with it; see
studio/README.md).
Or from the command line, with the first default voice and the OpenAI-compatible endpoint:
VOICE=$(curl -s http://127.0.0.1:1919/v2/speakers | python3 -c 'import json, sys; print(json.load(sys.stdin)["speakers"][0]["id"])')
curl -X POST http://127.0.0.1:1919/v1/audio/speech -H 'Content-Type: application/json' \
-d "{\"model\": \"zonos3\", \"input\": \"Hello from ZONOS3.\", \"voice\": \"$VOICE\", \"response_format\": \"wav\"}" \
--output hello.wavvoice is a speaker id of GET /v2/speakers; response_format is pcm (default) or wav.
POST /v2/generate is the native endpoint. Every request should carry a voice: a reference clip
(speaker_audio_base64) or the id of a voice listed by GET /v2/speakers (speaker_embedding_id). Without one,
generation is unconditioned.
# Request body with a reference clip
python3 - <<'EOF' > body.json
import base64, json
print(json.dumps({"text": "Hello from ZONOS3.", "language": "en_us", "stream": False,
"speaker_audio_base64": base64.b64encode(open("assets/default_voices/AmericanFemale.mp3", "rb").read()).decode()}))
EOF
# Whole utterance: raw float32 little-endian PCM, 44.1 kHz mono (the seed used comes back in X-Seed)
curl -X POST http://127.0.0.1:1919/v2/generate -H 'Content-Type: application/json' -d @body.json --output hello.pcm
ffmpeg -f f32le -ar 44100 -ac 1 -i hello.pcm hello.wavstream: true returns the audio progressively (an incremental decode of the causal decoder); "format": "wav" returns a
buffered 16-bit WAV instead of raw PCM (with stream: false). The API guide is docs/api.md; the
schemas are in servers/api/openapi.yaml.
source servers/sgl/scripts/env.sh
uv run --locked --package zonos3-sgl pythonfrom zonos3_sgl.tts import TTSLLM, TTSSamplingParams
# The server's settings: FlashAttention, per-request (naive) cache, and half the GPU for the KV cache so the codec
# encoder and decoder fit next to it.
tts = TTSLLM(model_path="hf://Zyphra/ZONOS3-Mini/lm/zonos3_mini",
attention_backend="fa", cache_type="naive", memory_ratio=0.5)
result = tts.generate_one("Hello from the offline Python API.", TTSSamplingParams(seed=42), language="en_us")
tts.save_audio(result["audio"], "offline.wav")
# Clone a voice from a reference clip (raw reference prefix) or a speaker embedding
(cloned,) = tts.generate(["This is spoken in the cloned voice."], TTSSamplingParams(seed=42),
speaker_reference_audio="assets/default_voices/AmericanFemale.mp3")
emb = tts.embed_speaker_file("assets/default_voices/AmericanFemale.mp3")
by_embedding = tts.generate_one("Same voice, from its embedding.", TTSSamplingParams(seed=42), speaker_embedding=emb)
# Stream one prompt as the server streams /v2/generate (silence prefill, prefix codec stream, early first chunk):
# float32 PCM chunks at 44.1 kHz as soon as they decode
for chunk in tts.generate_stream("Streamed from the offline API.", TTSSamplingParams(seed=42), speaker_embedding=emb):
play(chunk)The offline path applies the server's text normalization and conditioning (speaker, condition rows, accents, LACI);
generate_stream runs the server's streaming request without the frontend, the tokenizer process and their IPC (its
first call primes the codec stream and captures its CUDA graphs, as the server's tokenizer does at start).
servers/sgl/scripts/serve.sh sources servers/sgl/scripts/env.sh (CUDA toolchain, the TileLang gated-DeltaNet
backend and the five ZONOS3_USE_TRAINING_* exact-mode kernels; on a pre-Hopper GPU such as the A100 it selects the
portable Triton experts and gated-DeltaNet kernels instead, see
docs/tts_architecture.md) and serves the release LM
hf://Zyphra/ZONOS3-Mini/lm/zonos3_mini on 127.0.0.1:1919 with --attention-backend fa --cache-type naive, two running requests and CUDA graphs. Extra server flags are appended (e.g.
servers/sgl/scripts/serve.sh --port 1920). servers/mlx/scripts/serve.sh serves the GGUF files of
the gguf/ folder of Zyphra/ZONOS3-Mini with the same variables:
| Variable | Effect |
|---|---|
SERVE_MODEL |
Checkpoint directory or hf:// location (--model-path); default the release LM |
SERVE_VOICES |
Default-voice directory (--tts-default-voices-dir); default assets/default_voices/ |
STEER_BUNDLE |
Steering bundle (--steer-bundle) behind every steering control (emotion axes, styles, accent directions, word emphasis, …); default assets/steering/studio_bundle_mect60k_x10.json, empty serves no controls |
PHONEME_LEXICON |
Gold pronunciation lexicon directory (--tts-phoneme-lexicon) for POST /v2/phonemize |
ZONOS3_STUDIO_PROJECTS |
Shared studio project store (--studio-projects-dir); empty (default) keeps projects in the browser |
LACI_HEADS |
"lang=path ..." LACI alignment heads (--laci-heads) |
LACI_ALL |
1 passes LACI heads for every server language, from LACI_HEADS_DIR (default assets/laci_heads/): the directory's *_heads.json for every language, overridden by a *_heads_<speech code>.json (one per non-English language); en_gb included |
PLUGINS |
"name ..." server plugins (--plugins), e.g. dub from Zyphra/ZONOS3-dub |
The studio's steering controls come from STEER_BUNDLE.
- Speech recognition (optional for speech editing: transcripts of clips sent without one, and
verify) is Qwen3-ASR (Qwen/Qwen3-ASR-1.7B) in its own venv:bash tools/setup_asr_env.shonce creates.venv-asr(qwen-asr pins its own transformers). One worker process per server (model/src/zonos3/workers/asr.py) starts on first use;ZONOS3_ASR_PYTHONoverrides its interpreter (default.venv-asr/bin/python) andZONOS3_ASR_DEVICEits device (defaultcuda:0, else CPU). Without it/v2/capabilitiesreportsedit_transcribe: false, and editing needs the clip's transcript. - Speech editing needs the speech-edit LoRA (sgl:
--accent-adapters <dir with z3m_omni3b_edit_lora.pt>on the release LM; the LoRA is in the privateZyphra/ZONOS3_Mini,lm/rate30_20k_r2grpo/edit_lora/; see docs/guide.md) or an edit checkpoint (SERVE_MODEL=<edit checkpoint>), and FuseAlign for the word timings. The ggml and MLX servers get it fromgguf/backbone-ptq-edit.ggufandgguf/edit/accents.gguf. - Forced alignment (speech editing) is the FuseAlign aligner: the submodule
third_party/fusealign-multilingual(Zyphra/fusealign-multilingual, packagefusealign-hub, Apache-2.0, installed byuv sync) and its checkpoint from the Hugging Face repoZyphra/fusealign(one 1.34 GB file, downloaded on the first alignment). It runs in one worker process per server (model/src/zonos3/workers/fusealign.py, the workspace interpreter), started on first use;ZONOS3_FUSEALIGN_DEVICEpicks its device (defaultcuda:0, else CPU). Recordings over 30 s (or transcripts over 1022 UTF-8 bytes) are aligned long-form, anchored by Qwen3-ASR transcripts of their voice-activity chunks (at most 25 s each), or without speech recognition by FuseAlign's own voice-activity map; FuseAlign's built-in Whisper anchoring is never used. - Phoneme input, the start marker and pause markers read the release text rows (public
Zyphra/ZONOS3-Mini,lm/zonos3_mini/text_rows/pause_tokens_s5000.pt: phoneme, start and pause tokens), whichservers/sgl/scripts/serve.shandpython -m zonos3.referenceload with the release LM (other checkpoints:SERVE_TEXT_ROWS/--phoneme-rows; GGUFconvert_gguf.py lm --phoneme-rows;gguf/backbone-ptq-edit.ggufalready has them), or a checkpoint merged with them (tools/add_text_extra_rows.py). "Phonemize selection" needsPHONEME_LEXICON=<lexicon dir>(lexicons/gold_phonemes_v1of the privateZyphra/ZONOS3_Minirepo).uv sync --group phonemizeadds espeak-ng guesses forPOST /v2/phonemize(GPL-3.0, opt-in). - Accent adapters need
--accent-adapters <dir>.
ZONOS3-Mini is an 11-layer language model that mixes gated-DeltaNet layers with global attention (one global layer in four), uses Full AttnRes residuals and a latent mixture-of-experts. It reads SuperBPE text tokens and predicts 10 × 4096 dual-codec audio codes at 15 Hz. A causal multi-resolution iSTFT decoder turns the codes into 44.1 kHz audio. Voices are cloned from a raw reference clip (encoded into the same codes) or from a 192-d MECT-B2 speaker embedding.
The blog post covers training and architecture (the ZAC-1 codec, DPO and GRPO post-training), the ZTTS2-Eval results, comparisons with other TTS models, and control examples (voice design, accents, span whispering, emotion, pace, projection, liveliness) with their control values.
| Feature | Where |
|---|---|
HTTP API (/v2/generate, /v1/audio/speech, /v2/phonemize, …) |
docs/api.md, servers/api/openapi.yaml |
| Raw-reference and embedding voice cloning, speaker CFG, condition rows | docs/guide.md |
| Steering controls (emotion axes, moods, styles, voice quality, accent directions) and accent adapters | docs/guide.md |
| Speech editing | docs/guide.md |
| Pronunciation input (phoneme tokens), start and pause tokens | docs/guide.md |
| Zonos Voice Studio, server projects | docs/guide.md, studio/README.md |
| LACI, duration targets and server plugins (Dub: Zyphra/ZONOS3-dub) | docs/guide.md |
| Feature overview | docs/features.md |
| Runtime architecture and vocoder | docs/tts_architecture.md, docs/structures.md |
| Release checkpoints and registries | docs/release_checkpoints.md |
| Path | Contents |
|---|---|
model/ |
The zonos3 package: codec, speaker encoders, prompt / conditioning / steering / LACI code, the speech-editing runtime every server serves, the server plugin seam, registries and the Python workers (speech recognition, forced alignment, the ggml server's Python host) |
servers/sgl/ |
The zonos3-sgl package (zonos3_sgl): the CUDA server built on Mini-SGLang, its launch scripts and benchmark |
servers/ggml/ |
The C++/ggml server and CLI (CPU, CUDA, Metal, Vulkan); ggml is the submodule servers/ggml/ggml |
servers/mlx/ |
The zonos3-mlx package (zonos3_mlx): the Apple Silicon server running the ggml server's GGUF files in MLX |
servers/web/ |
The zonos3-web package: the in-browser server (WebGPU in a Web Worker, the v2 API behind a fetch-compatible transport) the studio runs with ?api=web |
studio/ |
Zonos Voice Studio (Preact, pnpm); studio/dist/ is the committed production build every server serves at / |
tools/ |
Checkpoint and GGUF conversion tools (zonos3-tools) |
servers/api/ |
The HTTP contract every server implements (openapi.yaml, its bundled openapi.json) and its conformance tests (zonos3-api) |
servers/space/ |
The ZeroGPU Hugging Face Space (app.py) and its deploy script |
assets/ |
Runtime assets shared by the servers: default_voices/, steering/ (steering bundles), laci_heads/ (LACI alignment heads) |
third_party/ |
Third-party license texts (third_party/licenses/) and the submodules: FuseAlign and the text normalizer zyphra-textnorm (Rust ports of the NeMo grammars; the ggml server links its C library, the Python servers install its PyPI wheel) |
model/ holds a plain-PyTorch implementation of the full generation path (zonos3.reference), the numerical oracle
for both servers. It runs on CPU or GPU:
uv run python -m zonos3.reference --model hf://Zyphra/ZONOS3-Mini/lm/zonos3_mini \
--text "Hello from the reference." -o ref.wav --device cuda--request req.json takes a v2 GenerateRequest instead of --text. GGUF files for the ggml server are built from
the same modules with uv run --package zonos3-tools python tools/convert_gguf.py <subcommand> (--help lists them).
Lingua training checkpoints are converted with tools/convert_lingua_checkpoint.py.
The repo is a uv workspace (model, servers/sgl, servers/mlx, tools, servers/api); the text normalizer comes
from PyPI (zyphra-textnorm), and the dev group (installed by default) holds the test tools.
source servers/sgl/scripts/env.sh
uv run --locked --group phonemize pytestTests that load weights run when ZONOS3_TEST_MODEL names a checkpoint (e.g. the release LM) and a GPU is present.
The API conformance suite runs against a live server of any kind (tests of capabilities the server lacks skip):
uv run --package zonos3-api pytest servers/api/tests/conformance --base-url http://127.0.0.1:1919The ggml parity tests compare the C++ build with the reference:
uv run --package zonos3-tools pytest servers/ggml/tests/parity --ggml-build servers/ggml/build. On Apple Silicon,
uv run --package zonos3-mlx pytest servers/mlx/tests runs the MLX server's tests (they skip elsewhere).
pnpm install at the root installs the pnpm workspace (studio, studio/mcp, servers/web; one pnpm-lock.yaml);
every typecheck, build and test script regenerates the untracked src/api/schema.ts from servers/api/openapi.json
first (gen:api). pnpm --dir servers/web test runs the in-browser server's unit tests, pnpm --dir studio/mcp test
the MCP server's, and pnpm --dir servers/web parity the WebGPU parity checks against CPU ggml goldens in headless
Chrome.
ZONOS3 is released under the MIT License. Third-party components are listed in NOTICE and
third_party/licenses/.
If you find this model useful in an academic context, please cite the technical report:
@misc{zyphra2026zonos3mini,
title = {{ZONOS3-Mini Technical Report}},
author = {Gabriel Clark and Sofian Mejjoute and George Close and Beren Millidge},
year = {2026},
eprint = {2611.16525},
archivePrefix = {arXiv},
primaryClass = {cs.SD},
url = {https://arxiv.org/abs/2611.16525},
}