The speed-up, step by step
How I made it 12.9× faster
Every step below is a real model file, measured in the same run as v1.1 on one desktop core (i7-14700K) in Node, which runs WebAssembly on the same V8 engine as Chrome. Every step that changed the weights had to keep quality: 400 dev sentences × 3 seeds, 1,600 more held-out sentences, and a second speech recogniser as a guard. The test set got one look per release.
Where I started
v1.1Paradee-8M v1.1: Kokoro-82M's af_heart voice distilled into 7.6M parameters. It sounds great, but in onnxruntime-web it ran at 15× realtime and took 3.6 s from a cold start to its first sound.
15×the baseline · 8.46 MB- 1
Faster DSP, same weights
A closed-form sine bank instead of a running-sum oscillator, radix-4 block STFTs, and DSP tables rebuilt when the session starts instead of stored in the file.
28×1.88× v1.1 · 8.12 MB - 2
Slimmer text side, packed weights
A smaller text model, and every layer stored at the fewest bits it can take (4, 6 or 8), unpacked at load. The file went from 8.46 MB to 4.60 MB.
33×2.15× v1.1 · 4.60 MB - 3
Copy-free decoder head
I laid out the head's tensors so the STFT stages never copy data between them. Same function, less memory traffic.
34×2.26× v1.1 · 4.61 MB - 4
GAN-trained decoder head
v2dA new head with a 300-point noise path, trained adversarially. It sounds better than v1.1's and does less work.
41×2.70× v1.1 · 5.00 MB - 5
A distilled, slimmer trunk
The decoder trunk went from 256 to 192 channels, distilled from the wider one.
45×2.98× v1.1 · 4.26 MB - 6
Quantisation-aware training, int8 math
v2eFine-tuned for its own 4-bit weights and 8-bit compute, so the biggest matrix multiplies run in int8 without costing quality.
50×3.34× v1.1 · 4.01 MB - 7
Slimmer again: 128 channels
A second distillation round. The trunk is now half as wide as v1.1's.
54×3.57× v1.1 · 3.56 MB - 8
A new DSP head
v2fHarmonics computed on the noise path's grid so one inverse STFT makes both, noise drawn by rows from a small table, and only ops a GPU backend supports.
73×4.85× v1.1 · 3.42 MB - 9
A smaller text model
liteA narrower text encoder: 0.8 MB smaller and about 15% faster, for a small word-error cost.
85×5.62× v1.1 · 2.64 MB - 10
No LSTM, fully streamable
v2gA convolutional text side with a sentence vector, and a decoder with fixed per-channel norms. Both run in chunks, so audio can start after about 10 ms.
97×5.96× v1.1 · 2.32 MB - 11
My own engine: pdn
pdnA C to WebAssembly engine written for exactly this model: 136 kB instead of onnxruntime-web's 21.6 MB, SIMD128 and relaxed-SIMD builds with int8 dot products, FFT-based DSP, its own noise generator, and streaming. Same v2g weights, 2.1× faster again. (v2f on pdn: 149×, 9.6× v1.1.)
201×12.91× v1.1 · 2.32 MB
v2f on pdn is already in production as the read-aloud voice of a web-novel reading site. The browser numbers above are on one thread, because a normal web page can't count on more: the 4-thread onnxruntime-web build needs cross-origin isolation, and pdn doesn't need any of it.