Kokoro-82M β€” ONNX export for Vernacula

Re-packaged ONNX export of hexgrad/Kokoro-82M (v1.0, StyleTTS2 / iSTFTNet, 24 kHz mono) plus its English voice packs in a flat binary layout, for use as the Kokoro text-to-speech engine in Vernacula.

Highlights

  • Our own export pipeline, not the onnx-community artifacts: we control the opset, the I/O contract and the validation metric. There is no upstream export script to reproduce theirs from.
  • Exported with disable_complex=True. The model's default complex-valued STFT cannot be exported at all (the TorchScript exporter dies on Unknown number type: complex); the real-valued STFT that replaces it is not bit-identical in the waveform domain (vocoder phase is not uniquely determined) but sits at 0.37 log-spectral L1 against PyTorch β€” below a single frame of jitter (0.77) and inaudible in A/B listening. The full argument, with numbers, is in docs/kokoro_onnx_investigation.md.
  • G2P stays outside the graph. The model takes token ids; in Vernacula the phonemes come from vernacula-phonemizer rendered into Kokoro's vocabulary, so the same frontend serves every engine.
  • Voice packs as flat float32, indexed by phoneme-string length, readable without a tensor library.
  • A variable-length batched graph (kokoro_batched.onnx) that renders several texts of different lengths in one call, at the model's own fidelity. Kokoro is batch=1 upstream, and naive padding corrupts the shorter items β€” AdaIN normalises over time, so padding frames pollute the per-item statistics, and the bidirectional LSTMs read padding backwards into real tokens and shift the predicted durations. Masking the statistics, packing the LSTMs and re-zeroing the padding after each AdaIN1d closes all three. It replaces the old single-item graph outright β€” at batch 1 it is ~1.08x faster than that graph was, so there is nothing to trade off.

Contents

File Purpose
kokoro_batched.onnx The whole model, with a dynamic batch axis: token ids + style vectors + speed β†’ 24 kHz waveforms (fp32, ~311 MB, weights inlined). Batch 1 is just the batch=1 case, and is faster than the old single-item graph, so this is the only model here
voices/<name>.bin One voice pack per voice: 510 Γ— 256 float32, little-endian β€” row n is the style vector for a phoneme string of length n + 1
manifest.json Per-file MD5 hashes for integrity checks

ONNX contract

Name Shape dtype Description
input_ids (in) [batch, tokens] int64 Right-padded token ids, one row per text
ref_s (in) [batch, 256] float32 Style vector per item (each indexed by its own phoneme-string length)
speed (in) [1] float32 Speech-rate multiplier, shared by the batch
input_lengths (in) [batch] int64 Real token count per item β€” required; padding is masked from it
audio (out) [batch, samples] float32 24 kHz waveform, padded to the batch's longest item
pred_dur (out) [batch, tokens] int64 Per-token frames, 0 on padded tokens

tokens, batch and samples are dynamic. The context window is 510 tokens per item; split longer text on sentence boundaries first.

Each item is valid for its own pred_dur.sum() * 600 samples; the rest of its row is batch padding, so trim before use. pred_dur is identical to what the item gets rendered alone, at any batch size β€” so word alignment never depends on which texts share a batch.

A batch is padded to its longest item, so grouping texts of similar length matters for throughput: an unsorted mix of one-line headings and long paragraphs fills only ~37% of the batch and is no faster than rendering one at a time. Sorting by phoneme length first roughly doubles it. Fidelity does not depend on the grouping β€” the padding error is a step function (two frames of padding cost as much as two hundred) and is masked out either way.

Voices

The 28 English voices of Kokoro v1.0 β€” American (af_* / am_*) and British (bf_* / bm_*), the prefix selecting the accent's phonemization:

af_alloy af_aoede af_bella af_heart af_jessica af_kore af_nicole af_nova af_river af_sarah af_sky am_adam am_echo am_eric am_fenrir am_liam am_michael am_onyx am_puck am_santa bf_alice bf_emma bf_isabella bf_lily bm_daniel bm_fable bm_george bm_lewis

Upstream also ships voices for other languages (export_voices.py --all); they are not included here because Vernacula's Kokoro frontend is English-only.

Export provenance

Exported via scripts/kokoro_export/ in the Vernacula repo: export_kokoro.py exports KModel.forward_with_tokens at opset 17 with disable_complex=True and validates it against the PyTorch reference on a real (input_ids, ref_s, speed) capture using log-spectral L1 (waveform SNR and random token ids both give meaningless verdicts here β€” see the investigation doc); export_voices.py flattens the voices/*.pt packs.

License

Apache-2.0, inherited from hexgrad/Kokoro-82M. The voice packs are upstream's, redistributed unchanged in layout only.

Using these files

In Vernacula, point Settings β†’ Text-to-Speech β†’ Kokoro-82M at a folder holding these files (or use its Download button). Outside Vernacula:

from huggingface_hub import snapshot_download
import numpy as np, onnxruntime as ort

path = snapshot_download(repo_id="christopherthompson81/kokoro-82m-onnx")
sess = ort.InferenceSession(f"{path}/kokoro_batched.onnx")

# ids: Kokoro vocabulary ids for the phoneme string (see upstream / misaki)
ids = np.array([[0, *phoneme_ids, 0]], dtype=np.int64)
pack = np.fromfile(f"{path}/voices/af_heart.bin", dtype="<f4").reshape(510, 256)
style = pack[len(phoneme_ids) - 1][None, :]
audio, = sess.run(None, {"input_ids": ids, "style": style, "speed": np.array([1.0], np.float32)})
# audio: float32 mono at 24 kHz

Limitations

English only, as packaged here. Inherits Kokoro-82M's own limits (see the upstream model card); the ONNX export adds the phase difference described above and nothing else. Word timing in Vernacula comes from the model's predicted durations, which is exact to the frame.

Citation

See the upstream model card and the StyleTTS 2 paper.

Acknowledgments

Issues with the ONNX export specifically: open an issue on the Vernacula repo. Issues with the underlying model: see the upstream model card.

See also

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for christopherthompson81/kokoro-82m-onnx

Quantized
(72)
this model

Paper for christopherthompson81/kokoro-82m-onnx