index-tts-2.5-mnn
IndexTTS-2.5 voice cloning on MNN — fast CPU inference (x86 / ARM, Linux / Windows / macOS), torch-free, and ships as a one-click uvx package that auto-downloads the weights from Hugging Face.
- Voice cloning from a short reference clip (≤15 s) — Chinese / English / Japanese / Cantonese, including mixed-language text with numbers and abbreviations.
- Reference-exact decoding: both shipped quant sets reproduce the PyTorch CPU reference greedy acoustic tokens exactly (73/73 and 83/83 on the verification fixtures); fp32 is additionally bit-exact at every stage.
- Torch-free: numpy + pymnn only. No PyTorch, no ONNX Runtime, no MLX.
- Quantized by default: every module ships as fp16 weights (fp32 compute) — half the download of fp32, gate-verified to reproduce the reference greedy acoustic tokens 100% on both zh/en fixtures.
Platform: any OS with Python 3.10+. The pip
MNNwheel is CPU-only; on Apple Silicon the MLX build (GPU) is ~7× faster than real-time, and on NVIDIA GPUs the ONNX build with CUDA is the fast path. This package is the fast CPU option — its BigVGAN vocoder runs ~4× faster than ONNX Runtime CPU.
Features
- Zero-shot voice cloning — supply any ≤15 s clean reference; the timbre and speaking style are carried into the output. Build the speaker once and reuse it across unlimited lines.
- Multilingual + code-switching —
zh,en,ja,yue, and mixed text in a single sentence (e.g.Use the CPU or GPU, 都可以). - Text normalization — numbers, abbreviations and symbols are read out correctly via
wetext. Disable with--no-normalization. - Rich decoding controls — greedy or sampling (
top_k/top_p/temperature/seed),repetition_penalty,duration_factor(speech rate), and the flow-matching solver knobs (n_timesteps,cfg_rate). - Auto-download — weights pull from Hugging Face on first run and are cached for reuse; CLI and Python API share the same cache.
- Timing report — every
synthprints load / clone / synth time, RTF, and a per-stage breakdown.
Install / one-click run
No install needed with uv:
uvx index-tts-2.5-mnn synth \
--ref /path/to/voice.wav \
--text "大家好, this is IndexTTS running on MNN." \
--out out.wav
The first run downloads the fp16 weights (~3.6 GB) from Hugging Face into the standard HF cache; later runs reuse it. Use --quant fp32 for the bit-exact reference set (~7 GB).
Or install into an environment:
pip install index-tts-2.5-mnn
Pre-download the weights ahead of time:
uvx index-tts-2.5-mnn download # fp16 (default)
uvx index-tts-2.5-mnn download --quant fp32
CLI usage
index-tts-2.5-mnn synth --ref REF.wav --text "..." --out out.wav [options]
| Option | Default | Description |
|---|---|---|
--ref |
(required) | Reference audio to clone (≤15 s, clear speech). |
--text |
(required) | Text to synthesize (zh/en/ja/yue, mixed OK). |
--out |
output.wav |
Output WAV path (22050 Hz, int16). |
--lang |
zh |
Language hint: zh, en, ja, yue. |
--quant |
fp16 |
fp16 (all modules, ~3.6 GB) or fp32 (bit-exact, ~7 GB). |
--threads |
4 |
CPU threads. |
--greedy |
off | Greedy decoding (deterministic). |
--seed |
random | RNG seed for sampling. |
--top-k / --top-p / --temperature |
30 / 0.8 / 0.8 |
Sampling controls. |
--repetition-penalty |
10.0 |
Repetition penalty. |
--max-mel-tokens |
1500 |
Max acoustic tokens per segment. |
--duration-factor |
1.0 |
Speech-rate multiplier. |
--n-timesteps / --cfg-rate |
25 / 0.7 |
Flow-matching solver controls. |
--model-dir |
auto | Use a local weight dir instead of downloading. |
--no-normalization |
off | Disable text normalization. |
Python API
from index_tts_2_5_mnn import IndexTTS
tts = IndexTTS(quant="fp16") # auto-downloads weights on first use
sr, pcm = tts.clone(
"AI 模型在 2025 年处理了 100 万条数据。",
ref_audio_path="voice.wav",
out="clone.wav", # optional; also returns pcm
lang="zh",
)
# Reuse one cloned voice across many lines (build the speaker once):
spk = tts.build_speaker("voice.wav")
for i, line in enumerate(["第一句。", "Second sentence.", "第三句。"]):
sr, pcm = tts.clone(line, ref_audio_path=None, spk=spk, out=f"line{i}.wav")
synthesize(...) returns the raw int16 PCM array (numpy) at tts.sample_rate (22050 Hz); clone(...) additionally writes a WAV when out is given. Use your own reference audio only with permission — see License.
Speed
End-to-end synthesis, warm, 4 threads (Apple M5 Pro, ~3 s of audio). RTF = synthesis time ÷ audio duration (lower is better).
| Backend | synth | RTF | gpt | cfm | bigvgan |
|---|---|---|---|---|---|
| MNN fp32 | 9.20 s | 3.16 | 3.61 s | 4.42 s | 1.12 s |
| MNN fp16 (default) | 9.48 s | 3.25 | 3.84 s | 4.42 s | 1.12 s |
| ONNX Runtime fp32 (CPU) | 9.53 s | 3.27 | 1.20 s | 3.51 s | 4.81 s |
fp16 is weight-only quantization: MNN dequantizes to fp32 at load and computes in fp32, so speed is the same — the win is half the download.
MNN's vocoder is ~4× faster than ONNX Runtime CPU (1.1 s vs 4.8 s); ORT wins the GPT decode. End-to-end they land at the same place on this machine — pick MNN for the smaller quantized download and the self-contained CPU wheel.
Quality / effect
Numeric fidelity — fp32 and fp16 both reproduce the PyTorch CPU reference greedy acoustic tokens exactly (fx0 73/73, fx1 83/83). fp32 is bit-exact at every stage (cosine = 1.0000, vocoder mel-SNR ≈ 70 dB). fp16 keeps stage cosine ≥ 0.99998 and vocoder mel-SNR 26–29 dB (gate: 25 dB — inaudible); only the GPT stays bit-exact under fp16, because greedy argmax absorbs the sub-1e-5 logit error.
Quantization: what ships and why. fp16 weights pass every gate on every module — that's the default set. Everything deeper was measured and rejected:
- int8/int4 BigVGAN destroys the vocoder (SNR ≤ 15 dB vs 64.5 dB fp32; int4 is pure noise at −1.4 dB).
- int8 CFM mel outliers (maxdiff 0.6–1.2) collapse even an fp32 vocoder.
- int8 CAMPPlus / semantic encoder shifts the GPT conditioning just enough (cos 0.992–0.999) to flip greedy argmax — the EN fixture keeps only 17% of reference tokens.
- int8 GPT (any block config) flips a close argmax (35% match); fp16 GPT compute (MNN
precision="low") also flips it (≤7%) — fp16 is only safe as a weight format, never as a compute precision.
So: fp16 weights everywhere, fp32 compute. No int8/int4 set is shipped because none preserved quality.
How it works
Pipeline: text frontend (tiktoken + wetext normalization) → w2v-bert semantic features → semantic codec → GPT autoregressive acoustic tokens → length regulator → flow-matching CFM (DiT) → BigVGAN vocoder → 22050 Hz WAV. The orchestration (samplers, solvers, DSP) is numpy; the heavy networks are MNN graphs converted from the ONNX export and verified stage-by-stage against the PyTorch reference.
Model weights: yunfengwang/IndexTTS-2.5-mnn.
License
Code in this package is provided under the same terms as the upstream project. IndexTTS-2.5 model weights are subject to the original Bilibili IndexTTS license — see the upstream model card. Use voice cloning responsibly and only with consent from the voice owner.
Metadata
Release files for index-tts-2.5-mnn 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| index_tts_2_5_mnn-0.1.1.tar.gz | 22.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| index_tts_2_5_mnn-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 50.3 kB
Release files / index_tts_2_5_mnn-0.1.1.tar.gz
| Download URL | index_tts_2_5_mnn-0.1.1.tar.gz |
|---|---|
| Size | 22.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d8ad1fcec564fe88b607f247513cbd990cb84736e71b11e250bded3588bb6606
|
|
BLAKE2b-256 checksum How to use checksums |
489e4d7c566309db8da14f7665131c558fdd1f9637d076f79d1369c522cc1c87
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / index_tts_2_5_mnn-0.1.1-py3-none-any.whl
| Download URL | index_tts_2_5_mnn-0.1.1-py3-none-any.whl |
|---|---|
| Size | 27.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1287ec5e0e61329b6a96a82f9b0d5c423fabfa1fbdd0b21c50d2a8f88278171e
|
|
BLAKE2b-256 checksum How to use checksums |
317e6ed6df43134813514014d695cda3214d07785aa63a1925a51ba0e5749dfd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|