Skip to content

chatterbox: cache prepared voice-conversion targets - #1253

Merged
0xShug0 merged 2 commits into
0xShug0:mainfrom
magnus-dev-melin:chatterbox-vc-reference-cache
Nov 10, 2026
Merged

0xShug0 merged 2 commits into
0xShug0:mainfrom
magnus-dev-melin:chatterbox-vc-reference-cache

Conversation

@magnus-dev-melin

Copy link
Copy Markdown
Contributor

Chatterbox VC prepares the target voice (speaker embedding, prompt mel and prompt tokens) on every request, even when converting into the same voice again, which is what a server converting a speaker's sentences one by one does. The session now keeps prepared targets in memory, keyed by the target audio, in chatterbox.vc_reference_cache_slots slots (default 1, 0 turns reuse off), the way chatterbox.conditionals_cache_slots does for cloning. ChatterboxVCComponent gains prepare_target() and a convert() overload that takes a prepared target; the existing convert(source, target_voice, config) is unchanged for callers and still checks settings and source audio before preparing the target. Model-local; no framework changes. Option added to model_specs/chatterbox.json, the loader option list and docs/tts.md.

Affects performance and repeatability: with the cache off, outputs are identical to main; with it on, a request gives the output main gives the first time (details below).

Validation (macOS, M1 Max, Metal, chatterbox_q8_0 as "task": "vc", num_inference_steps 3, legacy server, seed 7). The same 15 /v1/tasks/run requests after one warm-up: one target voice for 9 conversions of 3 sources, then two target voices taking turns 6 times, against a main build and this branch with 0, 1 and 2 slots, twice in alternating order:

target prepared cache hits preparation (median) RSS
main 15× — 208 / 247 ms 566–821 MB
slots 0 15× 0 216 / 310 ms 657–749 MB
slots 1 (default) 7× 8 233 / 254 ms 632–769 MB
slots 2 3× 12 174 / 288 ms 643–805 MB
  • A hit skips the preparation, about 0.2–0.3 s of a 1.2–1.6 s request here (S3Gen itself 0.9–1.3 s); whole-request times varied ±0.2 s between rounds on this machine, so the preparation count and time are the clearer measure.
  • Outputs (SHA-256 of the returned WAV): with slots 0, all 15 matched main in both rounds. With the cache on, the first request matched main, and repeating a request gave the same output again; on main a repeated request with the same seed gave a slightly different output after each new preparation, so cached results are also repeatable.
  • With 1 slot, two voices taking turns miss every time; with 2 slots they hit every time.
  • RSS stayed flat over the requests; a slot holds the target audio and its prepared reference.
  • model_spec_system_test, cli_request_options_test and tools/check_loader_catalog_sync.py pass.

Not measured: CUDA/Vulkan (the change is backend-independent), and the parallel runtime beyond building.

Chatterbox VC prepared the target voice (speaker embedding, prompt
features and tokens) on every request, even when converting into the
same voice again, as a server does for every sentence of one speaker.
The session now keeps prepared targets in memory, keyed by the target
audio, in chatterbox.vc_reference_cache_slots slots (default 1, 0 turns
it off), like conditionals_cache_slots does for cloning. Settings and
source audio are still checked before any target is prepared.
@0xShug0

0xShug0 commented Nov 10, 2026

Copy link
Copy Markdown
Owner

@magnus-dev-melin One issue is that a cache miss prepares the target voice before validating the source audio and conversion settings. With a negative guidance value, I got the same error in about 0.5 ms on main and 39 ms on this PR. Please validate the source and settings before preparing the target.

On a cache miss the session prepared the target voice before the
conversion settings and source audio were checked, so an invalid request
failed only after that work. The session now validates them first.
@magnus-dev-melin

Copy link
Copy Markdown
Contributor Author

Thanks, fixed in 0536593: on a cache miss the session now validates the settings and source audio before preparing the target (ChatterboxVCComponent::validate, which both convert overloads also use). Measured as you did, flow_guidance_scale -1 with a target not in the cache, round trip including HTTP on an M1 Max: main 1.7–3.9 ms, this branch 2.1–2.3 ms, same error. The 15-request sequence from the description still gives byte-identical outputs and the same 8 cache hits with 1 slot.

@0xShug0
0xShug0 merged commit de6fbe3 into 0xShug0:main Nov 10, 2026
7 checks passed
@0xShug0

0xShug0 commented Nov 10, 2026

Copy link
Copy Markdown
Owner

@magnus-dev-melin Merged. Thanks for the quick turnaround!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants