Kazeia-engine/dist/jni/cp_validate.cpp

71 lines
3.2 KiB
C++

// Validation : mon cp_inference (intégré dans tts_orchestrate) doit reproduire
// cp_runner standalone bit-exact. Sur test_cp_input.bin (33 frames hidden+CB0
// du Talker PyTorch) → comparer codes CB1..15 vs test_codes_greedy.bin
// (golden cp.generate do_sample=False). Cible : 33/33 frames parfaits.
#include "cp_inference.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include <vector>
#include <string>
int main(int argc, char** argv) {
if (argc < 6) {
printf("usage: %s <cp_gguf> <cp_heads.bin> <cp_codec_embs.bin> <test_cp_input.bin> <golden.bin>\n", argv[0]);
return 1;
}
CPState s; s.n_threads = 4;
if (!cp_load(s, argv[1], argv[2], argv[3])) { printf("cp_load FAILED\n"); return 1; }
// input : int32 T, T * (hidden[1024] + cb0_emb[1024]) f32
FILE* fi = fopen(argv[4], "rb"); if (!fi) { printf("input fail\n"); return 1; }
int32_t T = 0; if (fread(&T, 4, 1, fi) != 1) return 1;
std::vector<float> inbuf((size_t)T * 2 * 1024);
if (fread(inbuf.data(), sizeof(float), inbuf.size(), fi) != inbuf.size()) return 1;
fclose(fi);
// golden : pour test_codes_greedy.bin pas de header (T * 16 int32 direct, 33 * 16 * 4 = 2112 bytes ≈ 2116)
FILE* fg = fopen(argv[5], "rb"); if (!fg) return 1;
fseek(fg, 0, SEEK_END); long gsz = ftell(fg); fseek(fg, 0, SEEK_SET);
// 2 layouts possibles : (a) header int32+T*16 int32 (size = 4 + T*64),
// (b) raw T*16 int32 (size = T*64). On déduit.
bool has_hdr = (gsz == 4 + (long)T * 64);
if (has_hdr) { int32_t ng = 0; fread(&ng, 4, 1, fg); printf("golden has header, ng=%d\n", ng); }
std::vector<int32_t> gold((size_t)T * 16);
size_t expect = T * 16;
if (fread(gold.data(), sizeof(int32_t), expect, fg) != expect) {
// Maybe golden has fewer or different format
printf("golden short read; size %ld, expected %zu*4=%zu bytes (T=%d)\n", gsz, expect, expect*4, T);
fclose(fg); return 1;
}
fclose(fg);
printf("running CP on %d frames...\n", T);
long n_match_cb15 = 0, total_codes_cb15 = 0;
int n_perfect_cb15 = 0;
for (int f = 0; f < T; f++) {
const float* hidden = &inbuf[(size_t)f * 2 * 1024];
const float* cb0_emb = &inbuf[(size_t)f * 2 * 1024 + 1024];
int32_t codes15[15];
cp_predict(s, hidden, cb0_emb, codes15);
// golden format = [CB0 ... CB15] (16 entries per frame)
const int32_t* gf16 = &gold[(size_t)f * 16];
int match = 0;
for (int c = 0; c < 15; c++) if (codes15[c] == gf16[1 + c]) match++;
n_match_cb15 += match; total_codes_cb15 += 15;
if (match == 15) n_perfect_cb15++;
if (f < 3 || match < 15) {
printf("frame %2d: CB1..15 match %2d/15 -> CP=[%d,%d,%d,%d] PY=[%d,%d,%d,%d]\n",
f, match, codes15[0], codes15[1], codes15[2], codes15[3],
gf16[1], gf16[2], gf16[3], gf16[4]);
}
}
printf("\n=== cp_predict (engine) vs cp.generate greedy (golden) ===\n");
printf("codes match : %ld/%ld (%.1f%%)\n", n_match_cb15, total_codes_cb15, 100.0 * n_match_cb15 / total_codes_cb15);
printf("frames parfaits : %d/%d\n", n_perfect_cb15, T);
cp_free(s);
return (n_match_cb15 == total_codes_cb15) ? 0 : 5;
}