Download scripts/make_plots.py from Myric/apex-quant-benchmarks: direct link, hf CLI and curl.
- Browser
- Download file 11.1 kB
-
https://huggingface.co/Myric/apex-quant-benchmarks/resolve/main/scripts/make_plots.py
- Command line
-
hf download hf://Myric/apex-quant-benchmarks/scripts/make_plots.py
-
curl -L -o make_plots.py https://huggingface.co/Myric/apex-quant-benchmarks/resolve/main/scripts/make_plots.py
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() | |