Download src/beat_baselines.py from GOVINDFROM/parallel-consistent-masked-diffusion: direct link, hf CLI and curl.
- Browser
- Download file 8.2 kB
-
https://huggingface.co/GOVINDFROM/parallel-consistent-masked-diffusion/resolve/main/src/beat_baselines.py
- Command line
-
hf download hf://GOVINDFROM/parallel-consistent-masked-diffusion/src/beat_baselines.py
-
curl -L -o beat_baselines.py https://huggingface.co/GOVINDFROM/parallel-consistent-masked-diffusion/resolve/main/src/beat_baselines.py
8.2 kB
| """Head-to-head against inference-time decoding methods. | |
| This is the comparison that decides whether the paper's claim holds. Roughly a | |
| dozen 2026 papers accelerate diffusion decoding by choosing *which* positions to | |
| reveal together - confidence ranking, entropy gating, dependency-aware ordering. | |
| All of them take the trained marginals as given and only reorder commits. | |
| The argument of this project is that no such method can close the gap, because | |
| the marginals themselves were never trained for the one-pass regime. That is | |
| testable directly: take a BASELINE model, decode it with every strategy at every | |
| budget, and check whether any of them reaches the training-time method. | |
| For a fair fight each inference-time method is given its best configuration and | |
| is allowed MORE passes than our method uses. | |
| """ | |
| import argparse, glob, json, os, sys | |
| import numpy as np | |
| import torch | |
| sys.path.insert(0, os.path.dirname(__file__)) | |
| from data import build_addition | |
| from model import Transformer | |
| import diffusion as dfn | |
| from train_add import exact_match | |
| p = argparse.ArgumentParser() | |
| p.add_argument("--runs", default="runs") | |
| p.add_argument("--digits", type=int, default=12) | |
| p.add_argument("--n_eval", type=int, default=400) | |
| p.add_argument("--eval_bs", type=int, default=100) | |
| p.add_argument("--out", default="figures/beat_baselines.json") | |
| a = p.parse_args() | |
| dev = "cuda" if torch.cuda.is_available() else "cpu" | |
| SL = 3 * a.digits + 4 | |
| X, A, tok = build_addition(a.n_eval, a.digits, SL, seed=90_000, exact=True) | |
| X, A = torch.from_numpy(X), torch.from_numpy(A) | |
| def load(run_dir): | |
| cfg = json.load(open(os.path.join(run_dir, "result.json")))["args"] | |
| m = Transformer(len(tok), cfg["d"], cfg["layers"], cfg["heads"], cfg["pe"], | |
| causal=False, max_len=cfg["seq_len"] + 8).to(dev) | |
| m.load_state_dict(torch.load(os.path.join(run_dir, "model.pt"), map_location=dev)) | |
| m.eval() | |
| return m, cfg | |
| def run(model, steps, strategy, tau=None): | |
| accs = [] | |
| for i in range(0, len(X), a.eval_bs): | |
| xb, ab = X[i:i + a.eval_bs].to(dev), A[i:i + a.eval_bs].to(dev) | |
| x = torch.where(ab, torch.full_like(xb, tok.mask), xb) | |
| n_ans = int(ab[0].sum()) | |
| pred = None | |
| for s in range(steps, 0, -1): | |
| masked = (x == tok.mask) & ab | |
| if not masked.any(): | |
| break | |
| logits = model(x) | |
| probs = dfn.real_probs(logits, tok) | |
| conf, pred = probs.max(-1) | |
| if strategy == "random": | |
| score = torch.rand_like(conf) | |
| elif strategy == "entropy": | |
| ent = -(probs * probs.clamp_min(1e-9).log()).sum(-1) | |
| score = -ent | |
| elif strategy == "margin": | |
| top2 = probs.topk(2, dim=-1).values | |
| score = top2[..., 0] - top2[..., 1] | |
| else: | |
| score = conf | |
| score = score.masked_fill(~masked, -1e9) | |
| left = int(n_ans * (s - 1) / steps) | |
| for b in range(x.shape[0]): | |
| k = max(0, int(masked[b].sum()) - left) | |
| if strategy == "entropy" and tau is not None and k > 0: | |
| ent_b = -(probs[b] * probs[b].clamp_min(1e-9).log()).sum(-1) | |
| allowed = int(((ent_b < tau) & masked[b]).sum()) | |
| k = max(1, min(k, allowed)) if allowed else 1 | |
| if k: | |
| idx = score[b].topk(k).indices | |
| x[b, idx] = pred[b, idx] | |
| rem = (x == tok.mask) & ab | |
| if rem.any() and pred is not None: | |
| x[rem] = pred[rem] | |
| accs.extend(per_example(x.cpu(), xb.cpu(), ab.cpu())) | |
| return np.array(accs, dtype=float) | |
| def per_example(pred, gold, amask): | |
| """Correct/incorrect per evaluation item, not a batch mean. | |
| A paired test needs to know which items each system got right, on the SAME | |
| items. Batch means throw that away. | |
| """ | |
| out = [] | |
| for p, g, a in zip(pred.tolist(), gold.tolist(), amask.tolist()): | |
| pa = [p[i] for i in range(len(a)) if a[i]] | |
| ga = [g[i] for i in range(len(a)) if a[i]] | |
| out.append(float(pa == ga)) | |
| return out | |
| def paired_test(ours, theirs, n_perm=20000, seed=0): | |
| """Paired permutation test on the same evaluation items. | |
| The two systems are scored on identical inputs, so the items are paired and | |
| a paired test is the right one: under the null that the systems are | |
| interchangeable, the sign of each item's difference is exchangeable. | |
| Reports the observed difference, a bootstrap 95% interval on it, and the | |
| two-sided p-value. | |
| """ | |
| d = ours - theirs | |
| obs = float(d.mean()) | |
| rng = np.random.default_rng(seed) | |
| flips = rng.choice([-1.0, 1.0], size=(n_perm, len(d))) | |
| null = (flips * d).mean(axis=1) | |
| p = float((np.abs(null) >= abs(obs) - 1e-12).mean()) | |
| idx = rng.integers(0, len(d), size=(10000, len(d))) | |
| bs = d[idx].mean(axis=1) | |
| return {"diff": obs, "ci95": [float(np.percentile(bs, 2.5)), | |
| float(np.percentile(bs, 97.5))], | |
| "p_value": p, "n": int(len(d))} | |
| base_dirs = sorted(glob.glob(f"{a.runs}/g11-d{a.digits}-mdlm-s*")) | |
| ours_dirs = sorted(glob.glob(f"{a.runs}/g11-d{a.digits}-full-s*")) | |
| if not base_dirs or not ours_dirs: | |
| sys.exit(f"need both baseline and method runs for {a.digits} digits") | |
| results = {"digits": a.digits, "inference_time_on_baseline": {}, "ours": {}} | |
| print(f"\n=== {a.digits}-digit addition: can any inference-time method rescue " | |
| f"the baseline? ===") | |
| print(f"{'strategy':<22}{'1 pass':>9}{'2':>8}{'4':>8}{'8':>8}{'16':>8}") | |
| ITEMS = {} | |
| for strat, tau in [("confidence", None), ("entropy", None), ("entropy-gated", 0.5), | |
| ("margin", None), ("random", None)]: | |
| row, row_items = [], [] | |
| for steps in (1, 2, 4, 8, 16): | |
| vals = [run(load(d)[0], steps, | |
| "entropy" if strat == "entropy-gated" else strat, tau) | |
| for d in base_dirs] | |
| per = np.mean(np.stack(vals), axis=0) # per-item, averaged over seeds | |
| row.append(float(per.mean())); row_items.append(per) | |
| results["inference_time_on_baseline"][strat] = row | |
| ITEMS[strat] = row_items | |
| print(f"{strat:<22}" + "".join(f"{v*100:8.1f}" for v in row)) | |
| row, ours_items = [], [] | |
| for steps in (1, 2, 4, 8, 16): | |
| vals = [run(load(d)[0], steps, "confidence") for d in ours_dirs] | |
| per = np.mean(np.stack(vals), axis=0) | |
| row.append(float(per.mean())); ours_items.append(per) | |
| results["ours"]["confidence"] = row | |
| print(f"{'OURS (training-time)':<22}" + "".join(f"{v*100:8.1f}" for v in row)) | |
| print(f"\n=== is the difference significant? (paired permutation test) ===") | |
| print("Our method at ONE pass against each inference-time strategy at its BEST") | |
| print("budget, scored on identical evaluation items.\n") | |
| print(f"{'vs strategy':<22}{'their best':>12}{'ours @1':>10}{'diff':>9}" | |
| f"{'95% CI':>18}{'p':>10}") | |
| results["significance"] = {} | |
| for strat, rows in ITEMS.items(): | |
| best_i = int(np.argmax([r.mean() for r in rows])) | |
| st = paired_test(ours_items[0], rows[best_i]) | |
| results["significance"][strat] = dict(st, their_best_budget=[1, 2, 4, 8, 16][best_i]) | |
| print(f"{strat:<22}{rows[best_i].mean()*100:11.1f}%{ours_items[0].mean()*100:9.1f}%" | |
| f"{st['diff']*100:+8.1f}" | |
| f" [{st['ci95'][0]*100:+.1f},{st['ci95'][1]*100:+.1f}]" | |
| f"{st['p_value']:10.2g}") | |
| print(f"\n(n = {len(ours_items[0])} paired evaluation items; " | |
| f"p is two-sided, 20000 permutations)") | |
| best_inf = max(v[0] for v in results["inference_time_on_baseline"].values()) | |
| best_inf_any = max(max(v) for v in results["inference_time_on_baseline"].values()) | |
| print(f"\nbest inference-time method at 1 pass : {best_inf*100:.1f}%") | |
| print(f"best inference-time at ANY budget : {best_inf_any*100:.1f}%") | |
| print(f"ours at 1 pass : {row[0]*100:.1f}%") | |
| results["summary"] = {"best_inference_1pass": best_inf, | |
| "best_inference_any_budget": best_inf_any, | |
| "ours_1pass": row[0]} | |
| os.makedirs(os.path.dirname(a.out) or ".", exist_ok=True) | |
| json.dump(results, open(a.out, "w"), indent=2) | |
| print(f"\nwrote {a.out}") | |