Download src/collect.py from GOVINDFROM/parallel-consistent-masked-diffusion: direct link, hf CLI and curl.
- Browser
- Download file 20 kB
-
https://huggingface.co/GOVINDFROM/parallel-consistent-masked-diffusion/resolve/main/src/collect.py
- Command line
-
hf download hf://GOVINDFROM/parallel-consistent-masked-diffusion/src/collect.py
-
curl -L -o collect.py https://huggingface.co/GOVINDFROM/parallel-consistent-masked-diffusion/resolve/main/src/collect.py
20 kB
| """Aggregate every experiment into the paper's tables and figures. | |
| The organising variable across all three task families is DEPENDENCY DEPTH: | |
| shallow + unique (inflection) -> one pass already works, no method needed | |
| deep + unique (addition) -> one pass fails, and the method fixes it | |
| any + non-unique (probes) -> information-theoretic limit, unfixable | |
| """ | |
| import json, glob, math, os | |
| import numpy as np | |
| import matplotlib | |
| matplotlib.use("Agg") | |
| import matplotlib.pyplot as plt | |
| RUNS = os.environ.get("RUNS", "runs") | |
| OUT = os.environ.get("OUT", "figures") | |
| os.makedirs(OUT, exist_ok=True) | |
| R = [] | |
| for f in sorted(glob.glob(f"{RUNS}/*/result.json")): | |
| try: | |
| r = json.load(open(f)) | |
| except Exception: | |
| continue | |
| r["name"] = os.path.basename(os.path.dirname(f)) | |
| R.append(r) | |
| print(f"collected {len(R)} runs") | |
| MODE = {"mdlm": "MDLM baseline", "matched": "+ schedule matching", | |
| "distill": "+ one-pass supervision", "full": "fixed-K (K=1)", | |
| "prog": "parallelism curriculum", | |
| "anybudget": "any-budget (conditioned)", | |
| "anybudget_nc": "any-budget (no conditioning)"} | |
| COL = {"mdlm": "#c0392b", "matched": "#e67e22", | |
| "distill": "#2980b9", "full": "#1a5276", "prog": "#117a65"} | |
| def runs(prefix, **kw): | |
| out = [] | |
| for r in R: | |
| if not r["name"].startswith(prefix): | |
| continue | |
| a = r.get("args", {}) | |
| if all(a.get(k) == v for k, v in kw.items()): | |
| out.append(r) | |
| return out | |
| def boot(v, n=2000, seed=0): | |
| if len(v) < 2: | |
| return (np.mean(v) * 100,) * 2 | |
| rng = np.random.default_rng(seed) | |
| a = np.array(v) | |
| bs = [rng.choice(a, len(a), replace=True).mean() for _ in range(n)] | |
| return float(np.percentile(bs, 2.5) * 100), float(np.percentile(bs, 97.5) * 100) | |
| md = ["# Results\n"] | |
| # ---- Table 1: the headline, addition at one pass --------------------------- | |
| md.append("## Table 1 β Addition: exact match at ONE forward pass\n") | |
| md.append("The whole answer committed in a single pass. Depth scaled as " | |
| "log2(digits); learning rate 1e-4 with 4000 warmup steps, which " | |
| "matters - see Table 4.\n") | |
| md.append("| digits | MDLM baseline | full method | seeds >90% (base β ours) |") | |
| md.append("|---|---|---|---|") | |
| dig = sorted({r["args"]["digits"] for r in R | |
| if r["name"].startswith("g11-") and "digits" in r.get("args", {})}) | |
| for d in dig: | |
| cells = [] | |
| rel = [] | |
| for m in ("mdlm", "full"): | |
| rs = runs("g11-", digits=d, mode=m) | |
| if not rs: | |
| cells.append("β"); rel.append("β"); continue | |
| v = [r["accuracy_by_passes"]["1"] for r in rs] | |
| lo, hi = boot(v) | |
| cells.append(f"{np.mean(v)*100:.1f} [{lo:.0f},{hi:.0f}]") | |
| rel.append(f"{sum(x>0.9 for x in v)}/{len(v)}") | |
| md.append(f"| **{d}** | {cells[0]} | {cells[1]} | {rel[0]} β {rel[1]} |") | |
| md.append("") | |
| # ---- Figure 1: gap vs dependency depth ------------------------------------- | |
| fig, ax = plt.subplots(figsize=(7, 4.3)) | |
| for m in ("mdlm", "full"): | |
| xs, mu, sd = [], [], [] | |
| for d in dig: | |
| rs = runs("g11-", digits=d, mode=m) | |
| if not rs: | |
| continue | |
| v = [r["accuracy_by_passes"]["1"] for r in rs] | |
| xs.append(d); mu.append(np.mean(v) * 100); sd.append(np.std(v) * 100) | |
| if xs: | |
| ax.errorbar(xs, mu, yerr=sd, marker="o", capsize=3, color=COL[m], label=MODE[m]) | |
| ax.set_xlabel("operand digits (length of the carry chain)") | |
| ax.set_ylabel("exact match at one pass (%)") | |
| ax.set_title("The gap opens exactly where one forward pass stops sufficing") | |
| ax.legend(); ax.grid(alpha=.3); ax.set_ylim(-3, 103) | |
| fig.tight_layout(); fig.savefig(f"{OUT}/fig1_addition_frontier.png", dpi=160) | |
| # ---- Figure 2: accuracy vs passes ------------------------------------------ | |
| show = [d for d in dig if d >= 12][:3] or dig[:3] | |
| if show: | |
| fig, axes = plt.subplots(1, len(show), figsize=(4 * len(show), 3.8), | |
| sharey=True, squeeze=False) | |
| grid = [1, 2, 3, 4, 6, 8, 12, 16] | |
| for ax, d in zip(axes[0], show): | |
| for m in ("mdlm", "full"): | |
| rs = runs("g11-", digits=d, mode=m) | |
| if not rs: | |
| continue | |
| mu = [np.mean([r["accuracy_by_passes"][str(p)] for r in rs]) * 100 for p in grid] | |
| ax.plot(grid, mu, marker="o", ms=4, color=COL[m], label=MODE[m]) | |
| ax.set_xscale("log", base=2); ax.set_xlabel("denoising passes") | |
| ax.set_title(f"{d}-digit"); ax.grid(alpha=.3); ax.set_ylim(-3, 103) | |
| axes[0][0].set_ylabel("exact match (%)"); axes[0][0].legend(fontsize=7) | |
| fig.suptitle("Fewer passes = more parallelism") | |
| fig.tight_layout(); fig.savefig(f"{OUT}/fig2_accuracy_vs_passes.png", dpi=160) | |
| # ---- Table 2: SIGMORPHON, the shallow-dependency boundary ------------------ | |
| sig = [r for r in R if r["name"].startswith("gate-") or | |
| (r.get("args", {}).get("lang") if isinstance(r.get("args"), dict) else None)] | |
| sig = [r for r in sig if "lang" in r.get("args", {})] | |
| if sig: | |
| md.append("## Table 2 β Morphological inflection: where the problem does NOT arise\n") | |
| md.append("Answers are unique but only ~10 characters with shallow, local " | |
| "dependencies. One pass already suffices for the plain baseline, " | |
| "so there is no gap for any method to close. This is the boundary " | |
| "the account predicts, and it is reported as such.\n") | |
| md.append("| language | 1 pass | 32 passes | gap |") | |
| md.append("|---|---|---|---|") | |
| for r in sorted(sig, key=lambda x: x["args"]["lang"]): | |
| a = r["accuracy_by_passes"] | |
| md.append(f"| {r['args']['lang']} | {a['1']*100:.1f} | {a['32']*100:.1f} | " | |
| f"{(a['32']-a['1'])*100:+.1f} |") | |
| md.append("") | |
| # ---- Table 3: the unfixable limit ------------------------------------------ | |
| md.append("## Table 3 β Non-unique answers: the limit no training removes\n") | |
| md.append("On probes where a group must agree but the value is free, the " | |
| "likelihood-optimal marginal is uniform over the valid values, so two " | |
| "independent draws agree with probability 1/V. Sweeping an entropy " | |
| "penalty designed to break that symmetry over 66 runs: weak settings " | |
| "changed nothing, strong settings destroyed the model, failing even at " | |
| "fully sequential decoding. Succeeding would require abandoning the " | |
| "data distribution.\n") | |
| # ---- Table 4: the optimisation confound ------------------------------------ | |
| g10 = runs("g10-") | |
| if g10: | |
| md.append("## Table 4 β Why earlier runs appeared to fail (10-digit addition)\n") | |
| md.append("Every apparent failure at 10+ digits was a learning-rate artifact, " | |
| "not a limit of the method or of depth.\n") | |
| md.append("| layers | lr | warmup | mean @1 pass | seeds >90% |") | |
| md.append("|---|---|---|---|---|") | |
| by = {} | |
| for r in g10: | |
| a = r["args"] | |
| by.setdefault((a["layers"], a["lr"], a["warmup"]), []).append( | |
| r["accuracy_by_passes"]["1"]) | |
| for k in sorted(by): | |
| v = by[k] | |
| md.append(f"| {k[0]} | {k[1]} | {k[2]} | {np.mean(v)*100:.1f} | " | |
| f"{sum(x>0.9 for x in v)}/{len(v)} |") | |
| md.append("") | |
| # ---- Table 5: the definitive frontier, one configuration throughout --------- | |
| # Grid 11 mixed configurations across digit counts, which makes the curve a | |
| # statement about the configurations as much as about the method. Grid 16 reruns | |
| # every length at a single setting so the frontier means one thing. | |
| g16 = runs("g16-") | |
| if g16: | |
| md.append("## Table 5 β Addition frontier at ONE fixed configuration\n") | |
| md.append("12 layers, 150k steps, lr 1e-4, 3 seeds, identical at every " | |
| "length, so the curve reflects the method and not the config.\n") | |
| md.append("| digits | MDLM baseline | matched (ours) | seeds >90% |") | |
| md.append("|---|---|---|---|") | |
| for d in sorted({r["args"]["digits"] for r in g16}): | |
| cells, rel = [], [] | |
| for m in ("mdlm", "full"): | |
| rs = runs("g16-", digits=d, mode=m) | |
| if not rs: | |
| cells.append("β"); rel.append("β"); continue | |
| v = [r["accuracy_by_passes"]["1"] for r in rs] | |
| lo, hi = boot(v) | |
| cells.append(f"{np.mean(v)*100:.1f} [{lo:.0f},{hi:.0f}]") | |
| rel.append(f"{sum(x>0.9 for x in v)}/{len(v)}") | |
| md.append(f"| **{d}** | {cells[0]} | {cells[1]} | {rel[0]} β {rel[1]} |") | |
| md.append("") | |
| # ---- Table 6: the depth sweep, the theory's falsifiable prediction ---------- | |
| g14 = runs("g14-") | |
| if g14: | |
| md.append("## Table 6 β Minimum depth for one-pass addition\n") | |
| md.append("The account in THEORY.md predicts minimum depth growing as " | |
| "log2(n), since the carry is a prefix scan. A ripple-carry account " | |
| "predicts linear growth; an impossibility account predicts no " | |
| "depth suffices.\n") | |
| lays = sorted({r["args"]["layers"] for r in g14}) | |
| md.append("| digits | " + " | ".join(f"{l}L" for l in lays) + | |
| " | log2(n) | min depth >90% |") | |
| md.append("|---" * (len(lays) + 3) + "|") | |
| for d in sorted({r["args"]["digits"] for r in g14}): | |
| cells, mind = [], None | |
| for l in lays: | |
| rs = runs("g14-", digits=d, layers=l) | |
| if not rs: | |
| cells.append("β"); continue | |
| mu = np.mean([r["accuracy_by_passes"]["1"] for r in rs]) * 100 | |
| cells.append(f"{mu:.0f}") | |
| if mu > 90 and mind is None: | |
| mind = l | |
| md.append(f"| **{d}** | " + " | ".join(cells) + | |
| f" | {math.log2(d):.1f} | {mind or 'β'} |") | |
| md.append("") | |
| fig, ax = plt.subplots(figsize=(6.4, 4.2)) | |
| ds = sorted({r["args"]["digits"] for r in g14}) | |
| obs = [] | |
| for d in ds: | |
| mind = None | |
| for l in lays: | |
| rs = runs("g14-", digits=d, layers=l) | |
| if rs and np.mean([r["accuracy_by_passes"]["1"] for r in rs]) > 0.9: | |
| mind = l; break | |
| obs.append(mind) | |
| ok = [(d, m) for d, m in zip(ds, obs) if m] | |
| if ok: | |
| ax.plot([d for d, _ in ok], [m for _, m in ok], "o-", color="#1a5276", | |
| label="measured minimum depth") | |
| ax.plot(ds, [math.log2(d) for d in ds], "--", color="#117a65", | |
| label="log2(n) β prefix-scan prediction") | |
| ax.plot(ds, [d / 4 for d in ds], ":", color="#c0392b", | |
| label="n/4 β ripple-carry prediction") | |
| ax.set_xlabel("operand digits"); ax.set_ylabel("layers needed for >90% at one pass") | |
| ax.set_title("Does required depth grow like log n or like n?") | |
| ax.legend(fontsize=8); ax.grid(alpha=.3) | |
| fig.tight_layout(); fig.savefig(f"{OUT}/fig3_depth_scaling.png", dpi=160) | |
| # ---- Table 7: component ablation on inflection ----------------------------- | |
| g15 = runs("g15-") | |
| if g15: | |
| md.append("## Table 7 β Which component carries the gain (inflection)\n") | |
| modes = ["mdlm", "matched", "distill", "full"] | |
| langs = sorted({r["args"]["lang"] for r in g15}) | |
| md.append("| language | " + " | ".join(modes) + " | (gap 1β32) |") | |
| md.append("|---" * (len(modes) + 2) + "|") | |
| for L in langs: | |
| cells, gaps = [], [] | |
| for m in modes: | |
| rs = runs("g15-", lang=L, mode=m) | |
| if not rs: | |
| cells.append("β"); gaps.append("β"); continue | |
| one = np.mean([r["accuracy_by_passes"]["1"] for r in rs]) * 100 | |
| many = np.mean([r["accuracy_by_passes"]["32"] for r in rs]) * 100 | |
| cells.append(f"{one:.1f}"); gaps.append(f"{many-one:+.1f}") | |
| md.append(f"| {L} | " + " | ".join(cells) + " | " + " / ".join(gaps) + " |") | |
| md.append("") | |
| # ---- Table 8: text8, where the two fixes have to compose ------------------- | |
| t8 = [r for r in R if r["name"].startswith("t8-")] | |
| if t8: | |
| md.append("## Table 8 β text8: quality against compute\n") | |
| md.append("Generative perplexity under a from-scratch autoregressive " | |
| "character evaluator, against the number of function evaluations " | |
| "actually used. Entropy and distinct-4-gram rate are reported " | |
| "beside it because generative perplexity alone is gamed by " | |
| "degenerate repetition; the real-text reference row is the " | |
| "target, not zero.\n") | |
| ref = t8[0].get("reference", {}) | |
| md.append(f"Real text8 reference β ppl {ref.get('gen_ppl', float('nan')):.2f}, " | |
| f"entropy {ref.get('entropy', float('nan')):.3f}, " | |
| f"distinct-4 {ref.get('distinct4', float('nan')):.3f}\n") | |
| md.append("| training | decoding | NFE | gen ppl | entropy | distinct-4 | valid BPC |") | |
| md.append("|---|---|---|---|---|---|---|") | |
| by = {} | |
| for r in t8: | |
| by.setdefault(r["args"]["mode"], []).append(r) | |
| for mode in ("mdlm", "matched", "full"): | |
| for r in by.get(mode, [])[:1]: | |
| for key, row in sorted(r.get("decode", {}).items()): | |
| if row.get("gen_ppl") is None: | |
| continue | |
| md.append(f"| {mode} | {key} | {row['nfe']:.1f} | " | |
| f"{row['gen_ppl']:.2f} | {row['entropy']:.3f} | " | |
| f"{row['distinct4']:.3f} | {r.get('valid_bpc', float('nan')):.4f} |") | |
| md.append("") | |
| # quality/compute frontier: the plot the claim lives or dies on | |
| fig, ax = plt.subplots(figsize=(6.8, 4.4)) | |
| style = {"mdlm": ("#c0392b", "uniform-t training"), | |
| "matched": ("#e67e22", "matched training"), | |
| "full": ("#1a5276", "matched + high-ratio")} | |
| for mode, rs in by.items(): | |
| c, lbl = style.get(mode, ("#555", mode)) | |
| for fam, mk, ls in (("fixedK_", "o", "-"), ("entbudget_", "s", "--")): | |
| pts = [] | |
| for r in rs: | |
| for k, row in r.get("decode", {}).items(): | |
| if k.startswith(fam) and row.get("gen_ppl"): | |
| pts.append((row["nfe"], row["gen_ppl"])) | |
| if pts: | |
| pts.sort() | |
| ax.plot([p[0] for p in pts], [p[1] for p in pts], marker=mk, | |
| ms=4, ls=ls, color=c, alpha=.85, | |
| label=f"{lbl}, {'fixed-K' if fam[0]=='f' else 'entropy budget'}") | |
| if ref.get("gen_ppl"): | |
| ax.axhline(ref["gen_ppl"], color="k", lw=1, ls=":", label="real text8") | |
| ax.set_xscale("log", base=2); ax.set_yscale("log") | |
| ax.set_xlabel("forward passes (NFE)"); ax.set_ylabel("generative perplexity") | |
| ax.set_title("Quality against compute: do the two fixes compose?") | |
| ax.legend(fontsize=7); ax.grid(alpha=.3) | |
| fig.tight_layout(); fig.savefig(f"{OUT}/fig4_text8_quality_vs_compute.png", dpi=160) | |
| # ---- Table 9b: does budget conditioning remove the crossover? -------------- | |
| g18 = runs("g18-") | |
| if g18: | |
| md.append("## Table 9b β Any-budget conditioning vs a fixed budget\n") | |
| md.append("20-digit addition, one configuration. A fixed-K method wins at the " | |
| "budget it was trained for and loses away from it; the question is " | |
| "whether conditioning on the budget removes that trade.\n") | |
| md.append("| training | @1 pass | @sequential | spread |") | |
| md.append("|---|---|---|---|") | |
| rows = {} | |
| for r in g18 + runs("g13-", digits=20): | |
| rows.setdefault(r["args"]["mode"], []).append(r) | |
| for mode in ("mdlm", "full", "anybudget_nc", "anybudget"): | |
| rs = rows.get(mode) | |
| if not rs: | |
| continue | |
| one = np.mean([r["accuracy_by_passes"]["1"] for r in rs]) * 100 | |
| keys = [int(k) for k in rs[0]["accuracy_by_passes"]] | |
| seq = np.mean([r["accuracy_by_passes"][str(max(keys))] for r in rs]) * 100 | |
| md.append(f"| {MODE.get(mode, mode)} | {one:.1f} | {seq:.1f} | " | |
| f"{abs(one-seq):.1f} |") | |
| md.append("") | |
| # ---- Table 9: failed to parallelise, or failed to learn? ------------------- | |
| sc = os.path.join(OUT, "seq_check_g13.json") | |
| if os.path.exists(sc): | |
| rows = json.load(open(sc)) | |
| md.append("## Table 9 β Did the baseline fail to parallelise, or fail to learn?\n") | |
| md.append("A 20-digit answer occupies 21 slots, so the standard 16-pass grid " | |
| "is not a sequential decode. Re-decoded at one token per pass, the " | |
| "two explanations separate.\n") | |
| md.append("| digits | mode | @1 pass | fully sequential | reading |") | |
| md.append("|---|---|---|---|---|") | |
| agg = {} | |
| for r in rows: | |
| agg.setdefault((r["digits"], r["mode"]), []).append(r) | |
| for k in sorted(agg): | |
| v = agg[k] | |
| one = np.mean([x["acc_1pass"] for x in v]) * 100 | |
| seq = np.mean([x["acc_sequential"] for x in v]) * 100 | |
| read = ("never learned the task" if seq < 5 else | |
| "learned it, cannot parallelise" if one < seq - 5 else | |
| "learned it and parallelises") | |
| md.append(f"| {k[0]} | {k[1]} | {one:.1f} | {seq:.1f} | {read} |") | |
| md.append("") | |
| # ---- Table 10: graphs, where the ceiling is known exactly ------------------- | |
| gr1 = [r for r in R if r["name"].startswith("gr1-")] | |
| if gr1: | |
| md.append("## Table 10 β Structured graphs: measured against an exact ceiling\n") | |
| md.append("V* is the one-pass validity achievable from the TRUE marginals, so it " | |
| "bounds any model that reproduces the data distribution. Where the " | |
| "interval contains V* the residual failure is information-theoretic " | |
| "and untrainable; where it falls short, the shortfall is trainable.\n") | |
| md.append("| family | TC (bits) | V* | achieved @1 pass | reading |") | |
| md.append("|---|---|---|---|---|") | |
| by = {} | |
| for r in gr1: | |
| by.setdefault(r["args"]["family"], []).append(r) | |
| for fam in sorted(by, key=lambda f: -by[f][0]["exact"]["total_correlation_bits"]): | |
| rs = [r for r in by[fam] if r["args"]["mode"] == "mdlm"] | |
| if not rs: | |
| continue | |
| ex = rs[0]["exact"] | |
| v = np.mean([r["decode"]["fixedK_1"]["validity"] for r in rs]) * 100 | |
| V = ex["one_pass_ceiling"] * 100 | |
| read = "at the ceiling β untrainable" if v > 0.8 * V else "below ceiling β see Table 11" | |
| md.append(f"| {fam} | {ex['total_correlation_bits']:.2f} | {V:.2f}% | " | |
| f"{v:.2f}% | {read} |") | |
| md.append("") | |
| # ---- Table 11: the expressivity result ------------------------------------- | |
| gr2 = [r for r in R if r["name"].startswith("gr2-")] | |
| if gr2: | |
| md.append("## Table 11 β One-pass decoding needs ABSOLUTE position information\n") | |
| md.append("At t = 1 every input token is [MASK], so the sequence is constant and a " | |
| "relative encoding gives every position the same output. Position-dependent " | |
| "marginals are then inexpressible at any training budget. Matching is the " | |
| "control: its marginals are identical at every slot, so absolute " | |
| "information should buy nothing there.\n") | |
| md.append("| family | marginals | encoding | @1 pass | % of V* |") | |
| md.append("|---|---|---|---|---|") | |
| by = {} | |
| for r in gr2: | |
| by.setdefault((r["args"]["family"], r["args"]["pe"]), []).append(r) | |
| eff = {} | |
| for fam, marg in (("bipartite", "**vary**"), ("matching", "constant")): | |
| for pe in ("rope", "ape", "sin"): | |
| rs = by.get((fam, pe)) | |
| if not rs: | |
| continue | |
| v = np.mean([r["decode"]["fixedK_1"]["validity"] for r in rs]) | |
| V = rs[0]["exact"]["one_pass_ceiling"] | |
| eff[(fam, pe)] = v | |
| md.append(f"| {fam} | {marg} | {pe} | {v*100:.2f}% | {v/V*100:.1f}% |") | |
| md.append("") | |
| for fam in ("bipartite", "matching"): | |
| if (fam, "rope") in eff and (fam, "ape") in eff: | |
| delta = (eff[(fam, "ape")] - eff[(fam, "rope")]) * 100 | |
| md.append(f"- absolute β relative on **{fam}**: **{delta:+.3f}** points") | |
| md.append("") | |
| open(f"{OUT}/summary.md", "w").write("\n".join(md) + "\n") | |
| print("\n".join(md)) | |
| print(f"\nwrote figures + summary to {OUT}") | |