opsguard / scripts /make_plots.py
sai1906's picture
Upload folder using huggingface_hub
2612006 verified
Raw
History Blame Contribute Delete
3.28 kB
"""Generate baseline-vs-trained reward plots from eval rollouts.
Usage:
python scripts/make_plots.py --rollouts eval_outputs/real_baseline/rollouts.jsonl --out eval_outputs/real_baseline
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--rollouts", required=True)
ap.add_argument("--out", required=True)
args = ap.parse_args()
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
rows = [json.loads(l) for l in Path(args.rollouts).read_text(encoding="utf-8").splitlines() if l.strip()]
by_policy_scenario: dict[tuple[str, str], list[float]] = {}
for r in rows:
by_policy_scenario.setdefault((r["policy"], r["scenario_id"]), []).append(r["cumulative_reward"])
policies = sorted({p for p, _ in by_policy_scenario})
scenarios = sorted({s for _, s in by_policy_scenario})
fig, ax = plt.subplots(figsize=(10, 5))
width = 0.8 / max(1, len(policies))
for i, p in enumerate(policies):
means = []
stds = []
for s in scenarios:
vals = by_policy_scenario.get((p, s), [])
if vals:
m = sum(vals) / len(vals)
v = sum((x - m) ** 2 for x in vals) / max(1, len(vals) - 1)
means.append(m)
stds.append(v ** 0.5)
else:
means.append(0)
stds.append(0)
x = [j + i * width - 0.4 + width / 2 for j in range(len(scenarios))]
ax.bar(x, means, width=width * 0.95, yerr=stds, capsize=2, label=p)
ax.set_xticks(range(len(scenarios)))
ax.set_xticklabels(scenarios, rotation=20, ha="right")
ax.set_ylabel("Cumulative episode reward")
ax.set_title("OpsGuard: cumulative reward by policy × scenario")
ax.axhline(0, color="gray", linestyle="--", linewidth=0.8)
ax.legend(loc="upper left", fontsize=9)
ax.grid(axis="y", alpha=0.3)
plt.tight_layout()
out_path = Path(args.out) / "reward_by_policy.png"
plt.savefig(out_path, dpi=130)
print(f" wrote {out_path}")
fig2, ax2 = plt.subplots(figsize=(10, 5))
spam_recall_by = {}
for r in rows:
if r["n_spam_total"] == 0:
continue
spam_recall_by.setdefault((r["policy"], r["scenario_id"]), []).append(
r["n_spam_caught"] / r["n_spam_total"]
)
for i, p in enumerate(policies):
means = []
for s in scenarios:
vals = spam_recall_by.get((p, s), [])
means.append(sum(vals) / len(vals) if vals else 0.0)
x = [j + i * width - 0.4 + width / 2 for j in range(len(scenarios))]
ax2.bar(x, means, width=width * 0.95, label=p)
ax2.set_xticks(range(len(scenarios)))
ax2.set_xticklabels(scenarios, rotation=20, ha="right")
ax2.set_ylabel("Spam recall (caught / total)")
ax2.set_title("OpsGuard: spam recall by policy × scenario")
ax2.set_ylim(0, 1.05)
ax2.legend(loc="upper left", fontsize=9)
ax2.grid(axis="y", alpha=0.3)
plt.tight_layout()
out_path2 = Path(args.out) / "spam_recall.png"
plt.savefig(out_path2, dpi=130)
print(f" wrote {out_path2}")
if __name__ == "__main__":
main()