Refactor stage_bigvgan en variante stage_bigvgan_sched :
- ggml_init(no_alloc=true) + mem_size réduit 12 GB -> 16 MB
- ggml_set_input/output sur input/output
- causal_conv1d_TC : ggml_pad_ext au lieu de memset zeros + concat
- apply_snake_TC : lookup d.snake_consts pré-calculé (au lieu de host exp() per-frame)
- Pattern sched_reset + alloc_graph + tensor_set + compute + tensor_get
- Switch dans Decoder::forward : sched ? stage_bigvgan_sched : stage_bigvgan
Snake constants pré-calculées au load_with_backends :
- 29 paires (a_eff, inv_b) stockées dans ctx_const + buf_const sur le même
backend que buf_w. exp() host-side une fois au load au lieu de chaque frame.
- buf_const ~0.1 MB sur HTP0 (29 × 2 × C × f32 avec C de 96 à 1536).
Mesure tablette (KZTTS_DECODER_HTP=1 KZTTS_DECODER_SCHED=1 GGML_HEXAGON_USE_HMX=1) :
baseline CPU pur : decoder 3.34s, bigvgan 3.19s
sched HTP path neuf : decoder 3.95s, bigvgan 3.76s -> REGRESSION 18%
Cause : GGML_SCHED_DEBUG=2 révèle que TOUS les MUL_MAT tombent sur CPU.
ggml_hexagon_supported_mul_mat rejette ggml_nrows(src1) > 1024 (commentaire
'no huge batches (for now)'). BigVGAN block 3 résiduels : conv1d k=7 sur
T=59520, im2col_output [672, 59520] -> 59520 rows >> 1024. Tous les
MUL_MAT BigVGAN sont rejetés -> fallback CPU + copies inutiles -> régression.
PHASE 2b STATUT : refactor fait et stable, mais le gain HMX nécessite
soit (a) modifier ggml-hexagon pour gros batches, (b) splitter MUL_MAT
en chunks ≤ 1024, (c) reprendre via étape F (CP HMX) qui n'a pas ce
problème (nrows ≤ 16 par sub-forward).
Snapshots updatés dans dist/decoder_patches/.
Le path activé seulement si KZTTS_DECODER_SCHED=1 (opt-in, désactivé par
défaut). En mode KZTTS_DECODER_HTP=1 sans SCHED : path legacy CPU pur, perf
inchangée vs baseline (poids juste relogés sur HTP buffer via opt_hostbuf=1).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| README.md | ||
| decoder.cpp.snapshot | ||
| decoder.h.snapshot | ||
| gguf_loader.cpp.snapshot | ||
README.md
Snapshots decoder /opt/Kazeia/kazeia-tts-decoder-ggml/src/
Le repo decoder est externe (mono-repo /opt/Kazeia, fichiers untracked en pratique). Ces snapshots gardent une trace des modifications apportées pour Phase 2 du chantier BigVGAN HMX.
Modifications par fichier
decoder.h
- Ajout
std::vector<ggml_backend_t> backends+ggml_backend_sched_t scheddansstruct Decoder. - Ajout
bool owns_backendspour la libération. - Nouvelle méthode
load_with_backends(path, devs): variante deload_with_buftqui prend une liste de backends et crée optionnellement un sched (gated par envKZTTS_DECODER_SCHED). - Nouvelle méthode
compute_graph(ctx, gf, n_threads)qui dispatche verssched_computesi sched actif, sinonggml_graph_compute_with_ctxlegacy.
gguf_loader.cpp
- Impl de
load_with_backends: alloue les poids sur le buft du backend[0] (HTP si présent) viaload_with_buft. Sched créé seulement siKZTTS_DECODER_SCHED=1(le sched complet nécessite refactor des stages). - Impl de
compute_graph: sched path ou compute_with_ctx legacy. unload()libère sched + backends siowns_backends.
decoder.cpp
- Ajout du timing par stage dans
Decoder::forward(gated parKZTTS_DECODER_PROFILE=1). Imprime quant/preconv/pretr/upsample/bigvgan. - (pas d'autres modifs structurelles : le refactor stage_bigvgan en pattern sched-friendly reste à faire dans la session suivante)
Modes de fonctionnement
| Env | Effet |
|---|---|
| (rien) | path CPU pur historique, poids CPU buffer (default) |
KZTTS_DECODER_HTP=1 |
poids alloués sur HTP buffer, compute CPU pur via opt_hostbuf=1 (HTP buffer CPU-mappable). Pas de gain HMX mais valide la chaîne. |
KZTTS_DECODER_HTP=1 KZTTS_DECODER_SCHED=1 |
sched créé, mais stages encore en compute_with_ctx → assertion buffer_id >= 0 au premier compute. NE FONCTIONNE PAS sans refactor stages. |
Phase 2b livrée — mais bloquée par limite backend
Refactor stage_bigvgan en pattern sched-friendly fait :
- ✅ snake constants pré-calculées au load (
ctx_const+buf_const) - ✅
stage_bigvgan_sched(variante du stage_bigvgan legacy) - ✅
ggml_init(no_alloc=true)+ggml_set_input/output - ✅
memset zeros + concatremplacé parggml_pad_ext - ✅ Wrapping sched_reset + alloc + tensor_set + compute + tensor_get
- ✅ Switch dans
Decoder::forward:d.sched ? stage_bigvgan_sched : stage_bigvgan
MAIS : mesure montre que TOUS les nœuds tombent sur CPU malgré le sched.
Le sched_debug (GGML_SCHED_DEBUG=2) confirme :
- poids decoder bien sur HTP0 (buf_w 325 MB + buf_const 0.1 MB)
- MUL_MAT/IM2COL/PAD/ADD assignés à CPU
- decoder time = 3.95s (régression vs baseline 3.34s due aux copies inutiles)
Cause : ggml_hexagon_supported_mul_mat rejette les MUL_MAT avec
ggml_nrows(src1) > 1024 (commentaire "no huge batches (for now)").
BigVGAN block 3 résiduels font conv1d k=7 sur T=59520 → im2col output a 59520
rows × 672 cols → ggml_nrows(src1) >> 1024. Tous les MUL_MAT BigVGAN sont
au-dessus de la limite, donc rejetés par HTP, fallback CPU.
Reprise Phase 2b plus tard
Trois options pour débloquer :
(a) Modifier ggml-hexagon pour supporter les gros batches MUL_MAT. Sous-chantier kernel hexagon (VTCM tiling, copies multiples). Semaines.
(b) Split BigVGAN MUL_MAT en chunks ≤ 1024 rows côté graphe decoder. Refactor + copies CPU↔HTP par chunk. Gain incertain.
(c) Reprendre via étape F (CP HMX) d'abord. CP a des MUL_MAT nrows(src1) ≤ 16 (1 prefill 2 tokens + 14 decode 1 token), largement sous la limite. Pattern identique au talker Qwen3.5 déjà validé.
Rebuild
cd /opt/Kazeia/kazeia-tts-decoder-ggml/build-android-engine && \
make qwen3tts-decoder -j$(nproc)
# puis côté Kazeia-engine
cd /opt/Kazeia-engine/dist && ./build_tts_pipeline.sh