"""Reward curve and calibration improvement plots. Usage: python training/plot_results.py --log_path outputs/rewards.csv --output_dir outputs/ """ import argparse import csv import os def plot(log_path: str, output_dir: str): try: import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt import numpy as np except ImportError: print("matplotlib not installed. Skipping plots.") return if not os.path.exists(log_path): print(f"Log file not found: {log_path}") return os.makedirs(output_dir, exist_ok=True) # Read CSV episodes, mean_rewards, rolling_rewards = [], [], [] cal_scores, imp_scores, con_scores = [], [], [] with open(log_path) as f: reader = csv.DictReader(f) for row in reader: episodes.append(int(row["episode"])) mean_rewards.append(float(row.get("mean_reward", 0))) rolling_rewards.append(float(row.get("rolling_mean_reward", 0))) cal_scores.append(float(row.get("calibration_score", 0))) imp_scores.append(float(row.get("improvement_signal", 0))) con_scores.append(float(row.get("consistency_score", 0))) if not episodes: print("No data in log file.") return # --- Plot 1: Mean reward per episode + rolling mean --- fig, ax = plt.subplots(figsize=(10, 5)) ax.plot(episodes, mean_rewards, alpha=0.4, color="steelblue", label="Episode reward") ax.plot(episodes, rolling_rewards, color="steelblue", linewidth=2, label="Rolling mean (100 ep)") ax.set_xlabel("Episode") ax.set_ylabel("Reward") ax.set_title("Scorer Reward over Training") ax.legend() ax.grid(True, alpha=0.3) plt.tight_layout() out1 = os.path.join(output_dir, "reward_curve.png") plt.savefig(out1, dpi=150) plt.close() print(f"Saved: {out1}") # --- Plot 2: Per-component reward breakdown --- fig, axes = plt.subplots(1, 3, figsize=(15, 4)) components = [ (cal_scores, "Calibration Score", "darkorange"), (imp_scores, "Improvement Signal", "green"), (con_scores, "Consistency Score", "red"), ] for ax, (vals, label, color) in zip(axes, components): # Smooth with rolling window window = min(20, len(vals)) smoothed = [ sum(vals[max(0, i - window):i + 1]) / min(i + 1, window) for i in range(len(vals)) ] ax.plot(episodes, vals, alpha=0.3, color=color) ax.plot(episodes, smoothed, color=color, linewidth=2) ax.set_xlabel("Episode") ax.set_ylabel(label) ax.set_title(label) ax.grid(True, alpha=0.3) plt.suptitle("Reward Component Breakdown over Training") plt.tight_layout() out2 = os.path.join(output_dir, "reward_components.png") plt.savefig(out2, dpi=150) plt.close() print(f"Saved: {out2}") if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--log_path", required=True) parser.add_argument("--output_dir", default="outputs/") args = parser.parse_args() plot(args.log_path, args.output_dir)