Repository navigation
feat(qwen3_tts): stream the RKNN decoder with window semantics - #992
Conversation
|
@wOvAN One issue: Engine alias detection compares path strings, whereas memory accounting canonicalizes paths. Setting main and window to the same file using different spellings can load two contexts but count only one. |
The stateful RKNN vocoder voices each token once through a carried cache, which is why streaming on the NPU beats the CPU decoder on speed (57.7 s against 151.2 s) and misses it on waveform (16.4 dB SNR): the ggml streaming graph re-voices the 25-frame left context inside every window and drops its audio, a structurally different function. Add an optional `window` artifact to the `speech_decoder` RKNN plan. When present, every streaming event runs a full decode of its whole [left context + new] window from a zeroed cache (the same stateful graph, `cache_out` ignored, RoPE restarting at 0), reproducing the ggml streaming function per chunk. Naming the main engine aliases it — one resident context voices groups offline and windows streaming, and `engine_resources` prices it once. A dedicated smaller export is the per-event optimization. Measured on the RK3588 board, 307 Russian characters, seed 42, greedy, conv f16: streaming SNR against the ggml streaming render 47.4 dB (max sample delta 731/32767) against 16.4 dB for the stateful path, at 93.2 s wall against 44 s — the re-voicing price, and under the CPU's 106 s. Stateful streaming stays the default; offline decoding is untouched. The converter gains a small fix: with `--output *.rknn` the ONNX export now lands beside the engine path instead of under it.
3e47617 to
c2524de
Compare
|
@wOvAN Fixed — the alias test is now file-level, matching the accounting: Measured on the RK3588 board with the same file spelled two ways (
|
What
Streaming on the RKNN vocoder and streaming on ggml compute two different functions, and the shipped numbers show it: the stateful engine voices each token once through a carried cache (57.7 s wall for 307 characters), while the ggml streaming graph re-voices the 25-frame left context inside every window and drops its audio (106 s). The renders agree at 16.4 dB SNR — that gap is the conditioning semantics, not fp16 noise, and no engine retraining closes it.
This adds the second function to the NPU path as an opt-in plan artifact:
qwen3_tts.exec_plan→speech_decoder.rknngains an optionalwindowartifact. When present, every streaming event runs a full decode of its whole[left context + new]window: the same stateful graph withcache_inzeroed,cache_valid0 and RoPE restarting at 0, so the step is the full decode over the window; the context's audio is dropped and flush voices nothing (the engine is stateless in this mode). Offline decoding keeps usingmain, and stateful streaming stays the default when nowindowis named.windowthat names the same file asmainaliases it — one resident context voices groups offline and windows streaming, andengine_resources()already dedupes by canonical path, so the residency guard prices the three-role plan exactly as the pair (verified). A dedicated smaller export (--codes-length 25 + stream_frames_per_event) is the per-event optimization; the aliased B=64 engine covers the default 25 + 12 window.loader.cpp:model_resourcescountswindowalongsidefirst.--output *.rknnthe export stage now writes the ONNX beside the engine path instead of over it, so the one-command export→compile chain works with an engine-named--output.Validation
RK3588 board (native aarch64 build,
ENGINE_ENABLE_RKNN=ON, rebuilt after the change, 0 errors), 307 Russian characters, voice-clone fromassets/resources/b.wav, seed 42, greedy,conv_weight_type=f16,--threads 4:"window":"/root/tts-rknn/vocoder/vocoder_stateful_64b_fp16.rknn": 93.2 s wall, decoder 61.1 s (20 × 3.07 s events),qwen3_tts.speech_decoder.rknn.window_group 64in the log.--min-free-memory-mb 27300: refused withestimated 3.49 GiB + 27300 MiB headroom exceeds available host memory (29.88 GiB)— identical to the main+first pair estimate, so the aliased file is priced once.ctest -R "rknn|qwen3|server_config":rknn_engine_test,server_config_test,rknn_sidecar_testall pass.