SpiceNet / code /make_benchmark_table.py
Noushad999's picture
Upload folder using huggingface_hub
1ea7ba6 verified
Raw
History Blame Contribute Delete
3.92 kB
"""
Assemble the cross-source benchmark: every backbone vs the studio->wild collapse.
Reads bench_<model>.json (from eval_backbone_shortcut.py) plus SpiceFusionNet
(ours, from shortcut_multiseed_aggregate.json) and GranuFormer, and writes a
comparison table (markdown + LaTeX) and a clean collapse-leaderboard figure. The
takeaway: the collapse is architecture-universal.
"""
import sys, os, glob, json
from pathlib import Path
_base = "/mnt/d/SpiceNet" if os.path.exists("/mnt/d/SpiceNet") else "D:/SpiceNet"
sys.path.insert(0, _base)
import numpy as np
import figstyle
ROOT = Path(_base)
OUT = ROOT / "outputs" / "benchmark_collapse"
def collect():
rows = [] # (name, studio_within, studio_to_wild, tax, macroF1_cross)
# ours (3-seed)
agg = ROOT / "outputs" / "shortcut_multiseed_aggregate.json"
if agg.exists():
a = json.load(open(agg))["aggregate"]
rows.append(("SpiceFusionNet (ours)", a["in_within"]["mean"], a["in_cross"]["mean"],
a["in_tax_pp"]["mean"], None))
gf = ROOT / "outputs" / "shortcut_test_matrix_granuformer.json"
if gf.exists():
r = json.load(open(gf))
rows.append(("GranuFormer", r["in"]["in"]["acc"], r["in"]["ss"]["acc"],
(r["in"]["in"]["acc"] - r["in"]["ss"]["acc"]) * 100, None))
for f in sorted(glob.glob(str(ROOT / "outputs" / "bench_*.json"))):
r = json.load(open(f))
rows.append((r["model"], r["in"]["in"]["acc"], r["in"]["ss"]["acc"],
r["in_tax_pp"], r["in"]["ss"].get("macro_f1")))
return rows
def main():
rows = collect()
if not rows:
raise SystemExit("no benchmark results yet β€” run run_benchmark.py first")
rows.sort(key=lambda r: r[3]) # by collapse tax ascending (least collapse first)
md = ["# Cross-source benchmark (Indian/studio-trained -> SS/wild test)\n",
"| Model | Studio within | Studio->Wild | Collapse (pp) | Macro-F1 (wild) |",
"|---|---|---|---|---|"]
tex = [r"\begin{tabular}{lrrrr}", r"\hline",
r"Model & Studio within & Studio$\rightarrow$Wild & Collapse (pp) & Macro-F1 \\", r"\hline"]
for name, sw, stw, tax, f1 in rows:
f1s = f"{f1*100:.1f}" if f1 is not None else "--"
md.append(f"| {name} | {sw*100:.1f} | {stw*100:.1f} | {tax:.1f} | {f1s} |")
tex.append(f"{name} & {sw*100:.1f} & {stw*100:.1f} & {tax:.1f} & {f1s} \\\\")
tex += [r"\hline", r"\end{tabular}"]
(ROOT / "outputs" / "benchmark_table.md").write_text("\n".join(md), encoding="utf-8")
(ROOT / "outputs" / "benchmark_table.tex").write_text("\n".join(tex), encoding="utf-8")
# ── clean collapse-leaderboard figure ───────────────────────────────────
figstyle.apply()
import matplotlib.pyplot as plt
P = figstyle.PALETTE
names = [r[0] for r in rows]
within = np.array([r[1] for r in rows]) * 100
cross = np.array([r[2] for r in rows]) * 100
y = np.arange(len(names))[::-1]
fig, ax = plt.subplots(figsize=(7.2, 0.5 * len(names) + 1.5))
ax.barh(y + 0.18, within, 0.34, color=P["studio"], label="studio test (within)")
ax.barh(y - 0.18, cross, 0.34, color=P["cross_broken"], label="studio→wild (cross)")
for yi, c in zip(y, cross):
ax.text(c + 1, yi - 0.18, f"{c:.0f}", va="center", fontsize=8)
ax.axvline(12.5, color=P["chance"], ls=":", lw=1, label="random (1/8)")
ax.set_yticks(y); ax.set_yticklabels(names, fontsize=9)
ax.set_xlabel("Top-1 accuracy (%)"); ax.set_xlim(0, 108)
ax.set_title("Studio-trained models all collapse on wild data", fontsize=11)
ax.legend(loc="lower right", fontsize=8)
fig.tight_layout()
figstyle.save(fig, str(OUT))
print("\n".join(md))
if __name__ == "__main__":
main()