Upload eval.py with huggingface_hub
Browse files
eval.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import time
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
|
| 5 |
+
import torch
|
| 6 |
+
|
| 7 |
+
from indigo.common import (
|
| 8 |
+
build_tokenizer,
|
| 9 |
+
load_meta,
|
| 10 |
+
load_wordlist,
|
| 11 |
+
read_clean,
|
| 12 |
+
word_known_ratio,
|
| 13 |
+
)
|
| 14 |
+
from indigo.model import GPT, GPTConfig
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def muat(path):
|
| 18 |
+
from safetensors.torch import load_file
|
| 19 |
+
|
| 20 |
+
meta = load_meta(path)
|
| 21 |
+
model = GPT(GPTConfig(**meta["config"]))
|
| 22 |
+
missing, unexpected = model.load_state_dict(load_file(path), strict=False)
|
| 23 |
+
if missing or unexpected:
|
| 24 |
+
raise SystemExit(f"bobot tidak cocok untuk {path}: {missing[:3]} {unexpected[:3]}")
|
| 25 |
+
model.eval()
|
| 26 |
+
tokenizer = build_tokenizer(meta.get("tokenizer") or {"type": "char"}, meta.get("vocab"))
|
| 27 |
+
return model, tokenizer, meta
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
@torch.no_grad()
|
| 31 |
+
def nats_per_token(model, ids, block_size, device):
|
| 32 |
+
total_nll = 0.0
|
| 33 |
+
total_tok = 0
|
| 34 |
+
for i in range(0, max(0, len(ids) - 1), block_size):
|
| 35 |
+
potongan = ids[i : i + block_size + 1]
|
| 36 |
+
if len(potongan) < 2:
|
| 37 |
+
break
|
| 38 |
+
x = torch.tensor([potongan[:-1]], dtype=torch.long, device=device)
|
| 39 |
+
y = torch.tensor([potongan[1:]], dtype=torch.long, device=device)
|
| 40 |
+
logits, _ = model(x)
|
| 41 |
+
logp = torch.log_softmax(logits[0].float(), dim=-1)
|
| 42 |
+
total_nll += float(-logp[torch.arange(len(y[0])), y[0]].sum())
|
| 43 |
+
total_tok += len(potongan) - 1
|
| 44 |
+
return total_nll / max(1, total_tok), total_tok
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def main():
|
| 48 |
+
ap = argparse.ArgumentParser(
|
| 49 |
+
description="Skor checkpoint pada set uji tetap agar antar-run dapat dibandingkan"
|
| 50 |
+
)
|
| 51 |
+
ap.add_argument("--ckpt", nargs="+", required=True)
|
| 52 |
+
ap.add_argument("--test", default="data/sample.txt")
|
| 53 |
+
ap.add_argument("--device", default="cpu", choices=["cpu", "cuda"])
|
| 54 |
+
ap.add_argument("--guard", default=None, help="kamus opsional untuk metrik rasio ejaan")
|
| 55 |
+
ap.add_argument("--seed", type=int, default=42)
|
| 56 |
+
args = ap.parse_args()
|
| 57 |
+
|
| 58 |
+
teks = read_clean(args.test)
|
| 59 |
+
n_karakter = len(teks.encode("utf-8"))
|
| 60 |
+
wordset = prefiks = sufiks = None
|
| 61 |
+
if args.guard:
|
| 62 |
+
root = Path(__file__).resolve().parent
|
| 63 |
+
wordset = load_wordlist(args.guard)
|
| 64 |
+
p, s = root / "data" / "prefiks.txt", root / "data" / "sufiks.txt"
|
| 65 |
+
prefiks = load_wordlist(str(p)) if p.exists() else None
|
| 66 |
+
sufiks = load_wordlist(str(s)) if s.exists() else None
|
| 67 |
+
|
| 68 |
+
print(f"set uji: {args.test} ({n_karakter:,} karakter)")
|
| 69 |
+
print(f"{'checkpoint':44s} {'nats/tok':>9s} {'nat/kar':>8s} {'kamus':>7s}")
|
| 70 |
+
baris = []
|
| 71 |
+
for path in args.ckpt:
|
| 72 |
+
model, tokenizer, meta = muat(path)
|
| 73 |
+
ids = tokenizer.encode(teks)
|
| 74 |
+
npt, n_tok = nats_per_token(model, ids, meta["config"]["block_size"], args.device)
|
| 75 |
+
kompresi = n_karakter / max(1, n_tok)
|
| 76 |
+
npc = npt / kompresi
|
| 77 |
+
rasio = ""
|
| 78 |
+
if wordset:
|
| 79 |
+
t0 = time.time()
|
| 80 |
+
out = model.generate(
|
| 81 |
+
torch.tensor([[0]], dtype=torch.long, device=args.device),
|
| 82 |
+
120,
|
| 83 |
+
temperature=0.8,
|
| 84 |
+
top_k=40,
|
| 85 |
+
)
|
| 86 |
+
del t0
|
| 87 |
+
teks_out = tokenizer.decode(out[0].tolist())
|
| 88 |
+
rasio = f"{word_known_ratio(teks_out, wordset, prefiks, sufiks):6.0%}"
|
| 89 |
+
nama = Path(path).parent.parent.name + "/" + Path(path).name
|
| 90 |
+
print(f"{nama:44s} {npt:9.3f} {npc:8.3f} {rasio:>7s}")
|
| 91 |
+
baris.append({"ckpt": str(path), "nats_per_token": round(npt, 4), "nats_per_char": round(npc, 4)})
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
if __name__ == "__main__":
|
| 95 |
+
main()
|