Download eval.py from roanbrasil/attnres-devops-gpt: direct link, hf CLI and curl.
- Browser
- Download file 4.77 kB
-
https://huggingface.co/roanbrasil/attnres-devops-gpt/resolve/main/eval.py
- Command line
-
hf download hf://roanbrasil/attnres-devops-gpt/eval.py
-
curl -L -o eval.py https://huggingface.co/roanbrasil/attnres-devops-gpt/resolve/main/eval.py
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) | |