Thaki-SyntheticVoice-KO-2B-v0.1
A VoxCPM2 fine-tune on a ThakiCloud-designed synthetic Korean speaker. With the bundled fixed reference clip it performs on par with VoxCPM2 Base + the same reference. Without a reference it is clearly better than the base model in pronunciation accuracy and naturalness, but speaker consistency across utterances is still limited.
๐ฐ๐ท ํ๊ตญ์ด ์นด๋: MODEL_CARD.ko.md
Engineering blog: A Korean Voice Built Without a Real Person (ํ๊ตญ์ด: ๋ธ๋ก๊ทธ)
| Base | openbmb/VoxCPM2 (2B, Apache-2.0) |
| Speaker | F1, a synthetic voice created with VoxCPM2 Voice Design from a text description only (calm, low-pitched Korean woman in her thirties, corporate-assistant tone). No real person's voice was used as reference at any stage. |
| Method | Single-speaker LoRA (r = 32, ฮฑ = 32) on 80.8 min of speech synthesized by VoxCPM2 itself from the F1 reference, then merged into the base weights (single checkpoint) |
| Release format | model.safetensors (merged, bf16-loadable) + VoxCPM2 config/tokenizer/AudioVAE + reference/anchor_F1_16k.wav |
| Evaluation | 200 held-out sentences ร 3 seeds (with reference); 60 sentences ร 3 seeds (no reference); pre-registered gates T1โT5 |
| Cost | โ2.1 GPU-hours end to end on one H100 (voice design, synthesis, LoRA, merge, evaluation) |
โ ๏ธ What this model is not. It is not a better TTS than VoxCPM2 Base+Ref, and it does not guarantee an identical voice on every generation without a reference. It was evaluated only on Korean, clean synthetic conditions, one female voice, no emotion control. Read ยง4 before deploying.
0. Quick start
pip install -U voxcpm # the pinned commit we used: OpenBMB/VoxCPM@cce58a5b
Recommended: with the bundled reference (this is the configuration that was evaluated as "on par with Base+Ref").
import soundfile as sf
from voxcpm import VoxCPM
model = VoxCPM.from_pretrained("ThakiCloud/Thaki-SyntheticVoice-KO-2B-v0.1", load_denoiser=False)
REF_WAV = "reference/anchor_F1_16k.wav" # bundled, 8.3 s, 16 kHz
REF_TEXT = "์๋
ํ์ธ์. ์ ๋ ํํคํด๋ผ์ฐ๋์ ์์ฑ ๋น์์
๋๋ค. ์ค๋๋ ์ฐจ๋ถํ๊ณ ๋๋ ทํ ๋ชฉ์๋ฆฌ๋ก ํ์ํ ์ ๋ณด๋ฅผ ์๋ดํด ๋๋ฆฌ๊ฒ ์ต๋๋ค."
wav = model.generate(
text="์์ฒญํ์ ์์
์ ์ค๋ ์คํ ์ธ ์ ์ผ์ญ ๋ถ์ ์๋ฃ๋ ์์ ์
๋๋ค.",
prompt_wav_path=REF_WAV, prompt_text=REF_TEXT,
cfg_value=2.0, inference_timesteps=10, seed=0,
)
sf.write("out.wav", wav, model.tts_model.sample_rate) # 48 kHz
Experimental: without a reference. Produces a voice close to F1 with good naturalness, but the timbre varies between utterances (ยง2.2). Do not rely on it for a fixed brand voice yet.
wav = model.generate(text="์๋
ํ์ธ์. ํํคํด๋ผ์ฐ๋ ์์ฑ ์๋ด์
๋๋ค.", cfg_value=2.0, inference_timesteps=10, seed=0)
Input text convention. Write numbers, units and symbols the way they should be spoken (Korean words), e.g. 3์ต 2,500๋ง ์ โ ์ผ์ต ์ด์ฒ์ค๋ฐฑ๋ง ์, ์คํ 3์ 30๋ถ โ ์คํ ์ธ ์ ์ผ์ญ ๋ถ, B200 8์ฅ โ ๋น ์ด๋ฐฑ ์ฌ๋ ์ฅ, 12% โ ์ญ์ด ํผ์ผํธ. The training transcripts follow this convention; Arabic digits in the input were not trained and may be read inconsistently.
Optional: version-string preprocessing (separate code, not part of the model). The weights in this repository are the v0.1 weights and do not normalize text by themselves. In a follow-up check, the one input type that was read wrongly in display form was version strings: v1.2.3 (the v read as a letter name) and 2.0 (a dropped "zero"). For that case we ship a small rule-based normalizer as plain Python files in this repository, under text_normalization/ (text_norm.py + korean_numbers.py, no dependencies). VoxCPM.from_pretrained does not load it; you call it yourself before generate.
import sys
from huggingface_hub import snapshot_download
d = snapshot_download("ThakiCloud/Thaki-SyntheticVoice-KO-2B-v0.1", allow_patterns=["text_normalization/*"])
sys.path.insert(0, f"{d}/text_normalization")
from text_norm import normalize
text = normalize("VoxCPM 2.0 ๋ฒ์ ๊ณผ v1.2.3-rc1์ ๋น๊ตํฉ๋๋ค.")
# -> "VoxCPM ์ด ์ ์ ๋ฒ์ ๊ณผ ๋ฒ์ ์ผ ์ ์ด ์ ์ผ ์์จ ์ผ์ ๋น๊ตํฉ๋๋ค."
wav = model.generate(text=text, prompt_wav_path=REF_WAV, prompt_text=REF_TEXT,
cfg_value=2.0, inference_timesteps=10, seed=0)
It only rewrites version strings: v-prefixed numbers, dotted numbers with three or more parts, and two-part numbers right after a product name or before "๋ฒ์ /version". Dates (2026.10.26), IP addresses, URLs, e-mail addresses, file paths and decimals with units (3.5GB, 3.5๋ฐฐ) are left as they are, and every other number still follows the input convention above. On our 1,200-sentence script it changed 34 sentences, all to exactly the hand-written spoken form, and left spoken-form input unchanged. It is not a general Korean text normalizer.
1. What was trained
- Speaker design. Eight candidate voices (4 female, 4 male) were generated with VoxCPM2 Voice Design from text descriptions only (gender, age range, pitch, tone, pace). For each, a fixed 8.3 s anchor sentence and ten test sentences were synthesized and scored for naturalness (UTMOS), speaker consistency (WavLM-SV cosine to the anchor) and content (whisper CER). F1 was selected (UTMOS 3.46, cosine to anchor 0.988 mean / 0.976 min). The anchor file is the bundled reference (
sha256 cb73d996b1b9f0017bcd428d00ea12fd9dd262b60a0111640f13f898906dfbad). - Script. 1,200 self-written Korean sentences (general, enterprise/tech, numbers/money/dates, alphanumerics/product names, long sentences, customer-service dialogue, hard pronunciation), each with a display form and a spoken form; split by template so that no template appears in two splits.
- Synthesis. VoxCPM2 Base + the F1 reference synthesized the 1,000 training-split sentences (cfg 2.0, 10 steps). Each utterance was kept only if whisper-large-v3-turbo back-transcription matched the spoken text (CER โค 8 % after numeral-aware normalisation), WavLM-SV cosine to the anchor โฅ 0.95, UTMOS โฅ 2.9, no runaway/silence. 934 of 1,000 passed (80.8 min); 888 train / 46 validation utterances.
- LoRA. r 32, ฮฑ 32, lr 1e-4, batch 4 ร grad-accum 4, 2 epochs (112 steps), 40 % of rows with a same-speaker reference clip. Validation loss 0.689 โ 0.586. Then merged into the base (
W += BยทAยทฮฑ/r, 192 modules) and saved as one checkpoint.
This is self-distillation: the training audio is VoxCPM2's own output. It cannot teach the model anything the base cannot already produce; what it can do is bias the model toward one voice. Interpret the results accordingly.
2. Results (our measurements; same hardware, decoding and scorer for both arms)
Conditions: 1ร H100 NVL, bf16, cfg_value=2.0, inference_timesteps=10; CER = whisper-large-v3-turbo back-transcription vs. spoken text (Arabic-numeral output counts against both arms equally); speaker cosine = WavLM-base-plus-sv; naturalness = UTMOS22; RTF = synthesis time / audio length. Medians over seeds.
2.1 With the fixed F1 reference (200 held-out sentences ร seeds 0/1/2)
| Metric | VoxCPM2 Base + Ref | This model + Ref | Gate |
|---|---|---|---|
| CER (T1) | 3.13 % | 3.03 % | โค base โ pass |
| Speaker cosine, pairwise (T2) | 0.980 | 0.981 | โฅ base โ pass (2 of 3 seeds) |
| UTMOS (T3) | 3.494 | 3.489 | โฅ base โ 1 % โ pass |
| Runaway / silent rate (T4) | 0 / 0 | 0 / 0 | pass |
| RTF, merged checkpoint (T5, 60 sentences) | 0.1348 | 0.1465 | โค base ร 1.1 โ pass |
Verdict: non-inferior. No meaningful advantage over Base+Ref in this configuration. (The un-merged LoRA path was 22 % slower, 0.176; merging removes that overhead.)
2.2 Without any reference (60 category-balanced held-out sentences ร seeds 0/1/2)
| Metric | VoxCPM2 Base, no ref | This model, no ref |
|---|---|---|
| CER | 3.6 % | 1.8 % |
| UTMOS | 2.22 | 3.23 |
| Cosine to the F1 anchor, mean | 0.59 | 0.79 |
| Cosine to the F1 anchor, minimum | 0.21 | 0.40 |
| Pairwise cosine across utterances | 0.65 | 0.74 |
| Same sentence, different seed, cosine | 0.70 | 0.81 |
For scale: with the reference, cosine to the anchor is 0.98. Reading: without a reference the base model picks a different random voice each time; this model pulls strongly toward F1 and sounds much more natural, but a minimum cosine of 0.40 means some utterances still come out in a noticeably different voice. Speaker locking without a reference is partially achieved, not solved.
3. Intended use
- Korean read-speech / assistant-style prompts in the F1 voice, with the bundled reference, where you want a ready-made synthetic voice instead of cloning a person's recording.
- Research on reference-free speaker consistency (the no-reference numbers above are the baseline to beat).
Not intended for: impersonating any real person; emotional/expressive speech; languages other than Korean; production deployment without your own evaluation.
4. Limitations
- Speaker consistency without a reference is limited (anchor cosine 0.79 mean, 0.40 min). Use the reference for a stable voice.
- No advantage over Base+Ref with a reference. If you already pass a reference clip, the base model gives the same quality.
- Single female voice, neutral style. No emotion, speed or style control was trained or evaluated.
- Synthetic-only training data (self-distillation). Pronunciation errors of the base model can be inherited; we removed utterances the filters caught, and a human listening check of 30 number/English-alphanumeric outputs from this checkpoint passed 30/30, but the training data was not exhaustively hand-verified.
- Numerals must be written in Korean words (see ยง0). Arabic digits were not in the training transcripts.
- Evaluation scope: Korean, clean synthetic audio, whisper-based CER (which penalises both arms equally for numeral formatting), UTMOS22 (not calibrated for Korean), one GPU type. No listening test with external raters.
- RTF numbers are from an H100; expect different absolute values elsewhere.
5. Rights and data
- The speaker is synthetic, created from a text description with VoxCPM2 Voice Design. No real person's recording was used as a reference at any stage, and no celebrity, voice actor or character was named in the description. This is a factual statement about the process; it is not a legal opinion that no third-party right can be affected.
- No AI Hub data and no human voice-actor recordings were used for this model (unlike our ASR releases).
- Training audio (934 synthesized utterances) is not included in this repository. The 8.3 s synthetic reference clip is included so that the recommended configuration is reproducible.
- Base model
openbmb/VoxCPM2: Apache-2.0. These merged weights are a modified version of it, released under Apache-2.0; seeLICENSEandNOTICEfor the license text, attribution and a summary of our changes. - On generated audio: the VoxCPM maintainers stated (OpenBMB/VoxCPM #407, #409, 2026-10-12) that Voice Design output may be saved, reused as a reference, published, redistributed and used commercially, subject to applicable law and third-party rights; they noted this is their stance, not legal advice. Their statement does not specifically address training on generated audio, which is how this model was made.
- Please do not use the model to imitate an identifiable person, and tell listeners when speech they hear is AI-generated, as many jurisdictions require.
6. Reproducibility
- Base:
openbmb/VoxCPM2(S3 mirror of the Hub checkpoint;voxcpmat commitcce58a5b). - LoRA: official
train_voxcpm_finetune.pywith the config in ยง1; merge:W += BยทAยทฮฑ/rover the 192 LoRA linear modules; the merged state dict was loaded into a plain base object with 0 missing / 0 unexpected keys. - Decoding for every number here:
cfg_value=2.0,inference_timesteps=10, seeds 0/1/2. - SHA-256 of every file was checked before and after upload (see commit message / ledger).
7. Citation
@misc{thakicloud2026syntheticvoice,
title = {Thaki-SyntheticVoice-KO-2B-v0.1: VoxCPM2 fine-tuned on a designed synthetic Korean speaker},
author = {ThakiCloud},
year = {2026},
url = {https://huggingface.co/ThakiCloud/Thaki-SyntheticVoice-KO-2B-v0.1}
}
Base model: OpenBMB, VoxCPM2: Tokenizer-Free TTS for Multilingual Speech Generation, Creative Voice Design, and True-to-Life Cloning.