TU sampler tuning : top_p 1.0->0.95 + rep_penalty 1.05->1.10 nouveaux défauts

Validation à l'écoute (panel A/B 4 combos sur 'Bonsoir, comment tu te sens
ce soir ?'). Verdict utilisateur : combinaison TOPP_0.95_REPP_1.10 sonne le
moins robotique.

Analyse complémentaire TU.2 (dump codes via KZTTS_DUMP_CODES=path) sur 4
phrases panel a confirmé :
  - code 690 CB0 = attracteur silence (5.9% du panel, doublé systématiquement
    en début de phrase, jusqu'à 4 répétitions consécutives mesurées)
  - rep_penalty 1.05 trop doux pour casser ces 690 690
  - rep_penalty 1.10 plus nucleus 0.95 -> top_p coupe la queue improbable
    + rep défavorise les codes récents -> moins de pause robotique

Nouveaux défauts (tts_engine.h TtsSynthesizeCfg + tts_pipeline env defaults
+ TtsEngine.kt TtsSampling) :
  cp_top_p     = 0.95f  (était 1.0)
  cp_rep_penalty = 1.10f (était 1.05)
  talker_top_p = 0.95f  (était 1.0)
  talker_rep_penalty = 1.10f (était 1.05)
  cp_temp, top_k, talker_temp/top_k inchangés (0.9, 50).

Mesure panel 4 phrases avec nouveaux défauts + decoder chraac subproc :
  'Bonjour Kazeia'                            : N=29 RTF 2.19
  'Bonsoir, comment tu te sens ce soir ?'    : N=48 RTF 2.21
  'Je rumine la nuit.'                       : N=34 RTF 2.21
  'Comment puis-je t'aider aujourd'hui ?'   : N=29 RTF 2.27

RTF stable ~2.2. Compression légère sur phrases courtes (29 vs 33 baseline),
expansion sur phrases interrogatives ('Bonsoir' N=48 vs 41). Cohérent
avec top_p resserré qui choisit des codes plus pertinents.

KZTTS_DUMP_CODES=path ajouté dans tts_engine pour analyse future
(int32 binaire [N,16] time-major).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Richard Loyer 2026-05-31 11:18:25 +02:00
parent c332943181
commit 19ac123afa
4 changed files with 26 additions and 11 deletions

View File

@ -43,8 +43,9 @@ data class TtsResult(
// Configuration sampling. Défauts validés sur fixture FR (cf project_tts_session_28may). // Configuration sampling. Défauts validés sur fixture FR (cf project_tts_session_28may).
data class TtsSampling( data class TtsSampling(
val cpTemp: Float = 0.9f, val cpTopK: Int = 50, val cpTopP: Float = 1.0f, val cpRepPenalty: Float = 1.05f, // Défauts validés à l'écoute (top_p=0.95 + rep=1.10 moins robotique vs 1.0/1.05).
val talkerTemp: Float = 0.9f, val talkerTopK: Int = 50, val talkerTopP: Float = 1.0f, val talkerRepPenalty: Float = 1.05f val cpTemp: Float = 0.9f, val cpTopK: Int = 50, val cpTopP: Float = 0.95f, val cpRepPenalty: Float = 1.10f,
val talkerTemp: Float = 0.9f, val talkerTopK: Int = 50, val talkerTopP: Float = 0.95f, val talkerRepPenalty: Float = 1.10f
) )
class TtsEngine( class TtsEngine(

View File

@ -613,6 +613,17 @@ TtsSynthesizeResult tts_engine_synthesize(TtsEngine * eng, const TtsSynthesizeCf
R.frames = N_done; R.frames = N_done;
R.audio_s = N_done / 12.0; R.audio_s = N_done / 12.0;
// Dump optionnel des codes pour analyse des attracteurs (KZTTS_DUMP_CODES=path).
// Format : int32 binaire [N, 16] time-major (= codes_engine raw).
if (const char * dump = getenv("KZTTS_DUMP_CODES")) {
FILE * f = fopen(dump, "wb");
if (f) {
fwrite(codes_engine.data(), sizeof(int32_t), codes_engine.size(), f);
fclose(f);
fprintf(stderr, "codes dumped to %s (%d frames × 16)\n", dump, N_done);
}
}
// --- 8) Decoder final -> WAV --- // --- 8) Decoder final -> WAV ---
// KZTTS_DECODER_SUBPROC=path/kazeia_decoder_chraac : fork+exec un sous-process décodeur // KZTTS_DECODER_SUBPROC=path/kazeia_decoder_chraac : fork+exec un sous-process décodeur
// statiquement linké contre chraac (-22% sur decoder). Le talker reste qualcomm (qui marche). // statiquement linké contre chraac (-22% sur decoder). Le talker reste qualcomm (qui marche).

13
dist/jni/tts_engine.h vendored
View File

@ -30,16 +30,19 @@ struct TtsSynthesizeCfg {
int max_steps = 256; int max_steps = 256;
uint32_t seed = 42; uint32_t seed = 42;
// Sampling (par défaut = défauts in-house validés sur fixture FR) // Sampling : défauts validés à l'écoute (panel A/B) sur tts_engine + chraac subproc.
// top_p=0.95 + rep_penalty=1.10 : sweet spot moins robotique, moins de pauses 690
// doublées sur CB0 (cf TU.2 attracteurs identifiés). Ancien défaut top_p=1.0
// rep=1.05 disponible en surcharge via env KZTTS_REPP / KZTTS_TOPP.
float cp_temp = 0.9f; float cp_temp = 0.9f;
int cp_top_k = 50; int cp_top_k = 50;
float cp_top_p = 1.0f; float cp_top_p = 0.95f;
float cp_rep_penalty = 1.05f; float cp_rep_penalty = 1.10f;
float talker_temp = 0.9f; float talker_temp = 0.9f;
int talker_top_k = 50; int talker_top_k = 50;
float talker_top_p = 1.0f; float talker_top_p = 0.95f;
float talker_rep_penalty = 1.05f; float talker_rep_penalty = 1.10f;
}; };
struct TtsSynthesizeResult { struct TtsSynthesizeResult {

View File

@ -67,12 +67,12 @@ int main(int argc, char** argv) {
sc.seed = env_i("KZTTS_SEED", 42); sc.seed = env_i("KZTTS_SEED", 42);
sc.cp_temp = env_f("KZTTS_CP_TEMP", 0.9f); sc.cp_temp = env_f("KZTTS_CP_TEMP", 0.9f);
sc.cp_top_k = env_i("KZTTS_CP_TOPK", 50); sc.cp_top_k = env_i("KZTTS_CP_TOPK", 50);
sc.cp_top_p = env_f("KZTTS_CP_TOPP", 1.0f); sc.cp_top_p = env_f("KZTTS_CP_TOPP", 0.95f);
sc.cp_rep_penalty = env_f("KZTTS_CP_REPP", 1.05f); sc.cp_rep_penalty = env_f("KZTTS_CP_REPP", 1.10f);
sc.talker_temp = env_f("KZTTS_TEMP", 0.9f); sc.talker_temp = env_f("KZTTS_TEMP", 0.9f);
sc.talker_top_k = env_i("KZTTS_TOPK", 50); sc.talker_top_k = env_i("KZTTS_TOPK", 50);
sc.talker_top_p = env_f("KZTTS_TOPP", 1.0f); sc.talker_top_p = env_f("KZTTS_TOPP", 0.95f);
sc.talker_rep_penalty = env_f("KZTTS_REPP", 1.05f); sc.talker_rep_penalty = env_f("KZTTS_REPP", 1.10f);
auto R = tts_engine_synthesize(eng, sc); auto R = tts_engine_synthesize(eng, sc);
if (R.err) { fprintf(stderr, "tts_engine_synthesize FAIL err=%d\n", R.err); tts_engine_free(eng); return 4; } if (R.err) { fprintf(stderr, "tts_engine_synthesize FAIL err=%d\n", R.err); tts_engine_free(eng); return 4; }