Optimize Higgs Audio v3 inference#79
Conversation
- pack QKV and gate/up projections and use fused SwiGLU in the shared Qwen decoder path - use grouped FlashAttention, F16 bucketed KV caches, direct set-rows updates, and CUDA-friendly RoPE/view/set-rows graphs - retain and reuse cloned-reference KV prefixes so repeated server requests prefill only their text suffix - add graph and F16 KV correctness coverage plus fixed-seed request-level CUDA benchmark/parity tooling - document the optimized Higgs runtime controls and reproducible validation flow
|
@mirek190 Awesome optimization! I'm gonna merge it into dev directly. Sometimes I wonder whether I’ve been too strict about parity and missed out on significant performance gains. Maybe the best approach is to offer two modes: parity-first and performance-first. Users who are particularly sensitive to quality, like in issue #67, could use parity mode, while others could prioritize performance. Honestly, with TTS, both 90% and 99% parity can sound perfectly valid to me. |
|
I'm glad you like it |
|
@mirek190 Is that possible to achve the 2x improvement as you mentioned in #63 (comment)? Does it require bypassing the framework modules/templates, modifying GGML, or using any other special customizations? |
Actually that was a mistake ;) sorry |
|
Ah I see. Your optimization already provides a significant performance boost. I will test and try to merge OutieTTS after the world cup final, and then foucs on Higgs TTS. Linux + RTX 5090
|
|
With your RTX 5090 is even better .. wow |
Summary
Continuation work of 0xShug0
from commit 2e5c5e5
This PR optimizes the existing Higgs Audio v3 TTS implementation while keeping
the public model/session interface unchanged.
matrix multiplications and uses fused SwiGLU;
direct
SET_ROWSgraphs that expose the CUDAROPE -> VIEW -> SET_ROWSfusion pattern;
text suffix on subsequent requests with the same reference;
generation;
log-mel, timing, RTF, and frame-count comparison tool.
Base and comparison point
devat698ea146ca5a83ad074c9278522ab810729ee3cedevalready contains currentmainata0f3b4cc0669d854ef6a239c7cbcf6a90dac1b1d.2e5c5e568b252241d39d7d521d10c462ac8f442d.devtouches theHiggs model, shared Qwen decoder, or KV-cache paths changed here.
The historical commit did not register
higgs_tts_warm_benchas a CMaketarget and accepted only inline request JSON. For the detached baseline
worktree I made two harness-only changes: registered that existing source as a
warmbench target and added
--request-sequence-file. No baseline runtime ormodel source was changed.
Model setup and tested paths
Native model-manager package:
The benchmark used the standalone Q8 GGUF already produced by the GGUF tool:
Voice reference:
Exact candidate build commands
Windows PowerShell 5.1, Visual Studio 2022 17.13.5, Ninja, CUDA 12.4, RTX 3090
(
sm_86):The detached
2e5c5e5baseline used the same configure flags and a separatebuild/windows-cuda-benchmarkdirectory.Exact standalone run
Result: success, 24 kHz mono WAV generated.
Exact performance/parity run
Candidate command (run three times with labels
latest_dev_run1throughlatest_dev_run3):Baseline command used the detached historical executable, the same model and
case file, and labels
exact_2e5_run1throughexact_2e5_run3:Runs were alternated baseline/candidate. Model loading is excluded; each fresh
process performs one warmup request followed by five measured requests. Values
below are per-request mean +/- sample standard deviation across three fresh
processes. Speedup is baseline RTF / candidate RTF, so small output-length
differences do not inflate the result.
All five requests improved. Candidate RTF is
0.1668to0.2114on thisworkload.
Parity interpretation
These are fixed-seed sampled runs at temperature
1.0, top-p0.95, top-k50, matching the non-zero-temperature reference behavior. Greedy mode wasnot substituted because it is not the upstream Higgs generation setting.
The optimized default stores KV in F16, so small logit changes can change a
sampled token. Every request differs by only one or two 960-sample codec frames,
but the waveforms are not expected to be bit-identical after the sampled path
diverges. The table therefore reports the drift and similarity rather than
hiding it behind aggregate numbers.
-RequireSameFramesis available forcomparisons that are expected to be numerically identical.
This PR compares the optimized C++ path directly with the exact original C++
implementation. A new Python-vs-C++ numerical parity claim is not made for this
Q8/F16 optimization run: the available Python reference uses native weights,
so quantization and sampled-token drift would confound that comparison.
Memory notes
One isolated five-request process per revision, sampled every 100 ms:
2e5c5e5Windows WDDM did not expose reliable per-process VRAM, so the GPU values are
isolated total-device readings. The candidate reduced observed peak GPU memory
by about 142 MiB. Host RSS is higher; retained reference state and differences
between the historical and current framework are included in that figure.
Generated artifacts
Local, intentionally ignored by Git:
Each benchmark directory contains:
Tests
Passed:
The test covers packed-vs-separate projection values, suffix causal masks,
single and batched F16 KV writes, one grouped FlashAttention op, two direct KV
updates, fused GLU, no repeated KV-head materialization, and the
ROPE -> VIEW -> SET_ROWSgraph sequence.Also passed:
git diff --check.The all-target build was attempted. It currently stops in three Moss parity
test targets (
codec_encode_parity,codec_dequant_parity, andcodec_decode_parity) because those tests still call pre-refactor path-basedconstructors while current
origin/devrequiresTensorSource. Those files areunchanged by this PR; the requested Higgs, CLI, and server targets build.
Backend coverage
audiocpp_cli,audiocpp_server, focused unit test, warmbench.Known limitations
the same reference. A changed reference correctly rebuilds the prefix.
as reported above.
memory even though observed GPU memory decreased.
multi-client throughput measurements.