Files
qwen3-4b-blockdist/eval/scripts/acc_regress.py

90 lines
4.6 KiB
Python
Raw Permalink Normal View History

"""Honest accuracy-retention test: per-example regression analysis, not aggregate F1.
For each real LongBench QA: is dense correct? is sparse correct? Then count REGRESSIONS (dense right ->
sparse wrong) vs GAINS (dense wrong -> sparse right). Aggregate F1 can hide regressions; this can't.
Correct = gold answer (normalized) contained in the generated first line.
"""
from __future__ import annotations
import argparse, glob, json, string, torch, torch.nn as nn
import scripts.demo_infer as DM
LB = "/work/hdd/bdjx/hxia3/hf_cache/hub/datasets--Syon-Li--LongbenchSeg/snapshots/*/longbench_segmented.jsonl"
def norm(s):
return " ".join("".join(c for c in s.lower() if c not in string.punctuation).split())
def load(tok, sink, max_len, n, max_ans=50):
out = []
for line in open(glob.glob(LB)[0]):
if len(out) >= n: break
if len(line) > max_len*60: continue
try: r = json.loads(line)
except Exception: continue
if not r.get("chunks") or not r.get("answers") or len(r["chunks"]) < 3: continue
ans = r["answers"][0]
if not (1 <= len(ans) <= max_ans): continue
ids, blk, snk = [], [], []
def add(t,b,sp=False,sk=False):
for x in ([t] if sk else tok(t,add_special_tokens=sp)["input_ids"]):
ids.append(x); blk.append(b); snk.append(sk)
add(r["chunks"][0][:600], -1, sp=True)
for bi,c in enumerate(r["chunks"][1:11]):
for s in sink: ids.append(s); blk.append(bi); snk.append(True)
add("\n"+c, bi)
q0=len(ids); add(f"\nQuestion: {r['input']}\nAnswer:", -2)
if len(ids) <= max_len and (max(blk)+1) >= 3:
out.append((ids, blk, snk, q0, ans, r.get("dataset","?"), r["input"], list(r["chunks"][1:11])))
return out
@torch.no_grad()
def main():
ap = argparse.ArgumentParser(); ap.add_argument("--model", required=True)
ap.add_argument("--router", required=True); ap.add_argument("--n", type=int, default=80)
ap.add_argument("--k", type=int, default=2); ap.add_argument("--max-len", type=int, default=2000)
ap.add_argument("--max-new", type=int, default=24); ap.add_argument("--dump", default=None)
args = ap.parse_args(); dev="cuda"
from transformers import AutoModelForCausalLM, AutoTokenizer
tok = AutoTokenizer.from_pretrained(args.model)
model = AutoModelForCausalLM.from_pretrained(args.model, dtype=torch.bfloat16,
attn_implementation="eager", device_map="cuda").eval()
ck = torch.load(args.router, map_location=dev); summ = ck["summary_tokens"]
router = nn.Linear(ck["in_dim"],1).to(dev); router.load_state_dict(ck["state_dict"]); router.eval()
sink = tok("\n", add_special_tokens=False)["input_ids"]*4
ex = load(tok, sink, args.max_len, args.n)
print(f"per-example regression test on {len(ex)} short-answer LongBench QA (k={args.k}) ...\n")
dh=sh=reg=gain=both=0; regs=[]; dump=[]
for ids, blk, snk, q0, gold, ds, question, docs in ex:
gd = DM.gen(model,tok,ids,blk,snk,q0,'dense',None,0,args.max_new,0,summ).split("Answer:")[-1].split("\n")[0]
gs = DM.gen(model,tok,ids,blk,snk,q0,'sparse',router,args.k,args.max_new,0,summ).split("Answer:")[-1].split("\n")[0]
dc = norm(gold) in norm(gd); sc = norm(gold) in norm(gs)
dh+=dc; sh+=sc; both+=(dc and sc)
if dc and not sc: reg+=1; regs.append((gold, gd.strip()[:50], gs.strip()[:50], ds))
if sc and not dc: gain+=1
dump.append({"dataset": ds, "question": question, "documents": docs, "gold": gold,
"dense_output": gd.strip(), "sparse_output": gs.strip(),
"dense_correct": bool(dc), "sparse_correct": bool(sc)})
n=len(ex)
if args.dump:
import json as J
J.dump({"model": args.model, "k": args.k, "summary_tokens": summ,
"summary": {"n": n, "dense_correct": dh, "sparse_correct": sh,
"regressions": reg, "gains": gain}, "examples": dump},
open(args.dump, "w"), indent=2, ensure_ascii=False)
print(f"dumped {n} examples -> {args.dump}")
print(f"dense correct : {dh}/{n} ({dh/n*100:.0f}%)")
print(f"sparse correct: {sh}/{n} ({sh/n*100:.0f}%)")
print(f"REGRESSIONS (dense right -> sparse wrong): {reg}/{n}")
print(f"GAINS (dense wrong -> sparse right): {gain}/{n}")
print(f"net change: {sh-dh:+d} (agreement both-correct: {both})")
if regs:
print("\nregression cases (gold | dense | sparse | task):")
for g,d,s,ds in regs[:8]:
print(f" gold={g!r} | dense={d!r} | sparse={s!r} | {ds}")
if __name__ == "__main__":
main()