- GPT-SoVITS (official)
- + CUDA Graph
- Language
- Code
- Japanese
- 日文
- Chinese
- 中文
Specs
- GPT-SoVITS (official)+ CUDA Graph
- LanguageCode
- Japanese日文
- Chinese中文
- English英文
- EntryRecommended
- GPURTX 3060 6 GB
- CUDA11.8+
- RAM8 GB
- Python3.10
- OSWindows 10+
- PresetPre-capture
- fullYes
- minimalYes
- lazyNo
- offDisabled
- CaseFlash off
- T2S short, 3 chars~427 it/s
- T2S medium, 19 chars~448 it/s
- T2S long, 64 chars~461 it/s
- TTFP short~290ms
- TTFP medium~396ms
- TTFP long~687ms
- TTFP long early-cut~317ms
- MethodPath
- GET/health
- GET/presets
- POST/tts
- POST/tts/file
- GET/voices
- POST/voices/add
- DELETE/voices/{name}
- Env variableDefault
- GPT_SOVITS_HOME(required)
- AQUA_API_KEY(unset)
- AQUA_VOICE_JSON./voices.json
- AQUA_SESSION_CACHE_MAX8
- ENABLE_CUDA_GRAPH1
- ENABLE_CUDA_GRAPH_PRECAPTURE1
- AQUATTS_T2S_FLASH_ATTN0
README
🌊 Aqua-TTS: GPT-SoVITS Low-Latency Inference Runtime on GPU
Built for low-latency voice conversation with your LoRA characters
中文 | English
Aqua-TTS is a GPU-optimized inference runtime purpose-built for real-time voice conversation — specifically, low-latency streaming TTS with your own GPT-SoVITS v3 LoRA character voices. It does not replace model weights — it replaces the execution strategy: static KV cache buffers, bucketed CUDA Graph capture/replay, and pre-compiled BigVGAN CUDA kernels. On an RTX 4070 Ti SUPER, this reaches 440–470 it/s T2S throughput and reduces model-side first-audio latency from 1.0–3.6 s to ~0.26–0.40 s. In the full streaming player pipeline, practical first-audio latency is typically 0.4–0.7 s depending on chunk length, audio device startup, cache state, and scheduling overhead — see Highlights for the full comparison.
Highlights
<sub>Latency definitions: TTFP benchmark = model-side first audio latency under warm-cache (table below). E2E first-audio = full pipeline including audio buffer and playback startup, typically 0.4–0.7 s in practice. Cold start = init + model load + first inference, dominated by BigVGAN CUDA kernel compilation (~2 min on first run, then cached).</sub>
| GPT-SoVITS (official) | + CUDA Graph | Aqua-TTS | |
|---|---|---|---|
| T2S throughput | ~80-90 it/s | ~230 it/s | 440-470 it/s |
| TTFP (short, 3 chars) | 1061ms | 1016ms | ~257ms |
| TTFP (medium, 19 chars) | 1599ms | 1476ms | ~301ms |
| TTFP (long, 64 chars) | 3598ms | 2852ms | ~404ms |
| KV cache | Dynamic torch.cat |
Static scatter_ |
Static scatter_ buffer |
| CUDA Graph | None | Single lazy graph | 17 pre-captured graphs, 6 buckets |
| BigVGAN vocoder | PyTorch JIT | PyTorch JIT | Pre-compiled CUDA kernel |
| KV-cache allocation | Unbounded growth | Unbounded growth | Bounded per bucket config |
TTFP benchmark: NVIDIA GeForce RTX 4070 Ti SUPER (16 GB), PyTorch 2.5.1+cu121, float16, warm cache, static KV cache enabled, bucketed CUDA Graph pre-captured. Aqua-TTS numbers are median of 5 runs. Official baseline uses the same GPT checkpoint; TTFP for non-streaming baselines coincides with full utterance completion. See benchmarks/README.md for full methodology and raw repeats.
https://github.com/user-attachments/assets/581cef5f-f8ce-4570-81ae-a6c092698223
Features
- Static KV cache — pre-allocated scatter buffers eliminate per-step
torch.catoverhead - Bucketed CUDA Graph — 13 pre-captured graphs across 6 bucket sizes, no warmup jitter
- Pre-compiled BigVGAN — NVIDIA CUDA kernel auto-loaded from pre-built
.pyd, with torch fallback - Optional FlashAttention2 KV cache — experimental
flash_attn_with_kvcacheT2S path, disabled by default - Streaming API — generator-based
infer_stream()with early first-audio yield - Built-in presets — fast / balanced / quality generation presets; full / minimal / lazy / off CUDA Graph presets
- Voice registry — map voice names to reference audio + prompt, with JSON persistence
- HTTP server — lightweight FastAPI server with streaming TTS endpoint, voice management, and health check
- Source install —
pip install -e ".[runtime]"→from aquatts import TTSInferencer
Scope notice — Aqua-TTS is a self-contained runtime for GPT-SoVITS v3. It is not a plugin and does not track upstream changes. The techniques here — static KV cache, bucketed CUDA Graph, pre-compiled BigVGAN kernel — are documented in TECHNICAL.md and designed to be portable. If you need v4 support,
aquatts/modeling/andaquatts/_vendor/are the right starting points for adaptation.
Known limitations — Windows + CUDA is the primary tested path. Linux passes unit tests but GPU-dependent paths (CUDA Graph, BigVGAN kernel) have not been validated on Linux hardware. macOS is not supported. TTFP varies with GPU model, audio device, chunk size, and model weights — numbers in this README are measured on an RTX 4070 Ti SUPER with specific v3 LoRA weights and should not be treated as universal. Only GPT-SoVITS v3 is supported.
Supported Languages
Aqua-TTS inherits GPT-SoVITS v3's language support. Pass the code to text_language / prompt_language — reference audio and target text can use different languages.
| Language | Code |
|---|---|
| Japanese | 日文 |
| Chinese | 中文 |
| English | 英文 |
How it works
Aqua-TTS vendors overrides for two GPT-SoVITS files inside aquatts/_vendor/ using Python namespace packages (pkgutil.extend_path). When you import aquatts, the package automatically configures sys.path so the vendored files take precedence over the main GPT-SoVITS repo. Set GPT_SOVITS_HOME to point at your GPT-SoVITS installation — Aqua-TTS handles the rest:
aqua-tts/
├── aquatts/ # Pure Python package (pip-installable)
│ ├── __init__.py # sys.path configuration + lazy exports
│ ├── inferencer.py # TTSInferencer — main entry point
│ ├── server.py # FastAPI HTTP server
│ ├── voice_registry.py # Voice name → audio path mapping
│ ├── modeling/
│ │ ├── t2s_streaming.py # T2SBlockWithStaticCache, CUDA Graph patch
│ │ └── t2s_flash_attn.py # Optional FlashAttention2 KV-cache patch
│ ├── bigvgan/
│ │ ├── cuda/ # Standalone CUDA kernel loader + sources
│ │ └── torch/ # Pure-PyTorch fallback (resample, filter, act)
│ ├── inference/
│ │ ├── streaming.py # Audio post-processing (fade, chunk finalization)
│ │ ├── params.py # SoVITS parameter presets
│ │ └── presets.py # Named presets (generation + CUDA Graph)
│ └── _vendor/
│ └── GPT_SoVITS/ # Vendored overrides (namespace packages)
│ ├── AR/models/
│ │ └── t2s_model.py # Static KV + CUDA Graph T2S decoder
│ └── BigVGAN/alias_free_activation/cuda/
│ ├── load.py # Pre-compiled kernel loader (MSVC auto-discovery)
│ ├── activation1d.py # Fused anti-alias activation
│ └── *.cpp, *.cu, *.h # NVIDIA BigVGAN CUDA kernel sources
├── benchmarks/ # TTFP, T2S comparison, BigVGAN raw benchmarks
├── examples/ # basic_usage.py, streaming_inference.py
└── tests/ # Unit tests
See TECHNICAL.md for deep technical documentation.
Requirements
| Entry | Recommended | |
|---|---|---|
| GPU | RTX 3060 6 GB | RTX 4060 / 4070 8 GB+ |
| CUDA | 11.8+ | 12.x |
| RAM | 8 GB | 16 GB+ |
| Python | 3.10 | 3.11 / 3.12 |
| OS | Windows 10+ | Windows 11 |
Linux CI (Ubuntu) passes for all unit tests. GPU-dependent paths (CUDA Graph, BigVGAN kernel) have not been tested on Linux hardware. macOS is not supported — Aqua-TTS requires CUDA.
On 6 GB cards, use
cuda_graph_preset="lazy"or"off"to reduce VRAM pressure from pre-captured graphs.
Installation
1. Install GPT-SoVITS
You need a working GPT-SoVITS v3 installation. Aqua-TTS imports from it.
git clone https://github.com/RVC-Boss/GPT-SoVITS.git
cd GPT-SoVITS
pip install -r requirements.txt
Aqua-TTS has been tested against GPT-SoVITS v3 (2025-04-01 release).
2. Install PyTorch
Install PyTorch matching your CUDA version before installing Aqua-TTS — it is not included in the package dependencies so you can pick the right CUDA wheel:
# Example for CUDA 12.1 — see https://pytorch.org/get-started/locally/ for other versions
pip install torch --index-url https://download.pytorch.org/whl/cu121
Aqua-TTS has been tested with PyTorch 2.5.1+cu121 on an RTX 4070 Ti SUPER.
3. Install Aqua-TTS
git clone https://github.com/Lucas1479/Aqua-TTS.git
cd Aqua-TTS
# Core + runtime dependencies
pip install -e ".[runtime]"
# Or with HTTP server support
pip install -e ".[runtime,server]"
PyPI package is planned but not yet published.
Extras:
[runtime]— soundfile, librosa, peft (needed byTTSInferencer)[server]— FastAPI + uvicorn (includes[runtime]automatically)
4. Configure GPT-SoVITS path
Set the GPT_SOVITS_HOME environment variable to your GPT-SoVITS repo root:
# Windows (PowerShell)
$env:GPT_SOVITS_HOME = "C:\path\to\GPT-SoVITS"
# Linux / macOS
export GPT_SOVITS_HOME=/path/to/GPT-SoVITS
5. Download pretrained models
Aqua-TTS needs BigVGAN v2 pretrained weights from Hugging Face. Download them directly into your GPT-SoVITS repo with huggingface_hub:
pip install huggingface_hub
python -c "
from huggingface_hub import snapshot_download
snapshot_download(
repo_id='nvidia/bigvgan_v2_24khz_100band_256x',
local_dir='GPT_SoVITS/pretrained_models/models--nvidia--bigvgan_v2_24khz_100band_256x',
)
"
The models--nvidia--bigvgan_v2_24khz_100band_256x directory name is the HuggingFace Hub cache format — use it exactly as shown.
6. Prepare model weights
- GPT weights (T2S): A
Text2SemanticLightningModulecheckpoint (e.g.,s1v3.ckptor self-trainedxxx-e15.ckpt). - SoVITS weights (vocoder): A
SynthesizerTrncheckpoint with optional LoRA (e.g.,xxx_e2_s174_l32.pth). - Reference audio: A 3-10 second 24 kHz WAV file with known transcript.
Quick sanity check
Once GPT_SOVITS_HOME is set and models are in place, verify the package loads correctly:
python -c "from aquatts import TTSInferencer; print('aquatts OK')"
If this prints aquatts OK, the install is good. If it errors, check that GPT_SOVITS_HOME points to the right directory and all pretrained models are downloaded.
Usage
Python API
import os
os.environ["GPT_SOVITS_HOME"] = "/path/to/GPT-SoVITS"
os.environ["ENABLE_CUDA_GRAPH"] = "1"
from aquatts import TTSInferencer
tts = TTSInferencer(
device="cuda",
gpt_path="GPT_weights_v3/s1v3.ckpt",
sovits_path="SoVITS_weights_v3/your_model.pth",
cuda_graph_preset="full", # "full", "minimal", "lazy", or "off"
)
# Streaming generation — yields (sample_rate, audio_chunk, text) tuples
for sr, chunk, text in tts.infer_stream(
text="こんにちは、世界!",
ref_audio_path="reference audio/ref_audio.wav",
prompt_text="こんにちは。今日はいい天気ですね。",
text_language="日文",
prompt_language="日文",
preset="fast", # "fast", "balanced", or "quality"
):
# chunk is float32 numpy array at `sr` Hz
# text is the text segment being spoken
pass
See examples/basic_usage.py and examples/streaming_inference.py for runnable examples.
Presets
Two layers of presets control quality/speed trade-offs:
Generation presets (per-request, via infer_stream(preset=...)):
| Preset | Speed | Sample Steps | Top-K | Temperature |
|---|---|---|---|---|
fast |
1.3x | 4 | 3 | 0.6 |
balanced |
1.1x | 4 | 5 | 0.6 |
quality |
1.0x | 16 | 8 | 0.8 |
CUDA Graph presets (system-level, via TTSInferencer(cuda_graph_preset=...)):
| Preset | Pre-capture | Buckets | Description |
|---|---|---|---|
full |
Yes | 128, 256, 448, 512, 768, 1024 | All lengths covered |
minimal |
Yes | 256, 512, 1024 | Common lengths only |
lazy |
No | on-the-fly | Lower memory, slower TTFP |
off |
Disabled | none | Static KV only, no graphs |
Optional FlashAttention2 T2S path (experimental, disabled by default):
Aqua-TTS can replace the q_len=1 T2S static-KV attention step with
flash_attn_with_kvcache. This is an opt-in path because the useful valid
mode attends over the true KV length rather than the full zero-padded bucket,
so output can differ slightly from the default SDPA bucket path.
Enable it for long first-sentence or long-form T2S throughput experiments:
export AQUATTS_T2S_FLASH_ATTN=1
export AQUATTS_T2S_FLASH_ATTN_MODE=valid # valid | bucket
or from Python:
tts = TTSInferencer(..., use_flash_attn=True, flash_attn_mode="valid")
Keep it off for short demo lines, early-cut first-sentence demos, or strict
regression comparisons. On short 448/512-bucket shapes the extra path is often
within noise or slightly slower; it becomes more interesting on longer 768+
bucket decode.
Directional AB test on the shared Aqua/Amadeus v3 T2S path
(RTX 4070 Ti SUPER, PyTorch 2.5.1+cu124, flash-attn 2.7.0.post2,
CUDA Graph pre-captured, BigVGAN CUDA kernel cached):
| Case | Flash off | Flash on (valid) |
Note |
|---|---|---|---|
| T2S short, 3 chars | ~427 it/s | ~414 it/s | no benefit |
| T2S medium, 19 chars | ~448 it/s | ~478 it/s | small win |
| T2S long, 64 chars | ~461 it/s | ~500 it/s | ~8% throughput win |
| TTFP short | ~290ms | ~297ms | no benefit |
| TTFP medium | ~396ms | ~413ms | no benefit in this run |
| TTFP long | ~687ms | ~659ms | ~28ms model-side win |
| TTFP long early-cut | ~317ms | ~336ms | keep off for early-cut |
Treat these as guidance rather than headline numbers: FlashAttention2 helps
most when attention bucket length is the bottleneck, while Aqua's default
CUDA-Graph SDPA path is already very fast for short conversational turns.
from aquatts import apply_preset, list_presets
print(list_presets()) # ["balanced", "fast", "quality"]
params = apply_preset("fast", overrides={"top_k": 5})
HTTP Server
Start a lightweight inference server:
python -m aquatts.server \
--gpt-model GPT_weights_v3/s1v3.ckpt \
--sovits-model SoVITS_weights_v3/model.pth \
--cuda-graph-preset full \
--host 127.0.0.1 --port 8000
# With authentication (required when binding to a non-loopback address)
python -m aquatts.server ... --host 0.0.0.0 --api-key mysecrettoken
# or: export AQUA_API_KEY=mysecrettoken
Endpoints:
| Method | Path | Description |
|---|---|---|
GET |
/health |
Model load status |
GET |
/presets |
List available presets |
POST |
/tts |
Streaming TTS (float32 PCM chunks) |
POST |
/tts/file |
One-shot TTS (downloadable .wav) |
GET |
/voices |
List registered voices |
POST |
/voices/add |
Register a new voice |
DELETE |
/voices/{name} |
Remove a registered voice |
# Streaming TTS — returns raw float32 PCM (24kHz, mono, little-endian)
curl -X POST "http://127.0.0.1:8000/tts?text=Hello&voice=alice" --output - \
| play -t raw -r 24k -e floating-point -b 32 -c 1 -
# Download WAV file
curl -X POST "http://127.0.0.1:8000/tts/file?text=Hello&voice=alice" -o output.wav
Voice Registry
Manage multiple characters/voices without repeating paths:
from aquatts import Voice, VoiceRegistry
registry = VoiceRegistry(json_path="./voices.json")
registry.add(Voice(
name="alice",
ref_audio_path="./voices/alice_ref.wav",
prompt_text="こんにちは。今日はいい天気ですね。",
prompt_language="日文",
))
voice = registry.get("alice")
for sr, chunk, text in tts.infer_stream(
text="Hello world",
ref_audio_path=voice.ref_audio_path,
prompt_text=voice.prompt_text,
prompt_language=voice.prompt_language,
):
pass
On the HTTP server, pass voice instead of ref_audio_path:
curl -X POST "http://127.0.0.1:8000/tts?text=Hello&voice=alice"
For production deployments, pass an explicit registry path:
python -m aquatts.server ... --voice-registry /data/voices.json
# or
export AQUA_VOICE_JSON=/data/voices.json
Configuration
| Env variable | Default | Description |
|---|---|---|
GPT_SOVITS_HOME |
(required) | Path to GPT-SoVITS repo root |
AQUA_API_KEY |
(unset) | Bearer token for all server endpoints; unset = no auth |
AQUA_VOICE_JSON |
./voices.json |
Path to voice registry JSON file. Always set this — default is relative to process CWD and will be lost on directory change |
AQUA_SESSION_CACHE_MAX |
8 |
Max number of cached reference audio sessions |
ENABLE_CUDA_GRAPH |
1 |
Enable CUDA Graph replay |
ENABLE_CUDA_GRAPH_PRECAPTURE |
1 |
Pre-capture all bucket graphs at startup |
AQUATTS_T2S_FLASH_ATTN |
0 |
Enable experimental FlashAttention2 flash_attn_with_kvcache path for T2S |
AQUATTS_T2S_FLASH_ATTN_MODE |
valid |
FlashAttention mode: valid uses true KV length; bucket preserves zero-padded bucket length |
TTS_OUTPUT_LANGUAGE |
日文 |
Default output language. Change to 中文 or 英文 if not using Japanese |
TTS_REF_TEXT_JA |
こんにちは。今日はいい天気ですね。 |
Default Japanese reference text |
TTS_REF_TEXT_EN |
(empty) | Default English reference text |
TTS_STREAM_SYNC_TIMING |
0 |
Enable per-step CFM timing (adds GPU sync overhead) |
Benchmarks
# T2S comparison (official vs official+CUDA Graph vs Aqua-TTS)
# Replace with your own GPT checkpoint (s1v3.ckpt or a self-trained .ckpt)
python benchmarks/t2s_comparison_bench.py --gpt-model GPT_weights_v3/xxx-e15.ckpt
# TTFP benchmark (streaming end-to-end)
python benchmarks/aqua_ttfp.py \
--gpt-model GPT_weights_v3/xxx-e15.ckpt \
--sovits-model SoVITS_weights_v3/xxx_e2_s174_l32.pth \
--ref-audio "reference audio/ref_audio.wav" \
--ref-text "transcript of reference audio"
# BigVGAN raw kernel timing
python benchmarks/bigvgan_raw_bench.py
See benchmarks/README.md for full methodology and results.
Speaker Demo
pip install -e ".[playback]"
python examples/play_ete.py --gpt-sovits-home /path/to/GPT-SoVITS-v3lora
The demo plays three Kurisu-style Japanese utterances (short, medium, long) through PyAudio and prints TTFP plus live T2S throughput for each scripted line. Pass --show-total to also print audio duration, wall time, and RTF.
Playback demos default to the low-latency live profile (--top-p 1 --speed 1.1 --sample-steps 4 --how-to-cut 按标点符号切) with queue-based playback, chunk merging, short fades, and padding to reduce chunk-boundary artifacts. To inspect whole-utterance T2S throughput without punctuation splitting, pass --how-to-cut 不切.
For recording an interactive demo, load the voice once and type any Japanese text:
python examples/live_talk.py --gpt-sovits-home /path/to/GPT-SoVITS-v3lora
Acknowledgements
Aqua-TTS was inspired by GENIE-TTS, which demonstrated that a focused, self-contained inference runtime could meaningfully close the latency gap in GPT-SoVITS. That framing — optimise the runtime, not the model — shaped the direction of this project.
License
MIT — see LICENSE.
Third-party code:
- GPT-SoVITS: vendored
aquatts/_vendor/GPT_SoVITS/AR/models/t2s_model.pyis based on GPT-SoVITS (MIT) — see NOTICE. - NVIDIA BigVGAN: CUDA kernel sources under Apache 2.0 — see NOTICE.
- alias-free-torch:
aquatts/bigvgan/torch/adapted under Apache 2.0 — see NOTICE.
Development
git clone https://github.com/Lucas1479/Aqua-TTS.git
cd Aqua-TTS
pip install -e ".[runtime]"
pip install -r requirements-dev.txt
export GPT_SOVITS_HOME=/path/to/GPT-SoVITS
python -m pytest tests/ -v
See CONTRIBUTING.md for contribution guidelines and CHANGELOG.md for release history.