// Code Predictor (Qwen3-TTS) inference, extrait de // /opt/Kazeia/kazeia-tts-decoder-ggml/src/cp_runner.cpp et exposé en API // utilisable depuis tts_orchestrate. Architecture : transformer qwen3 5 couches, // hidden 1024, GQA 16/8, head_dim 128, RMS eps 1e-6, RoPE NEOX theta=1e6. // q_norm/k_norm AVANT RoPE (gotcha critique). // // Deux variantes de forward : // - cp_predict : approche "recompute" historique (15 graphes, L=2..16). Reste // comme oracle bit-exact référence. // - cp_predict_cached : KV cache f32 persistant entre étapes. 1 graphe prefill // (L=2) + 14 graphes decode (L=1). Speedup ~8x mesuré, math // équivalente mais ordre des sommes f32 peut différer. #pragma once #include "sampler.h" #include #include #include #include struct ggml_context; struct ggml_tensor; // Nombre de couches du CP — fixe par l'archi. Déclaré ici car taille tableaux KV cache. #define CP_N_LAYER 5 struct CPState { ggml_context * weights_ctx = nullptr; std::unordered_map tensors; // weights par nom std::vector heads; // [15, 2048, 1024] f32 std::vector codec_embs; // [15, 2048, 1024] f32 int n_threads = 4; // Sampler HF-style (rep_penalty + top_k + top_p + temperature). Par défaut = greedy // (top_k=1 -> argmax). Pour TTS prod, configurer en {temp=0.9, top_k=50, rep_penalty=1.05} // ce qui matche Python subtalker_*. Sampler sampler = { /*temp=*/0.0f, /*top_k=*/1, /*top_p=*/1.0f, /*rep_penalty=*/1.0f, /*rep_window=*/16, /*rng_state=*/1u, {} }; // --- KV cache (utilisé uniquement par cp_predict_cached). Alloué paresseusement au // premier appel via cp_cache_init(). Layout per-layer : [HEAD_DIM=128, N_KV=8, T_MAX=16] // f32 contigu, même layout que K/V juste après reshape+norm+RoPE (avant permute). // Pas d'état conservé entre frames : à chaque cp_predict_cached() on réécrit pos 0..15. ggml_context * cache_ctx = nullptr; ggml_tensor * K_cache[CP_N_LAYER] = { nullptr }; ggml_tensor * V_cache[CP_N_LAYER] = { nullptr }; }; // Charge cp_f16.gguf + cp_heads.bin + cp_codec_embs.bin. Retourne false en cas d'échec. bool cp_load(CPState& s, const char* gguf_path, const char* heads_path, const char* embs_path); // Libère les ressources. void cp_free(CPState& s); // Prédit CB1..CB15 (15 codes int32) depuis le hidden state du Talker et l'embed de CB0. // hidden : float[1024] // cb0_emb: float[1024] // out_codes : int32_t[15] (CB1..CB15) void cp_predict(CPState& s, const float* hidden, const float* cb0_emb, int32_t* out_codes); // Même contrat que cp_predict, mais avec KV cache : 1 prefill (n_new=2) + 14 decode (n_new=1). // Speedup ~8x (CP 233ms -> ~28ms par frame mesuré sur SM8750), permet de viser RTF <1. // La math est équivalente (mêmes éléments contractés, attention causale identique) mais l'ordre // f32 des sommations dans mul_mat dépend de la shape, donc bit-exactness non garantie. void cp_predict_cached(CPState& s, const float* hidden, const float* cb0_emb, int32_t* out_codes);