tiny-voca

tiny-voca is a small English text-to-speech model with two voices, F2 (female) and M2 (male). The complete model, including the waveform generator, has 4.5M parameters and was trained from scratch on about 18 hours of synthetic speech. It runs about 70x faster than real time on four CPU threads.

Parameters 4,537,291
Voices F2, M2 (American English)
Output 24 kHz mono
Input Text, converted to phonemes with dizione
Pretrained weights in the model None
License Apache-2.0

Files

File Size Contents
tiny-voca.pt 18.2 MB PyTorch weights, float32
onnx/model.onnx 21.4 MB ONNX export, float32, opset 17
config.json Model settings, phoneme vocabulary, voices
phonemizer/ 5.4 MB Data files for dizione
samples/ The audio on this page

SHA256:

  • tiny-voca.pt: ebb22871524c5732520fb1652e6aefcec708a7452e83bdd00adcf6181db5ef70
  • onnx/model.onnx: fe6d918791a15b82e37465981d7f27a070e46b46635e5a3482fc8dff87a1ae46

Samples

Text F2 M2
Hello! This is tiny voca, a small text to speech model that runs on a phone or in a browser.
The meeting moved to 3:30 pm on March 14th, so we have about 45 minutes left.
Did you really think I would forget your birthday?
She had never seen the sea before, and for a long while she stood at the edge of the water without saying a word.

Usage

PyTorch

pip install git+https://github.com/n4ze3m/dizione git+https://github.com/n4ze3m/tiny-voca
hf download n4ze3m/tiny-voca --local-dir tiny-voca
export DIZIONE_DATA=tiny-voca/phonemizer

python -m tiny_voca.infer \
  --checkpoint tiny-voca/tiny-voca.pt \
  --voice F2 \
  --text "Hello! This is tiny voca." \
  --output hello.wav
Option Default Meaning
--voice F2 F2 or M2
--speed 1.0 Speaking rate
--pitch-shift 0 Added to log F0. 0.058 is about one semitone.
--pitch-range 1.0 Scales pitch movement around the utterance mean.

ONNX

The graph takes phoneme ids and stress values and returns the waveform. Text is converted to ids outside the graph with dizione; the ids are the positions in vocab in config.json.

import numpy as np
import onnxruntime as ort
import soundfile as sf
import dizione   # needs DIZIONE_DATA=tiny-voca/phonemizer

phones = dizione.phonemize("Hello! This is tiny voca.")
one = lambda value: np.array([value], dtype=np.float32)

session = ort.InferenceSession("tiny-voca/onnx/model.onnx")
audio, durations = session.run(None, {
    "tokens": np.array([phones.ids], dtype=np.int64),
    "stress": np.array([phones.stress], dtype=np.int64),
    "voice": np.array([0], dtype=np.int64),      # 0 = F2, 1 = M2
    "speed": one(1.0),
    "pitch_shift": one(0.0),
    "pitch_range": one(1.0),
})
sf.write("hello.wav", audio[0], 24000)
Input Type Shape Meaning
tokens int64 [1, N] Phoneme ids, including the start and end tokens
stress int64 [1, N] 0 none, 1 primary, 2 secondary
voice int64 [1] 0 = F2, 1 = M2
speed float32 [1] 1.0 as predicted; larger is faster
pitch_shift float32 [1] Added to log F0
pitch_range float32 [1] Scales pitch movement
Output Type Shape Meaning
audio float32 [1, samples] Waveform at 24 kHz
durations int64 [1, N] Length of each token in frames of 256 samples

The model reads one utterance per call, up to 512 tokens and 32 seconds. Split longer text into sentences. The same file runs in onnxruntime-web (WebAssembly). Its audio matches the PyTorch model to within 0.6% of the peak amplitude, apart from the random noise signal, which each runtime draws itself.

Model

Text is converted to phonemes with a stress value for each. A transformer encoder (4 blocks) reads the phonemes, a duration predictor gives each one a length in frames, and two frame-level transformers (2 and 5 blocks) predict pitch, voicing and energy and then the parameters of the waveform generator. All blocks use 192 channels, 4 heads and rotary position embeddings.

The waveform is produced by a source-filter synthesizer instead of a neural vocoder. A band-limited pulse train at the predicted pitch and a noise signal are each shaped by a time-varying filter, whose cepstrum the network predicts once per frame (256 samples, 10.7 ms). This part has 25,862 parameters.

Component Parameters
Embeddings (phoneme, stress, voice) 16,704
Text encoder 1,588,864
Duration and pause predictor 123,906
Frame transformer A, prosody head 795,971
Frame transformer B 1,985,984
Source-filter waveform head 25,862
Total 4,537,291

Training

Data n4ze3m/tiny-voca: 16,018 clips, 17.6 hours, two voices
Steps 104,737
Hardware One RTX 4090, 7.7 hours
Losses Multi-resolution spectral losses; adversarial loss with multi-period and multi-resolution discriminators after step 8,000

The training audio is synthetic. Both voices were created from text descriptions with Qwen3-TTS VoiceDesign, and the recordings were generated with Qwen3-TTS 1.7B Base. No recording of a real speaker is involved. Phoneme durations come from forced alignment with facebook/wav2vec2-lv-60-espeak-cv-ft, which is used only to label the training data. No pretrained weights are part of the model.

Evaluation

Word error rate of synthesized speech, transcribed with Whisper small.en. The recordings of the same sentences are scored the same way for reference.

Sentences Clips WER, tiny-voca WER, recordings
Validation 8 0.6% 0.6%
Test 8 0.9% 0.9%
New sentences, not in the dataset 16 0.0%

These sets are small and the scores are a sanity check, not a benchmark. No formal listening test has been run.

Limitations

  • English only, two fixed voices, no voice cloning.
  • The voice is clear but can sound slightly synthetic.
  • The same text is always read the same way. There is no sampling of prosody.
  • Speech is slightly faster than the training recordings at the default speed.
  • Foreign names and unusual spellings are often mispronounced. Numbers, abbreviations and homographs depend on the phonemizer.
  • No streaming.
  • The training data is itself synthetic, so the model cannot be more natural than the model that generated it.

Cost

The whole project cost $9.56 of GPU time on one rented RTX 4090. That is the dataset, the failed tries and the final training run.

Cost breakdown

Support

It cost less than a pizza to make. If you like it, you can buy me one: https://ko-fi.com/n4ze3m

License

The weights and code are released under Apache-2.0. The files in phonemizer/ are derived from the CMU Pronouncing Dictionary and other sources; their licenses are in phonemizer/LICENSE.cmudict and phonemizer/LICENSE.homograph-data.

Citation

@software{nazeem2026tinyvoca,
  author = {Nazeem, Muhammed},
  title  = {tiny-voca: a 4.5M-parameter two-voice English text-to-speech model},
  year   = {2026},
  url    = {https://huggingface.co/n4ze3m/tiny-voca}
}

Author: Muhammed Nazeem (ORCID 0009-0002-9991-0217).

Acknowledgements

The design builds on FastSpeech 2 (explicit duration and prosody prediction), DDSP and the neural homomorphic vocoder (source-filter synthesis with predicted filters), and HiFi-GAN and UnivNet (discriminators). No code or weights from these projects are used.

Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support

Dataset used to train n4ze3m/tiny-voca

Space using n4ze3m/tiny-voca 1