Решения

Синтез речи (TTS) на GPU: качество vs латентность

Задача страницы. Инженерный гид по построению TTS‑сервисов на GPU: выбор стеков «текст→мел‑спектрограмма→вокодер», низкая латентность для интерактива vs офлайн‑батчи высокого качества, стриминг (SSE/WebSocket), измерения (TTFA, jitter, RTF), тюнинг и экономика на профилях 24/48/80 ГБ. Все примеры ориентированы на локальный NVMe‑кэш, режимы On‑Demand и Interruptible, и развёртывания в контейнерах/K8s.

TL;DR

  • Два режима:
    On‑Demand (реал‑тайм) — минимальная латентность (TTS для ассистентов/презентаций).
    Interruptible (батчи) — офлайн генерация аудио каталога/видео‑озвучки с упором на качество.
  • Стек: Text Normalize → Phonemize/Tokenizer → Acoustic (FastSpeech‑класс/Glow‑TTS/VITS‑класс) → Vocoder (HiFi‑GAN/BigVGAN/WaveRNN‑класс) → Post‑process.
  • Латентность vs качество:
    Ускоряют — не‑АР вокодеры (GAN‑класс), FP16/BF16, фьюзинг, ONNX/TensorRT, стриминг блоками 20–40 мс.
    Улучшают качество — более тяжёлые акустические модели, высокие частоты дискретизации (22–24–48 кГц), продвинутая пост‑обработка.
  • Ключевые метрики: TTFA (time‑to‑first‑audio), RTF_TTS (synth_time / audio_time), jitter, drop‑rate, p50/p95.
  • Экономика: Cost_per_min = (c_gpu * RTF_TTS / U) / 60; sizing по суммарному RTF_TTS. См. https://cloudcompute.ru/solutions/cost-planner/ и https://cloudcompute.ru/solutions/throughput-vs-latency/
  • Тюнинг: FP16/BF16, кэш фонем/спикер‑эмбеддингов на NVMe, батчирование в батч‑режиме, zero‑copy. См. https://cloudcompute.ru/solutions/performance-tuning/ https://cloudcompute.ru/solutions/fp8-bf16/
  • Наблюдаемость: TTFA, p95 латентности, SPS (samples/sec), GPU util/HBM peak, буферные underruns. См. https://cloudcompute.ru/solutions/monitoring-logging/https://cloudcompute.ru/solutions/llm-inference/observability/

Сценарии использования

  • Интерактив/ассистенты/IVR: мгновенный TTS для ответов, систем оповещения, презентаций.
  • Озвучка видео/курсов/игр: пакетная генерация дорожек с высоким качеством и контролем тембра/стиля.
  • Локализация: мультиязычный TTS, выбор голоса/спикера, управление темпом/паузами/ударениями.
  • Доступность/саблайны: оперативная озвучка текстов, экранные дикторы.
  • A/B‑качество: итеративный рендер в батч‑режиме с несколькими конфигурациями вокодера.

Архитектуры и пайплайны

1) Real‑time TTS (низкая латентность, стриминг блоками)

Text Input

  └─> Normalize/Tokenize

       └─> GPU: Acoustic Model (stream blocks)

            └─> GPU: Vocoder (20–40 ms frames, FP16/BF16)

                 └─> Ring Buffer (200–500 ms, jitter control)

                      └─> Stream Out (SSE/WebSocket, PCM/Opus)

Особенности: TTFA ≤ 150–300 мс, стабильный буфер, backpressure, динамический выбор размера блока по загрузке GPU.

2) Батчи высокого качества (Interruptible)

Text Corpus ─┬─> Normalizer/Phonemizer Cache (NVMe)

              ├─> Work Queue (prio, retries, idempotency)

              └─> N x GPU Workers:

                   ├─> Acoustic (HQ)

                   └─> Vocoder (HQ, non-AR preferred)

                        └─> Post-process (denoise, loudness)

                             └─> Writer (WAV/FLAC/segments + metadata)

                                  └─> Object Storage / DB

Особенности: чанкование по фразам/пунктуации, ретраи ≤ 120 с задач, кэш фонем/эмбеддингов, NVMe для временных артефактов.

3) Мульти‑тенант/мульти‑голос

Ingress ─> Auth ─> Router(by tenant/voice/lang) ─> GPU Pools (24/48/80 ГБ)

                                              └> Autoscaler (target U, TTFA SLA)

                                              └> Profiles (low-latency vs HQ)

GPU‑профили и ориентиры

Диапазоны для одновременных потоков real‑time при TTFA ≤ 300 мс, RTF_TTS ≈ 0.3–0.6, U≈0.7. Для батчей используйте формулы из «Экономики».

Профиль GPU

Память

Типичные стеки

Реал‑тайм потоки*

Батчи (параллель)

Комментарии

24 ГБ (Compact)

24 ГБ

FastSpeech‑класс + HiFi‑GAN

1–3

2–6

Низкая латентность, 22–24 кГц, хороший «радио‑уровень» качества.

48 ГБ (Balanced)

48 ГБ

VITS‑класс / Glow‑TTS + HiFi‑GAN/BigVGAN

3–6

6–12

Баланс качества, поддержка мультиязычия/спикеров, стабильный TTFA.

80 ГБ (HQ)

80 ГБ

Усиленный акустик + BigVGAN

6–12

12–24

HQ‑аудио (до 48 кГц), тяжёлые голоса/эмоции, пост‑проц фильтры.

* Зависит от частоты дискретизации, длины фраз, EMOTION/STYLE‑фич и пост‑обработки.

См. тюнинг: https://cloudcompute.ru/solutions/performance-tuning/https://cloudcompute.ru/solutions/fp8-bf16/https://cloudcompute.ru/solutions/throughput-vs-latency/

Конфиги и скелеты кода

Docker Compose (реал‑тайм + батчи)

				
					version: "3.9"

x-common-env: &env
  MODELS_DIR: /models
  CACHE_DIR: /var/cache/tts
  SAMPLE_RATE: "24000"
  FRAME_MS: "20"
  TTS_PRECISION: "fp16"     # bf16|fp16
  VOICE: "default"
  LANG: "auto"
  STREAM_CODEC: "pcm_s16le" # или opus

services:
  tts-realtime:
    image: cloudcompute/tts-service:latest
    environment:
      <<: *env
      SERVICE_MODE: "realtime"
      TTFA_TARGET_MS: "200"
    deploy:
      resources:
        reservations:
          devices: [{ capabilities: ["gpu"] }]
    ports: ["8081:8081"]
    volumes:
      - /nvme/models:/models
      - /nvme/tts-cache:/var/cache/tts
    command: ["python", "serve_realtime.py", "--host=0.0.0.0", "--port=8081"]

  tts-batch:
    image: cloudcompute/tts-service:latest
    environment:
      <<: *env
      SERVICE_MODE: "batch"
      MAX_TASK_SEC: "120"
    deploy:
      resources:
        reservations:
          devices: [{ capabilities: ["gpu"] }]
    volumes:
      - /nvme/models:/models
      - /nvme/tts-cache:/var/cache/tts
      - /mnt/texts:/data/in
      - /mnt/audio:/data/out
    command: ["python", "run_batch.py", "--input=/data/in", "--output=/data/out"]


				
			

K8s (скелет, 1 GPU на под)

				
					apiVersion: apps/v1
kind: Deployment
metadata:
  name: tts-realtime
spec:
  replicas: 2
  selector: { matchLabels: { app: tts-realtime } }
  template:
    metadata:
      labels: { app: tts-realtime }
    spec:
      containers:
        - name: tts
          image: cloudcompute/tts-service:latest
          ports: [{ containerPort: 8081 }]
          env:
            - { name: TTS_PRECISION, value: "fp16" }
            - { name: SAMPLE_RATE, value: "24000" }
            - { name: FRAME_MS, value: "20" }
            - { name: TTFA_TARGET_MS, value: "200" }
          volumeMounts:
            - { name: models, mountPath: /models }
            - { name: cache,  mountPath: /var/cache/tts }
          resources:
            limits:
              nvidia.com/gpu: 1
              memory: "24Gi"
              cpu: "4"
      volumes:
        - name: models
          hostPath: { path: /nvme/models }
        - name: cache
          hostPath: { path: /nvme/tts-cache }


				
			

Конфиг пайплайна (YAML)

				
					pipeline:
  text:
    normalize: true
    lang: auto
    split_sentences: true
  acoustic:
    model: "fastspeech_like"   # или vits_like/glow_tts_like
    precision: "fp16"
    speaker_id: "default"
    style: { speed: 1.0, energy: 1.0, pitch: 1.0 }
    stream_blocks_ms: 80
  vocoder:
    type: "hifigan_like"       # или bigvgan_like/wavernn_like
    frame_ms: 20
    precision: "fp16"
    stream: true
  output:
    sample_rate: 24000
    codec: pcm_s16le
    stream_chunk_ms: 40
    formats: [wav, segments_json]


				
			

FastAPI: стриминг аудио (SSE с base64‑фреймами)

				
					from fastapi import FastAPI, Body
from sse_starlette.sse import EventSourceResponse
import base64, asyncio, json

app = FastAPI()

async def tts_stream(text: str):
    # Генерируем аудио блоками 20–40 мс: bytes PCM16LE @ 24kHz
    async for frame in synth_blocks(text):
        yield base64.b64encode(frame).decode("ascii")

@app.post("/tts/stream")
async def tts_stream_endpoint(payload: dict = Body(...)):
    text = payload.get("text", "")
    async def event_gen():
        async for b64_chunk in tts_stream(text):
            yield {"event": "audio", "data": b64_chunk}
        yield {"event": "done", "data": "{}"}
    return EventSourceResponse(event_gen())


				
			

Пакетная генерация (псевдокод)

				
					from pathlib import Path
from concurrent.futures import ThreadPoolExecutor

def normalize_and_cache(texts):
    # нормализация/фонемизация с кэшем на NVMe
    ...

def synth(text, voice="default", sr=24000):
    mel = acoustic_infer(text, voice=voice, precision="fp16", stream=False)
    wav = vocoder_infer(mel, sr=sr, precision="fp16")
    return postprocess(wav)

def batch_tts(input_dir, output_dir, workers):
    texts = [p.read_text() for p in Path(input_dir).glob("*.txt")]
    texts = normalize_and_cache(texts)
    with ThreadPoolExecutor(max_workers=workers) as ex:
        for i, wav in enumerate(ex.map(synth, texts)):
            write_wav(Path(output_dir)/f"utt_{i:06d}.wav", wav, sr=24000)


				
			

Наблюдаемость, метрики, алерты

Метрики (Prometheus‑стиль):

  • TTFA: tts_ttfa_seconds{mode=rt} — время до первого аудиофрейма. Цель p95 ≤ 0.3 с.
  • RTF_TTS: tts_rtf{mode=rt|batch} — отношение времени синтеза к длительности аудио.
  • Latency: tts_latency_seconds{phase=normalize|acoustic|vocoder|post} (p50/p95).
  • Throughput: tts_samples_per_sec, tts_frames_per_sec.
  • Jitter: tts_jitter_ms — вариации интервала выдачи фреймов.
  • Drops/Underruns: tts_buffer_underrun_total, tts_stream_drop_rate.
  • GPU: tts_gpu_utilization, tts_gpu_memory_bytes, tts_gpu_mem_peak_bytes.
  • I/O: tts_nvme_read_mb_s, tts_nvme_write_mb_s, hit‑rate кэша фонем/спикеров.

Алерты (примеры):

  • TTFA_p95 > 0.5s 5 мин — увеличить пул low‑latency или уменьшить stream_blocks_ms.
  • RTF_TTS_p95 > 0.8 — деградация; проверить акустик/вокодер/precision/параллелизм.
  • GPU_mem_peak / HBM > 0.9 — снизить размер блоков/включить offload/оптимизировать граф.
  • buffer_underrun_total > 0 — увеличить ring buffer до 300–500 мс, проверить backpressure.

См. https://cloudcompute.ru/solutions/monitoring-logging/ и https://cloudcompute.ru/solutions/llm-inference/observability/

Экономика и формулы

Обозначения: c_gpu — цена GPU/час, U — целевая загрузка GPU, RTF_TTSt_synth / t_audio.

  • Сколько GPU для стриминга:
    GPU_count = ceil( (Σ RTF_TTS_streams) / U )
    Пример: 10 потоков, каждый RTF_TTS≈0.4, U=0.7ceil((10×0.4)/0.7)=6 GPU.
  • Стоимость минуты аудио:
    Cost_per_min = (c_gpu * RTF_TTS / U) / 60.
  • Батчи (время партии):
    T_batch ≈ (RTF_TTS × L_audio_total) / (GPU_count × U).
  • Кэш выгоден, если Hit_rate_cache × t_precompute > t_miss_overhead.
    Кэшируйте фонемизацию и спикер‑эмбеддинги на NVMe.

См. https://cloudcompute.ru/solutions/cost-planner/ и https://cloudcompute.ru/solutions/throughput-vs-latency/

Безопасность и политики

  • PII в тексте: фильтры/маскирование (телефоны, адреса) до логирования.
  • Голоса/спикеры: храните эмбеддинги/референсы отдельно, с доступом по ролям.
  • Ретеншн: временные артефакты (мел‑спектры, промежуточные WAV) — авто‑очистка по TTL.
  • Секреты: ключи/токены — только через Secret‑хранилища/переменные окружения.
  • Изоляция: отдельные GPU‑пулы для тенантов/языков, контроль доступа к бакетам.

Подробнее: https://cloudcompute.ru/solutions/security/https://cloudcompute.ru/solutions/llm-inference/guardrails/

Траблшутинг

Симптом

Возможная причина

Решение

Долгий TTFA

Крупные блоки/инициализация на запрос

Подогрев, stream_blocks_ms 60–80, кэш моделей/эмбеддингов

Дребезг/«металл»

Агрессивный вокодер/низкая частота

Переключить на HQ‑вокодер, 24–48 кГц, мягкий пост‑фильтр

Паузы «ломаются»

Сплит по пунктуации некорректен

Улучшить нормализацию, ограничить длину фразы, расставить SSML‑паузу

Статтеринг/повторы

Нестабильность акустика при длинных фразах

Короткие блоки, ограничить max‑len, стабилизировать prosody параметры

Щелчки между блоками

Границы фреймов/неконсистентный gain

Кросс‑фейд 5–10 мс, общий loudness‑норм, единый dither

Jitter/underruns

Недогружен ring buffer/нет backpressure

Буфер 200–500 мс, управление темпом стриминга, фикс потоков

VRAM OOM

Тяжёлый стек/высокая частота/много потоков

FP16/BF16, уменьшить блоки, разделить акустик/вокодер по пулам

Низкий U

Мелкие задачи/частые переключения

Микро‑батчинг для батч‑режима, pinning, совмещение очередей

Качество «плоское»

Неверные style/pitch/energy

Калибровка style‑параметров, контроль скорости речи

См. https://cloudcompute.ru/solutions/performance-tuning/https://cloudcompute.ru/solutions/interruptible-patterns/

Как запустить в cloudcompute.ru

  1. Откройте Шаблоны запусков: https://cloudcompute.ru/solutions/templates/
    Выберите TTS (Real‑time) или TTS (Batch).
  2. Профиль GPU: 24/48/80 ГБ. Для интерактива — low‑latency стек (HiFi‑GAN‑класс), для HQ — BigVGAN‑класс.
  3. Диски/кэш: смонтируйте /nvme/models и /nvme/tts-cache; для батчей — /mnt/texts и /mnt/audio.
  4. Настройте переменные окружения (частоты, блоки, precision, голос/язык) как в docker-compose.yml.
  5. Для продакшна: автоскейл по U/TTFA, отдельные пулы на low‑latency и HQ, мониторинг/алерты.

Дополнительно:
https://cloudcompute.ru/solutions/triton-inference-server/ — сервинг моделей через Triton/ONNX/TensorRT.
https://cloudcompute.ru/solutions/gradio-fastapi/ — быстрый UI/эндпойнты.
https://cloudcompute.ru/solutions/containers-ci-cd/ — сборка и доставка контейнеров.

Чек‑лист перед продом

  • Замерены TTFA p50/p95, RTF_TTS p50/p95, jitter под целевой корпус.
  • Выбран стек под профиль (24/48/80 ГБ) и SLA; запас по U ≥ 0.2.
  • NVMe‑кэш подключён; кэш фонем/эмбеддингов активен.
  • Стриминг блоками 20–40 мс; ring buffer 200–500 мс; backpressure протестирован.
  • Форматы вывода и кодеки проверены (WAV/Opus/segments JSON).
  • Алерты по TTFA/RTF/GPU‑HBM/underruns включены.
  • Политики PII/ретеншна и доступов к голосам внедрены.
  • Interruptible‑джобы идемпотентны, ретраи ≤ 120 с.
  • Нагрузочное тестирование ≥ 30 мин на целевом профиле.