Spaces:
Running
Running
Download scripts/make_plots.py from ishansurdi/SDK-Sovereign: direct link, hf CLI and curl.
- Browser
- Download file 5.54 kB
-
https://huggingface.co/spaces/ishansurdi/SDK-Sovereign/resolve/main/scripts/make_plots.py
- Command line
-
hf download hf://spaces/ishansurdi/SDK-Sovereign/scripts/make_plots.py
-
curl -L -o make_plots.py https://huggingface.co/spaces/ishansurdi/SDK-Sovereign/resolve/main/scripts/make_plots.py
5.54 kB
| """Rebuild Phase 8 plots from eval_results.json without re-running the models.""" | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import os | |
| import statistics | |
| from collections import defaultdict | |
| from pathlib import Path | |
| from typing import Any, Iterable | |
| def _load_eval_results(path: Path) -> dict[str, list[dict[str, Any]]]: | |
| """Load baseline/trained eval results from disk.""" | |
| payload = json.loads(path.read_text(encoding="utf-8")) | |
| baseline = payload.get("baseline") | |
| trained = payload.get("trained") | |
| if not isinstance(baseline, list) or not isinstance(trained, list): | |
| raise ValueError("eval_results.json must contain 'baseline' and 'trained' lists") | |
| return {"baseline": baseline, "trained": trained} | |
| def _safe_mean(values: Iterable[float]) -> float: | |
| """Return the arithmetic mean or zero for an empty iterable.""" | |
| values = list(values) | |
| return statistics.mean(values) if values else 0.0 | |
| def _write_placeholder_curve(plot_path: Path, role: str) -> None: | |
| """Write an honest placeholder plot when WandB metrics are unavailable.""" | |
| import matplotlib.pyplot as plt | |
| plt.figure(figsize=(8, 4)) | |
| plt.text( | |
| 0.5, | |
| 0.5, | |
| f"No training curve available for {role}.\nRun Phase 7 with WandB or export metrics first.", | |
| ha="center", | |
| va="center", | |
| fontsize=12, | |
| ) | |
| plt.axis("off") | |
| plt.title(f"GRPO training - {role}") | |
| plt.tight_layout() | |
| plt.savefig(plot_path, dpi=150, bbox_inches="tight") | |
| plt.close() | |
| def build_plots(eval_results_path: Path, plots_dir: Path) -> list[Path]: | |
| """Generate the six PRD plot artifacts from saved evaluation results.""" | |
| import matplotlib.pyplot as plt | |
| import numpy as np | |
| results = _load_eval_results(eval_results_path) | |
| baseline_results = results["baseline"] | |
| trained_results = results["trained"] | |
| plots_dir.mkdir(parents=True, exist_ok=True) | |
| created: list[Path] = [] | |
| b_rate = sum(bool(item.get("success")) for item in baseline_results) / max(len(baseline_results), 1) | |
| t_rate = sum(bool(item.get("success")) for item in trained_results) / max(len(trained_results), 1) | |
| pass_rate_path = plots_dir / "pass_rate_baseline_vs_trained.png" | |
| plt.figure(figsize=(6, 4)) | |
| plt.bar(["Baseline (untrained)", "Trained (two LoRAs)"], [b_rate, t_rate], color=["#bbbbbb", "#1f77b4"]) | |
| plt.ylabel("Pass rate (all tests passed)") | |
| plt.title("SDK-Sovereign - pass rate") | |
| plt.ylim(0, 1) | |
| for index, value in enumerate([b_rate, t_rate]): | |
| plt.text(index, value + 0.02, f"{value:.0%}", ha="center", fontweight="bold") | |
| plt.tight_layout() | |
| plt.savefig(pass_rate_path, dpi=150, bbox_inches="tight") | |
| plt.close() | |
| created.append(pass_rate_path) | |
| mean_reward_path = plots_dir / "mean_reward.png" | |
| plt.figure(figsize=(6, 4)) | |
| plt.bar( | |
| ["Baseline", "Trained"], | |
| [_safe_mean(item.get("total_reward", 0.0) for item in baseline_results), _safe_mean(item.get("total_reward", 0.0) for item in trained_results)], | |
| color=["#bbbbbb", "#1f77b4"], | |
| ) | |
| plt.ylabel("Mean episode reward") | |
| plt.axhline(0, color="k", lw=0.5) | |
| plt.title("Mean total reward per episode") | |
| plt.tight_layout() | |
| plt.savefig(mean_reward_path, dpi=150, bbox_inches="tight") | |
| plt.close() | |
| created.append(mean_reward_path) | |
| for role in ("lead", "auditor"): | |
| curve_path = plots_dir / f"reward_curve_{role}.png" | |
| _write_placeholder_curve(curve_path, role) | |
| created.append(curve_path) | |
| b_per: defaultdict[str, list[bool]] = defaultdict(list) | |
| t_per: defaultdict[str, list[bool]] = defaultdict(list) | |
| for item in baseline_results: | |
| b_per[str(item.get("repo", "unknown_repo"))].append(bool(item.get("success"))) | |
| for item in trained_results: | |
| t_per[str(item.get("repo", "unknown_repo"))].append(bool(item.get("success"))) | |
| repos = sorted(set(b_per) | set(t_per)) | |
| per_repo_path = plots_dir / "per_repo_pass_rate.png" | |
| plt.figure(figsize=(8, 4)) | |
| x = np.arange(len(repos)) | |
| width = 0.35 | |
| plt.bar(x - width / 2, [_safe_mean(b_per[repo]) for repo in repos], width, label="Baseline", color="#bbbbbb") | |
| plt.bar(x + width / 2, [_safe_mean(t_per[repo]) for repo in repos], width, label="Trained", color="#1f77b4") | |
| plt.xticks(x, repos, rotation=15) | |
| plt.ylabel("Pass rate") | |
| plt.legend() | |
| plt.title("Pass rate by repo") | |
| plt.tight_layout() | |
| plt.savefig(per_repo_path, dpi=150, bbox_inches="tight") | |
| plt.close() | |
| created.append(per_repo_path) | |
| completion_turns_path = plots_dir / "completion_turns.png" | |
| b_turns = [int(item.get("turns", 0)) for item in baseline_results if item.get("success")] | |
| t_turns = [int(item.get("turns", 0)) for item in trained_results if item.get("success")] | |
| plt.figure(figsize=(7, 4)) | |
| plt.hist([b_turns, t_turns], bins=list(range(1, 9)), label=["Baseline", "Trained"], color=["#bbbbbb", "#1f77b4"], edgecolor="white") | |
| plt.xlabel("Turns to completion (successful episodes only)") | |
| plt.ylabel("Count") | |
| plt.legend() | |
| plt.title("Distribution of completion turns") | |
| plt.tight_layout() | |
| plt.savefig(completion_turns_path, dpi=150, bbox_inches="tight") | |
| plt.close() | |
| created.append(completion_turns_path) | |
| return created | |
| def main() -> None: | |
| """CLI entrypoint for regenerating plots from saved evaluation JSON.""" | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--eval-results", default="eval_results.json", help="Path to eval_results.json") | |
| parser.add_argument("--plots-dir", default="plots", help="Directory for generated PNGs") | |
| args = parser.parse_args() | |
| created = build_plots(Path(args.eval_results), Path(args.plots_dir)) | |
| print("Generated plots:") | |
| for path in created: | |
| size = os.path.getsize(path) | |
| print(f"- {path} ({size} bytes)") | |
| if __name__ == "__main__": | |
| main() | |