De grens van snelheid en kosten verleggen voor Qwen3-TTS

Samenvatting (TL;DR)

Onze implementatie van Qwen3-TTS 1.7B CustomVoice behaalt 10 requests per seconde (RPS) en een p95 time-to-first-audio (TTFA) van minder dan 50 ms, terwijl real-time weergave behouden blijft op een enkele NVIDIA H100 SXM.

We hebben vijf implementaties vergeleken: de onze, vLLM-Omni, SGLang-Omni△, VoxServe en M*, onder Poisson open-loop verkeer. Na het tunen van elke implementatie voor low-latency streaming, is de onze de enige die een p95 TTFA van minder dan 50 ms behaalt. We behouden deze p95 TTFA van onder de 50 ms tot 10 RPS, en houden deze onder de 100 ms, zelfs bij 20 RPS.

Ons systeem produceert ongeveer 630 tekens per seconde bij 10 RPS. Bij een kostprijs van $4,29 per uur voor een 1× H100 SXM-instantie, vertaalt dit zich naar ongeveer $2 per 1 miljoen tekens bij volledige benutting¹. Ter vergelijking: ElevenLabs V3 kost $100 per 1 miljoen tekens en Cartesia Sonic 3.5 kost $49 per 1 miljoen tekens, bij een hogere TTFA.

We stellen de implementatie en de benchmark open source beschikbaar. Onze methodologie wordt hieronder toegelicht.

Definiëren van "Real-time" TTS

Laten we beginnen met wat een real-time TTS-server moet bereiken. Wij zien dit als een probleem dat uit vier delen bestaat:

  1. Lage hoorbare TTFA: De tijd vanaf het verzenden van het verzoek tot het eerste hoorbare sample moet laag zijn.
  2. Geen underruns: Zodra de weergave begint, mag de client niet zonder gebufferde audio komen te zitten.
  3. Capaciteit: Punten 1 en 2 moeten standhouden naarmate de RPS toeneemt.
  4. Geen malformed output: De spraak moet verstaanbaar zijn.

We hebben gekozen voor Qwen3-TTS CustomVoice 1.7B omdat dit een van de meest populaire TTS-modellen is met een permissieve licentie. Op basis van de bovenstaande definitie richten we ons op een lage p95 hoorbare TTFA zonder underruns, terwijl we een hoge RPS behouden op een enkele NVIDIA H100 SXM.

Alle benchmarks zijn vijf minuten uitgevoerd onder Poisson open-loop verkeer om realistische werklasten te benaderen, in navolging van de LLM-benchmark van Fireworks AI. Elke engine ontvangt de volledige tekst in één HTTP-verzoek, terwijl de audio-output gestreamd blijft. We detecteren de hoorbare TTFA, reconstrueren de weergave vanuit de ontvangen PCM en evalueren de voltooide audio met behulp van Deepgram STT.

Hoe presteren andere engines?

De onderstaande tabel toont het standaardresultaat bij 1 RPS voor elke engine. In deze run zijn alleen wijzigingen voor compatibiliteit toegepast.

Enginep95 hoorbare TTFAp95 beginstilteVerzoeken met underruns
vLLM-Omni277,883 ms90 ms100%
SGLang-Omni△1.140,69 ms80 ms0%
VoxServe315,064 ms30 ms0%
M*1.159,956 ms90 ms0%

Deze standaardinstellingen bieden aanzienlijke ruimte voor verbetering. We hebben elke serving engine getuned op basis van de eigen eisen voor latentie, continuïteit, kwaliteit en capaciteit.

1. Verwijderen van beginstilte

De eerste PCM die door een model wordt teruggegeven, kan tientallen milliseconden stilte bevatten voordat het eerste aanhoudende geluid klinkt. Deze kloof duwt de hoorbare TTFA naar achteren.

We hebben een dynamische trim toegevoegd. Deze detecteert aanhoudende spraak via korte RMS-vensters, verwijdert samples vóór de onset en streamt de resterende audio normaal. Deze wijziging verbetert de TTFA met ongeveer 80 ms, maar maakt de modelinferentie zelf niet sneller.

2. Tunen van frame-accumulatie

We hebben ook getuned hoeveel codec-frames worden verzameld voordat ze worden gedecodeerd en een audio-chunk wordt vrijgegeven.

Kleinere initiële chunks verminderen de TTFA, maar bieden minder weergave-headroom en zorgen voor frequentere decoder-activiteit. Grotere chunks zijn gemakkelijker te batchen en maken continue weergave veiliger, maar vertragen de eerste hoorbare output. Een effectieve configuratie begint daarom met een kleine chunk en vergroot de chunk-grootte voor latere output.

De exacte instellingen verschillen per engine: vLLM-Omni biedt instellingen zoals codecchunkframes en codecchunkramp; de andere engines bieden equivalente chunk- of stride-controles. We hebben deze waarden geïtereerd om de configuratie te vinden die het beste past bij: een lage p95 TTFA, nul underruns en stabiel gedrag bij toenemende belasting.

Prestaties na tuning van bestaande serving engines

De volgende tabel toont het geselecteerde profiel zonder underruns voor elke engine, na tuning van de beginstilte en frame-accumulatie.

Enginep95 TTFA (1 RPS)p95 TTFA (6 RPS)
vLLM-Omni56,815 ms93,451 ms
SGLang-Omni△120,879 ms273,700 ms
VoxServe49,3 ms363,2 ms
M*104,035 ms179,501 ms

VoxServe bereikt een p95 TTFA van minder dan 50 ms bij 1 RPS, terwijl de andere drie engines dat niet doen. Rond de 6 RPS zit elke engine op een p95 TTFA van ongeveer 100 ms of hoger².

Hoe we Qwen3-TTS hebben geoptimaliseerd

Om te optimaliseren moeten we eerst de architectuur van Qwen3-TTS begrijpen. Het is een model uit drie delen dat hiërarchische multi-codebook generatie uitvoert:

  • De Talker voorspelt het eerste codebook-token voor elk audioframe.
  • De Code Predictor genereert de resterende 15 codebook-tokens.
  • De causale Codec converteert codebook-tokens naar waveform-samples.

Elke module heeft zijn eigen compute-profiel, batching-gedrag en latentie-eisen. In plaats van elke module geïsoleerd te optimaliseren, richtten we ons op de vraag: hoe moet een serving-systeem deze heterogene taken coördineren?

1. Drie modules onder één scheduler brengen

De meeste implementaties van Qwen3-TTS zijn verdeeld in twee fasen: de Talker en Code Predictor draaien samen, terwijl de Codec apart draait. Deze scheiding maakt het mogelijk om token-generatie en waveform-decodering over verschillende verzoeken heen te laten overlappen.

Wij gaan een stap verder. We presenteren de Talker, Code Predictor en Codec als drie onafhankelijk planbare taken. De kern is niet alleen het splitsen in delen, maar het brengen van alle drie op een gedeeld scheduling-oppervlak dat door één scheduler wordt beheerd. Dit ontwerp is geïnspireerd door M* (arXiv).

Met deze opzet kan de scheduler beslissen of hij de Talker moet uitvoeren, de Code Predictor moet laten vorderen, of prioriteit moet geven aan een Codec-taak die zijn weergave-deadline nadert. Ook kunnen verzoeken die wachten op dezelfde module worden gebatched. In plaats van een vaste volgorde te volgen, kunnen we het werk herschikken op basis van urgentie.

Het combineren van de Talker en Code Predictor lijkt efficiënter omdat het een tussenliggende grens verwijdert. Echter, de gecombineerde operatie kan een niet-onderbreekbare eenheid van werk worden die urgentere Code Predictor- of Codec-taken blokkeert. Door de modules gescheiden te houden, ontstaan kortere eenheden van werk, wat de scheduler meer mogelijkheden geeft om verzoeken af te wisselen.

2. Scheduling rond de behoeften van speech streaming

Speech streaming kent twee verschillende vormen van urgentie:

  • Vóórdat het eerste audio-chunk arriveert, verhoogt elke milliseconde de TTFA; deze route moet dus prioriteit krijgen.
  • Zodra de weergave begint, verandert het doel: het volgende chunk hoeft alleen maar aan te komen voordat de huidige audio stopt met spelen. Het eerder produceren hiervan biedt geen zichtbaar voordeel voor de gebruiker.

Daarom geven we hoge prioriteit aan verzoeken die nog geen eerste audio hebben geproduceerd, terwijl bestaande streams pas urgent worden wanneer ze hun weergave-deadline naderen.

Het alleen uitvoeren van elk urgent verzoek zou de batching-efficiëntie vernietigen. In plaats daarvan selecteert onze scheduler een urgent verzoek als "anker" en vult de rest van de batch aan met compatibel werk. Dit helpt het kritieke verzoek om zijn deadline te halen, terwijl de GPU effectief wordt benut. Deze policy werkt bijzonder goed omdat alle drie de modules een gedeeld scheduling-oppervlak delen.

3. Benutten van de regelmatige structuur van de Code Predictor

De Code Predictor is een autoregressieve transformer, maar de uitvoering is ongebruikelijk regelmatig. Hij voert altijd een vast aantal stappen (15) per frame uit om de resterende audio-codebooks te vullen.

We benutten deze vaste structuur door de KV-cache vooraf toe te wijzen en de volledige frame-generatie-loop vast te leggen als een enkele CUDA-grafiek. We gebruiken daarnaast een Triton attention-kernel die gespecialiseerd is in deze korte, begrensde context. Door een host-gestuurde sequentie te vervangen door een vast GPU-programma, verlagen we de latentie en vereenvoudigen we het uitvoeringssysteem.

4. De Codec herbouwen rond gecachte status

De Qwen3-TTS Codec bestaat uit Transformers en CNN's. Het genereren van het volgende audio-chunk hangt af van zowel de Transformer-context als de convolutionele status van vorige chunks.

Een naïve implementatie verwerkt bij elke update de volledige frame-geschiedenis opnieuw, waardoor oude audio herhaaldelijk wordt gedecodeerd naarmate de uiting groeit. Om dit te voorkomen, gebruiken we een Codec op basis van een state-cache. Elk verzoek behoudt de Transformer-context en de convolutionele status die nodig zijn voor het volgende chunk. Incrementele decodering hergebruikt deze gecachte status en verwerkt alleen nieuw gearriveerde frames.

Het initialiseren van de state-cache vanuit het eerste frame voegt overhead toe en schaadt de TTFA. Daarom gebruiken we volledige decodering voor de eerste audio, en schakelen we daarna over op state-cached incrementele decodering voor efficiënte aanhoudende weergave. We variëren op soortgelijke wijze de chunk-groottes gedurende een verzoek: kleinere chunks laten de weergave snel beginnen, terwijl grotere chunks de batching en GPU-efficiëntie verbeteren tijdens aanhoudende weergave.

5. Aanvullende serving-optimalisaties

  • We leggen CUDA-grafieken vast voor een vooraf gedefinieerde set batch-groottes. Als een groep klaarstaan verzoeken de grootste vastgelegde batch-grootte overschrijdt, splitsen we deze over verschillende scheduling-beurten in plaats van terug te vallen op de eager-modus.
  • We vermijden onnodige CPU-GPU synchronisatie. Bijvoorbeeld: zolang EOS (End Of Sentence) is onderdrukt, kan de generatie niet stoppen. We stellen de controle op beëindiging daarom uit tot EOS is ingeschakeld. Hierdoor kan de CPU vervolgwerk voorbereiden en indienen zonder op de GPU te wachten.
  • Ten slotte ondersteunen we input-streaming voor modulaire speech-to-speech systemen. Terwijl een upstream LLM tokens genereert, kan het TTS-model beginnen met het synthetiseren van spraak voordat de volledige respons is ontvangen, wat de end-to-end latentie vermindert.

Wat is het vervolg?

Qwen3-TTS is slechts het begin van ons werk aan multimodale inferentie. We zijn van plan onze scope uit te breiden naar beeld-, video- en wereldmodellen, evenals fine-tuning. Onze uiteindelijke visie is om de wereld 1:1 te simuleren via real-time multimodale inferentie.

Wij zijn een team van experts in multimodale AI-onderzoek en infrastructuur. Ons open TTS-model, Dia, is meer dan twee miljoen keer gedownload en stond op nummer 1 op Hugging Face. Ons team van voormalige YC-, KRAFTON- en NAVER-engineers heeft onderzoek gepubliceerd op NeurIPS en ICLR en drie gouden medailles behaald bij de IOI en ICPC World Finals. Nari Labs wordt ondersteund door Y Combinator.

***

De upstream SGLang-Omni ondersteuning was nog onvolledig op het moment van testen in medio augustus 2026.

¹ Deze schatting sluit netwerking, idle-capaciteit en operationele overhead uit.

² Let op dat de enige wijziging die we maken buiten het configuratiebestand de trimmen van beginstilte is. Ondanks onze inspanningen kan er een configuratie bestaan die de onze nipt verslaat.