Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
from pathlib import Path

# --- Paths -----------------------------------------------------------------
# Derived from this file's location (``<repo>/logs/curve_plotting/plot_config.py``)
# so the scripts work from any checkout without a hardcoded ``~`` path.
REPO_ROOT = Path(__file__).resolve().parents[2]
# Derived from this file's location (``<repo>/artifacts/tech_report_v1/
# appendix_training_curves/curve_plotting/plot_config.py``) so the scripts
# work from any checkout without a hardcoded ``~`` path.
REPO_ROOT = Path(__file__).resolve().parents[4]
REPORT_ROOT = Path(__file__).resolve().parent
DEFAULT_LOG_DIR = REPO_ROOT / "logs" / "self_tuning"
DEFAULT_PLOT_DIR = REPO_ROOT / "logs" / "curve_plotting"
DEFAULT_DATA_PATH = DEFAULT_PLOT_DIR / "curve_data.csv"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import argparse
import os
import sys
from functools import partial
from multiprocessing import Pool
from pathlib import Path
Expand All @@ -28,6 +29,9 @@

matplotlib.use("Agg") # headless-safe; avoids the Qt "no display" crash.

if __name__ == "__main__" and not __package__:
sys.path.insert(0, str(Path(__file__).resolve().parents[4]))

import matplotlib.pyplot as plt # noqa: E402
import numpy as np # noqa: E402
import pandas as pd # noqa: E402
Expand All @@ -36,9 +40,12 @@
ALGO_CONFIGS,
DEFAULT_DATA_PATH,
DEFAULT_PLOT_DIR,
PLOT_RC_PARAMS,
is_higher_better,
)
from artifacts.tech_report_v1.report_utils import ( # noqa: E402
NOTEBOOK_STYLE,
set_plot_style,
)

GRID_POINTS = 150
TIME_COL = "accumulated_submission_time"
Expand Down Expand Up @@ -134,19 +141,6 @@ def compute_ylimits(values, target_value, higher_is_better, zoom):
return ymin, ymax


def _style_axis(ax):
ax.grid(True, which="major", color="#e8e8e8", linewidth=0.8)
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.spines["left"].set_color("#cccccc")
ax.spines["bottom"].set_color("#cccccc")


def _legend(ax):
ax.legend(fontsize=9, frameon=True, facecolor="white", framealpha=0.9,
edgecolor="#e5e5e5")


def _plot_metric(ax, submissions, wdf, x_col, x_scale):
"""Metric mean + std band per submission; returns pooled values for ylim."""
all_vals = []
Expand Down Expand Up @@ -223,8 +217,7 @@ def plot_workload(workload, wdf, submissions, out_dir, dpi=200):
label=f"Target ({target:g})")
ax.set_xlabel(xlab, fontweight="semibold")
ax.set_ylabel(mlabel, fontweight="semibold")
_legend(ax)
_style_axis(ax)
ax.legend()
ax_mt.set_title(f"Validation {metric} vs. wall-clock time", fontsize=12)
ax_ms.set_title(f"Validation {metric} vs. training steps", fontsize=12)

Expand All @@ -235,8 +228,7 @@ def plot_workload(workload, wdf, submissions, out_dir, dpi=200):
for ax, xlab in [(ax_gt, "Wall-clock time (hours)"), (ax_gs, "Training steps (x10³)")]:
ax.set_xlabel(xlab, fontweight="semibold")
ax.set_ylabel(glabel, fontweight="semibold")
_legend(ax)
_style_axis(ax)
ax.legend()
ax_gt.set_title("Distance to target vs. wall-clock time", fontsize=12)
ax_gs.set_title("Distance to target vs. training steps", fontsize=12)
else:
Expand All @@ -253,7 +245,7 @@ def plot_workload(workload, wdf, submissions, out_dir, dpi=200):

def _render_job(job, dpi):
workload, wdf, submissions, out_dir = job
plt.rcParams.update(PLOT_RC_PARAMS) # rcParams don't survive a spawn start.
set_plot_style(NOTEBOOK_STYLE) # rcParams don't survive a spawn start.
return plot_workload(workload, wdf, submissions, out_dir, dpi=dpi)


Expand Down Expand Up @@ -290,7 +282,7 @@ def main() -> None:
if not args.data.is_file():
raise SystemExit(f"No curve data at {args.data}. Run parse_logs.py first (pass 1).")

plt.rcParams.update(PLOT_RC_PARAMS)
set_plot_style(NOTEBOOK_STYLE)
data = pd.read_csv(args.data)
algos = list(ALGO_CONFIGS) if args.algo == "all" else [args.algo]
print(f"Plotting algorithms: {algos}")
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1,138 changes: 1,138 additions & 0 deletions artifacts/tech_report_v1/appendix_training_curves/plot.ipynb

Large diffs are not rendered by default.

97 changes: 97 additions & 0 deletions artifacts/tech_report_v1/appendix_training_curves/plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# ---
# jupyter:
# jupytext:
# formats: ipynb,py:percent
# text_representation:
# extension: .py
# format_name: percent
# format_version: '1.3'
# jupytext_version: 1.19.5
# kernelspec:
# display_name: myenv
# language: python
# name: python3
# ---

# %% [markdown]
# # Curve Plotter
#
# This notebook imports the helper functions from `plot_helper.py` to generate and display publication-grade comparison plots for self-tuning algorithms (e.g., `sfadamw`, `muon`, `ademamix`, etc.).
# You can customize the styling parameters below and select which algorithms/workloads to plot.

# %%
import sys
from pathlib import Path

# Ensure the scratch directory is in python path
scratch_dir = Path('./').resolve()
if str(scratch_dir) not in sys.path:
sys.path.append(str(scratch_dir))

import plot_helper
from plot_helper import (
ALGO_CONFIGS,
configure_styling,
plot_workload,
find_workloads,
find_repo_root,
)

# %% [markdown]
# ## Customize Styling
#
# You can override any Matplotlib RC parameters in the dictionary below. Call `configure_styling(custom_params)` to apply them.

# %%
# configure_styling()'s defaults already match score_submissions.py's theme
# (Section 4 leaderboards); add overrides here only if you want to deviate
# from that shared look for this notebook.
custom_styles = {}

# Apply styling configurations
configure_styling(custom_styles)

# %% [markdown]
# ## Select Algorithm & Generate Plots
#
# Generates plots for every algorithm in `ALGO_CONFIGS` (set `ALGO_NAMES` to a
# subset to limit it) and the given zoom type (`'log'` or `'percentile'`).
# Outputs go to `out/<algo>/<workload>_curves.png`, next to this notebook —
# one subdirectory per algorithm, mirroring each algorithm's `sub_dir`.

# %%
# Parameters - feel free to change these
ALGO_NAMES = list(ALGO_CONFIGS.keys()) # e.g. ['sfadamw', 'muon'] to limit to a subset
ZOOM_TYPE = 'log' # Options: 'log', 'percentile'

# Configure directories (repo root found by walking up from plot_helper.py,
# not hardcoded to any user's home directory). base_save_dir is anchored to
# plot_helper.py's own location (reliable even when this notebook's own
# __file__ isn't set) so outputs land in out/ next to this notebook.
REPO_ROOT = find_repo_root()
base_log_dir = REPO_ROOT / 'logs' / 'self_tuning'
base_save_dir = Path(plot_helper.__file__).resolve().parent / 'out'

for algo_name in ALGO_NAMES:
if algo_name not in ALGO_CONFIGS:
print(f"Algorithm '{algo_name}' not found in ALGO_CONFIGS. Available: {list(ALGO_CONFIGS.keys())}")
continue

config = ALGO_CONFIGS[algo_name]
submissions = config['submissions']

# Find all workloads for this algorithm
workloads = find_workloads(base_log_dir, submissions)
print(f"\n=== {algo_name}: found workloads {workloads} ===")

for workload in workloads:
print(f"Processing workload: {workload}")
plot_workload(
workload=workload,
algo_name=algo_name,
submissions=submissions,
base_log_dir=base_log_dir,
base_save_dir=base_save_dir,
zoom=ZOOM_TYPE,
show_plot=True, # displays every figure inline, in addition to saving it
)
Loading
Loading