PiVo-1.4M
How many parameters does a voice need? PiVo is our attempt at an answer: two English voices, Pi and Vo, from a complete text-to-speech stack with 1,401,562 learned parameters, vocoder included. A 584,965-parameter acoustic model predicts vocoder features, and an 816,597-parameter FARGAN-derived vocoder turns them into 16 kHz mono audio.
Everything runs locally on a CPU with NumPy and ONNX Runtime. There is no PyTorch, teacher model, speaker encoder or network connection involved at inference time.
PiVo is a research model. Its speech is very intelligible, but some sentences still have a metallic or robotic texture. The technical report describes what we measured and what we tried.
Author: Leon Lehmann (lehmann@empero.org) ยท Empero Research (research@empero.org)
Listen
Both samples read "NASA is ready for the next mission."
Quick start
With Python 3.11 or newer, from a clone of this repository:
python -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
python inference.py synthesize --model-dir . --voice Pi \
--text "NASA is ready for the next mission." --output pi.wav
python inference.py synthesize --model-dir . --voice Vo \
--text "Hello, my name is Vo." --output vo.wav
Or from Python:
from pivo import PiVo
model = PiVo(".", threads=1)
model.save("pi.wav", "NASA is ready for the next mission.", voice="Pi")
audio = model.synthesize("Hello, my name is Vo.", voice="Vo", speed=1.0)
# float32 mono PCM at model.sample_rate (16000 Hz)
PiVo uses its own small ONNX runtime, so it does not work with
Transformers AutoModel or the hosted Inference API. Our companion code
repository adds an installable command-line tool, an HTTP server, a
Dockerfile and tests.
Text handling
PiVo speaks English only, in the voices Pi and Vo. Its frontend looks
words up in the CMU pronouncing dictionary and expands numbers, currency
amounts, ordinals and ISO dates. When a word is not in the dictionary, it
raises an error instead of guessing. You can supply the pronunciation in
ARPAbet:
model.save("name.wav", "Hello, Zzvo.", voice="Vo",
overrides={"zzvo": ["Z", "IY1", "V", "OW0"]})
Short all-caps words such as "CPU" are spelled out letter by letter; "NASA" is read as a word. Ambiguous input such as slash dates and fractions, or unsupported characters, also raise a clear error.
The whole input is encoded before audio generation starts. After that,
iter_audio yields audio in 10 ms frames, so playback can begin while the
rest of the sentence is generated.
By default, input is limited to 2,000 characters and 512 frontend tokens. One utterance can be at most 30 seconds long (3,000 acoustic frames), and speed can be set from 0.5 to 2.0. Split longer text into sentences or clauses.
How it works
The acoustic design is inspired by Mariusz Kurman's Neuroblast; our implementation is original. A 96-wide text encoder mixes attention and dilated convolution, predicts a duration for each phone, and adds a few simple timing signals that tell the decoder where it is within each phone. Two causal decoder blocks then predict 18 cepstral coefficients, pitch and pitch correlation every 10 ms. The FARGAN-derived vocoder generates four 40-sample subframes per frame. The discriminators used during training are not part of the released model.
Training data
Pi and Vo are synthetic voices. We designed them with Qwen3-TTS
VoiceDesign and used Qwen3-TTS Base to record the training data. After
filtering, the corpus contains 8,628 utterances (4,314 scripts read by both
voices), about 12.29 hours of audio, or 10.77 hours after trimming silence.
We split it into 8,362 training, 114 validation and 152 test utterances.
The exact teacher models and revisions are listed in
evidence/teachers.json and evidence/teacher-model-card-provenance.json.
Evaluation
We evaluated PiVo and 12 other candidates on the same 266 held-out utterances, transcribing the output with Whisper small.en:
| Split | Utterances | Reference words | Word errors | Word error rate |
|---|---|---|---|---|
| Validation | 114 | 1,738 | 15 | 0.863% |
| Test | 152 | 2,254 | 12 | 0.532% |
These numbers say the words come through clearly. They do not measure naturalness, and because the held-out text comes from the same sources and teacher as the training data, they are not a general English benchmark. Test scores played no part in choosing the model.
We also tried adapting the vocoder to reduce the robotic texture. In a blind comparison of 20 sentence pairs, one listener rated the original and adapted vocoders 6.10 and 6.15 out of 10 on average, with 18 ties and one win each. Since it made no consistent difference, this release keeps the original vocoder.
The ONNX graphs match the PyTorch model closely: the largest differences are 1.23e-6 (encoder), 6.68e-6 (decoder), 3.87e-7 (conditioning) and 2.98e-7 (vocoder step). Full results are in evaluation.json.
Limitations
- Some text sounds metallic or robotic, especially around sibilants and pauses.
- Pronunciation is limited to the CMU dictionary plus your overrides.
- Listening results come from a single listener and are not a MOS study.
- We have not yet measured speed or memory on ARM or mobile devices, and have not tested quantized versions.
Files
| Path | Contents |
|---|---|
onnx/ |
The four inference graphs and their metadata |
checkpoints/acoustic.pt |
Acoustic model checkpoint (SHA256 0b4a2dc993e7e500aac1825465886ff23c11f2e1a2662577f2f5cd27f4efb4eb) |
checkpoints/vocoder.pt |
Converted FARGAN vocoder (SHA256 355d470826817afaa4e729d1b19c8383e985f365af5d2b913f1b9acdf8f7eca4) |
model_manifest.json |
Sizes and hashes checked when the model loads |
PROVENANCE.json, evidence/ |
Model lineage and teacher details |
evaluation.json |
Full evaluation results |
pivo/, inference.py |
Reference inference code |
samples/ |
Demonstration audio |
technical_report.pdf, CITATION.cff |
Technical report and citation |
The PyTorch checkpoints are included for reference; inference only loads
the ONNX graphs, and their hashes are checked against model_manifest.json
at startup.
License
Our code and the acoustic model weights are released under Apache-2.0. The
FARGAN-derived code and converted vocoder weights keep the Xiph/Opus BSD
license, and the pronunciation dictionary keeps its CMU license. Neither
the teacher weights nor the training recordings are included. Please keep
LICENSE, NOTICE, LICENSES/ and THIRD_PARTY.md with any
redistribution.
Citation
@techreport{lehmann2026pivo,
title = {PiVo: two English voices in 1.4 million inference parameters},
author = {Lehmann, Leon},
institution = {Empero Research},
year = {2026},
month = {November},
note = {Technical report, version 1.0}
}