Downloads · 30 days
7
18% of all-time downloads
thanhhai03/OmniVoice-Luna-vi
OmniVoice-Luna-vi is a text-to-speech model from thanhhai03. Use it when you need text read aloud. It is set up for transformers. The card lists the license as cc-by-nc-4.0.
Single-speaker Vietnamese text-to-speech. A LoRA finetune of k2-fsa/OmniVoice on one Vietnamese voice ("Luna"), with the adapter merged back into the base weights — load it and it speaks in that voice.
Downloads · 30 days
7
18% of all-time downloads
All-time downloads
40
Public
Parameters
613M
3.3 GB on disk
Likes
0
Public
Click a slice to open those files.
.safetensors3.3 GB · 100%
How the weights are stored.
F32613M · 100%
From the Hugging Face model README
Single-speaker Vietnamese text-to-speech. A LoRA finetune of k2-fsa/OmniVoice on one Vietnamese voice ("Luna"), with the adapter merged back into the base weights — load it and it speaks in that voice.
No reference clip needed. The base model is zero-shot and wants a voice prompt on every call; here the voice lives in the weights. Dropping the prompt removes a ~300-token prefix that every target token has to attend to, which is worth 1.3 GB of VRAM at serve time (7,134 MB → 5,794 MB measured) on top of being one less thing to ship.
import soundfile as sf
import torch
from omnivoice import OmniVoice
model = OmniVoice.from_pretrained(
"thanhhai03/OmniVoice-Luna-vi", device_map="cuda:0", dtype=torch.float16)
wav = model.generate(
text=["Xin chào, đây là giọng đọc tiếng Việt."],
language="vi",
voice_clone_prompt=None, # giọng nằm trong trọng số — không cần clip tham chiếu
num_step=16,
guidance_scale=2.0,
pad_duration=0.0,
fade_duration=0.02,
)
sf.write("out.wav", wav[0], 24000)
Output is 24 kHz mono float32.
num_stepnum_step is the number of denoising steps. It is the one knob that matters,
and it trades accuracy against latency on the same weights:
num_step | CER ↓ | WER ↓ | CER p90 ↓ | % clips ≤5% CER ↑ | use when |
|---|---|---|---|---|---|
| 16 | 0.468 % | 1.243 % | 1.85 % | 98.6 | quality first; RTF still far below 1 |
| 4 | 1.508 % | 2.724 % | 5.26 % | 88.4 | latency first (TTFA 161 ms, RTF 0.035) |
Start at 16. Drop to 4 only if you are latency-bound; below 4 quality falls off sharply.
435 held-out Vietnamese sentences, of which 422 after removing 13 that
overlap the training set. ASR for CER/WER is faster-whisper large-v3.
Speaker similarity (SECS) is Resemblyzer cosine against a 500-clip reference
set of the target speaker; UTMOS is SpeechMOS utmos22_strong; FAD is VGGish
against the same reference set.
| this model (16 step) | this model (4 step) | base, zero-shot + prompt | human reference | |
|---|---|---|---|---|
| CER ↓ | 0.468 % | 1.508 % | 2.532 % | — |
| WER ↓ | 1.243 % | 2.724 % | 4.023 % | — |
| CER p90 ↓ | 1.85 % | 5.26 % | 6.85 % | — |
| % clips ≤5% CER ↑ | 98.6 | 88.4 | 83.2 | — |
| SECS ↑ | 0.9228 | 0.9105 | 0.8476 | 0.9507 |
| UTMOS ↑ | 2.728 | 2.321 | 2.158 | 2.422 |
| FAD ↓ | 0.784 | 1.400 | 3.056 | 0.0 |
| f0 std (semitone) | 2.877 | 2.597 | 2.274 | 2.387 |
Against the zero-shot base on the same test set and the same metrics: 5.4× lower CER, 3.2× lower WER, speaker similarity up from 0.8476 to 0.9228 (the human reference itself scores 0.9507, so this closes most of the gap), and FAD down from 3.056 to 0.784.
Two caveats worth reading before you quote these numbers:
Measured through a WebSocket server with FlashInfer + torchao fp8 +
torch.compile, at num_step=4:
| this model | base, zero-shot + prompt | |
|---|---|---|
| Time to first audio | 161 ms | 155 ms |
| RTF | 0.035 | 0.036 |
| VRAM while serving | 5,794 MB | 7,134 MB |
Finetuning does not make the model faster — latency is identical within noise. What it buys is the 1.3 GB, and that comes specifically from being able to drop the voice prompt: serving this model with a prompt still costs 7,183 MB.
LoRA on the base model, then merged.
| rank / alpha / dropout | 32 / 64 / 0.05 |
| target modules | q_proj k_proj v_proj o_proj gate_proj up_proj down_proj |
| fully trained (not LoRA) | audio_embeddings, audio_heads |
| LR / schedule | 1e-4, cosine, 5 % warmup |
| steps | 2,000 · 4,096 batch tokens · grad accum 2 |
| precision | bf16, flex attention |
| data | 5,425 train / 286 dev utterances, single speaker |
audio_embeddings and audio_heads are trained in full rather than through
LoRA: the model has 8 parallel codebooks with a head each, and a low-rank update
on those two layers is too narrow to move the audio-token distribution to a new
speaker.
Per-codebook loss weights are [8, 8, 6, 6, 4, 4, 2, 2] — the first codebooks
carry the coarse envelope and timbre and are weighted 4× the last ones, which
only carry residual detail.
⚠️ Do not pick checkpoints by eval loss. OmniVoice re-samples its mask positions at every evaluation, so eval loss is stochastic and does not track audio quality. Select on CER/SECS from generated audio instead.
CC-BY-NC-4.0 — non-commercial. This is inherited from the base model, whose weights are CC-BY-NC because of constraints in its training data (Emilia); it is not a choice made here and it cannot be relaxed downstream.
The bundled audio_tokenizer/ carries its own separate license (Boson Higgs
Audio 2 Community License, derived from the Meta Llama 3 license) — see
audio_tokenizer/LICENSE.
This model reproduces the voice of a specific speaker. Do not use it to impersonate anyone, to attribute speech to a person without their consent, or to produce audio intended to deceive. Synthetic speech should be disclosed as synthetic wherever a listener might reasonably assume otherwise.
Base model: k2-fsa/OmniVoice (Qwen3-0.6B backbone, masked-diffusion audio LM, 8 codebooks at 25 Hz). Audio codec: Boson Higgs Audio 2 tokenizer.