apex-quant-benchmarks / scripts /make_plots.py
Myric's picture
align Glimmer and Heretic labels
0adbb6b verified
Raw History Blame Contribute Delete
11.1 kB
#!/usr/bin/env python3
"""Generate the wall-clock / parameters / verbosity plots from models.json + results.json.
Usage
-----
python scripts/make_plots.py --models models.json --results results.json --out plots
Requires matplotlib. Time plots use GB10 runs only (Thor wall-clock is not comparable).
Each point is the best valid run for that model/quant, matching the table.
"""
from __future__ import annotations
import argparse
import json
import os
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
def best_run(model: dict, runs: list[dict]) -> dict | None:
matches = [r for r in runs if r["label"].startswith(model["group"]) and r["total_valid"] > 0]
if not matches:
return None
return max(matches, key=lambda r: (r["total_passed"], r["total_valid"], -r["total_void"]))
def build(models: list[dict], runs: list[dict]) -> list[dict]:
data = []
for model in models:
run = best_run(model, runs)
if not run:
continue
data.append({
**model,
"box": run["box"],
"wall_h": run["total_wall_s"] / 3600,
"tokens": run["total_tokens_out"],
"tokens_per_task_k": run["total_tokens_out"] / max(1, run["total_valid"]) / 1000,
"tok_s": run["total_tokens_out"] / max(1, run["total_wall_s"]),
"score": run["total_passed"] / run["total_valid"],
"valid": run["total_valid"],
"void": run["total_void"],
})
return data
def scatter(points: list[dict], xkey: str, ykey: str, title: str, xlabel: str, ylabel: str,
out: str, logx: bool = True) -> None:
fig, ax = plt.subplots(figsize=(8, 5.5), dpi=150)
xs = [p[xkey] for p in points]
ys = [p[ykey] for p in points]
sc = ax.scatter(xs, ys, c=[p["score"] for p in points], cmap="RdYlGn", vmin=0.9, vmax=1.0,
s=75, edgecolors="black", linewidths=0.4, zorder=3)
if logx:
ax.set_xscale("log")
for p in points:
if p.get("annotate"):
dx, dy = p.get("offset", (6, 5))
ax.annotate(p.get("short", p["model"]), (p[xkey], p[ykey]), textcoords="offset points",
xytext=(dx, dy), ha=("right" if dx < 0 else "left"), fontsize=7, alpha=0.9)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.set_title(title)
ax.grid(True, which="both", alpha=0.25, zorder=0)
ax.margins(x=0.30)
cb = fig.colorbar(sc, ax=ax, pad=0.02)
cb.set_label("valid-task score")
fig.tight_layout()
fig.savefig(out, bbox_inches="tight")
plt.close(fig)
def scatter_country(points: list[dict], xkey: str, ykey: str, title: str, xlabel: str, ylabel: str,
out: str, logx: bool = True) -> None:
from matplotlib.lines import Line2D
from matplotlib.patches import Patch
fig, ax = plt.subplots(figsize=(9.5, 6.3), dpi=150)
colors = {
"US": "#2E5FA3",
"China": "#C0392B",
"Germany": "#E6A817",
"Czechia": "#7D5BA6",
"UAE": "#2E8B57",
"Unknown": "#777777",
"Abliterated": "#888888",
}
def color(country):
return colors.get(country, colors["Unknown"])
def base_of(p):
return p.get("base_country", p.get("country", "Unknown"))
def post_of(p):
return p.get("post_country", p.get("country", "Unknown"))
for p in points:
ax.scatter(p[xkey], p[ykey], s=90, marker="o",
facecolors=color(base_of(p)), edgecolors=color(post_of(p)),
linewidths=2.0, zorder=3)
if logx:
ax.set_xscale("log")
for p in points:
if p.get("annotate"):
dx, dy = p.get("offset", (6, 5))
ax.annotate(p.get("short", p["model"]), (p[xkey], p[ykey]), textcoords="offset points",
xytext=(dx, dy), ha=("right" if dx < 0 else "left"), fontsize=7, alpha=0.9)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.set_title(title)
ax.text(0.01, 0.01, "Wall time includes tasks voided by timeout/truncation. "
"Fill = pretrained base; edge = post-training/compression.",
transform=ax.transAxes, fontsize=7, alpha=0.7)
ax.grid(True, which="both", alpha=0.25, zorder=0)
ax.margins(x=0.30)
ax.set_ylim(bottom=0)
base_present = sorted({base_of(p) for p in points})
post_present = sorted({post_of(p) for p in points})
fill_handles = [Patch(facecolor=color(c), edgecolor="black", label=c) for c in base_present]
edge_handles = [Line2D([0], [0], marker="o", linestyle="none", markerfacecolor="white",
markeredgecolor=color(c), markeredgewidth=2.0, markersize=8, label=c)
for c in post_present]
leg1 = ax.legend(handles=fill_handles, title="Base (fill)", fontsize=7, title_fontsize=7,
loc="upper left", framealpha=0.95)
ax.add_artist(leg1)
ax.legend(handles=edge_handles, title="Post-train (edge)", fontsize=7, title_fontsize=7,
loc="upper right", framealpha=0.95)
fig.tight_layout()
fig.savefig(out, bbox_inches="tight")
plt.close(fig)
def main() -> None:
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument("--models", default="models.json")
ap.add_argument("--results", default="results.json")
ap.add_argument("--out", default="plots")
args = ap.parse_args()
models = json.load(open(args.models))["models"]
runs = json.load(open(args.results))["runs"]
data = build(models, runs)
gb = [d for d in data if d["box"] == "gb10"]
os.makedirs(args.out, exist_ok=True)
scatter(gb, "active_b", "wall_h",
"Wall clock vs active parameters (GB10, 42 tasks)",
"Active parameters (B, log)", "Wall clock (hours)",
os.path.join(args.out, "wall_vs_active.png"))
perfect = [d for d in gb if d["valid"] > 0 and d["score"] >= 0.999999]
# Spark-X2.5 is a 14.5 h BF16 outlier and compresses the y-scale for the origin plots.
origin_pts = [d for d in perfect if not d["model"].startswith("Spark-X2.5")]
scatter_country(origin_pts, "active_b", "wall_h",
"Wall clock vs active parameters — perfect-score runs (GB10)",
"Active parameters (B, log)", "Wall clock (hours)",
os.path.join(args.out, "wall_vs_active_perfect_country.png"))
scatter_country(origin_pts, "total_b", "wall_h",
"Wall clock vs total parameters — perfect-score runs (GB10)",
"Total parameters (B, log)", "Wall clock (hours)",
os.path.join(args.out, "wall_vs_total_perfect_country.png"))
scatter(gb, "total_b", "wall_h",
"Wall clock vs total parameters (GB10, 42 tasks)",
"Total parameters (B, log)", "Wall clock (hours)",
os.path.join(args.out, "wall_vs_total.png"))
scatter(gb, "tokens", "wall_h",
"Wall clock vs output tokens (GB10, 42 tasks)",
"Output tokens (thousands, log)", "Wall clock (hours)",
os.path.join(args.out, "wall_vs_tokens.png"))
# verbosity: all boxes, marker = box
fig, ax = plt.subplots(figsize=(8, 5.5), dpi=150)
last_sc = None
for box, marker, label in (("gb10", "o", "GB10"), ("thor", "s", "Thor")):
pts = [d for d in data if d["box"] == box]
if not pts:
continue
last_sc = ax.scatter([p["active_b"] for p in pts], [p["tokens_per_task_k"] for p in pts],
c=[p["score"] for p in pts], cmap="RdYlGn", vmin=0.9, vmax=1.0,
marker=marker, s=75, edgecolors="black", linewidths=0.4,
label=label, zorder=3)
for p in data:
if p.get("annotate"):
dx, dy = p.get("offset", (6, 5))
ax.annotate(p.get("short", p["model"]), (p["active_b"], p["tokens_per_task_k"]),
textcoords="offset points", xytext=(dx, dy),
ha=("right" if dx < 0 else "left"), fontsize=7)
ax.set_xscale("log")
ax.set_xlabel("Active parameters (B, log)")
ax.set_ylabel("Output tokens per valid task (thousands)")
ax.set_title("Verbosity vs active parameters (42 tasks)")
ax.grid(True, which="both", alpha=0.25)
ax.margins(x=0.30)
ax.legend()
if last_sc is not None:
cb = fig.colorbar(last_sc, ax=ax, pad=0.02)
cb.set_label("valid-task score")
fig.tight_layout()
fig.savefig(os.path.join(args.out, "tokens_per_task_vs_active.png"), bbox_inches="tight")
plt.close(fig)
# performance per byte: capability and throughput vs quant file size
sized = [d for d in data if d.get("size_gb")]
gb_sized = [d for d in sized if d["box"] == "gb10"]
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(13, 5.5), dpi=150)
for box, marker, label in (("gb10", "o", "GB10"), ("thor", "s", "Thor")):
pts = [d for d in sized if d["box"] == box]
if not pts:
continue
ax1.scatter([d["size_gb"] for d in pts], [d["score"] * 100 for d in pts],
marker=marker, s=75, edgecolors="black", linewidths=0.4, label=label, zorder=3)
for d in sized:
if d.get("annotate") and (d["score"] < 0.995 or d.get("highlight")):
dx, dy = d.get("size_offset", d.get("offset", (6, 5)))
ax1.annotate(d.get("short", d["model"]), (d["size_gb"], d["score"] * 100),
textcoords="offset points", xytext=(dx, dy),
ha=("right" if dx < 0 else "left"), fontsize=7)
ax1.set_xscale("log")
ax1.set_xlabel("Quant file size (GB, log)")
ax1.set_ylabel("Valid-task score (%)")
ax1.set_title("Capability per byte")
ax1.grid(True, which="both", alpha=0.25)
ax1.margins(x=0.30)
ax1.legend()
sc = ax2.scatter([d["size_gb"] for d in gb_sized], [d["tok_s"] for d in gb_sized],
c=[d["score"] for d in gb_sized], cmap="RdYlGn", vmin=0.9, vmax=1.0,
s=75, edgecolors="black", linewidths=0.4, zorder=3)
for d in gb_sized:
if d.get("annotate"):
dx, dy = d.get("size_offset", d.get("offset", (6, 5)))
ax2.annotate(d.get("short", d["model"]), (d["size_gb"], d["tok_s"]),
textcoords="offset points", xytext=(dx, dy),
ha=("right" if dx < 0 else "left"), fontsize=7)
ax2.set_xscale("log")
ax2.set_xlabel("Quant file size (GB, log)")
ax2.set_ylabel("Output tokens/s (end-to-end)")
ax2.set_title("Throughput per byte (GB10)")
ax2.grid(True, which="both", alpha=0.25)
ax2.margins(x=0.30)
cb = fig.colorbar(sc, ax=ax2, pad=0.02)
cb.set_label("valid-task score")
fig.suptitle("Performance per byte (42 tasks)")
fig.tight_layout()
fig.savefig(os.path.join(args.out, "perf_per_byte.png"), bbox_inches="tight")
plt.close(fig)
print(f"wrote 7 plots to {args.out} ({len(gb)} GB10 / {len(data) - len(gb)} Thor rows)")
if __name__ == "__main__":
main()