pip install inno-kokoro
Zero-shot voice tuner for Kokoro-82M.
Outputs base Kokoro compatible voice packs @ [510, 1, 256]. (write-up)
Same passage for every voice, enrolled from the references. LibriTTS-R speakers are dev-clean held out from training.
| voice | tuned | reference |
|---|---|---|
| am_libritts1272 | ||
| af_libritts5338 | ||
| am_libritts6241 | ||
| af_ameliaearhart | ||
| bf_janegoodall | ||
| am_vincentprice |
Code available on Github: remsky/inno-kokoro.
Integrated into Kokoro-FastAPI (v0.9.0+)
PyTorch, with kokoropip install "inno-kokoro[torch]"
from inno_kokoro.enroll import Tuner, enroll, read
import torch
from kokoro import KPipeline
tuner = Tuner(backend="torch") # caches model from HF on first use
pack, _ = enroll(*read("my_ref.wav"), tuner, return_pt=True) # [510, 1, 256]
torch.save(pack, "am_me.pt")
pipe = KPipeline(lang_code="a")
wav = next(pipe("Hello from a tuned voice.", voice=pack)).audio
ONNX (no torch), with kokoro-onnxpip install inno-kokoro kokoro-onnx
from inno_kokoro.enroll import Tuner, enroll, read
import numpy as np
from kokoro_onnx import Kokoro
tuner = Tuner(backend="onnx") # downloads model.safetensors + model.onnx on first use
pack, _ = enroll(*read("my_ref.wav"), tuner) # [510, 1, 256] float32 NumPy
np.save("am_me.npy", pack)
kokoro = Kokoro("kokoro-v1.0.onnx", "voices-v1.0.bin") # from the kokoro-onnx releases
wav, sr = kokoro.create("Hello from a tuned voice.", voice=pack, lang="en-us")
Notes:
af_, am_, bf_, bm_enroll(..., fmax=180): can override when needed (archival sources, etc)model.onnx: the speaker encoder and style head for onnxruntime (fp32, 31.5 MB). Used by Tuner(backend="onnx") from inno-kokoro 0.4.0. Same packs as torch, about 2x faster on CPU.
fbank [1, frames, 80] float32: kaldi log-mel of the first 30 s at 16 kHz (inno_kokoro/fbank.py)embedding [1, 512] (unit, UniSpeech-SAT-sv space) and style [1, 256]export_onnx.py (inno-kokoro tools/export_onnx.py at b442727)| reference | onnxruntime | torch |
|---|---|---|
| 8 s | 100 ms | 165 ms |
| 30 s | 410 ms | 890 ms |
CPU (best of 5 runs)
A 5 to 30 s reference clip in, a stock-shaped Kokoro voice pack out. Everything loads from model.safetensors, no extra downloads.
Enrollment embeds an input audio sample via the baked speaker encoder and maps through model.safetensors to build the encoder side; prosody aspects are measured to build the predictor half.
enroll(..., head=False) skips it.Enrollment runs in about 0.05 s per second of reference on CPU (a 30 s reference in 1.4 s) and 0.1-0.3 s total on a GPU, after the one-time model load.
Total model size @ fp16: ~24mb
All stages: Kokoro frozen; LibriTTS-R train-clean-100 unless noted.
Trained via HF Jobs a10g-small; under $20 in GPU time:
1 - cos(student, teacher) over LibriTTS-R crops with synthetic channel damage; the style head is untouched. Inno gets about a third of the normalized similarity range, twice as close as the nearest stock pack (with UTMOS intact and keeping Kokoro's stable natural style).
Benchmark Plot: Zero-shot speaker similarity comparison on LibriSpeech test-clean. Full benchmark results and methodologyLibriSpeech test-clean, F5-TTS cross-sentence split (1127 utterances, 39 held-out speakers. Reference in, new sentence out, scored against the speaker's real recording.
| system | SIM-o | normalized | ECAPA | UTMOS | RTF |
|---|---|---|---|---|---|
| ground truth (second recording) | 0.695 | 1.00 | 0.656 | 4.10 | |
| F5-TTS v1 base | 0.650 | 0.94 | 0.713 | 3.86 | 0.48 |
| StyleTTS2 (LibriTTS zero-shot) | 0.386 | 0.46 | 0.415 | 4.40 | 0.06 |
| Inno v0.2 | 0.288 | 0.32 | 0.288 | 4.45 | 0.07 |
| OpenVoice v2 | 0.227 | 0.23 | 0.316 | 3.80 | 0.12 |
| Kokoro, nearest stock pack | 0.167 | 0.15 | 0.215 | 4.25 | 0.06 |
StyleTTS2 uses a related architecture with an unfrozen decoder, a possible ceiling for this style space.
Measured on the shipped weights through the stock KPipeline: one fixed passage rendered for the seven sample voices plus ten hold-out dev-clean speakers, F0 by Praat over 6 s chunks with the reference's tracking ceiling applied to both sides.
| metric | v0.1 blend only | v0.2 with head |
|---|---|---|
| speaker cosine (WavLM-sv), samples / dev-clean | 0.926 / 0.956 | 0.935 / 0.959 |
| F0 mean, render minus reference | 0.65 st mean abs | 0.8 st mean abs |
| F0 spread, render minus reference | 0.65 st mean abs | 0.5 st mean abs |
| DNSMOS | 3.50 | 3.50 |
The head's gain is spread; on F0 mean it scatters more per speaker and flips the signed bias from -0.2 to +0.3 st.
Adapter weights and code: Apache-2.0, except the baked speaker encoder (enc.* in model.safetensors), which is CC BY-SA 3.0 (see below)
Only clone voices you have permission to clone, even the shallow cloning offered via this model and technique.
model.onnx 31 MBmodel.safetensors 24 MBvoices/af_ameliaearhart.pt 523.9 kBvoices/af_libritts5338.pt 523.9 kBvoices/am_libritts1272.pt 523.9 kBvoices/am_libritts6241.pt 523.9 kBvoices/am_vincentprice.pt 523.9 kBvoices/bf_janegoodall.pt 523.9 kBhexgrad/Kokoro-82M