One of the most downloaded small TTS models is not a language model at all. We profiled where its time goes and why your first sound arrives late.

SnackOnAI Engineering | Senior AI Systems Researcher | Technical Deep Dive | October 23, 2026

The promise: by the end of this issue you will understand how Kokoro gets broadcast quality narration out of 82 million parameters and about $1,000 of training compute, where its compute actually goes, and when its design makes it the wrong choice.

The fence: we cover the kokoro inference library, the Kokoro-82M model card and voice list, the misaki G2P engine, and the two papers it builds on: StyleTTS 2 and iSTFTNet. We skip training code (not released) and the Chinese v1.1 variant except in passing; quality judgments come from the model card and community reports.

What It Actually Does

Kokoro-82M is an open weight TTS model by the developer hexgrad, released as v1.0 on January 27, 2025, under Apache 2.0. You give it text and pick a preset voice; it returns 24 kHz audio. There is no voice cloning: the 54 voices are fixed.

Property

Value

Parameters

81.8M by our count from the shipped config

Architecture

StyleTTS 2 style, non autoregressive, iSTFTNet vocoder, no diffusion

Languages

American and British English, Spanish, French, Hindi, Italian, Japanese, Brazilian Portuguese, Mandarin

Voices

54 presets (20 American English, 4 Hindi, 1 French)

Training data

"A few hundred hours" of permissive, public domain, and synthetic audio

Training compute

~1,000 A100 80GB hours across v0.19 and v1.0, about $1,000

Adoption

~10.5M Hugging Face downloads in the last month; 100+ Spaces

Hosted price (per card)

Under $1 per million characters, under $0.06 per hour of audio

Around it sits a large ecosystem: kokoro.js for the browser, community ONNX exports, an OpenAI compatible FastAPI server, and TensorRT builds. The model card even warns that look alike "kokoro" domains are unaffiliated and likely scams, which tells you how popular it got.

The Architecture, Unpacked

Kokoro is a parallel synthesizer. It reads the whole utterance, predicts a duration for every phoneme, expands the phonemes into a time grid, and decodes all frames in one forward pass. No step depends on a previous output.

Caption: Everything above the decoder is bookkeeping for time. The decoder, 65% of the parameters, turns a fixed grid of frames into audio in one shot.

Four design decisions do the work.

One: explicit durations instead of attention alignment. Autoregressive TTS learns alignment implicitly and can skip or repeat words. Kokoro predicts integer frame counts per phoneme, then builds a hard alignment matrix. Words cannot be skipped, and speed control is a division: duration / speed.

Two: phonemes, not text. misaki converts text to IPA with dictionaries, spaCy part of speech tags for homographs, and an espeak-ng fallback. You can override pronunciation inline: [Kokoro](/kˈOkəɹO/). The model's vocabulary is just 178 symbols.

Three: style as a vector, not a prompt. StyleTTS 2 samples style with a diffusion model; Kokoro drops the diffusion and ships precomputed style vectors. Each voice file stores one 256 number vector per utterance length, half for timbre (fed to the decoder), half for prosody (fed to the duration and pitch predictors). Voices mix by averaging: voice="af_bella,af_sky".

Four: an iSTFT vocoder. Instead of upsampling all the way to waveform samples with convolutions, iSTFTNet upsamples 60x, predicts a small spectrum (11 frequency bins of magnitude and phase), and lets an inverse STFT do the last 5x. That removes the most expensive late convolution layers.

The Code, Annotated

First, the real API, from the README.

from kokoro import KPipeline
import soundfile as sf

pipe = KPipeline(lang_code='h')                 # 'h' = Hindi, routed to espeak-ng
text = "नमस्ते, यह एक छोटा परीक्षण है।\nदूसरी पंक्ति यहाँ है।"
for i, (graphemes, phonemes, audio) in enumerate(
        pipe(text, voice='hf_alpha', speed=1.0, split_pattern=r'\n+')):
    sf.write(f'{i}.wav', audio, 24000)          # one chunk per newline

en = KPipeline(lang_code='a')
en("[Kokoro](/kˈOkəɹO/) reads IPA overrides.", voice='af_heart,af_bella')  # mixed voice

Caption: Chunks are your unit of latency. For espeak languages like Hindi, the pipeline warns that automatic chunking is not implemented, so split on newlines yourself or long text is truncated at 510 phonemes.

Second, the core of inference, from kokoro/model.py. This is the whole trick of non autoregressive TTS in ten lines.

s = ref_s[:, 128:]                                  # prosody half of the style vector
d = self.predictor.text_encoder(d_en, s, input_lengths, text_mask)
x, _ = self.predictor.lstm(d)
duration = torch.sigmoid(self.predictor.duration_proj(x)).sum(axis=-1) / speed
pred_dur = torch.round(duration).clamp(min=1).long().squeeze()   # frames per phoneme
indices = torch.repeat_interleave(torch.arange(input_ids.shape[1]), pred_dur)
pred_aln_trg = torch.zeros((input_ids.shape[1], indices.shape[0]))
pred_aln_trg[indices, torch.arange(indices.shape[0])] = 1         # hard alignment
en = d.transpose(-1, -2) @ pred_aln_trg              # phonemes → frames
F0_pred, N_pred = self.predictor.F0Ntrain(en, s)     # pitch and energy per frame
audio = self.decoder(t_en @ pred_aln_trg, F0_pred, N_pred, ref_s[:, :128])

Caption: Duration is a sum of 50 sigmoids, so each phoneme lasts at most 50 frames (1.25 s). After this, every frame is known in advance and the decoder can run them all in parallel.

Third, our profiler. The Hugging Face weights are blocked from our sandbox, so we built KModel from the published config.json with random weights (identical shapes, so identical compute) and timed each stage, fixing durations at 3 frames (75 ms) per phoneme, a normal English speaking rate.

m = KModel(repo_id='hexgrad/Kokoro-82M', config=cfg, model='empty.pth')
# parameter split
# bert 6.29M (7.7%) · bert_encoder 0.39M · predictor 16.20M (19.8%)
# text_encoder 5.61M (6.9%) · decoder 53.31M (65.2%) · total 81.81M
# alignment frame = 600 samples → 40 Hz

# 2 vCPU Xeon @ 2.8 GHz, PyTorch 2.14 fp32, 2 threads
#  20 phonemes →  1.5 s audio in   964 ms → 1.6x real time, decoder 89%
# 150 phonemes → 11.2 s audio in 6,706 ms → 1.7x real time, decoder 95%
# at 6 frames/phoneme, 500 phonemes → 75 s audio, decoder 98%

Caption: The language understanding part (PL-BERT) is 1% to 5% of runtime. Kokoro's cost is almost entirely the vocoder, and it grows with seconds of audio, not with text.

It In Action

Input: a 150 phoneme English paragraph (about two sentences) with voice af_heart, on 2 vCPUs of a 2.8 GHz cloud Xeon, plain PyTorch.

Step one, G2P. misaki produces IPA, looking up a gold and silver lexicon first and falling back to espeak-ng for unknown words.

Step two, style. The pipeline picks row 149 of the voice pack, a 256 number vector tuned for utterances of that length.

Step three, durations. At about 3 frames per phoneme, 150 phonemes become 450 frames, 11.2 seconds of speech.

Step four, decode. The decoder turns 450 frames into 270,000 samples in one pass. Total time 6.7 s, of which 95% is the decoder.

Output: 11.2 seconds of audio, but nothing plays until 6.7 seconds have passed, because the chunk is generated as a whole.

Runtime

Real time factor

Source

PyTorch, 2 vCPU Xeon, fp32

1.7x

SnackOnAI measurement

ONNX, Intel i7-11700

~2.4x

Kokoro-FastAPI README

Apple M3 Pro CPU

5x+

Kokoro-FastAPI README

RTX 4060 Ti

35 to 50x

Kokoro-FastAPI README

M2 MacBook Air, WebGPU

2.5 to 5x

community browser benchmark

Mid range x86 laptop, WASM q8, 1 thread

~0.9x

community browser benchmark

Caption: The same model spans 0.9x to 50x depending on runtime. Parallel decoding is why GPUs help Kokoro far more than they help autoregressive CPU models.

Why This Design Works, and What It Trades Away

Why it works. Most TTS failures (skipped words, repeated phrases, runaway generations) come from implicit alignment in autoregressive models. Kokoro removes alignment as a learning problem: durations are explicit, the grid is fixed, and the decoder only has to render. That makes an 82M model stable enough for audiobooks, and parallel enough to saturate a GPU. Training on a few hundred hours of carefully curated audio, including synthetic speech from commercial TTS providers, gave consistent, clean target voices for about $1,000 of compute.

What it trades away.

  • Time to first audio. A chunk is all or nothing. Our 150 phoneme chunk waited 6.7 s on CPU; a maximal 510 phoneme chunk is ~38 s of speech and, at 1.7x, ~23 s of silence first. Streaming servers shrink chunks, and Kokoro-FastAPI warns that smaller chunks can add intonation artifacts.

  • Cloning. No reference audio path at all. You get 54 voices or averages of them.

  • Non English depth. Hindi has 4 voices, each graded C by the author and trained on tens of minutes of data; it relies on espeak-ng and has no automatic chunking. French has one voice.

  • Length sweet spot. Voices work best around 100 to 200 tokens; under 10 to 20 can sound poor, over 400 can sound rushed.

  • Expressiveness. No emotion control beyond choosing a voice and a speed.

Technical Moats

  • Data curation over scale. Permissive and synthetic audio only, graded per voice (target quality and hours of data, HH down to M). The recipe, not the architecture, is what others have struggled to reproduce, and the training code is not public.

  • misaki. A purpose built G2P with lexicons, homograph handling, and per language frontends (pyopenjtalk for Japanese pitch accent, paddlespeech style Chinese). Bad phonemes cap any TTS, and most open models still lean on raw espeak.

  • Apache 2.0 weights plus ubiquity. Commercial friendly licensing turned Kokoro into the default local voice for agents and apps, with ONNX, WebGPU, TensorRT and OpenAI compatible servers already built.

  • Graph friendliness. No sampling loop, no KV cache, fixed shape buckets. That is why it exports cleanly to ONNX and TensorRT, where one community build hits ~100 ms per 4.5 s bucket on a GTX 1650.

Contrarian Insights

Insight One: Kokoro is a vocoder with a small front end attached. "82M parameters" invites comparison with tiny language models, but the language part is the smallest piece. PL-BERT runs 12 layers with one shared ALBERT weight set of just 6.3M parameters and takes 1% to 5% of CPU time in our profile. The decoder holds 65% of parameters and 89% to 98% of time. If you want Kokoro faster on CPU, quantizing or pruning the text side buys almost nothing. The convolutional decoder is the whole game.

Insight Two: "faster on CPU" depends on what you measure. Community comparisons often call Kokoro faster than streaming models like Pocket TTS. On the same 2 vCPU machine in plain PyTorch, we measured Kokoro at 1.7x real time and Pocket TTS at 1.9x, close enough that runtime choices decide the winner. The bigger difference is latency shape: Pocket TTS plays its first 80 ms after one frame, while Kokoro plays nothing until the full chunk is rendered. For voice agents, choose chunk size first and model second.

Surprising Takeaway

Two very different small TTS designs, Kokoro (parallel, duration based) and Pocket TTS (autoregressive, continuous latents), hit the same wall: the waveform decoder. In our Kokoro profile it takes 95% of runtime for a normal paragraph. The next big win in on device speech will come from cheaper vocoders, not smarter text models.

TL;DR For Engineers

  • Kokoro-82M is a non autoregressive StyleTTS 2 derivative with an iSTFTNet decoder; Apache 2.0; 54 preset voices, no cloning.

  • Parameters by our count: decoder 53.3M (65%), prosody predictor 16.2M, PL-BERT 6.3M (12 shared layers), text encoder 5.6M.

  • On 2 vCPUs in PyTorch fp32: 1.7x real time, decoder 89% to 98% of time; GPU runtimes report 35 to 100x.

  • First audio arrives only after a whole chunk renders; keep chunks short for interactive use, longer for narration quality.

  • Non English voices are thin (Hindi graded C); espeak languages need manual newline chunking.

Explain It Like I'm New

Think about how a choir director might prepare a song. Before anyone sings, the director marks on the sheet music exactly how long each syllable lasts, where the pitch rises and falls, and how loud each part should be. Once that plan is written down, the whole choir can sing the entire piece at once.

Kokoro works the same way. First, it turns your text into speech sounds, the small units like "k" and "oh" that make up words. Then it decides how long each sound should last and how high or low the voice should go. Only after that full plan exists does it produce the actual audio, all in one go.

This makes it very reliable. It does not lose its place or repeat words, a common problem with other AI voices. It is also small and cheap: it was trained for about a thousand dollars and can run on a regular computer.

The catch is waiting. Because Kokoro creates a whole passage at once, you hear nothing until that passage is finished. On a powerful graphics card that wait is tiny, but on a basic laptop it can be several seconds. And most of the work is not understanding your words; it is the final step of turning the plan into actual sound waves.

See It In Action

  • Kokoro samples, hexgrad. SAMPLES.md. Reference audio across voices and languages from the model card.

  • Misaki G2P demo, hexgrad on Hugging Face Spaces. hf.co/spaces/hexgrad/Misaki-G2P. See exactly which phonemes Kokoro will receive for your text.

  • Kokoro-FastAPI, community. github.com/opencoca/AI-Voice-Kokoro-FastAPI. OpenAI compatible speech endpoint with streaming, voice mixing, and CPU or GPU backends.

  • Kokoro ONNX for the web, onnx-community. Kokoro-82M-v1.0-ONNX. The export behind kokoro.js, runnable with WebGPU or WASM.

Community Conversation

  • andrew.ooo, Pocket TTS review. Summarizes r/LocalLLaMA comparisons in which Kokoro was rated as good or better than Pocket TTS for fixed voices and faster on CPU, but out of the running for cloning, since it has none.

  • Kokoro-FastAPI README, streaming notes. The author reports ~300 ms first audio on GPU but ~3,500 ms on an older i7 CPU, and warns that smaller streaming chunks can add intonation artifacts.

  • voicechanger.live, browser TTS benchmarks. Puts Kokoro at RTF 0.2 to 0.4 on WebGPU but about 1.1 (slower than real time) on single thread WASM, against Piper at about 0.11.

  • msgflux, Kokoro streaming ONNX. Fixed 96 token buckets reach ~101 ms per call under TensorRT on a GTX 1650, showing how far graph compilers can push a parallel model.

  • Kokoro model card, Hugging Face. The author's own scam warning about look alike domains is a signal of how widely the model spread.

Small Voice Models Are Now Decoder Engineering

Kokoro showed that a small team with $1,000 of compute, careful data, and an unglamorous architecture could ship the voice that a large share of local agents and apps now use. Its strengths come from refusing to be a language model: explicit durations, fixed voices, one parallel pass. Its weaknesses come from the same place: no cloning, all or nothing chunks, and a decoder that eats nearly all the compute. Use Kokoro for narration, batch generation, and GPU servers. For interactive CPU voice agents, measure time to first audio before you commit.

References

Kokoro-82M is an Apache 2.0, non autoregressive TTS model that predicts explicit phoneme durations and renders a whole chunk at once through an iSTFTNet decoder, trained for about $1,000. Our profiling shows the decoder holds 65% of parameters and up to 98% of CPU time, and that first audio waits for the entire chunk.

Sponsored Ad If you enjoy practical AI insights, check out SnackOnAI and support the newsletter by subscribing, sharing, and exploring our sponsored ad—it helps us keep building and delivering value 🚀

Leave Granola and get up to 12 months free of Wispr Flow Notetaker + Dictation

If you have paid time left on an individual Granola plan, we'll match it with a Wispr Flow subscription that includes Notetaker and dictation, and add bonus time, up to 12 months total. Sign in or create a Wispr account and submit proof of your plan to check eligibility.

Recommended for you

View all
caret-right