Matcha-TTS Nepali — v1, single-speaker (fresh)
Self-contained release of a single-speaker Nepali Matcha-TTS model: acoustic
checkpoint, vocoder, the exact training configs, the matcha package, a seeded
synthesis script and reference audio. Everything needed to reproduce the shipped
samples bit-for-bit is in this directory.
Access: this repo is gated — submit an access request from the file listing and it will be reviewed. For questions or to be whitelisted, contact smartharry499@gmail.com.
| Run | logs/train/nepali_real_fresh/runs/2026-08-11_15-33-57 |
| Repo commit | e154b4b7f23c25010f3951b594ae310d7c5d1b9b (branch feature/finetune-english-male-voice) |
| Trained | 2026-08-11, single NVIDIA GB10, 1000 epochs |
| Sample rate | 22 050 Hz, 80-band mel, hop 256 |
| Speakers | 1 (single voice) |
| Vocabulary | union symbol set, n_vocab = 264 |
| Params | 20.9 M |
| Training data | chatterbox-nepali corpus (~1441 utterances), Devanagari only |
Which checkpoint to use
Two checkpoints are shipped so they can be compared by ear.
| file | epoch | step | note |
|---|---|---|---|
matcha_nepali_fresh.ckpt (default) |
249 | 5750 | best loss/val_epoch = 2.7284 |
matcha_nepali_fresh_epoch999.ckpt |
999 | 23000 | final / last.ckpt |
synthesize.py loads the epoch 249 checkpoint by default. The run trained
the full 1000 epochs (its original config had max_epochs: 1000), but the best
validation loss is epoch 249 and the experiment config now notes that longer runs
overfit and degrade prosody. The shipped samples are all rendered from epoch 249.
Contents
version1-nepali-fresh/
├── README.md this file
├── synthesize.py seeded, standalone synthesis (no speaker id)
├── synth_samples.sh regenerates samples/{short,medium,long}.wav
├── requirements.txt exact pinned runtime
├── MANIFEST.sha256 checksums for every shipped file
├── checkpoints/
│ ├── matcha_nepali_fresh.ckpt epoch 249 (best) — default
│ └── matcha_nepali_fresh_epoch999.ckpt epoch 999 (final)
├── vocoder/
│ └── g_02500000 HiFi-GAN universal v1 generator
├── configs/
│ ├── experiment_nepali_real_fresh.yaml hydra experiment config
│ ├── data_nepali_real.yaml hydra data config
│ ├── train_config_resolved.yaml fully-resolved config as trained
│ ├── train_overrides.yaml CLI overrides for the run
│ └── train.log training log for the run
├── matcha/ the model/text/vocoder package
└── samples/
├── texts.txt the 3 source sentences
├── phonemes.txt their G2P output + token counts
├── short.wav / medium.wav / long.wav epoch 249, seeded
Synthesis
pip install -r requirements.txt # see the note about `real_nepali`
# single sentence
python synthesize.py --text "नमस्कार, तपाईंलाई नमस्ते।" --out out.wav
# the two-length reference set
bash synth_samples.sh
# the final (epoch 999) checkpoint instead
python synthesize.py --ckpt checkpoints/matcha_nepali_fresh_epoch999.ckpt \
--text "नमस्कार, तपाईंलाई नमस्ते।" --out out.wav
Defaults: --steps 25 --temperature 0.667 --denoiser_strength 0.02 --symbols union,
HiFi-GAN universal v1. Useful extras: --speaking_rate 1.1 (>1 is slower),
--lowpass_khz 9 (tames HF hiss), --print-phonemes.
This is a single-speaker model — there is no --spk flag; speaker
conditioning is not part of the encoder, so spks is always None.
Text frontend
Devanagari is phonemized by the hand-written real_nepali G2P
(profile real_nepali_v0.2), not espeak-ng — it comes from the
nepali_frontend repo, pinned at commit b7395f28, installed editable.
samples/phonemes.txt records the exact token string and id count for each
sample sentence — diff against it (or --print-phonemes) to confirm your
frontend matches this release before blaming the acoustic model.
Reproducibility
synthesize.py seeds the RNG per utterance (--seed, default 1234). This
matters: the flow-matching prior is torch.randn_like(mu) * temperature, and
unseeded runs give slightly different audio every time. Seeding is why the
shipped wavs have stable checksums.
PYTHON=python bash synth_samples.sh # re-render the three sample wavs
sha256sum -c MANIFEST.sha256 # confirm byte-for-byte match
Verified bit-exact on the training machine (NVIDIA GB10, CUDA 13.0,
torch 2.13.0+cu130). On different GPU/CUDA/library versions the audio is
perceptually identical but checksums will differ. Pass --seed -1 for varied
output.
Training recipe
Warm-started from the English LJSpeech base checkpoint after its vocabulary was
extended to the union set (scripts/extend_vocab.py →
checkpoints/matcha_tts_english_plus_nepali.ckpt), then trained on the Nepali
(chatterbox) phone stream.
| Init | checkpoints/matcha_tts_english_plus_nepali.ckpt |
| Optimizer | Adam, lr 1e-4, no scheduler, weight decay 0 |
| Epochs | 1000 (ran to completion at training time) |
| Batch | 32, accumulate_grad_batches: 2 (effective 64) |
| Precision | 16-mixed, gradient_clip_val: 5.0 |
| Encoder | RoPE, 6 layers, 192 ch, 2 heads (single-speaker: spk path not wired) |
| Decoder | CFM/euler, sigma_min 1e-4, channels [256, 256], snakebeta |
| Mel stats | mel_mean -5.980818, mel_std 2.582703 |
| Seed | 1234 |
Full settings in configs/train_config_resolved.yaml.
Known limitations
- Trained on a single voice from the chatterbox-nepali corpus; there is no speaker conditioning, so you cannot pick between voices with this model.
- Training data is Devanagari-only; code-switched Nepali+English is not covered by the training set.
- The run was originally allowed to train 1000 epochs; validation loss bottoms out around epoch 249 and the config note warns later epochs overfit and add noise. Prefer the shipped epoch 249 checkpoint.