roanbrasil's picture
Upload eval.py with huggingface_hub
d8c4a8f verified
Raw
History Blame Contribute Delete
4.77 kB
"""
Avalia e compara os modelos treinados.
MΓ©tricas:
1. Perplexidade no val set
2. GeraΓ§Γ£o de texto a partir de prompts DevOps reais
3. Top-k tokens mais provΓ‘veis para completar frases tΓ­picas
Uso:
python eval.py
python eval.py --prompt "apiVersion: apps/v1\nkind: Deployment"
"""
import json
import math
import argparse
import numpy as np
import torch
from pathlib import Path
from tokenizers import ByteLevelBPETokenizer
from model import GPT, GPTConfig
from train import BinaryDataset, DEVICE, DTYPE, EVAL_ITERS, SEQ_LEN, evaluate
DATA_DIR = Path(__file__).parent / "data"
CKPT_DIR = Path(__file__).parent / "checkpoints"
DEVOPS_PROMPTS = [
"apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name:",
"resource \"aws_eks_cluster\" \"main\" {\n name =",
"helm install my-release stable/nginx-ingress --namespace",
"kubectl apply -f deployment.yaml --namespace",
"kind: HelmRelease\napiVersion: helm.toolkit.fluxcd.io/v2beta1\nmetadata:\n name:",
"spec:\n replicas: 3\n selector:\n matchLabels:\n app:",
"terraform {\n required_providers {\n kubernetes = {",
"argocd app create --app-name",
]
def load_model(variant: str) -> tuple[GPT, dict]:
ckpt_path = CKPT_DIR / f"{variant}_latest.pt"
if not ckpt_path.exists():
raise FileNotFoundError(f"Checkpoint nΓ£o encontrado: {ckpt_path}")
ck = torch.load(ckpt_path, map_location=DEVICE, weights_only=False)
cfg = GPTConfig(**ck["config"])
model = GPT(cfg).to(DEVICE)
# torch.compile adiciona prefixo "_orig_mod." β€” remover ao carregar
state = ck["model"]
state = {k.replace("_orig_mod.", ""): v for k, v in state.items()}
model.load_state_dict(state)
model.eval()
return model, ck
def load_tokenizer() -> ByteLevelBPETokenizer:
tok_dir = DATA_DIR / "tokenizer"
return ByteLevelBPETokenizer(
str(tok_dir / "vocab.json"),
str(tok_dir / "merges.txt"),
)
def run_eval(args):
meta = json.loads((DATA_DIR / "meta.json").read_text())
val_ds = BinaryDataset(DATA_DIR / "val.bin", SEQ_LEN)
tok = load_tokenizer()
models = {}
for v in ("baseline", "attnres"):
try:
m, ck = load_model(v)
models[v] = (m, ck)
print(f"Carregado: {v} (step {ck.get('step', '?')})")
except FileNotFoundError as e:
print(f"SKIP: {e}")
if not models:
print("Nenhum checkpoint encontrado. Rode train.py primeiro.")
return
# ── 1. Perplexidade ──────────────────────────────────────────────────────
print("\n" + "=" * 55)
print("PERPLEXIDADE NO VAL SET")
print("=" * 55)
for v, (m, _) in models.items():
loss = evaluate(m, val_ds)
ppl = math.exp(loss)
params = m.n_params()
print(f" {v:10s} loss {loss:.4f} ppl {ppl:8.2f} params {params:,}")
# ── 2. GeraΓ§Γ£o de texto ──────────────────────────────────────────────────
prompts = [args.prompt] if args.prompt else DEVOPS_PROMPTS
print("\n" + "=" * 55)
print("GERAÇÃO DE TEXTO")
print("=" * 55)
for prompt in prompts[:4]:
print(f"\nPrompt: {prompt!r}")
enc_ids = tok.encode(prompt).ids
x = torch.tensor([enc_ids], dtype=torch.long, device=DEVICE)
for v, (m, _) in models.items():
out_ids = m.generate(x, max_new=60, temperature=0.7, top_k=30)
text = tok.decode(out_ids[0].tolist())
cont = text[len(prompt):]
print(f" [{v:10s}] {cont[:120]!r}")
# ── 3. Curvas de convergΓͺncia (se ambos disponΓ­veis) ─────────────────────
if len(models) == 2:
print("\n" + "=" * 55)
print("CURVAS DE CONVERGÊNCIA (val_ppl por step)")
print("=" * 55)
print(f"{'Step':>6} {'Baseline':>10} {'AttnRes':>10} {'Ξ” (A-B)':>10}")
print("-" * 45)
ck_b = models["baseline"][1]
ck_a = models["attnres"][1]
h_b = ck_b.get("history", {})
h_a = ck_a.get("history", {})
for s, lb, la in zip(h_b.get("val_steps", []),
h_b.get("val_loss", []),
h_a.get("val_loss", [])):
pb, pa = math.exp(lb), math.exp(la)
print(f"{s:6d} {pb:10.2f} {pa:10.2f} {pa-pb:+10.2f}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--prompt", type=str, default=None)
args = parser.parse_args()
run_eval(args)