#!/usr/bin/env python3 """71_treino_v090.py — AVALIAÇÃO COM DADOS REAIS dos mecanismos v0.9.0. Pipeline (dados: Wikipédia PT-BR, wikimedia/wikipedia 20231101.pt): 1. Fases A/B/C CURTAS com entrada NUMPY (novo caminho _np — exercita a fronteira rust-numpy em treino real); 2. JEPA-T sobre LATENTES REAIS do tokenizador treinado: fração adaptativa (Thompson, 4 braços) vs fração fixa 0,35 — mesma semente, mesmas épocas; 3. GNG sobre latentes reais: critério padrão (erro máximo) vs entropia_com_piso (T-G1') no mesmo orçamento de vértices; 4. Painel de telemetria v090 (despacho SIMD agregado). """ import json, os, sys, time import numpy as np def main(): pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, pasta) os.makedirs(os.path.join(pasta, "resultados"), exist_ok=True) import khtst_rust as K cfg = K.Config(os.path.join(pasta, "configs", "base_rust.json")) ck_tok = os.path.join(pasta, "resultados", "tokenizador_conceitos.json") ck_ger = os.path.join(pasta, "resultados", "gerador_conceitos.json") tel_c = os.path.join(pasta, "resultados", "telemetria_fase_c.jsonl") bpe = K.Bpe.carregar(os.path.join(pasta, "dados", "bpe.json")) seqs = [] with open(os.path.join(pasta, "dados", "shard_treino.jsonl")) as f: for linha in f: ids = bpe.codificar(json.loads(linha)["texto"]) for i in range(0, max(1, len(ids) - 256), 128): seqs.append(ids[i:i + 256]) seqs = seqs[:1400] PAD = 0 # crate::tokens::PAD largura = max(len(s) for s in seqs) seqs_np = np.array( [s + [PAD] * (largura - len(s)) for s in seqs], dtype=np.uint32 ) rel = { "versao": "0.9.0", "dados": {"sequencias": len(seqs), "fonte": "wikimedia/wikipedia 20231101.pt"}, "fases": {}, } print(f"sequências: {len(seqs)} (ctx=256) | numpy {seqs_np.shape}", flush=True) # -------------------------------- fase A (numpy) if not os.path.exists(ck_tok): print("=== FASE A — tokenizador (entrada NUMPY) ===", flush=True) t0 = time.time() saida = K.treinar_fase_a_np(cfg, seqs_np, None, ck_tok, None, 200.0) rel["fases"]["a"] = {**saida["resumo"], "tempo_s": round(time.time() - t0, 1)} print(json.dumps(rel["fases"]["a"], indent=1, ensure_ascii=False), flush=True) else: print("fase A: checkpoint presente", flush=True) # -------------------------------- fase B (numpy) if not os.path.exists(ck_ger): print("=== FASE B — gerador (entrada NUMPY) ===", flush=True) t0 = time.time() saida_b = K.treinar_fase_b_np(cfg, seqs_np, ck_tok, None, ck_ger, teto_seg=200.0) rel["fases"]["b"] = {**saida_b["resumo"], "tempo_s": round(time.time() - t0, 1)} print(json.dumps(rel["fases"]["b"], indent=1, ensure_ascii=False), flush=True) else: print("fase B: checkpoint presente", flush=True) # -------------------------------- fase C (numpy, curta) print("=== FASE C — conjunto (entrada NUMPY, 60 passos) ===", flush=True) t0 = time.time() saida_c = K.treinar_fase_c(cfg, seqs, ck_tok, passos=60, caminho_gerador=ck_ger, caminho_telemetria=tel_c, teto_seg=120.0) rc = saida_c["resumo"] rc["tempo_s"] = round(time.time() - t0, 1) rel["fases"]["c"] = rc print(json.dumps({k: rc[k] for k in list(rc)[:8]}, indent=1, ensure_ascii=False), flush=True) # -------------------------------- latentes reais print("=== LATENTES REAIS (tokenizador treinado) ===", flush=True) lat = K.codificar_latentes(cfg, ck_tok, seqs_np[:64]) print(f"latentes: {lat.shape} {lat.dtype}", flush=True) # -------------------------------- JEPA-T real: adaptativa vs fixa print("=== JEPA-T REAL — fração adaptativa vs fixa ===", flush=True) cfg_j = json.dumps({"epocas": 40, "d_emb": 48, "semente": 42, "lr": 2e-3}) resultados_j = {} # um JEPA por janela (8 janelas) — patches = latentes da janela (256, d_lat) quedas_fix, quedas_ada = [], [] for w in range(4): janela = lat[w].astype(float).tolist() # (256, d_lat) fixo = K.treinar_jepa(janela, [256], "tjepa", cfg_j) ada = K.treinar_jepa_adaptativa( janela, [256], "tjepa", [0.2, 0.35, 0.5, 0.65], cfg_j) quedas_fix.append(fixo["queda_pct"]) quedas_ada.append(ada["queda_pct"]) if w == 0: resultados_j["janela0"] = { "fixa": {"perda_ini": fixo["perda_pred_inicial"], "perda_fim": fixo["perda_pred_final"], "queda_pct": fixo["queda_pct"]}, "adaptativa": {"perda_ini": ada["perda_pred_final"] and ada["perda_pred_inicial"], "perda_fim": ada["perda_pred_final"], "queda_pct": ada["queda_pct"], "jogadas": ada["jogadas_por_braco"], "posterior": ada["posterior"]}, } media_fix = sum(quedas_fix) / len(quedas_fix) media_ada = sum(quedas_ada) / len(quedas_ada) resultados_j["media_queda_fixa_pct"] = media_fix resultados_j["media_queda_adaptativa_pct"] = media_ada resultados_j["por_janela"] = {"fixa": quedas_fix, "adaptativa": quedas_ada} rel["jepa_real"] = resultados_j print(f" queda média: fixa {media_fix:.1f}% | adaptativa {media_ada:.1f}%", flush=True) # -------------------------------- GNG real: padrão vs entropia_com_piso print("=== GNG REAL — erro máximo vs entropia+piso ===", flush=True) # nuvem = latentes achatados (256×256, d_lat) subamostrados nuvem = lat.reshape(-1, lat.shape[-1]) sel = np.random.default_rng(3).choice(len(nuvem), 2000, replace=False) nuvem_list = nuvem[sel].astype(float).tolist() cfg_g = json.dumps({"passos": 4000, "max_vertices": 48, "semente": 42}) g_pad = K.treinar_gng(nuvem_list, cfg_g) g_piso = K.treinar_gng(nuvem_list, json.dumps({ "passos": 4000, "max_vertices": 48, "semente": 42, "criterio": "entropia_com_piso"})) rel["gng_real"] = { "padrao": {"vertices": g_pad["vertices"], "eq": g_pad["eq_medio"], "insercoes": g_pad["insercoes"]}, "entropia_piso": {"vertices": g_piso["vertices"], "eq": g_piso["eq_medio"], "insercoes": g_piso["insercoes"], "bloqueadas": g_piso["insercoes_bloqueadas_entropia"]}, "eq_ratio_piso_vs_padrao": (g_piso["eq_medio"] / g_pad["eq_medio"]) if g_pad["eq_medio"] > 0 else None, } print(json.dumps(rel["gng_real"], indent=1, ensure_ascii=False), flush=True) # -------------------------------- painel v090 rel["simd"] = K.simd_relatorio() with open(os.path.join(pasta, "resultados", "treino_v090.json"), "w") as f: json.dump(rel, f, indent=1, ensure_ascii=False) print("salvo: resultados/treino_v090.json", flush=True) if __name__ == "__main__": main()