pragnosia / eval_external.py
4AshishKmr's picture
add eval_external.py
14eb335 verified
Raw
History Blame Contribute Delete
5.91 kB
"""Zero-shot evaluation of the spin-dominant LM on standard public benchmarks.
Custom 16K tokenizer -> we report WORD-normalized perplexity (tokenizer-independent) and
log-likelihood multiple-choice accuracy (also tokenizer-independent). CPU/GPU, read-only."""
import os, sys, math, json, time
os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
os.environ.setdefault("HF_HUB_DISABLE_PROGRESS_BARS", "1")
import torch, torch.nn.functional as F, s6_hybrid as H
from tokenizers import Tokenizer
CKPT = sys.argv[1] if len(sys.argv) > 1 else "pragnosia_spin.pt"
DEV = "cuda" if torch.cuda.is_available() else "cpu"
c = json.load(open("pragnosia.json")); H.VOC, H.L = c["vocab"], c["ctx"]; CTX = c["ctx"]
tok = Tokenizer.from_file(c["tokenizer"])
m = H.SpinAttentionLM(c["vocab"], c["d"], c["heads"], c["layers"], mlp_mult=c["mlp_mult"], carrier=c["carrier"]).to(DEV)
m.load_state_dict(torch.load(CKPT, map_location="cpu", weights_only=True))
m = m.bfloat16().eval() if DEV == "cuda" else m.eval()
print(f"loaded {sys.exit if False else ''}{H.n_params(m)/1e6:.0f}M {c['carrier']} on {DEV}\n", flush=True)
@torch.no_grad()
def cont_lp(ctx, cont):
"""sum log p(cont | ctx) and #cont-tokens, context truncated to the model window."""
full = tok.encode(ctx + cont).ids
ci = len(tok.encode(ctx).ids)
n = len(full) - ci
if n <= 0: return -1e9, 1
full = full[-CTX:] # cap to window (cont is at the tail)
n = min(n, len(full) - 1)
x = torch.tensor([full], device=DEV)
lg = m(x)[0].float().log_softmax(-1)
lp = sum(lg[j - 1, full[j]].item() for j in range(len(full) - n, len(full)))
return lp, n
def mc(name, items, norm=True, cap=1000):
"""items: list of (context, [options], gold_idx). Returns acc."""
import random; random.seed(0)
if len(items) > cap: items = random.sample(items, cap)
ok = 0
for ctx, opts, gold in items:
sc = []
for o in opts:
lp, nt = cont_lp(ctx, o)
sc.append(lp / nt if norm else lp)
if max(range(len(sc)), key=lambda i: sc[i]) == gold: ok += 1
print(f" {name:14} {ok/len(items)*100:5.1f}% (n={len(items)}, chance {100/len(items[0][1]):.0f}%)", flush=True)
return ok / len(items)
from datasets import load_dataset
res = {}
# ---- WikiText-2 word-perplexity ----
try:
t0 = time.time(); wt = load_dataset("wikitext", "wikitext-2-raw-v1", split="test")
text = "\n".join(r for r in wt["text"] if r.strip())
words = len(text.split()); ids = tok.encode(text).ids; tot = 0.0
for i in range(0, len(ids) - 1, CTX):
ch = ids[i:i + CTX + 1]
if len(ch) < 2: break
x = torch.tensor([ch[:-1]], device=DEV)
lg = m(x)[0].float()
tot += F.cross_entropy(lg, torch.tensor(ch[1:], device=DEV), reduction="sum").item()
res["wikitext2_word_ppl"] = math.exp(tot / words)
print(f" WikiText-2 word-ppl {res['wikitext2_word_ppl']:.1f} ({words/1e3:.0f}K words, {time.time()-t0:.0f}s)", flush=True)
except Exception as e: print(" WikiText-2 skipped:", str(e)[:60], flush=True)
# ---- LAMBADA (last-word accuracy) ----
try:
lb = load_dataset("EleutherAI/lambada_openai", "en", split="test")
items = []
for r in lb:
s = r["text"].strip(); k = s.rfind(" ")
if k > 0: items.append((s[:k], [s[k:]], 0)) # predict the last word
# accuracy = greedy last token matches; approximate via: the gold continuation is the only option,
# so instead score whether argmax-continuation equals the word -> use a small generate
import random; random.seed(0); sub = random.sample(items, min(1000, len(items)))
ok = 0
for ctx, (gold,), _ in sub:
gid = tok.encode(ctx + gold).ids[len(tok.encode(ctx).ids):]
if not gid: continue
full = tok.encode(ctx).ids[-CTX:]
pred = int(m(torch.tensor([full], device=DEV))[0, -1].argmax())
ok += (pred == gid[0])
res["lambada_acc"] = ok / len(sub)
print(f" LAMBADA {res['lambada_acc']*100:5.1f}% (first-token of last word, n={len(sub)})", flush=True)
except Exception as e: print(" LAMBADA skipped:", str(e)[:60], flush=True)
# ---- HellaSwag (acc_norm) ----
try:
hs = load_dataset("Rowan/hellaswag", split="validation")
items = [(r["ctx"], r["endings"], int(r["label"])) for r in hs if r["label"] != ""]
res["hellaswag_accn"] = mc("HellaSwag", items, norm=True)
except Exception as e: print(" HellaSwag skipped:", str(e)[:60], flush=True)
# ---- ARC-Easy (acc_norm) ----
try:
ar = load_dataset("allenai/ai2_arc", "ARC-Easy", split="test")
items = []
for r in ar:
ch = r["choices"]["text"]; lab = r["choices"]["label"]
if r["answerKey"] in lab: items.append(("Question: " + r["question"] + "\nAnswer: ", ch, lab.index(r["answerKey"])))
res["arc_easy_accn"] = mc("ARC-Easy", items, norm=True)
except Exception as e: print(" ARC-Easy skipped:", str(e)[:60], flush=True)
# ---- ARC-Challenge (acc_norm) ----
try:
ac = load_dataset("allenai/ai2_arc", "ARC-Challenge", split="test")
items = []
for r in ac:
ch = r["choices"]["text"]; lab = r["choices"]["label"]
if r["answerKey"] in lab: items.append(("Question: " + r["question"] + "\nAnswer: ", ch, lab.index(r["answerKey"])))
res["arc_challenge_accn"] = mc("ARC-Challenge", items, norm=True)
except Exception as e: print(" ARC-Challenge skipped:", str(e)[:60], flush=True)
# ---- PIQA (acc) ----
try:
pq = load_dataset("piqa", split="validation", revision="refs/convert/parquet")
items = [(r["goal"] + " ", [r["sol1"], r["sol2"]], r["label"]) for r in pq if r["label"] in (0, 1)]
res["piqa_acc"] = mc("PIQA", items, norm=False)
except Exception as e: print(" PIQA skipped:", str(e)[:60], flush=True)
print("\nJSON:", json.dumps({k: round(v, 3) for k, v in res.items()}), flush=True)