# Orpheus TTS - Benchmark com Continuous Batching **Data:** 2024-12-25 **GPU:** NVIDIA RTX 4090 (24GB VRAM) **Modelo:** canopylabs/orpheus-3b-0.1-ft (3B parametros) ## Resumo Implementamos e testamos **Continuous Batching** com vLLM AsyncLLMEngine para o Orpheus TTS, conseguindo **12x mais capacidade** comparado ao uso sequencial. ## Resultados do Teste de Stress | Requests Simultaneos | Taxa Sucesso | Tempo Wall-Clock | Audio Gerado | RTF | Usuarios Real-Time | |---------------------|--------------|------------------|--------------|-----|-------------------| | 4 | 100% | 2.93s | 11.61s | 0.253 | 4.0 | | 8 | 100% | 2.94s | 22.78s | 0.129 | 7.8 | | 12 | 100% | 3.13s | 34.05s | 0.092 | 10.9 | | 16 | 100% | 4.03s | 50.77s | 0.079 | **12.6** | ## Comparacao | Metodo | RTF | Usuarios Real-Time | Melhoria | |--------|-----|-------------------|----------| | Sequencial (orpheus_tts lib) | 0.85 | ~1 | baseline | | Continuous Batching (4 req) | 0.253 | 4.0 | 4x | | Continuous Batching (16 req) | 0.079 | 12.6 | **12x** | ## Otimizacoes Ativas (vLLM 0.13.0) - Flash Attention 2 - Chunked Prefill - Prefix Caching - CUDA Graphs - torch.compile ## Configuracao do Engine ```python engine_args = AsyncEngineArgs( model="canopylabs/orpheus-3b-0.1-ft", dtype="bfloat16", max_model_len=4096, gpu_memory_utilization=0.9, max_num_seqs=16, # Continuous batching enable_chunked_prefill=True, enable_prefix_caching=True, enforce_eager=False, ) ``` ## Problema com a Biblioteca orpheus_tts A biblioteca oficial `orpheus_tts` tem um bug onde o engine vLLM morre apos a primeira inferencia (`EngineDeadError`). A solucao e usar o `AsyncLLMEngine` do vLLM diretamente. ## Formato do Prompt Orpheus ```python # Tokens especiais START_TOKEN = 128259 END_TOKENS = [128009, 128260, 128261, 128257] STOP_TOKEN = 128258 AUDIO_TOKEN_BASE = 128266 # Formato do prompt prompt = f"{voice}: {text}" # Depois adiciona os tokens especiais ``` ## Decodificacao de Audio (SNAC) Os tokens de audio sao organizados em frames de 7 tokens: - Layer 0: offset 0 - Layer 1: offset 4096 (2 tokens por frame) - Layer 2: offset 8192, 12288, etc. (4 tokens por frame) ## Latencia TTFT (Time-To-First-Token) Medimos a latencia ate o primeiro chunk de audio ser gerado: | Requisicoes Simultaneas | TTFT (min) | TTFT (max) | TTFF* (avg) | |------------------------|------------|------------|-------------| | 1 (sequencial) | 12ms | 12ms | **63ms** | | 4 | 12ms | 28ms | **81ms** | | 8 | 12ms | 29ms | **82ms** | | 12 | 14ms | 32ms | **85ms** | | 16 | 16ms | 38ms | **93ms** | *TTFF = Time to First Frame (7 tokens = ~23ms de audio playable) **Conclusao:** Mesmo com 16 requisicoes simultaneas, cada usuario recebe o primeiro chunk de audio em menos de **100ms** - imperceptivel para o usuario! ## Tecnicas de Otimizacao Utilizadas ### 1. Continuous Batching Permite processar multiplas requisicoes simultaneamente na mesma GPU. Em vez de processar uma requisicao por vez (sequencial), o vLLM agrupa varias requisicoes e as processa em paralelo. ```python max_num_seqs=16 # Ate 16 requisicoes simultaneas ``` ### 2. Chunked Prefill + Prefix Caching - **Chunked Prefill**: Divide o processamento do prompt em chunks menores, permitindo intercalar prefill de novas requisicoes com a geracao de tokens de requisicoes existentes - **Prefix Caching**: Reutiliza computacoes de prefixos comuns entre requisicoes (como tokens especiais do Orpheus) ```python enable_chunked_prefill=True enable_prefix_caching=True ``` ## Teste de Limite Maximo (max_num_seqs=256) Testamos ate onde a RTX 4090 aguenta com frases curtas identicas: | Users | Sucesso | TTFF Max | RTF | |-------|---------|----------|-----| | 32 | 100% | 116ms | 0.154 | | 64 | 100% | 136ms | 0.125 | | 128 | 100% | 228ms | 0.091 | | 200 | 100% | 335ms | 0.284 | | 256 | 100% | 413ms | 0.244 | **Resultado:** 256 usuarios simultaneos sem erros, TTFF < 500ms. ## Teste Realista de Streaming (frases variadas) Testamos com frases de tamanhos variados (curtas, medias, longas) para simular uso real: | Users | Max Gap | RTF Max | Streaming com buffer 500ms | |-------|---------|---------|---------------------------| | 32 | 86ms | 3.67 | OK | | 64 | 105ms | 4.51 | OK | | 100 | 139ms | 5.98 | OK | | 128 | 160ms | 6.88 | OK | | 200 | 232ms | 9.80 | OK | | 256 | 375ms | 11.78 | OK | **Conclusao do teste realista:** - Com buffer de ~500ms no cliente: ate 256 usuarios funcionam sem travamento - Sem buffer (streaming puro): ~12-16 usuarios com RTF < 1.0 - Para aulas de idiomas com avatar: recomendado usar buffer no cliente ## Arquivos - `scripts/orpheus_continuous_batching.py` - Script de teste de continuous batching - `scripts/orpheus_stress_test.py` - Teste de stress com 4/8/12/16 usuarios - `scripts/orpheus_ttft_test.py` - Teste de latencia TTFT - `scripts/orpheus_max_users_test.py` - Teste de limite maximo de usuarios - `scripts/orpheus_streaming_test.py` - Teste realista de streaming com frases variadas ## Conclusao Com Continuous Batching + Chunked Prefill + Prefix Caching, uma unica RTX 4090 pode suportar: **Streaming puro (sem buffer):** - **~12-16 usuarios** com RTF < 1.0 - **12x melhoria** sobre o metodo sequencial - **<100ms latencia** para primeiro audio **Com buffer de 500ms no cliente:** - **Ate 256 usuarios simultaneos** sem travamento - Max gap entre frames: 375ms (coberto pelo buffer) - Ideal para aplicacoes de avatar interativo e aulas de idiomas **Recomendacao:** Para aulas de idiomas, usar buffer de ~500ms no cliente para suportar mais usuarios.