"""Estimate J_l = E_{prompt, t, t'>=t}[dh_final,t'/dh_l,t] over a pretraining-like corpus.""" import argparse, json, sys, time from pathlib import Path import torch sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from jlens.core import load_model, prompt_jacobian_pairsum def corpus_texts(n, min_chars=400): from datasets import load_dataset ds = load_dataset("HuggingFaceFW/fineweb-edu", name="sample-10BT", split="train", streaming=True) got = 0 for ex in ds: t = ex["text"].strip() if len(t) >= min_chars: yield t got += 1 if got >= n: return def main(): ap = argparse.ArgumentParser() ap.add_argument("--n-prompts", type=int, default=256) ap.add_argument("--seq-len", type=int, default=64) ap.add_argument("--chunk", type=int, default=128) ap.add_argument("--out", default="results/jbar.pt") ap.add_argument("--dtype", default="float32") args = ap.parse_args() model, tok = load_model(dtype=getattr(torch, args.dtype)) L = len(model.model.language_model.layers) d = model.config.get_text_config().hidden_size Jsum = torch.zeros(L, d, d, device="cuda", dtype=torch.float32) pairs_total = 0 t0 = time.time() for i, text in enumerate(corpus_texts(args.n_prompts)): ids = tok(text, return_tensors="pt", truncation=True, max_length=args.seq_len)["input_ids"].cuda() if ids.shape[1] < args.seq_len: continue J, n_pairs = prompt_jacobian_pairsum(model, ids, chunk=args.chunk) Jsum += J pairs_total += n_pairs if i % 5 == 0 or i == args.n_prompts - 1: el = time.time() - t0 print(f"[{i+1}/{args.n_prompts}] {el:.0f}s ({el/(i+1):.1f}s/prompt)", flush=True) if i % 50 == 49: # checkpoint torch.save({"Jbar": (Jsum / pairs_total).cpu(), "n_prompts": i + 1, "seq_len": args.seq_len}, args.out + ".ckpt") Jbar = (Jsum / pairs_total).cpu() Path(args.out).parent.mkdir(parents=True, exist_ok=True) torch.save({"Jbar": Jbar, "n_prompts": args.n_prompts, "seq_len": args.seq_len, "pairs": pairs_total}, args.out) print("saved", args.out) if __name__ == "__main__": main()