from __future__ import annotations import json from pathlib import Path import numpy as np import pandas as pd import trackio from experiment import ROOMS, run_agent from safetensors.torch import save_file PROJECT_DIR = Path(__file__).resolve().parent ARTIFACT_DIR = PROJECT_DIR / "artifacts" / "curiosity-cabinet" DATA_DIR = PROJECT_DIR / "data" def aggregate(records: list[dict], reward: str) -> dict: subset = [record for record in records if record["reward"] == reward] return { "runs": len(subset), "mean_middle_action_fraction": { room: float( np.mean( [ record["middle_action_fraction"][room] for record in subset ] ) ) for room in ROOMS }, "mean_final_action_fraction": { room: float( np.mean( [record["final_action_fraction"][room] for record in subset] ) ) for room in ROOMS }, "learnable_world_model_mse": { "mean": float( np.mean( [record["learnable_world_model_mse"] for record in subset] ) ), "median": float( np.median( [record["learnable_world_model_mse"] for record in subset] ) ), }, } def main() -> None: runs = 60 steps = 1_200 trackio.init( project="curiosity-cabinet", name="error-versus-learning-progress-v1", config={ "runs_per_reward": runs, "steps_per_run": steps, "rooms": ROOMS, "epsilon": 0.15, }, ) records = [] representative = {} for run in range(runs): for reward in ["prediction_error", "learning_progress"]: record = run_agent(reward, seed=9000 + run, steps=steps) if run == 0: representative[reward] = record records.append( { key: value for key, value in record.items() if key not in {"actions", "losses", "learnable_state_dict"} } ) if (run + 1) % 10 == 0: recent = records[-20:] trackio.log( { "completed_runs": run + 1, "error_noisy_tv_fraction": float( np.mean( [ item["middle_action_fraction"]["noisy_tv"] for item in recent if item["reward"] == "prediction_error" ] ) ), "progress_noisy_tv_fraction": float( np.mean( [ item["middle_action_fraction"]["noisy_tv"] for item in recent if item["reward"] == "learning_progress" ] ) ), } ) summary = { reward: aggregate(records, reward) for reward in ["prediction_error", "learning_progress"] } report = { "benchmark": "Curiosity Cabinet noisy-TV stress test", "runs_per_reward": runs, "steps_per_run": steps, "summary": summary, } ARTIFACT_DIR.mkdir(parents=True, exist_ok=True) DATA_DIR.mkdir(parents=True, exist_ok=True) (ARTIFACT_DIR / "evaluation.json").write_text( json.dumps(report, indent=2), encoding="utf-8" ) for reward, record in representative.items(): save_file( record["learnable_state_dict"], ARTIFACT_DIR / f"{reward}_world_model.safetensors", ) np.savez_compressed( ARTIFACT_DIR / f"{reward}_trajectory.npz", actions=np.asarray(record["actions"], dtype=np.int8), losses=np.asarray(record["losses"], dtype=np.float32), ) rows = [] for record in records: row = { "reward": record["reward"], "seed": record["seed"], "learnable_world_model_mse": record["learnable_world_model_mse"], } for window in ["middle_action_fraction", "final_action_fraction"]: for room in ROOMS: row[f"{window}_{room}"] = record[window][room] rows.append(row) pd.DataFrame(rows).to_parquet(DATA_DIR / "seeded_results.parquet", index=False) trackio.log( { "error_noisy_tv_fraction": summary["prediction_error"][ "mean_middle_action_fraction" ]["noisy_tv"], "progress_noisy_tv_fraction": summary["learning_progress"][ "mean_middle_action_fraction" ]["noisy_tv"], "error_learnable_mse": summary["prediction_error"][ "learnable_world_model_mse" ]["mean"], "progress_learnable_mse": summary["learning_progress"][ "learnable_world_model_mse" ]["mean"], } ) trackio.finish() print(json.dumps(report, indent=2)) if __name__ == "__main__": main()