| """Fetch baseline and rhaister model results from WandB 'perturbation-eval' project. |
| |
| Saves to baseline_results.json and rhaister_results.json at repo root. |
| |
| Usage: |
| python scripts/fetch_wandb.py |
| """ |
| import json |
| import os |
| import re |
| import sys |
|
|
|
|
| import wandb |
|
|
| REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| SPLITS = [f"tahoe_{i}_holdout" for i in range(5, 10)] |
|
|
| METRIC_KEYS = [ |
| "pdex_static/pearson_delta_mean", |
| "pdex_static/auprc_p05", |
| "state/pearson_delta_mean", |
| "state/spearman_lfc_sig_mean", |
| "state/pr_auc_mean", |
| "state/de_overlap_mean", |
| "state/de_spearman_sig", |
| "state/discrimination_mean", |
| ] |
|
|
|
|
| def _summary_metrics(run): |
| summary = dict(run.summary) |
| return {k: summary[k] for k in METRIC_KEYS if k in summary} |
|
|
|
|
| def fetch_baselines(): |
| """Fetch baseline runs. Uses the old 'eval_baseline_{name}_{split}' convention. |
| If not available, falls back to time-based inference on recent batches.""" |
| api = wandb.Api() |
| runs = list(api.runs("perturbation-eval", filters={"jobType": "baseline"}, order="-created_at")) |
|
|
| |
| named = {} |
| for r in runs: |
| m = re.match(r"eval_baseline_(\w+?)_(tahoe_\d+_holdout)$", r.name) |
| if m: |
| baseline_name, split = m.groups() |
| |
| key = (split, baseline_name) |
| if key not in named: |
| named[key] = r |
|
|
| if len(named) >= 20: |
| print(f"Using {len(named)} named baseline runs") |
| results = {split: {} for split in SPLITS} |
| for (split, baseline_name), run in named.items(): |
| if split in results: |
| results[split][baseline_name] = _summary_metrics(run) |
| return results |
|
|
| |
| print(f"Only {len(named)} named runs; inferring splits from time batches") |
| recent = [r for r in runs if not re.match(r"eval_baseline_\w+_tahoe_\d+_holdout$", r.name)] |
| recent = recent[:20] |
| recent.reverse() |
|
|
| results = {split: {} for split in SPLITS} |
| for i, run in enumerate(recent): |
| split_idx = i // 4 |
| split = SPLITS[split_idx] |
| |
| baseline_name = run.name.replace("baseline_", "") |
| results[split][baseline_name] = _summary_metrics(run) |
| return results |
|
|
|
|
| def fetch_rhaister(run_name_suffix=None): |
| """Fetch rhaister eval_splits runs. Groups by time batch (5 consecutive = one full sweep). |
| If run_name_suffix given, only fetches runs matching eval_rhaister_{suffix}.""" |
| api = wandb.Api() |
| filters = {"jobType": "rhaister"} |
| if run_name_suffix: |
| filters["displayName"] = f"eval_rhaister_{run_name_suffix}" |
| runs = list(api.runs("perturbation-eval", filters=filters, order="-created_at")) |
|
|
| |
| by_name = {} |
| for r in runs: |
| by_name.setdefault(r.name, []).append(r) |
|
|
| out = {} |
| for name, name_runs in by_name.items(): |
| if len(name_runs) < 5: |
| continue |
| |
| sweep = sorted(name_runs[:5], key=lambda r: r.created_at) |
| split_results = {} |
| for i, run in enumerate(sweep): |
| split_results[SPLITS[i]] = _summary_metrics(run) |
| out[name] = split_results |
| return out |
|
|
|
|
| def main(): |
| print("Fetching baselines...") |
| baselines = fetch_baselines() |
| baseline_path = os.path.join(REPO_ROOT, "baseline_results.json") |
| with open(baseline_path, "w") as f: |
| json.dump(baselines, f, indent=2, sort_keys=True) |
| print(f" saved to {baseline_path}") |
| for split in SPLITS: |
| print(f" {split}: {list(baselines[split].keys())}") |
|
|
| print("\nFetching rhaister eval_splits results...") |
| rhaister = fetch_rhaister() |
| rhaister_path = os.path.join(REPO_ROOT, "rhaister_results.json") |
| with open(rhaister_path, "w") as f: |
| json.dump(rhaister, f, indent=2, sort_keys=True) |
| print(f" saved to {rhaister_path}") |
| for name in rhaister: |
| print(f" {name}: {list(rhaister[name].keys())}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|