PAMPAr-Coder / scripts /diagnose_routing.py
lucas-mella's picture
feat: upload PAMPAr-Coder code and documentation
a2d6a0d verified
Raw
History Blame Contribute Delete
4.26 kB
#!/usr/bin/env python3
"""Diagnóstico detallado de errores de routing por token."""
import torch
import sys
import sentencepiece as spm
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))
from pampar.coder.v3.config import PRESET_V3
from pampar.coder.v3.modelo import PamparV3
from pampar.coder.v3.llaves import clasificar_token
from pampar.coder.v3.zonas import ZONA_TERRITORIO, Territorio
TERR_NAMES = ["SINT", "SEMA", "LOGI", "ESTR"]
WEAK_SAMPLES = [
("numeros", "pi = 3.14159"),
("with", "with open('file.txt') as f:"),
("excepcion", "try:\n result = 1 / 0\nexcept ZeroDivisionError:"),
("comparacion", "x == y or x != z"),
("lambda", "fn = lambda x: x * 2"),
("imports", "from pathlib import Path"),
("literals", "name = 'hello world'"),
("decorador", "@staticmethod\ndef create():"),
]
def main() -> None:
tok = spm.SentencePieceProcessor()
tok.Load(str(ROOT / "data" / "tokenizer" / "pampar_48k.model"))
vocab_size = tok.GetPieceSize()
territory_table = torch.zeros(vocab_size, dtype=torch.long)
for tid in range(vocab_size):
piece = tok.IdToPiece(tid)
z, _c = clasificar_token(piece)
territory_table[tid] = ZONA_TERRITORIO[z].value
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = PamparV3(PRESET_V3).to(device)
ckpt = torch.load(
str(ROOT / "checkpoints" / "v3_ghidra_v4.pt"),
map_location=device,
weights_only=False,
)
model.load_state_dict(ckpt["modelo"])
model.registrar_tokenizer(tok)
model.eval()
del ckpt
# Import forward_instrumentado from brain_scanner
from brain_scanner import forward_instrumentado
all_errors: list[dict] = []
for label, code in WEAK_SAMPLES:
tids = tok.Encode(code, out_type=int)
pieces = [tok.IdToPiece(t) for t in tids]
inp = torch.tensor([tids], dtype=torch.long, device=device)
with torch.no_grad():
info = forward_instrumentado(model, inp)
terr_last = info["terr_por_nivel"][-1]
print(f"\n{'='*60}")
print(f" {label}: {repr(code[:50])} ({len(tids)} tokens)")
print(f"{'='*60}")
for i, (tid, piece) in enumerate(zip(tids, pieces)):
expected = territory_table[tid].item()
actual = terr_last[i].argmax().item()
zona, conf = clasificar_token(piece)
acts = terr_last[i].tolist()
mark = "✓" if actual == expected else "✗"
if actual != expected:
all_errors.append({
"sample": label,
"token": piece,
"zona": zona.name,
"conf": conf,
"expected": TERR_NAMES[expected],
"actual": TERR_NAMES[actual],
"acts": acts,
})
acts_str = " ".join(
f"{TERR_NAMES[j]}={a:.3f}" for j, a in enumerate(acts)
)
print(
f" {mark} {piece:20s} exp={TERR_NAMES[expected]:4s} "
f"act={TERR_NAMES[actual]:4s} zona={zona.name:20s} "
f"conf={conf:.0%} [{acts_str}]"
)
print(f"\n{'='*60}")
print(f" RESUMEN DE ERRORES: {len(all_errors)} tokens mal routeados")
print(f"{'='*60}")
# Group errors by pattern
from collections import Counter
patterns = Counter()
for e in all_errors:
key = f"{e['expected']}->{e['actual']}"
patterns[key] += 1
print("\n Patrones de error:")
for pattern, count in patterns.most_common():
print(f" {pattern}: {count} tokens")
print("\n Detalle de cada error:")
for e in all_errors:
margin = sorted(e["acts"], reverse=True)
m = margin[0] - margin[1]
print(
f" [{e['sample']:12s}] {e['token']:20s} "
f"{e['expected']:4s}->{e['actual']:4s} "
f"zona={e['zona']:20s} conf={e['conf']:.0%} "
f"margin={m:.4f}"
)
if __name__ == "__main__":
main()