From 501abb67e5ed4da5f0c0aefec16e5cd9adaa9097 Mon Sep 17 00:00:00 2001 From: Richard Loyer Date: Wed, 27 May 2026 10:12:37 +0200 Subject: [PATCH] =?UTF-8?q?dist:=20prefill=20HTP=20R=C3=89CUP=C3=89RABLE?= =?UTF-8?q?=20=E2=80=94=20charabia=20=3D=201=20op=20(SSM=5FCONV)=20cass?= =?UTF-8?q?=C3=A9e,=20fix=20OPFILTER?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Investigation détaillée: décomposé le prefill HTP charabia op par op (test-backend-ops -b HTP0 par op + OPFILTER bisect en génération). Coupable unique = SSM_CONV (conv1d) cassé sur HTP en multi-token (prefill) pour d_inner=1024/2048 (oracle FAIL ERR~1.3; decode n=1 OK; 1536 passe; bug backend hexagon, HVX+scalaire HTP faux, ggml-cpu correct). FIX immédiat: GGML_HEXAGON_OPFILTER =SSM_CONV (conv sur CPU, reste HTP) -> prefill HTP 181 t/s + sortie FR cohérente, x13 vs CPU 14. Renverse le "prefill HTP mort": il est récupérable. 3 configs (A CPU-only livrée / B mono-ctx HTP+OPFILTER 181/6.4 / C dual-ctx 181/10.9 +2.3GB). TODO: corriger SSM_CONV HTP (gate oracle). Co-Authored-By: Claude Opus 4.7 (1M context) --- dist/HANDOFF.md | 28 ++++++++++++++++------------ dist/PERF.md | 13 +++++++------ dist/STATUS.md | 7 ++++--- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/dist/HANDOFF.md b/dist/HANDOFF.md index f75bdf6..ad8209a 100644 --- a/dist/HANDOFF.md +++ b/dist/HANDOFF.md @@ -24,22 +24,26 @@ Config déjà correcte et alignée : (−40%, idem à d=512). Le déquant KV en flash-attn coûte plus que le BW épargné. `type_k/v` repassé en `GGML_TYPE_F16`. → **rebuild `libkazeia_engine.so` avant de shipper** (le .so livré contient encore l'ancien q8_0). q8_0 seulement si OOM KV en très long contexte. -2. **Prefill : CPU-only OBLIGATOIRE — le prefill HTP est CASSÉ (vérifié 27/05).** Le HTP a un gros - débit (q35-lmq4 126-189 t/s) MAIS produit un **état/logits corrompus → sortie charabia**. Confirmé 3× - (harness dual-contexte, device HTP0 explicite, et `llama-cli -dev HTP0` sortant de l'anglais cassé - sur un prompt FR). Le dense Qwen3-4B sur HTP **crashe** (V79 0x2e). Preuve que c'est le prefill et pas - le transfert : decode CPU repartant d'un état prefillé-CPU = FR cohérent ; repartant d'un état - prefillé-HTP = charabia. Donc les « 189/98/285 » sont du **débit jamais validé en sortie**, inutilisables. - → **JNI reste `ngl0` (CPU prefill 14 t/s + CPU decode 10.9).** Mécanique du split (2 contextes + transfert - KV) validée et prête (jni/dual_ctx.cpp) — réutilisable LE JOUR où le prefill HTP sera numériquement - correct (bug backend frontière). Pour accélérer le prefill maintenant : raccourcir le prompt/historique. +2. **Prefill HTP : RÉCUPÉRABLE via `GGML_HEXAGON_OPFILTER=SSM_CONV`.** Cause du charabia localisée : + **une seule op, SSM_CONV (conv1d), est cassée sur HTP en multi-token (prefill) pour d_inner=1024/2048** + (oracle FAIL ERR~1.3 ; decode n=1 OK ; bug côté backend hexagon, pas le calcul — les 2 chemins HTP + échouent, ggml-cpu est correct). En forçant cette op sur CPU (`OPFILTER=SSM_CONV`), le reste du prefill + tourne sur HTP et la **sortie redevient cohérente** : « Je comprends que cette rumination nocturne… ». + Mesuré : **prefill HTP 181 t/s** (×13 vs CPU 14) avec sortie correcte. Trois options d'intégration : + - **A (livrée) CPU-only** : prefill 14, decode 10.9, 2.4 GB. Simple. + - **B mono-contexte HTP + OPFILTER** : prefill **181**, decode HTP **6.4**, 2.4 GB (+ION). Gros gain prefill, + decode + lent, aucune RAM en plus, peu de code (ngl99 + env). **Recommandé** pour prompts longs/multi-tour. + - **C dual-contexte (prefill HTP+OPFILTER → transfert KV → decode CPU)** : prefill 181, decode **10.9**, + **+2.3 GB** RAM (2e instance). Optimal mais + complexe. Harness prouvé : `jni/dual_ctx.cpp`. + TODO propre : corriger SSM_CONV HTP (gate `test-backend-ops -o SSM_CONV` = 45/45) → enlèverait l'OPFILTER. ## Perf (sains, 27/05, device froid) | | prefill | decode | RAM | |---|--:|--:|--:| -| q35-lmq4 — JNI (CPU-only, **config livrée**) | 14 (CPU t4) | **10.9** (t4+fa, KV f16) | 2.4 GB | -| q35-lmq4 — HTP | 126-189 *(débit, sortie CASSÉE → inutilisable)* | — | — | -| dense Qwen3-4B | ~14 CPU / HTP crash 0x2e | 11.7 | 2.2 GB | +| q35-lmq4 — A: CPU-only (**config livrée**) | 14 (CPU t4) | **10.9** | 2.4 GB | +| q35-lmq4 — B: HTP+OPFILTER mono-ctx | **181** | 6.4 (HTP) | 2.4 GB +ION | +| q35-lmq4 — C: HTP-prefill / CPU-decode | **181** | **10.9** | 4.7 GB +ION | +| q35-lmq4 — HTP sans OPFILTER | 189 *(sortie CASSÉE: SSM_CONV)* | — | — | Decode = ce que l'utilisateur ressent (10.9, OK). Prefill CPU 14 t/s → prompt 200 tok ≈ 14 s ; garder le system prompt + l'historique courts. Le prefill HTP rapide existe mais sort du charabia (cf décision 2). diff --git a/dist/PERF.md b/dist/PERF.md index e1482b2..9bd3e14 100644 --- a/dist/PERF.md +++ b/dist/PERF.md @@ -9,12 +9,13 @@ Decode optimum = **t4 / fa1 / KV f16** (PAS t8 : contention ; PAS KV q8_0 : déq | Qwen3.5-9B | — | — | ~4-5 | 5.0 | Notes : -- **PREFILL HTP = CASSÉ (27/05, vérifié 3×).** Débit réel (126-189 t/s) mais **état/logits corrompus → - sortie charabia** (harness dual-ctx, device HTP0 explicite, et `llama-cli -dev HTP0` → anglais cassé sur - prompt FR). Preuve = c'est le prefill, pas le transfert : decode CPU depuis état prefillé-CPU = FR cohérent, - depuis état prefillé-HTP = charabia. Les anciens « 189/98/285 » = débit jamais validé en sortie, **inutilisables**. - Dense sur HTP **crashe** (V79 0x2e). → **prefill obligatoirement CPU.** Le KV transfer (Path A) marche - (CPU→CPU cohérent), prêt si le prefill HTP devient un jour correct (bug backend frontière). +- **PREFILL HTP charabia = 1 op cassée, SSM_CONV (conv1d), RÉCUPÉRABLE.** Localisé 27/05 : SSM_CONV sur HTP + est faux en multi-token (prefill) pour d_inner=1024/2048 (oracle FAIL ERR~1.3 ; decode n=1 OK ; bug backend + hexagon, pas le calcul — HVX ET scalaire HTP échouent, ggml-cpu correct). Fix immédiat = `GGML_HEXAGON_OPFILTER=SSM_CONV` + (route conv sur CPU, reste sur HTP) → **prefill HTP 181 t/s + sortie cohérente** (« Je comprends que cette + rumination… »), ×13 vs CPU 14. 3 configs : A CPU-only (14/10.9, livrée), B mono-ctx HTP+OPFILTER (181/6.4), + C dual-ctx prefill-HTP/decode-CPU (181/10.9, +2.3GB). cf HANDOFF.md décision 2. Dense sur HTP crashe (0x2e). + TODO: corriger SSM_CONV HTP (gate test-backend-ops -o SSM_CONV = 45/45) → supprime l'OPFILTER. - **KV f16 ≫ q8_0 au decode** : q35-lmq4 f16=10.9 vs q8_0=6.5 (−40%, idem à d=512). → JNI `type_k/v=F16`. - **GDN-compute n'est PAS le goulot prefill** (débit) : serial f32 / fp16 / WY = même pp512. Piste kernel GDN close. - NPU≈CPU au decode (GEMV M=1 latency-bound). RAM = GGUF mmap + ~3.3 GB ION/session. diff --git a/dist/STATUS.md b/dist/STATUS.md index 8aedf81..ed57c3b 100644 --- a/dist/STATUS.md +++ b/dist/STATUS.md @@ -5,9 +5,10 @@ thinking-off déterministe. Modèle tranché = `q35-lmq4` (éval qualité ../eva Perf : prefill clos côté kernel GDN (pas le goulot), decode au plafond CPU. LIMITES / OUVERT : -1. **Prefill HTP = CASSÉ (sortie charabia), prefill OBLIGATOIREMENT CPU (~14 t/s).** Vérifié 27/05 - (cli -dev HTP0 + harness). Le débit HTP est réel mais l'état produit est corrompu. Dense sur HTP crashe - (0x2e). Bridge CPU-only (ngl0) = la seule config correcte. cf PERF.md / HANDOFF.md décision 2. +1. **Prefill HTP RÉCUPÉRABLE** (27/05) : charabia causé par 1 op, SSM_CONV (conv1d), cassée sur HTP en + prefill. Fix = `GGML_HEXAGON_OPFILTER=SSM_CONV` → prefill HTP 181 t/s cohérent (×13). Config livrée = CPU-only + (A) ; B = mono-ctx HTP+OPFILTER (181/decode 6.4) ; C = dual-ctx (181/decode 10.9, +2.3GB). cf HANDOFF.md déc.2. + TODO backend : corriger SSM_CONV HTP (oracle test-backend-ops -o SSM_CONV). 2. **KV = f16 (résolu, JNI corrigé)** : f16=10.9 vs q8_0=6.5 au decode. Rebuild .so requis (livré=q8_0). 3. `generate()` applique déjà ChatML + thinking-off. App fournit `sys`/`usr` (voir system_fr.txt). 4. TTS Talker GGUF chargeable mais **audio e2e non validé** (= intégration app).