TAI BUI
Back to curriculum
BuildPython

Text-to-Speech (TTS) — From Tacotron to F5 and Kokoro

ASR inverts speech to text; TTS inverts text to speech. The 2026 stack is three parts: text → tokens, tokens → mel, mel → waveform. Each part has a default model that fits in a laptop.

TIME: ~75 minutesPREREQUISITES: Phase 6 · 02 (Spectrograms & Mel), Phase 5 · 09 (Seq2Seq), Phase 7 · 05 (Full Transformer)

Learning Objectives

  • Break the TTS pipeline into its three stages: text frontend, acoustic model, and vocoder, and identify which stage produced a given failure
  • Name the major TTS acoustic models (Tacotron 2, FastSpeech 2, VITS, F5-TTS, Kokoro) and explain the core architectural tradeoff each one makes
  • Implement a full TTS pipeline in code: phonemize text, synthesize speech with Kokoro and with F5-TTS voice cloning, and connect a vocoder to turn mel spectrograms into audio
  • Pick the right evaluation metric for a TTS system (MOS, CMOS, UTMOS/DNSMOS, CER via ASR, SECS) and avoid the pipeline's most common production pitfalls

The Problem

You have a string: "Please remind me to water the plants at 6 pm." You need a 3-second clip that sounds natural, gets the prosody right (pauses, stress), pronounces "plants" with the correct vowel, and runs in under 300 ms on a CPU inside a live voice assistant. You also need to swap voices on demand and not embarrass yourself on someone's name. Code-switched input ("remind me at 6 pm, daijoubu?") is a real production headache too, but multilingual phonemization is its own problem, out of scope here.

The modern TTS pipeline breaks into three stages:

  1. Text frontend. Normalize the text (dates, numbers, emails), convert it to phonemes or subword tokens, and predict prosody features.
  2. Acoustic model. Text → mel spectrogram. Tacotron 2 (2017), FastSpeech 2 (2020), VITS (2021), F5-TTS (2024), Kokoro (2024).
  3. Vocoder. Mel → waveform. WaveNet (2016), WaveRNN, HiFi-GAN (2020), BigVGAN (2022), neural codec vocoders from 2024 on.

By 2026 the line between acoustic model and vocoder has blurred: end-to-end diffusion and flow-matching models (techniques that turn noise into structured output through iterative refinement, rather than one deterministic pass) collapse both stages into one. The three-part mental model still earns its keep when you're debugging, though: it tells you which stage produced the bad output.

Warm-up0/3
1. A sequence model that generates output one step at a time, each step conditioned on everything generated so far, is called autoregressive. Compared to a model that produces its entire output in one parallel pass, what tradeoff would you expect an autoregressive model to have at inference time?Warm-up
Two diagrams. Model A: input x, then outputs y1 to y4 in a chain, each with an arrow to the next. Model B: input x into a model box with four arrows going directly to y1 to y4. A question mark sits on the right.
Schematic of the two generation styles in the question.
2. What does a spectrogram of an audio clip show?Warm-up
A heat map image of a one second audio clip with time along the bottom from 0 s to 1 s, three horizontal bands of brightness that step upward, a question mark beside the vertical axis and a question mark beside a column of brightness colours.
Computed with numpy from a synthetic clip of three steady tones. The axes and colours are left unnamed.
3. An audio file is stored with a sample rate of 24,000 Hz. What does that number mean?Warm-up
A file info card for clip.wav with a line sample rate: 24,000 Hz and a small waveform drawn under it, followed by a question mark asking what the number counts.
Typed file info card, for illustration.
Check: The Problem0/3
1. What are the three stages of the modern TTS pipeline, in order?Define
The sentence Please remind me to water the plants at 6 pm. at the top, an audio clip at the bottom, and three unordered chips vocoder, text frontend and acoustic model between them with a dashed arrow and a question mark asking in what order.
Schematic. The chips are shown in a shuffled order.
2. What does a vocoder do in a TTS pipeline?Define
A box labelled vocoder highlighted in orange, with an arrow in from a box marked input question mark and an arrow out to a box marked output question mark, and a question below asking what it does.
Schematic. Only the stage the question asks about is named.
3. Why does the lesson keep the three-stage model even though end-to-end models blur the stages together?Explain
A text box feeding one large rounded box labelled one diffusion or flow model, containing three dashed faint boxes frontend, acoustic and vocoder, which outputs an audio box. A question below asks why the lesson still teaches the three-stage model.
Schematic of an end-to-end model with its stages merged.

The Concept

Tacotron, FastSpeech, VITS, F5/Kokoro side-by-side

Tacotron 2 (2017). A seq2seq model: char-embedding → BiLSTM encoder → location-sensitive attention → autoregressive LSTM decoder, emitting mel frames one at a time. Slow, because it's autoregressive, and wobbly on long text, but still the baseline everyone cites.

FastSpeech 2 (2020). Non-autoregressive: a duration predictor decides how many mel frames each phoneme gets, and the whole spectrogram comes out in one pass, 10× faster than Tacotron. It trades away some naturalness for that speed (monotonic alignment forces rigid timing), but it ships everywhere.

VITS (2021). Jointly trains an encoder, a flow-based duration model, and a HiFi-GAN vocoder end-to-end with variational inference: one model, high quality, and the dominant open-source TTS choice from 2022 to 2024. Variants include YourTTS (multi-speaker, zero-shot) and XTTS v2 (2024, Coqui).

F5-TTS (2024). A diffusion transformer over flow matching, with natural prosody and zero-shot voice cloning from 5 seconds of reference audio. Tops the 2026 open-source TTS leaderboards at 335M params.

Kokoro (2024). Small at 82M params, runs on CPU, and is best-in-class English TTS for real-time use, though it's English-only with a closed vocabulary, licensed Apache 2.0.

OpenAI TTS-1-HD, ElevenLabs v2.5, Google Chirp-3. Commercial state of the art. ElevenLabs v2.5's emotion tags ("[whispered]", "[laughing]") and character voices dominate audiobook production in 2026.

Vocoder evolution

EraVocoderLatencyQuality
2016WaveNetoffline onlySOTA at release
2018WaveRNN~realtimegood
2020HiFi-GAN100× realtimenear-human
2022BigVGAN50× realtimegeneralizes across speakers/langs
2024SNAC, DAC (neural codecs)integrated with AR modelsdiscrete tokens, bit-efficient

By 2026 most "TTS" models run end-to-end from text to waveform. The mel spectrogram is just an internal representation now.

Evaluation

  • MOS (Mean Opinion Score). 1–5 scale, crowd-sourced. Still the gold standard, and still painfully slow to collect.
  • CMOS (Comparative MOS). A-vs-B preference judgment, with tighter confidence intervals per annotation than MOS.
  • UTMOS, DNSMOS. Reference-free neural MOS predictors; what the leaderboards actually run.
  • CER (Character Error Rate) via ASR. Run the TTS output back through Whisper and compute CER against the input text: a cheap proxy for intelligibility.
  • SECS (Speaker Embedding Cosine Similarity). Voice-cloning quality, measured directly.

2026 numbers on LibriTTS test-clean:

ModelUTMOSCER (via Whisper)Size
Ground truth4.081.2%—
F5-TTS3.952.1%335M
XTTS v23.813.5%470M
VITS3.623.1%25M
Kokoro v0.193.871.8%82M
Parler-TTS Large3.762.8%2.3B
Check: The Concept0/12
1. What does FastSpeech 2's duration predictor do?Define
Six phoneme chips P L AH N T S, an arrow into a highlighted box labelled duration predictor with a question mark asking about its output, then a decoder box that leads to a mel spectrogram.
Schematic. Phonemes come from running the lesson's toy grapheme-to-phoneme code.
2. What is F5-TTS?Define
A code block from the lesson that imports F5TTS, creates it and calls tts.infer with ref_file my_voice_5s.wav, a reference text about a quick brown fox, and a gen_text about watering the plants.
Copied from the lesson's Build It step 3.
3. What is Kokoro?Define
A code block from the lesson importing KPipeline from kokoro, creating it with lang_code a and calling it on the sentence Please remind me to water the plants at 6 pm. with the voice af_bella.
Copied from the lesson's Build It step 2, trailing comments removed.
4. What is HiFi-GAN?Define
A short Python class sketch named HiFiGAN with an init taking mel_channels 80 and upsample_rates [8, 8, 2, 2], and a forward method that takes mel and returns self.blocks of mel.
Copied from the lesson's Build It step 4, comments removed.
5. What does MOS report?Define
A typed evaluation report card listing system TTS model A, test set held-out sentences and a line MOS with its value shown as a question mark, followed by a question mark asking what the number reports.
Typed example. The card is illustrative.
6. What does SECS measure?Define
A tile titled SECS with a value shown as a question mark, and a waveform labelled one synthesized clip on its right.
Schematic. The waveform is a made-up shape.
7. What does FastSpeech 2 give up in exchange for being about 10x faster than Tacotron 2?Explain
Two rows. Tacotron 2 draws eight separate mel frame squares emitted one at a time. FastSpeech 2 draws the same width as one block made in a single pass. A line says FastSpeech 2 is about 10 times faster, followed by a question mark asking what it gives up.
Schematic. The 10x figure is from the lesson.
8. How is VITS's architecture different from a pipeline of separate models?Explain
Top: text, an acoustic model box and a vocoder box in a row with arrows, ending in audio. Bottom: VITS (2021) with text going into a dashed box containing a question mark, ending in audio.
Schematic. The VITS box is left blank on purpose.
9. How do MOS and CMOS differ as TTS evaluation methods?Explain
Two waveforms labelled model A output and model B output feeding two boxes named MOS and CMOS, each with an arrow to a question mark.
Schematic. Waveform shapes are made up.
10. In the LibriTTS test-clean table, ground truth has 1.2% CER via Whisper. Which synthesized model comes closest to that?Apply
A number line from 0 percent to 4 percent with a single orange marker at 1.2 percent labelled ground truth.
Axis in character error rate percent. Values from the lesson's table.
11. A cloned voice scores well on UTMOS and CER, but listeners say it does not sound like the target speaker. Which metric measures that gap?Analyze
A target speaker's clip and a cloned clip with an arrow to a card saying UTMOS scores well, CER scores well, and listeners say it does not sound like the target.
Schematic of the stem's situation. No real scores are shown.
12. F5-TTS has UTMOS 3.95 and Kokoro 3.87, yet Kokoro has the lower CER (1.8% vs 2.1%). What is a fair reading?Analyze
Two bar charts. UTMOS: F5-TTS 3.95 and Kokoro 3.87. CER: F5-TTS 2.1 percent and Kokoro 1.8 percent.
Values from the lesson's table.

Build It

Step 1: phonemize input

Phonemes are the universal bridge between text and audio. Feed raw text to anything below VITS-level quality and pronunciation gets rough fast.

python
from phonemizer import phonemize
ph = phonemize("Hello world", language="en-us", backend="espeak")
# 'həloʊ wɜːld'

Step 2: run Kokoro (2026 CPU default)

Runs entirely offline, ships as a single file, and weighs in at 82M params.

python
from kokoro import KPipeline
tts = KPipeline(lang_code="a")  # "a" = American English
audio, sr = tts("Please remind me to water the plants at 6 pm.", voice="af_bella")
# audio: float32 tensor, sr=24000

Step 3: run F5-TTS with voice cloning

Pass a 5-second reference clip and its transcript, and F5 clones both the prosody and the timbre.

python
from f5_tts.api import F5TTS
tts = F5TTS()
wav = tts.infer(
    ref_file="my_voice_5s.wav",
    ref_text="The quick brown fox jumps over the lazy dog.",
    gen_text="Please remind me to water the plants.",
)

Step 4: HiFi-GAN vocoder from scratch

Too big to fit in a tutorial script, but the shape is:

python
class HiFiGAN(nn.Module):
    def __init__(self, mel_channels=80, upsample_rates=[8, 8, 2, 2]):
        super().__init__()
        # 4 upsample blocks, total 256x to go from mel-rate to audio-rate
        ...
    def forward(self, mel):
        return self.blocks(mel)  # -> waveform

Training combines an adversarial loss (a discriminator judging short windows), a mel-spectrogram reconstruction loss, and a feature-matching loss. It's commoditized at this point: grab pretrained checkpoints from the hifi-gan repo or nvidia-NeMo instead of training from scratch.

Step 5: the full pipeline (pseudocode)

python
text = "Please remind me at 6 pm."
phones = phonemize(text)
mel = acoustic_model(phones, speaker=alice)      # [T, 80]
wav = vocoder(mel)                                # [T * 256]
soundfile.write("out.wav", wav, 24000)
Check: Build It0/5
1. What is a phoneme?Define
The lesson's phonemize call on Hello world and its returned string həloʊ wɜːld, with the ten letters of hello world in chips above and the eight returned symbols in orange chips below.
Output string copied from the lesson, split into symbols by hand.
2. How is a HiFi-GAN vocoder trained?Explain
A mel box feeding a highlighted HiFiGAN box that produces a generated waveform, a real recording waveform below it, and a question mark on the right asking about the training signal.
Schematic. Waveform shapes are made up.
3. In the Kokoro example, KPipeline(lang_code="a") is called with a sentence. What sample rate does the returned audio use?Apply
The lesson's Kokoro code block with a final comment reading audio: float32 tensor, sr equals a question mark.
Copied from the lesson's Build It step 2, with the number replaced by ?.
4. In the HiFi-GAN sketch, upsample_rates=[8, 8, 2, 2]. A mel with 100 frames goes in. About how long is the 24 kHz output?Apply
A heat map of a mel spectrogram labelled 100 frames by 80 channels, a code box with upsample_rates [8, 8, 2, 2] and a note that the output sample rate is 24 kHz, and a question mark asking how long the output audio is.
The mel picture is made up; the numbers are from the question.
5. In the F5-TTS call, ref_text is 'The quick brown fox jumps over the lazy dog.' and gen_text is 'Please remind me to water the plants.' What does the output audio say?Apply
The F5-TTS infer call with ref_file, ref_text about a quick brown fox and gen_text about watering the plants, and an arrow down to an output wav box that says question mark for what it says and question mark for the voice.
Call copied from the lesson's Build It step 3.

Use It

Picking a model in 2026 comes down to the situation:

SituationPick
Real-time English voice assistantKokoro (CPU) or XTTS v2 (GPU)
Voice cloning from 5 s referenceF5-TTS
Commercial character voicesElevenLabs v2.5
Audiobook narrationElevenLabs v2.5 or XTTS v2 + fine-tune
Low-resource languageTrain VITS on 5–20 h target-lang data
Expressive / emotion tagsElevenLabs v2.5 or StyleTTS 2 fine-tune

The open-source leaders as of 2026: F5-TTS for quality, Kokoro for efficiency. Don't reach for Tacotron unless you're a historian.

Check: Use It0/3
1. You must support a low-resource language that no large TTS model covers. What does the lesson's selection table suggest?Design
A card with target language low-resource, large TTS models that cover it: none, and what you will collect or use shown as a question mark.
Typed summary of the question's situation.
2. A product needs expressive speech that can whisper or laugh on cue through emotion tags. Which choice fits?Design
A script card with two lines: a line tagged [whispered] reading Someone is at the door, and a line tagged [laughing] reading Just kidding.
Typed illustration. The tag style comes from the lesson; the sentences are made up.
3. You are shipping an English voice assistant that must answer in under 300 ms on a CPU with no GPU. Which model fits best?Design
A requirements card: language English, hardware CPU only with no GPU, answer latency under 300 ms.
Typed summary of the question's requirements.

Pitfalls

  • No text normalizer. "Dr. Smith" reads as "Doctor" or "Drive"? "2026" as "twenty twenty six" or "two zero two six"? Normalize before the phonemizer ever sees the text.
  • OOV proper nouns. "Nguyen" → "en-goo-yen"? Ship a fallback grapheme-to-phoneme model for unknown tokens.
  • Clipping. Vocoder output rarely clips on its own, but a mel-scaling mismatch at inference can overshoot ±1.0. Always call np.clip(wav, -1, 1).
  • Sample-rate mismatch. Kokoro outputs 24 kHz. If your downstream pipeline expects 16 kHz, resample it, or you'll get aliasing.
Check: Pitfalls0/5
1. Why must text normalization happen before the phonemizer, as in the 'Dr. Smith' and '2026' examples?Explain
The text Dr. Smith moved here in 2026. with Dr. and 2026 outlined in orange, an arrow down into a highlighted phonemizer box, and an output arrow to a question mark.
Typed example text, built from the two examples in the question.
2. What clipping risk does the lesson warn about, and what is the fix?Explain
A waveform whose peaks rise above a dashed line marked +1.0 and below a dashed line marked -1.0.
Synthetic waveform scaled to exceed the range, for illustration.
3. A pipeline built on Kokoro sends its output straight to a system that expects 16 kHz audio, with no resampling step. What happens?Apply
A Kokoro box with sample rate shown as a question mark, an arrow through a dashed no-resample slot into a downstream box that expects 16 kHz, and a question mark asking what happens.
Schematic of the situation in the question.
4. A TTS system reads '2026' as 'two zero two six'. Swapping VITS for F5-TTS does not change it. Which stage should you inspect first?Analyze
Three boxes text frontend, acoustic model and vocoder in a row. The text 2026 enters on the left. Under the middle box a note says swapping VITS for F5-TTS gives the same output, and a question asks which stage to inspect first.
Schematic of the situation in the question.
5. Your TTS mispronounces the name 'Nguyen' as 'en-goo-yen' because it is not in the vocabulary. What does the lesson recommend?Analyze
The name Nguyen going into a TTS system and coming out pronounced en-goo-yen, with a note that the name is not in the pronunciation vocabulary and a question asking what the lesson recommends.
Schematic of the situation in the question.

Ship It

outputs/skill-tts-designer.md is a reusable skill: pick a TTS model, voice, text-normalization scope, and evaluation plan for a given language, style, and latency target.

Author's Note

The three-stage mental model (frontend, acoustic model, vocoder) is worth keeping even once you're running an end-to-end diffusion model that hides those seams internally. Every real TTS bug I've chased down lived in the text frontend, not the neural network everyone wants to blame first. A model mispronouncing a date or a name is a normalization problem, not an acoustic one, and swapping VITS for F5-TTS won't fix a phonemizer that never saw the right input. Debug top-down: check what actually reached the acoustic model before you touch the model itself.

Exercises

  1. Easy. Run code/main.py. It builds a phoneme dictionary from a toy vocab, estimates duration per phoneme, and prints a fake "mel" schedule.
  2. Medium. Install Kokoro and synthesize the same sentence with voices af_bella and am_adam. Compare audio durations and subjective quality.
  3. Hard. Record a 5-second reference clip of yourself, clone it with F5-TTS, and report the SECS between the reference and the cloned output.

Key Terms

TermWhat people sayWhat it actually means
PhonemeSound unitAbstract sound class; 39 in English (ARPABet).
Duration predictorHow long each phoneme lastsNon-AR model output; integer frames per phoneme.
VocoderMel → waveformNeural net mapping mel-spec to raw samples.
HiFi-GANStandard vocoderGAN-based; dominant 2020–2024.
MOSSubjective quality1–5 mean opinion score from human raters.
SECSVoice-clone metricCosine similarity between target and output speaker embedding.
F5-TTS2024 open-source SOTAFlow-matching diffusion; zero-shot cloning.
KokoroCPU English leader82M-param model, Apache 2.0.

Further Reading

Code

Ships With