Instructions to use EryriLabs/pocket-tts-cymraeg with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Pocket-TTS
How to use EryriLabs/pocket-tts-cymraeg with Pocket-TTS:
from pocket_tts import TTSModel import scipy.io.wavfile tts_model = TTSModel.load_model("EryriLabs/pocket-tts-cymraeg") voice_state = tts_model.get_state_for_audio_prompt( "hf://kyutai/tts-voices/alba-mackenna/casual.wav" ) audio = tts_model.generate_audio(voice_state, "Hello world, this is a test.") # Audio is a 1D torch tensor containing PCM data. scipy.io.wavfile.write("output.wav", tts_model.sample_rate, audio.numpy()) - Notebooks
- Google Colab
- Kaggle
Pocket TTS Cymraeg (Welsh), PyTorch weights
As far as we can find, the first Welsh TTS that can speak in a custom voice from a few seconds of reference audio, running locally on a CPU.
A community model, trained from scratch in Welsh by EryriLabs on 173 hours of openly licensed Welsh speech. None of Kyutai's language weights are in it. What it borrows from Kyutai is the Pocket TTS recipe and the frozen Mimi codec, and both are credited below.
Try it in the browser: EryriLabs/pocket-tts-cymraeg-demo
GGUF build for llama-tts: EryriLabs/pocket-tts-GGUF, in the welsh/ folder.
Files
| File | Size | What it holds |
|---|---|---|
model.safetensors |
1,344.3 MB | the whole TTSModel state dict, float32: the 316 M parameter FlowLM and the 20 M parameter frozen Mimi codec together |
tokenizer.model |
0.30 MB | our own SentencePiece BPE tokenizer, 4,000 pieces, trained on Welsh text |
config.yaml |
small | the model as pocket_tts reads it, with hf:// paths so it loads from anywhere |
config.relative.yaml |
small | the same config with model.safetensors and tokenizer.model as plain relative paths, for a local copy of this folder |
manifest.json |
small | parameter counts, SHA-256 checksums, Mimi provenance |
| Half | Parameters | Whose |
|---|---|---|
| FlowLM, 24 layers, d_model 1024 | 316,013,953 | ours, trained from a Gaussian initialisation |
| Mimi codec, frozen | 20,054,337 | Kyutai's, CC-BY-4.0 |
| Total | 336,068,290 |
Float32 throughout, which is why 336 M parameters occupy 1.34 GB.
Usage
pip install pocket-tts==3.0.2
from pocket_tts import TTSModel
model = TTSModel.load_model(config="hf://EryriLabs/pocket-tts-cymraeg/config.yaml")
# A few seconds of reference audio is all the voice conditioning needs.
voice = model.get_state_for_audio_prompt("my_reference_voice.wav", truncate=True)
audio = model.generate_audio(voice, "Mae'r tywydd yn braf yng Nghymru heddiw.")
print(audio.shape[-1] / model.sample_rate, "seconds at", model.sample_rate, "Hz")
generate_audio_stream yields chunks as they are decoded, if you want to start playing before the
sentence is finished. Output is 24 kHz mono.
The reference wav is read by the standard library wave module, so it must be PCM. A float32 wav
or an mp3 raises wave.Error: unknown format: 3. Convert first.
For int8 on a CPU, pass quantize=True to load_model, or apply it yourself:
from pocket_tts.quantization import RECOMMENDED_CONFIG, apply_dynamic_int8
apply_dynamic_int8(model.flow_lm, RECOMMENDED_CONFIG)
Two things to know before they surprise you:
The default temperature is 0.3, carried in the config. It is what every gate and every checkpoint ranking in this project used. It is not the package default.
The inference API does not do classifier-free guidance. The evaluation gates generated with
cfg_coef=2.0 through the training code path and generate_audio has no such argument, so
numbers measured through the public API are not directly comparable with gate numbers.
Threads. pocket_tts calls torch.set_num_threads(1) when it is imported, so the package
default is single threaded. Set torch.set_num_threads(n) after the import if you want more.
Speed on a CPU
Measured on a 13th Gen Intel Core i9-13900K, torch 2.13.0, quantisation engine FBGEMM, six frozen Welsh gate prompts, three runs each, CPU only. Real time factor is generation seconds divided by seconds of audio produced, so lower is better and anything under 1.0 is faster than real time. The voice prompt is encoded before the clock starts, since that is a one off per voice.
| Variant | Threads | Median RTF | Range | First audio | RSS after load |
|---|---|---|---|---|---|
| float32 | 1 | 0.71 | 0.70 to 0.73 | 0.23 s | 2,019 MB |
| float32 | 8 | 0.48 | 0.47 to 0.48 | 0.10 s | 2,020 MB |
| int8 | 1 | 0.40 | 0.39 to 0.41 | 0.10 s | 1,388 MB |
| int8 | 8 | 0.31 | 0.30 to 0.32 | 0.06 s | 1,462 MB |
So it speaks Welsh faster than real time on a single core, and about three times faster than real time on eight cores with int8. Peak resident memory during loading is about 3.3 GB for every variant, because each one is built in float32 and then quantised; what int8 buys is visible in the resident set after the load, 2,019 MB down to 1,388 MB.
bfloat16 does not work on CPU here. Casting the FlowLM alone leaves Mimi handing it float32
latents, and casting both halves moves the failure into the Mimi encoder, which reads the
reference wav as float32. There is no supported bfloat16 CPU path in pocket_tts without
patching it.
Does int8 hurt what the model says? Not by anything this sample can detect. Scored with the pinned
Welsh ASR (techiaith/whisper-large-ft-cy-en at revision 014eacd4), a voicing gate applied
before the ASR sees anything, median WER was 0.050 and 0.000 for float32 at 1 and 8 threads and
0.182 and 0.091 for int8, against a draw to draw spread of about 0.13 within a single cell. Every
gap between the four cells is smaller than the spread inside one of them, and the number of draws
that survive the voicing gate is the same 9 or 10 of 18 throughout. That is parity, not proof of
equality: six prompts and three draws is a sanity check, not an equivalence test.
Known weaknesses
About 40% of draws fail the voicing gate, and they are mostly the long sentences. This is the headline weakness. On the 40 sentence held out set at this checkpoint, 73 of 120 draws were scoreable, so 39% were not. The draws that do come through are close to perfect, which is why the median word error rate is low. The problem is not that the model says the wrong words, it is that a sizeable minority of attempts produce audio that is not properly voiced at all.
In practice: split long text into shorter sentences, and generate more than one draw and keep the best.
Voice transfer to an unseen speaker is limited. The reference conditioning works, and it is the point of the model, but this was trained on 173 hours from one language and a few thousand speakers rather than the tens of thousands of hours a large multilingual model sees. A reference voice unlike anything in the training data will come through as an approximation of itself rather than a close match, and reference audio recorded in noisy or unusual conditions does worse still. Four to six seconds of clean, well voiced speech is what it likes.
It speaks a little faster than the human reference. Duration ratio sits around 0.78 to 0.9 against the ground truth recordings. It passes the 0.7 to 1.4 band comfortably and nobody has complained about it by ear, but it is a real bias rather than noise.
Welsh only. No other language was trained and none should be expected.
No phone measurement exists. Everything above is a desktop CPU. No claim is made about phone performance until it has been measured on a phone.
How it was made
Trained from a Gaussian initialisation on one RTX 3090, power capped, with nightly shutdowns and a resume every morning: 164.6 GPU hours of active stepping across 16.9 days, 400,000 steps, 49 sessions and 48 resumes, about 25 kWh for the card, which is roughly six pounds of electricity at a UK domestic tariff. That figure is the card alone and not the wall.
The released checkpoint is step 300,000, not the final one. All five late candidates (300k, 325k, 350k, 375k, 400k) were ranked on the full 40 sentence held out set, three draws each, with the tie rule fixed before the numbers existed: scoreable fraction first, then median WER, then duration ratio. 300k came first on the first two criteria, 61% scoreable and median WER 0.000, and 400k came last at 53%. The last 100,000 steps of the cosine tail made the model slightly worse on that set. The margin over 325k was 61% against 60%, which is a lead rather than a gulf.
The weights here are the EMA shadow overlaid on the trained weights, which is exactly what those rankings scored.
Training data
173.1 hours of Welsh speech, all of it openly licensed.
| Corpus | Train hours | Licence |
|---|---|---|
| Common Voice 16.1 Welsh, Techiaith repack | 98.0 | CC0-1.0 |
| Banc Trawsgrifiadau Bangor | 20.9 | CC0-1.0 |
| BU-TTS / Corpws Talentau Llais | 20.8 | CC0-1.0, see the note below |
| CLlLC / WLGA | 14.2 | CC0-1.0 |
| Lleisiau ARFOR | 12.2 | CC0-1.0 |
| WISPR | 2.7 | BSD-2-Clause |
| Paldaruo v5 | 1.2 | CC BY 4.0 |
The rows sum to 170.0 hours. The remaining 3.3 hours are rows recovered from the Bangor and CLlLC corpora during a re-audit of material an earlier build had rejected.
BU-TTS. The Bangor GitLab repository corpws-talentau-llais carries no LICENSE file and no
licence in its metadata. The CC0-1.0 claim rests on the same publisher's Hugging Face card for the
same corpus, techiaith/bu-tts-cy-en, which declares license: cc0-1.0. That is a documentation
gap at source rather than a conflict, and Bangor have been asked to state the licence in the
repository itself.
Common Voice. The corpus is CC0-1.0, so the licence is not the issue. Speaker grouping was recovered by joining the Techiaith repack to a frozen 2024 community mirror of Common Voice 17. Mozilla moved Common Voice off Hugging Face in October 2025 partly so that contributor deletion requests could be honoured, and a frozen mirror cannot reflect those. No Common Voice audio, transcript or identifier is redistributed here, and no speaker identifier of any kind is in this repository, but the point is worth stating plainly rather than leaving implicit.
Paldaruo's CC BY 4.0 carries an attribution requirement, which is met here: Cooper, S., Chan, D., Jones, D. B. (2017), The Paldaruo Speech Corpus.
Responsible use
Reference voices must be your own, or used with the speaker's permission. The demo voices in the Space are Common Voice speakers labelled Voice 1 to Voice 8, with no identities or identifiers carried through anywhere. No claim is made that the output sounds exactly like any given person.
Licence and attribution
CC-BY-4.0.
The Welsh model was trained by EryriLabs. The recipe and architecture are Kyutai's Pocket TTS
(kyutai/pocket-tts,
paper), and the Mimi codec inside model.safetensors is
Kyutai's, CC-BY-4.0, used unmodified and frozen, taken from kyutai/pocket-tts at revision
39592ff2. The 316 M parameter FlowLM, which is everything that knows any Welsh, was trained from
a random initialisation and contains none of their weights.
- Downloads last month
- -