Add kokoro_batched.onnx: variable-length batched graph (masked AdaIN + packed LSTMs), supersedes kokoro.onnx
Browse files
README.md
CHANGED
|
@@ -42,12 +42,20 @@ layout, for use as the Kokoro text-to-speech engine in
|
|
| 42 |
rendered into Kokoro's vocabulary, so the same frontend serves every engine.
|
| 43 |
- **Voice packs as flat float32**, indexed by phoneme-string length, readable without a
|
| 44 |
tensor library.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
|
| 46 |
## Contents
|
| 47 |
|
| 48 |
| File | Purpose |
|
| 49 |
|---|---|
|
| 50 |
-
| `
|
|
|
|
| 51 |
| `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* |
|
| 52 |
| `manifest.json` | Per-file MD5 hashes for integrity checks |
|
| 53 |
|
|
@@ -63,6 +71,27 @@ layout, for use as the Kokoro text-to-speech engine in
|
|
| 63 |
`tokens` and `samples` are dynamic. The context window is 510 tokens; split longer text
|
| 64 |
on sentence boundaries first.
|
| 65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
### Voices
|
| 67 |
|
| 68 |
The 28 English voices of Kokoro v1.0 β American (`af_*` / `am_*`) and British
|
|
@@ -100,7 +129,7 @@ from huggingface_hub import snapshot_download
|
|
| 100 |
import numpy as np, onnxruntime as ort
|
| 101 |
|
| 102 |
path = snapshot_download(repo_id="christopherthompson81/kokoro-82m-onnx")
|
| 103 |
-
sess = ort.InferenceSession(f"{path}/kokoro.onnx")
|
| 104 |
|
| 105 |
# ids: Kokoro vocabulary ids for the phoneme string (see upstream / misaki)
|
| 106 |
ids = np.array([[0, *phoneme_ids, 0]], dtype=np.int64)
|
|
|
|
| 42 |
rendered into Kokoro's vocabulary, so the same frontend serves every engine.
|
| 43 |
- **Voice packs as flat float32**, indexed by phoneme-string length, readable without a
|
| 44 |
tensor library.
|
| 45 |
+
- **A variable-length batched graph** (`kokoro_batched.onnx`) that renders several texts of
|
| 46 |
+
*different* lengths in one call, at the model's own fidelity. Kokoro is batch=1 upstream, and
|
| 47 |
+
naive padding corrupts the shorter items β AdaIN normalises over time, so padding frames
|
| 48 |
+
pollute the per-item statistics, and the bidirectional LSTMs read padding backwards into real
|
| 49 |
+
tokens and shift the predicted durations. Masking the statistics, packing the LSTMs and
|
| 50 |
+
re-zeroing the padding after each `AdaIN1d` closes all three. It supersedes `kokoro.onnx`,
|
| 51 |
+
being faster even at batch 1.
|
| 52 |
|
| 53 |
## Contents
|
| 54 |
|
| 55 |
| File | Purpose |
|
| 56 |
|---|---|
|
| 57 |
+
| `kokoro_batched.onnx` | **Preferred.** The whole model with a dynamic batch axis: renders a padded batch of different-length texts in one call (fp32, ~311 MB, weights inlined) |
|
| 58 |
+
| `kokoro.onnx` | The original batch=1 graph, kept for older clients: token ids + style vector + speed β 24 kHz waveform (fp32, ~310 MB, weights inlined) |
|
| 59 |
| `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* |
|
| 60 |
| `manifest.json` | Per-file MD5 hashes for integrity checks |
|
| 61 |
|
|
|
|
| 71 |
`tokens` and `samples` are dynamic. The context window is 510 tokens; split longer text
|
| 72 |
on sentence boundaries first.
|
| 73 |
|
| 74 |
+
### ONNX contract β `kokoro_batched.onnx`
|
| 75 |
+
|
| 76 |
+
| Name | Shape | dtype | Description |
|
| 77 |
+
|---|---|---|---|
|
| 78 |
+
| `input_ids` (in) | `[batch, tokens]` | int64 | Right-padded token ids, one row per text |
|
| 79 |
+
| `ref_s` (in) | `[batch, 256]` | float32 | Style vector per item (each indexed by *its own* phoneme-string length) |
|
| 80 |
+
| `speed` (in) | `[1]` | float32 | Speech-rate multiplier, shared by the batch |
|
| 81 |
+
| `input_lengths` (in) | `[batch]` | int64 | Real token count per item β **required**; padding is masked from it |
|
| 82 |
+
| `audio` (out) | `[batch, samples]` | float32 | 24 kHz waveform, padded to the batch's longest item |
|
| 83 |
+
| `pred_dur` (out) | `[batch, tokens]` | int64 | Per-token frames, 0 on padded tokens |
|
| 84 |
+
|
| 85 |
+
Each item is valid for its **own** `pred_dur.sum() * 600` samples; the rest of its row is batch
|
| 86 |
+
padding, so trim before use. `pred_dur` is identical to what the item gets rendered alone, at any
|
| 87 |
+
batch size β so word alignment never depends on which texts share a batch.
|
| 88 |
+
|
| 89 |
+
A batch is padded to its longest item, so grouping texts of **similar length** matters for
|
| 90 |
+
throughput: an unsorted mix of one-line headings and long paragraphs fills only ~37% of the batch
|
| 91 |
+
and is no faster than rendering one at a time. Sorting by phoneme length first roughly doubles it.
|
| 92 |
+
Fidelity does not depend on the grouping β the padding error is a step function (two frames of
|
| 93 |
+
padding cost as much as two hundred) and is masked out either way.
|
| 94 |
+
|
| 95 |
### Voices
|
| 96 |
|
| 97 |
The 28 English voices of Kokoro v1.0 β American (`af_*` / `am_*`) and British
|
|
|
|
| 129 |
import numpy as np, onnxruntime as ort
|
| 130 |
|
| 131 |
path = snapshot_download(repo_id="christopherthompson81/kokoro-82m-onnx")
|
| 132 |
+
sess = ort.InferenceSession(f"{path}/kokoro.onnx") # or kokoro_batched.onnx, see above
|
| 133 |
|
| 134 |
# ids: Kokoro vocabulary ids for the phoneme string (see upstream / misaki)
|
| 135 |
ids = np.array([[0, *phoneme_ids, 0]], dtype=np.int64)
|