Kazeia-engine/dist/decoder_patches
Richard Loyer bdd528ed25 chantier BigVGAN HMX Phase 2b: refactor sched-friendly + limite backend découverte
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>
2026-05-29 14:05:35 +02:00
..
README.md chantier BigVGAN HMX Phase 2b: refactor sched-friendly + limite backend découverte 2026-05-29 14:05:35 +02:00
decoder.cpp.snapshot chantier BigVGAN HMX Phase 2b: refactor sched-friendly + limite backend découverte 2026-05-29 14:05:35 +02:00
decoder.h.snapshot chantier BigVGAN HMX Phase 2b: refactor sched-friendly + limite backend découverte 2026-05-29 14:05:35 +02:00
gguf_loader.cpp.snapshot chantier BigVGAN HMX Phase 2b: refactor sched-friendly + limite backend découverte 2026-05-29 14:05:35 +02:00

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 sched dans struct Decoder.
  • Ajout bool owns_backends pour la libération.
  • Nouvelle méthode load_with_backends(path, devs) : variante de load_with_buft qui prend une liste de backends et crée optionnellement un sched (gated par env KZTTS_DECODER_SCHED).
  • Nouvelle méthode compute_graph(ctx, gf, n_threads) qui dispatche vers sched_compute si sched actif, sinon ggml_graph_compute_with_ctx legacy.

gguf_loader.cpp

  • Impl de load_with_backends : alloue les poids sur le buft du backend[0] (HTP si présent) via load_with_buft. Sched créé seulement si KZTTS_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 si owns_backends.

decoder.cpp

  • Ajout du timing par stage dans Decoder::forward (gated par KZTTS_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 :

  1. snake constants pré-calculées au load (ctx_const + buf_const)
  2. stage_bigvgan_sched (variante du stage_bigvgan legacy)
  3. ggml_init(no_alloc=true) + ggml_set_input/output
  4. memset zeros + concat remplacé par ggml_pad_ext
  5. Wrapping sched_reset + alloc + tensor_set + compute + tensor_get
  6. 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