AURORA v7 — RETREINO OBSERVADO: estados antigos apagados; treino do zero com monitor de RAM integral (Agente Engenheiro); métricas de tests/test_aurora_v6.py comparadas com o treino anterior; gráficos de desempenho publicados no card
7eea4b4 verified Download scripts/05_avaliar.py from PowerMachine/aurora-multimodal-ptbr: direct link, hf CLI and curl.
- Browser
- Download file 32 kB
-
https://huggingface.co/PowerMachine/aurora-multimodal-ptbr/resolve/main/scripts/05_avaliar.py
- Command line
-
hf download hf://PowerMachine/aurora-multimodal-ptbr/scripts/05_avaliar.py
-
curl -L -o 05_avaliar.py https://huggingface.co/PowerMachine/aurora-multimodal-ptbr/resolve/main/scripts/05_avaliar.py
32 kB
| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| """Avaliação v3 — relatório de QUALIDADE DO APRENDIZADO com evidências: | |
| 1. perplexidade LM: modelo inicial (aleatório) vs treinado vs por época; | |
| 2. perdas por tarefa (9 tarefas) treinado vs aleatório; | |
| 3. MoE agrupável (roteamento POR TOKEN causal): top experts POR TAREFA; | |
| 4. MTP adaptativo: perdas por cabeça, α e ECONOMIA de termos de CE; | |
| 5. W8A8: delta de perda com/sem quantização na lm_head; | |
| 6. SOM: taxa de neurônios ativos, EQ, TE por variante; | |
| 7. geração: amostras com/sem punição dinâmica de repetição; | |
| 8. MICROUNIDADES: ramos ativos, gating α por tarefa, refino recursivo; | |
| 9. CONFIANÇA: posterior Beta, cota de Bernstein, ECE de calibração; | |
| 10. MEMÓRIA INTERNA: hit-rate, escritas conficientes, compressão VQ; | |
| 11. CRESCIMENTO: eventos de expansão/poda das microunidades. | |
| Salva telemetria_out/avaliacao_v5.json (v5: + Agente Engenheiro e difusão).""" | |
| import base64 | |
| import json | |
| import math | |
| import os | |
| import random | |
| import sys | |
| import time | |
| sys.path.insert(0, "/home/z/my-project/aurora/src") | |
| import torch | |
| from aurora.config import Config | |
| from aurora.dados.checkpoints import GestorCheckpoints | |
| from aurora.geracao import GeradorMultimodal | |
| from aurora.qualidade import AgenteEngenheiro | |
| from aurora.dados.tokenizador import TokenizadorAurora | |
| from aurora.memoria.orquestrador import OrquestradorSOM | |
| from aurora.nucleo.modelo import AURORAModel | |
| from aurora.telemetria.hub import TelemetryHub | |
| from aurora.treino.treinador import (TAREFAS_AUDIO, TAREFAS_IMAGEM, | |
| _audio_para_tensor, _imagem_para_tensor, | |
| TreinadorExtensao) | |
| CORPUS = "/home/z/my-project/aurora/cache_dados/corpus_v2.jsonl" | |
| TOKENIZADOR = "/home/z/my-project/aurora/cache_dados/tokenizador.json" | |
| RELATORIO = "/home/z/my-project/aurora/telemetria_out/avaliacao_v7.json" | |
| def carregar_registros(caminho): | |
| regs = [] | |
| with open(caminho, encoding="utf-8") as f: | |
| for linha in f: | |
| try: | |
| r = json.loads(linha) | |
| except Exception: | |
| continue | |
| if isinstance(r.get("imagem"), str): | |
| r["imagem"] = base64.b64decode(r["imagem"]) | |
| if isinstance(r.get("audio"), str): | |
| r["audio"] = base64.b64decode(r["audio"]) | |
| regs.append(r) | |
| return regs | |
| def perda_lote(modelo, tk, registros, tarefa, n_lotes=6, lote=8): | |
| """Perda CE média da tarefa (multimodais usam o prefixo real treinável-não).""" | |
| pool = [r for r in registros if r["tarefa"] == tarefa] | |
| if not pool: | |
| return None | |
| perdas = [] | |
| for _ in range(n_lotes): | |
| amostras = random.sample(pool, min(lote, len(pool))) | |
| L = modelo.cfg.modelo.comprimento_ctx | |
| seqs, extras = [], [] | |
| for s in amostras: | |
| inp = tk.encode(s.get("entrada") or "", tarefa=tarefa, max_len=L // 2) \ | |
| if tarefa not in ("lm", "noticia") else [1] | |
| saida_fonte = s.get("saida") or s.get("texto") or "" | |
| out = tk.encode(saida_fonte, tarefa=None, | |
| max_len=max(L - len(inp) - 4, 8), com_bos=False) | |
| if len(out) < 4: | |
| continue | |
| seqs.append(inp + out) | |
| extras.append(s) | |
| if not seqs: | |
| continue | |
| Tmax = max(len(s) for s in seqs) | |
| ids = torch.zeros(len(seqs), Tmax, dtype=torch.long) | |
| alvo = torch.full((len(seqs), Tmax), -100, dtype=torch.long) | |
| emb_prefixo = None | |
| for i, (s, seq) in enumerate(zip(extras, seqs)): | |
| ids[i, :len(seq)] = torch.tensor(seq) | |
| if tarefa not in ("lm", "noticia"): | |
| ninp = len(tk.encode(s.get("entrada") or "", tarefa=tarefa, | |
| max_len=L // 2)) | |
| alvo[i, ninp:len(seq)] = ids[i, ninp:len(seq)] | |
| else: | |
| alvo[i, 1:len(seq)] = ids[i, 1:len(seq)] | |
| if modelo.usar_multimodal: | |
| entradas = {} | |
| if tarefa in TAREFAS_IMAGEM: | |
| lado = modelo.cfg.modelo.imagem["resolucao"] | |
| entradas["imagem"] = torch.stack([ | |
| _imagem_para_tensor(s["imagem"], lado) if s.get("imagem") | |
| else torch.zeros(3, lado, lado) for s in extras]) | |
| if tarefa in TAREFAS_AUDIO: | |
| ondas = [_audio_para_tensor(s["audio"]) for s in extras if s.get("audio")] | |
| if ondas: | |
| Nmax = max(o.shape[0] for o in ondas) | |
| pad = torch.zeros(len(ondas), Nmax) | |
| for i, o in enumerate(ondas): | |
| pad[i, :o.shape[0]] = o | |
| entradas["audio"] = pad | |
| if entradas: | |
| emb_prefixo = modelo.codificar_multimodal(entradas) | |
| _, perda = modelo(ids, alvo=alvo, emb_prefixo=emb_prefixo, tarefa=tarefa) | |
| perdas.append(float(perda)) | |
| return sum(perdas) / len(perdas) if perdas else None | |
| def perdas_som_amostra(modelo, tk, registros, orquestrador, n=64): | |
| seqs = [] | |
| for r in registros[:n]: | |
| seqs.append(tk.encode(r.get("texto") or (r.get("saida") or r.get("entrada", "")), | |
| tarefa=r["tarefa"], max_len=64)[:64]) | |
| Tmax = max(len(s) for s in seqs) | |
| ids = torch.zeros(len(seqs), Tmax, dtype=torch.long) | |
| for i, s in enumerate(seqs): | |
| ids[i, :len(s)] = torch.tensor(s) | |
| ctx = modelo.contexto(ids) | |
| out = {} | |
| for nome, v in orquestrador.variantes.items(): | |
| if hasattr(v, "taxa_ativos"): | |
| out[nome] = {"taxa_ativos": v.taxa_ativos(), | |
| "eq": v.eq(ctx) if hasattr(v, "eq") else None} | |
| return out | |
| def _salvar(rel: dict): | |
| """Salvamento incremental — evidência parcial sobrevive a cortes de tempo.""" | |
| os.makedirs(os.path.dirname(RELATORIO), exist_ok=True) | |
| with open(RELATORIO, "w", encoding="utf-8") as f: | |
| json.dump(rel, f, ensure_ascii=False, indent=2, default=str) | |
| def main(): | |
| cfg = Config().de_arquivo("/home/z/my-project/aurora/configs/base.json") | |
| random.seed(cfg.dados.semente) | |
| torch.manual_seed(cfg.dados.semente) | |
| hub = TelemetryHub(cfg.telemetria.arquivo_jsonl) | |
| tk = TokenizadorAurora(TOKENIZADOR) | |
| registros = carregar_registros(CORPUS) | |
| modelo = AURORAModel(cfg, usar_multimodal=True) | |
| checkpoints = GestorCheckpoints(dir_local=cfg.checkpoints.dir_local) | |
| tag = checkpoints.ultima_tag() | |
| if tag: | |
| checkpoints.carregar(modelo, tag) | |
| print(f"estado carregado: {tag or 'NENHUM (avaliando aleatório!)'}") | |
| orquestrador = OrquestradorSOM(cfg.modelo.d_modelo, cfg.som, hub=hub, | |
| cfg_atencao=vars(cfg.som_atencao) if hasattr(cfg, "som_atencao") else None) | |
| # v5 — os SOMs são tensors puros (fora do state_dict): re-consolidação | |
| # determinística a partir do modelo treinado (mesmo protocolo do 07 / | |
| # Teorema 16.5) — as evidências de memória refletem o estado TREINADO. | |
| print("== re-consolidação SOM (protocolo doc 16 §4/§5) ==") | |
| relatorio = {"estado": tag} | |
| amostras = random.sample(registros, min(4 * 64, len(registros))) | |
| ctxs = [] | |
| for i in range(0, len(amostras), 64): | |
| pedaco = amostras[i:i + 64] | |
| seqs = [tk.encode(r.get("texto") or (r.get("saida") or r.get("entrada", "")), | |
| tarefa=r["tarefa"], max_len=64)[:64] for r in pedaco] | |
| Tmax = max(len(x) for x in seqs) | |
| ids_l = torch.zeros(len(seqs), Tmax, dtype=torch.long) | |
| for j, x in enumerate(seqs): | |
| ids_l[j, :len(x)] = torch.tensor(x) | |
| ctxs.append(modelo.contexto(ids_l).detach()) | |
| ctx = torch.cat(ctxs, dim=0) | |
| dominante = "instrucao" if any(r["tarefa"] == "instrucao" for r in amostras) else "lm" | |
| orquestrador.escolher({"rotulo_tarefa": dominante, "denso": True}) | |
| orquestrador.treinar_memoria(ctx, epocas=2) | |
| if getattr(orquestrador, "atencao", None) is not None: | |
| inv = orquestrador.atencao.verificar_sem_orfas(orquestrador, dados=ctx, | |
| resemear=True) | |
| print(" invariante zero-órfãos:", inv.pop("_invariante_ok", None)) | |
| # v6 — consolidação do ROTEADOR S-SOM com os MESMOS (ctx, tarefa) — | |
| # contagens empíricas Laplace-suavizadas (doc 18 §1.1, Teorema 18.3) | |
| if getattr(modelo, "roteador_ssom", None) is not None: | |
| from aurora.percepcao.roteador_ssom import LISTA_TAREFAS as _LT | |
| _rot = torch.tensor( | |
| [_LT.index(r["tarefa"]) if r["tarefa"] in _LT else 0 for r in amostras], | |
| dtype=torch.long) | |
| eq_rot = modelo.roteador_ssom.consolidar(ctx, _rot, passos=6) | |
| st_rot = modelo.roteador_ssom.estatisticas() | |
| relatorio["roteador_ssom"] = st_rot | |
| print(f" roteador S-SOM consolidado: eq={eq_rot:.4f} " | |
| f"conf_media={st_rot['conf_media']} frac_rotas={st_rot['frac_rotas_ativas']} " | |
| f"taxa_ativos={st_rot['taxa_ativos']}") | |
| print(" ativos:", json.dumps(orquestrador.telemetria_ativos())[:200]) | |
| # 1-2) perdas treinado vs aleatório | |
| modelo.eval() | |
| modelo_aleatorio = AURORAModel(cfg, usar_multimodal=True) | |
| modelo_aleatorio.eval() | |
| print("== perdas por tarefa (treinado vs aleatório) ==") | |
| perdas_tarefa = {} | |
| for tarefa in ("lm", "noticia", "instrucao", "pontuacao", "imagem_caption", | |
| "vqa", "ocr", "asr", "tts"): | |
| p_t = perda_lote(modelo, tk, registros, tarefa) | |
| p_a = perda_lote(modelo_aleatorio, tk, registros, tarefa) | |
| perdas_tarefa[tarefa] = {"treinado": p_t, "aleatorio": p_a} | |
| print(f" {tarefa:16s} treinado={p_t if p_t is None else round(p_t,3)} " | |
| f"aleatório={p_a if p_a is None else round(p_a,3)}") | |
| relatorio["perdas_tarefa"] = perdas_tarefa | |
| _salvar(relatorio) | |
| if perdas_tarefa["lm"]["treinado"]: | |
| relatorio["ppl_lm"] = math.exp(min(perdas_tarefa["lm"]["treinado"], 12)) | |
| relatorio["ppl_lm_aleatorio"] = math.exp(min(perdas_tarefa["lm"]["aleatorio"], 12)) | |
| print(f" ppl treinado={relatorio['ppl_lm']:.1f} " | |
| f"aleatório={relatorio['ppl_lm_aleatorio']:.1f}") | |
| # 3) MoE foco na tarefa: uso de experts por tarefa | |
| print("== MoE fase foco: top-2 por tarefa (foco na tarefa) ==") | |
| modelo.definir_fase_moe("foco") | |
| moe_uso = {} | |
| for tarefa in ("lm", "vqa", "ocr", "asr", "tts"): | |
| perda_lote(modelo, tk, registros, tarefa, n_lotes=2) | |
| moes = [b.moe for b in modelo.blocos if b.moe is not None] | |
| moe_uso[tarefa] = [ | |
| {"experts_top": [int(i) for i in m.ultimo_p.topk(2).indices.tolist()], | |
| "grupo_top": [int(m.grupo_de_idx[i]) for i in m.ultimo_p.topk(2).indices]} | |
| for m in moes] | |
| for tarefa, uso in moe_uso.items(): | |
| grupos = uso[0]["grupo_top"] if uso else [] | |
| print(f" {tarefa:16s} grupos top: {grupos}") | |
| relatorio["moe_uso_por_tarefa"] = moe_uso | |
| _salvar(relatorio) | |
| # 4) MTP (uma passada LM para popular os α e perdas por cabeça) | |
| if modelo.mtp is not None: | |
| ids_m, alvo_m = _lote_lm(tk, registros) | |
| _, _ = modelo(ids_m, alvo=alvo_m, tarefa="lm") | |
| modelo.mtp_do_trunk(ids_m, alvo_m, tarefa="lm") | |
| relatorio["mtp"] = modelo.mtp.ultimos | |
| print("== MTP ==" , relatorio["mtp"]) | |
| # 5) W8A8 delta | |
| ids, alvo = _lote_lm(tk, registros) | |
| _, p_fp = modelo(ids, alvo=alvo, tarefa="lm") | |
| modelo.qat = True | |
| _, p_q = modelo(ids, alvo=alvo, tarefa="lm") | |
| modelo.qat = False | |
| relatorio["w8a8_delta"] = float(p_q - p_fp) | |
| print(f"== W8A8: Δperda = {relatorio['w8a8_delta']:+.5f} ==") | |
| # 6) SOM — métricas TREINADAS vêm do resumo do treino (o orquestrador | |
| # não é nn.Module: seu estado é consolidado na fase SOM e gravado lá) | |
| resumo_path = "/home/z/my-project/aurora/telemetria_out/resumo_treino_v6.json" | |
| if os.path.exists(resumo_path): | |
| som_treinado = json.load(open(resumo_path)).get("som", {}) | |
| relatorio["som_treinado"] = som_treinado | |
| print("== SOM (fase de consolidação — taxa de neurônios ativos) ==") | |
| for nome, st in som_treinado.get("variantes", {}).items(): | |
| if isinstance(st, dict) and "taxa_ativos" in st: | |
| print(f" {nome}: taxa_ativos={st['taxa_ativos']:.2f} " | |
| f"alvo={st.get('atingiu_alvo')}") | |
| # EQ fresco no espaço atual (referência) | |
| relatorio["som_eq_fresco"] = perdas_som_amostra(modelo, tk, registros, orquestrador) | |
| _salvar(relatorio) | |
| # 7) geração com/sem punição | |
| prompt = tk.encode("Recomende um filme brasileiro:", tarefa="instrucao", max_len=24) | |
| ids_p = torch.tensor([prompt]) | |
| sem_pun = modelo.gerar(ids_p, max_novos=30, punicao_repeticao=1.0, top_k=0, top_p=0.9) | |
| com_pun = modelo.gerar(ids_p, max_novos=30, punicao_repeticao=1.4, top_k=0, top_p=0.9) | |
| relatorio["geracao"] = { | |
| "sem_punicao": tk.decode(sem_pun), | |
| "com_punicao": tk.decode(com_pun)} | |
| print("== geração (amostra) ==") | |
| print(" sem punição:", relatorio["geracao"]["sem_punicao"][:120]) | |
| print(" com punição:", relatorio["geracao"]["com_punicao"][:120]) | |
| # 8) MICROUNIDADES (doc 11): ramos, gating α por tarefa, recursão | |
| print("== microunidades (composição serial/paralela/recursiva) ==") | |
| micra = {} | |
| for tarefa in ("lm", "vqa", "asr", "instrucao"): | |
| perda_lote(modelo, tk, registros, tarefa, n_lotes=1) | |
| micra[tarefa] = [ | |
| {"ramos": c.nome_ramos, | |
| "alpha_medio": [round(a, 4) for a in c.ultimo_alpha.tolist()] | |
| if c.ultimo_alpha is not None else None, | |
| "passos_rec": c.ultimo_passos_rec} | |
| for c in modelo.compositores] | |
| for t, ms in micra.items(): | |
| if ms and ms[0]["alpha_medio"]: | |
| print(f" {t:10s} α bloco0 = {ms[0]['alpha_medio']} rec = {ms[0]['passos_rec']}") | |
| relatorio["microunidades"] = micra | |
| # 9-11) CONFIANÇA / MEMÓRIA / CRESCIMENTO — estado consolidado no resumo | |
| resumo_v3 = json.load(open(resumo_path)) if os.path.exists(resumo_path) else {} | |
| if resumo_v3: | |
| for chave in ("prs_v8", "confianca", "memoria", "crescimento", "microunidades"): | |
| if chave in resumo_v3 and chave not in relatorio: | |
| relatorio[f"treino_{chave}"] = resumo_v3[chave] | |
| if resumo_v3.get("confianca"): | |
| c = resumo_v3["confianca"] | |
| print(f"== confiança: h_ema={c.get('h_ema')}, ECE={c.get('ece')}, " | |
| f"Bernstein={c.get('bernstein')} ==") | |
| if resumo_v3.get("memoria"): | |
| m = resumo_v3["memoria"] | |
| print(f"== memória: hit_rate={m.get('hit_rate')}, escritas={m.get('escritas')}, " | |
| f"rejeitadas={m.get('rejeitadas_confianca')}, " | |
| f"entropia_codebook={m.get('entropia_codebook')} ==") | |
| if resumo_v3.get("crescimento") is not None: | |
| print(f"== crescimento: {len(resumo_v3['crescimento'])} eventos ==") | |
| # 12) MEMÓRIA INTERNA EM EXECUÇÃO (doc 11 §9): evidência de integração | |
| # real — escrita conficiente dos contextos do corpus, consulta, evicção, | |
| # compressão VQ e contratos, com o modelo JÁ TREINADO | |
| print("== memória interna em execução (contextos reais do modelo) ==") | |
| from aurora.memoria.interna import MemoriaInterna | |
| from aurora.treino.confianca import AgenteConfianca | |
| mi = MemoriaInterna(d=modelo.d, n_slots=32, h_escrita=0.25, | |
| idade_compressao_s=0.0, n_codigos=64) | |
| ag = AgenteConfianca() | |
| amostras_mem = random.sample(registros, min(64, len(registros))) | |
| h_escreveras = 0 | |
| for r in amostras_mem[:48]: | |
| seq = tk.encode(r.get("texto") or (r.get("saida") or r.get("entrada", "")), | |
| tarefa=r["tarefa"], max_len=64)[:64] | |
| if len(seq) < 4: | |
| continue | |
| ids_m = torch.zeros(1, len(seq), dtype=torch.long) | |
| ids_m[0] = torch.tensor(seq) | |
| logits_m, _ = modelo(ids_m, tarefa=r["tarefa"]) | |
| perda_m = modelo.ultima_perda or 6.0 | |
| h_m = float(ag(AgenteConfianca.features_logits(logits_m), | |
| perda_atual=float(perda_m))) | |
| z_m = modelo.contexto(ids_m)[0] | |
| if mi.escrever(z_m, h_m, origem="nucleo", tarefa=r["tarefa"]): | |
| h_escreveras += 1 | |
| consultas_ok = 0 | |
| for r in amostras_mem[48:]: | |
| seq = tk.encode(r.get("texto") or (r.get("saida") or r.get("entrada", "")), | |
| tarefa=r["tarefa"], max_len=64)[:64] | |
| if len(seq) < 4: | |
| continue | |
| ids_m = torch.zeros(1, len(seq), dtype=torch.long) | |
| ids_m[0] = torch.tensor(seq) | |
| z_m = modelo.contexto(ids_m)[0] | |
| rec_m = mi.consultar(z_m, m=3, origem="raciocinio") | |
| consultas_ok += int(rec_m["acerto"]) | |
| n_comp_m = mi.comprimir_antigos(origem="treino") | |
| stats_m = mi.estatisticas() | |
| stats_m["escritas_aceitas"] = h_escreveras | |
| stats_m["consultas_com_acerto"] = consultas_ok | |
| stats_m["comprimidos_agora"] = n_comp_m | |
| relatorio["memoria_execucao"] = stats_m | |
| _salvar(relatorio) | |
| print(f" escritas aceitas={h_escreveras}/48 · consultas com acerto=" | |
| f"{consultas_ok}/16 · comprimidos={n_comp_m} · " | |
| f"entropia_codebook={stats_m['entropia_codebook']:.3f} · " | |
| f"economia_bits/slot={stats_m['economia_bits_por_slot']:.4f} · " | |
| f"violações_contrato={stats_m['violacoes_contrato']}") | |
| # curva de épocas (telemetria) | |
| resumo_path = "/home/z/my-project/aurora/telemetria_out/resumo_treino_v6.json" | |
| if os.path.exists(resumo_path): | |
| relatorio["curva_epocas"] = [ | |
| {"epoca": e["epoca"], "perda_media": e["perda_media"], | |
| "ppl_lm": e["avaliacao"].get("ppl_lm")} | |
| for e in json.load(open(resumo_path)).get("epocas", [])] | |
| # v4 (doc 15 §3.5): COERÊNCIA À MEDIDA QUE OS DADOS CRESCEM | |
| print("== coerência (repetição/ancoragem/entropia) por fator de corpus ==") | |
| try: | |
| coer = metricas_coerencia(modelo, tk, registros) | |
| relatorio["coerencia"] = coer | |
| for chave in ("corpus_25pct", "corpus_50pct", "corpus_100pct"): | |
| if chave in coer: | |
| c = coer[chave] | |
| print(f" {chave}: n={c['n_registros']} " | |
| f"repetição={c['repeticao_pct']}% " | |
| f"ancoragem={c['ancoragem_bigramas']} " | |
| f"entropia={c['entropia_logits']}") | |
| for s in coer.get("amostras", []): | |
| print(f" amostra: {s[:100]}") | |
| except Exception as e: | |
| relatorio["coerencia_erro"] = f"{type(e).__name__}: {e}" | |
| print(f" (coerência falhou: {type(e).__name__})") | |
| # v6 (doc 18 §3): PACOTE COMPLETO DE MÉTRICAS — alinhamento cross-modal, | |
| # geração de texto, benchmarks e SOM expandido (QE/TE/distorção/σ/α/drift/ | |
| # freq de ativação/U-Matrix) | |
| print("== v6: ALINHAMENTO CROSS-MODAL (CLIP Score + ITM + PPL Multimodal) ==") | |
| try: | |
| from aurora.metricas import (avaliar_clip, avaliar_itm, avaliar_todos, | |
| codigos_visuais, metricas_variante, | |
| pacote_completo, ppl_multimodal_texto, | |
| ppl_visual_bigrama, treinar_itm) | |
| from PIL import Image | |
| import io as _io | |
| pares_mm = [] | |
| for r in registros: | |
| if r["tarefa"] in ("imagem_caption", "vqa") and r.get("imagem"): | |
| try: | |
| img = Image.open(_io.BytesIO(r["imagem"])).convert("RGB") | |
| lado = modelo.cfg.modelo.imagem["resolucao"] | |
| import numpy as _np | |
| arr = _np.asarray(img.resize((lado, lado)), | |
| dtype=_np.float32) / 255.0 | |
| tens = torch.from_numpy(arr).permute(2, 0, 1) | |
| pares_mm.append((r.get("entrada") or "Descreva a imagem:", tens)) | |
| except Exception: | |
| continue | |
| if len(pares_mm) >= 32: | |
| break | |
| if pares_mm: | |
| relatorio["clip_score"] = avaliar_clip(modelo, tk, pares_mm, | |
| n_controle=16) | |
| print(" CLIP Score:", relatorio["clip_score"]) | |
| cab, _ = treinar_itm(modelo, tk, pares_mm[:24], epocas=3, lote=8) | |
| relatorio["itm"] = avaliar_itm(cab, modelo, tk, pares_mm[24:]) | |
| print(" ITM:", relatorio["itm"]) | |
| # corrente visual: códigos VQ por imagem → PPL bigrama | |
| codigos = [codigos_visuais(modelo, p[1]) for p in pares_mm[:24]] | |
| relatorio["ppl_visual"] = ppl_visual_bigrama( | |
| codigos, n_codigos=max(2, max(max(c) for c in codigos) + 1 | |
| if codigos and codigos[0] else 2)) | |
| print(" PPL visual (bigrama códigos VQ):", relatorio["ppl_visual"]) | |
| relatorio["ppl_multimodal"] = ppl_multimodal_texto(modelo, tk, registros) | |
| print(" PPL Multimodal (texto sob prefixo visual/áudio):", | |
| relatorio["ppl_multimodal"]) | |
| except Exception as e: | |
| relatorio["alinhamento_erro"] = f"{type(e).__name__}: {e}" | |
| print(" (alinhamento falhou:", relatorio["alinhamento_erro"], ")") | |
| print("== v6: GERAÇÃO DE TEXTO (CIDEr + BLEU 1-4 + ROUGE-L + METEOR) ==") | |
| try: | |
| from collections import Counter as _Counter | |
| from aurora.metricas import pacote_completo | |
| from aurora.metricas.geracao_texto import tokenizar as gen_tokenizar | |
| pool_cap = [r for r in registros if r["tarefa"] in ("imagem_caption", "vqa") | |
| and (r.get("saida") or "").strip()][:12] | |
| if pool_cap: | |
| df_corpus = _Counter() | |
| for r in pool_cap: | |
| toks = gen_tokenizar(r["saida"]) | |
| for n in range(1, 5): | |
| for i in range(len(toks) - n + 1): | |
| df_corpus[tuple(toks[i:i + n])] += 1 | |
| medias = {} | |
| por_item = [] | |
| for r in pool_cap: | |
| prompt = (r.get("entrada") or "Descreva a imagem:")[:140] | |
| ids_p = torch.tensor([tk.encode(prompt, tarefa=r["tarefa"], | |
| max_len=48)]) | |
| novos = modelo.gerar(ids_p, max_novos=20, temperatura=0.7, | |
| top_p=0.9) | |
| hip = tk.decodificar(novos) | |
| m = pacote_completo(hip, [r["saida"]], df_corpus=df_corpus, | |
| n_docs=len(pool_cap)) | |
| por_item.append({"hipotese": hip[:80], "ref": r["saida"][:60], | |
| "bleu": m["bleu"], "rouge_l": m["rouge_l"], | |
| "meteor": m["meteor"], "cider": m["cider"]}) | |
| for chave in ("bleu", "rouge_l", "meteor", "cider"): | |
| vals = [p[chave] for p in por_item] | |
| medias[chave] = round(sum(vals) / len(vals), 4) | |
| relatorio["geracao_metricas"] = {"medias": medias, | |
| "n": len(por_item), | |
| "amostras": por_item[:4]} | |
| print(" médias:", medias) | |
| except Exception as e: | |
| relatorio["geracao_metricas_erro"] = f"{type(e).__name__}: {e}" | |
| print(" (geração-métricas falhou:", relatorio["geracao_metricas_erro"], ")") | |
| print("== v6: BENCHMARKS (MMMU / MME / MathVista — proxies PT-BR) ==") | |
| try: | |
| from aurora.metricas import avaliar_todos | |
| relatorio["benchmarks"] = avaliar_todos(modelo, tk, registros, n_max=30) | |
| for k, v in relatorio["benchmarks"].items(): | |
| print(f" {v.get('benchmark')}: n={v.get('n')} " | |
| f"score={v.get('acuracia', v.get('score_mme'))}") | |
| except Exception as e: | |
| relatorio["benchmarks_erro"] = f"{type(e).__name__}: {e}" | |
| print(" (benchmarks falhou:", relatorio["benchmarks_erro"], ")") | |
| print("== v6: SOM EXPANDIDO (QE/TE/distorção/σ/α/drift/freq/U-Matrix) ==") | |
| try: | |
| from aurora.metricas import metricas_variante | |
| som_exp = {} | |
| probe_x = ctx # contexto da re-consolidação (doc 16 §4) | |
| for nome, v in orquestrador.variantes.items(): | |
| som_exp[nome] = metricas_variante(nome, v, probe_x) | |
| relatorio["som_expandido"] = som_exp | |
| for nome, mv in som_exp.items(): | |
| if "qe" in mv: | |
| print(f" {nome}: QE={mv['qe']} TE={mv['te']} " | |
| f"distorcao={mv['distorcao']} " | |
| f"drift={mv.get('codebook_drift')} " | |
| f"u={mv.get('u_matrix_resumo', {}).get('u_media')}") | |
| except Exception as e: | |
| relatorio["som_expandido_erro"] = f"{type(e).__name__}: {e}" | |
| print(" (som expandido falhou:", relatorio["som_expandido_erro"], ")") | |
| # v5 — Agente Engenheiro: observação de INFERÊNCIA + relatório final | |
| print("== Agente Engenheiro (inferência + relatório integral) ==") | |
| try: | |
| ag = AgenteEngenheiro( | |
| tolerancia_regressao=cfg.agente_engenheiro.tolerancia_regressao, | |
| hub=hub) | |
| for tarefa, ids_ex in (("instrucao", None),): | |
| pass | |
| _ids = torch.tensor([tk.encode("Pergunta: quem escreveu isso? Resposta:", | |
| tarefa="instrucao", max_len=24)]) | |
| t0 = time.time() | |
| _novos = modelo.gerar(_ids, max_novos=24) | |
| relatorio["inferencia_agente"] = ag.observar_inferencia( | |
| modelo, _ids, _novos, time.time() - t0) | |
| print(" ", relatorio["inferencia_agente"]) | |
| # v5 — ciclo de compreensão geracional (difusão, modo honesto) | |
| if cfg.difusao.ativo: | |
| gd = GeradorMultimodal(repo_id=cfg.difusao.repo_id, | |
| altura=cfg.difusao.altura, | |
| largura=cfg.difusao.largura, | |
| passos_inferencia=cfg.difusao.passos_inferencia, | |
| guia_escala=cfg.difusao.guia_escala, hub=hub) | |
| r = gd.compreensao_geracional("o pantanal ao entardecer", modelo, | |
| orquestrador=orquestrador, op="txt2img") | |
| relatorio["difusao"] = {"modo": r.get("modo"), | |
| "prompt_enriquecido": r.get("prompt_enriquecido"), | |
| "latencia_s": r.get("latencia_s"), | |
| "gerou_pixels": r.get("modo") == "real"} | |
| print(" difusão:", relatorio["difusao"]["modo"], "—", | |
| relatorio["difusao"]["prompt_enriquecido"]) | |
| rel_ag = ag.relatorio(orquestrador_som=orquestrador, | |
| avaliacao={"ppl_lm": relatorio.get("ppl_lm")}) | |
| relatorio["agente_engenheiro"] = { | |
| "revisoes_aprovadas": rel_ag["revisoes_aprovadas"], | |
| "revisoes_bloqueadas": rel_ag["revisoes_bloqueadas"], | |
| "som_invariante_sem_orfaos": rel_ag.get("som_invariante_sem_orfaos"), | |
| "som_ativos": rel_ag.get("som_ativos")} | |
| except Exception as e: | |
| relatorio["agente_erro"] = f"{type(e).__name__}: {e}" | |
| os.makedirs(os.path.dirname(RELATORIO), exist_ok=True) | |
| with open(RELATORIO, "w", encoding="utf-8") as f: | |
| json.dump(relatorio, f, ensure_ascii=False, indent=2, default=str) | |
| print(f"relatório → {RELATORIO}") | |
| def _lote_lm(tk, registros, lote=8, L=192): | |
| pool = [r for r in registros if r["tarefa"] == "lm"] or registros | |
| seqs = [] | |
| for r in random.sample(pool, min(lote, len(pool))): | |
| t = (r.get("texto") or r.get("saida") or r.get("entrada") or "")[:800] | |
| seqs.append(tk.encode(t, tarefa="lm", max_len=L)) | |
| Tmax = max(len(s) for s in seqs) | |
| ids = torch.zeros(len(seqs), Tmax, dtype=torch.long) | |
| alvo = torch.full((len(seqs), Tmax), -100, dtype=torch.long) | |
| for i, s in enumerate(seqs): | |
| ids[i, :len(s)] = torch.tensor(s) | |
| alvo[i, 1:len(s)] = ids[i, 1:len(s)] | |
| return ids, alvo | |
| # ---------------- v4 (doc 15 §3.5): COERÊNCIA das respostas ---------------- | |
| def metricas_coerencia(modelo, tk, registros, rotulos_prompts=None): | |
| """Coerência medida em três dimensões (doc 15 §3.5): | |
| (i) REPETIÇÃO: n-gramas repetidos por 100 tokens gerados; | |
| (ii) ANCORAGEM no corpus: fração de bigramas gerados que existem nos | |
| bigramas do corpus (proxy de coerência de língua); | |
| (iii) ENTROPIA média dos logits (confiança da política). | |
| Avaliada em FATORES de tamanho de corpus — coerência exibida À MEDIDA | |
| QUE OS DADOS CRESCEM (requisito do usuário).""" | |
| prompts = rotulos_prompts or [ | |
| "O Brasil é um país", | |
| "Para fazer um bolo simples você precisa", | |
| "A previsão do tempo para amanhã", | |
| "O melhor jeito de estudar é", | |
| ] | |
| # bigramas de referência do corpus (hash de pares de ids) | |
| corpus_bg: set[int] = set() | |
| pool = [r for r in registros if r.get("texto") or r.get("saida")] or registros | |
| for r in random.sample(pool, min(60, len(pool))): | |
| t = (r.get("texto") or r.get("saida") or r.get("entrada") or "")[:600] | |
| ids = tk.encode(t, tarefa="lm", max_len=96) | |
| for a, b in zip(ids, ids[1:]): | |
| corpus_bg.add(a * 1000003 + b) | |
| resultados = {} | |
| gerados_todos: list[list[int]] = [] | |
| for fator in (0.25, 0.5, 1.0): # subcorpus crescente | |
| n = max(1, int(len(pool) * fator)) | |
| sub = pool[:n] | |
| # bigramas de referência do subcorpus (menor → menos âncoras) | |
| bg_sub: set[int] = set() | |
| for r in random.sample(sub, min(40, len(sub))): | |
| t = (r.get("texto") or r.get("saida") or r.get("entrada") or "")[:600] | |
| ids = tk.encode(t, tarefa="lm", max_len=96) | |
| for a, b in zip(ids, ids[1:]): | |
| bg_sub.add(a * 1000003 + b) | |
| repeticoes, ancoragens, entropias = [], [], [] | |
| for p in prompts: | |
| ids_p = tk.encode(p, tarefa="lm", max_len=24) | |
| t_ids = torch.tensor([ids_p]) | |
| novos = modelo.gerar(t_ids, max_novos=36, temperatura=0.85, | |
| top_p=0.92) | |
| gerados_todos.append(novos) | |
| if not novos: | |
| continue | |
| # (i) repetição: fração de 3-gramas duplicados | |
| trigs = [tuple(novos[i:i + 3]) for i in range(len(novos) - 2)] | |
| rep = 1.0 - (len(set(trigs)) / len(trigs)) if trigs else 0.0 | |
| repeticoes.append(rep * 100.0) | |
| # (ii) ancoragem: bigramas gerados presentes no subcorpus | |
| bigs = [novos[i] * 1000003 + novos[i + 1] | |
| for i in range(len(novos) - 1)] | |
| anc = (sum(1 for g in bigs if g in bg_sub) / len(bigs)) if bigs else 0.0 | |
| ancoragens.append(anc) | |
| # (iii) entropia média dos logits (confiança) | |
| modelo.eval() | |
| with torch.no_grad(): | |
| x = modelo.emb(t_ids) | |
| for bloco in modelo.blocos: | |
| x, _, _ = bloco(x) | |
| h = modelo.norm_f(x) | |
| if modelo.nlp is not None: | |
| h, _ = modelo.nlp(h) | |
| lg = torch.log_softmax(modelo.lm_head(h[:, -1]), dim=-1) | |
| entropias.append(float(-(lg.exp() * lg).sum())) | |
| resultados[f"corpus_{int(fator*100)}pct"] = { | |
| "n_registros": n, | |
| "repeticao_pct": round(sum(repeticoes) / max(1, len(repeticoes)), 2), | |
| "ancoragem_bigramas": round(sum(ancoragens) / max(1, len(ancoragens)), 4), | |
| "entropia_logits": round(sum(entropias) / max(1, len(entropias)), 4), | |
| } | |
| # amostras para o relatório (legibilidade humana) | |
| resultados["amostras"] = [tk.decodificar(g)[:140] for g in gerados_todos[:4]] | |
| return resultados | |
| if __name__ == "__main__": | |
| main() | |