From 5ab644db6823491ffadb793162be36f4aa5edd04 Mon Sep 17 00:00:00 2001 From: YurenHao0426 Date: Mon, 10 Aug 2026 10:25:00 -0500 Subject: results: retain GoToObj as diagnostic only --- experiments/analyze_babyai_shared_b1.py | 127 ++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 experiments/analyze_babyai_shared_b1.py (limited to 'experiments/analyze_babyai_shared_b1.py') diff --git a/experiments/analyze_babyai_shared_b1.py b/experiments/analyze_babyai_shared_b1.py new file mode 100644 index 0000000..ebcdb17 --- /dev/null +++ b/experiments/analyze_babyai_shared_b1.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +"""Summarize the frozen BabyAI GoToObj shared-feedback endpoint.""" + +import argparse +import json +from pathlib import Path +import statistics + +import gymnasium as gym +import minigrid # noqa: F401 - registers BabyAI environments + + +ROOT = Path(__file__).resolve().parents[1] +DEFAULT_RESULTS = ROOT / "results" / "babyai_shared" / "b1" +DEFAULT_OUT = ROOT / "results" / "babyai_shared" / "b1_analysis.json" +SEEDS = (4101, 4102, 4103) +CONDITIONS = ("bp", "clean_kp", "raw_shared", "sdil") + + +def summarize(values): + return { + "values": values, + "mean": statistics.mean(values), + "sample_std": statistics.stdev(values), + } + + +def object_counts(env_id, seeds): + counts = [] + for seed in seeds: + env = gym.make(env_id) + try: + env.reset(seed=seed) + counts.append(sum( + cell is not None and cell.type in {"ball", "box", "key"} + for cell in env.unwrapped.grid.grid)) + finally: + env.close() + return counts + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--results", type=Path, default=DEFAULT_RESULTS) + parser.add_argument("--out", type=Path, default=DEFAULT_OUT) + args = parser.parse_args() + records = {} + for seed in SEEDS: + for condition in CONDITIONS: + path = args.results / f"seed{seed}_{condition}.json" + with open(path, encoding="utf-8") as handle: + records[(seed, condition)] = json.load(handle) + + condition_summary = {} + for condition in CONDITIONS: + condition_records = [records[(seed, condition)] for seed in SEEDS] + condition_summary[condition] = { + "rollout_success_percent": summarize([ + 100.0 * row["rollout"]["success"] + for row in condition_records]), + "expert_action_accuracy_percent": summarize([ + 100.0 * row["validation"]["accuracy"] + for row in condition_records]), + "mission_lesion_rollout_success_percent": summarize([ + 100.0 * row["mission_lesion_rollout"]["success"] + for row in condition_records]), + "training_wall_seconds": summarize([ + row["training"]["training_wall_seconds"] + for row in condition_records]), + "all_finite": all(row["finite"] for row in condition_records), + } + rollout_gaps = [100.0 * ( + records[(seed, "sdil")]["rollout"]["success"] + - records[(seed, "raw_shared")]["rollout"]["success"]) + for seed in SEEDS] + action_gaps = [100.0 * ( + records[(seed, "sdil")]["validation"]["accuracy"] + - records[(seed, "raw_shared")]["validation"]["accuracy"]) + for seed in SEEDS] + counts = object_counts("BabyAI-GoToObjS6-v1", range(256)) + task_required = min(counts) > 1 + checks = { + "all_runs_finite": all( + row["finite"] for row in records.values()), + "bp_and_clean_kp_mean_rollout_at_least_80": ( + condition_summary["bp"]["rollout_success_percent"]["mean"] >= 80 + and condition_summary["clean_kp"] + ["rollout_success_percent"]["mean"] >= 80), + "sdil_rollout_above_raw_every_seed": all( + value > 0 for value in rollout_gaps), + "mission_structurally_required": task_required, + } + report = { + "stage": "babyai_shared_b1_analysis", + "gate": "pass" if all(checks.values()) else "fail", + "checks": checks, + "conditions": condition_summary, + "paired_sdil_minus_raw": { + "rollout_success_points": summarize(rollout_gaps), + "expert_action_accuracy_points": summarize(action_gaps), + }, + "task_structure_audit": { + "env_id": "BabyAI-GoToObjS6-v1", + "audited_episode_seeds": 256, + "minimum_task_object_count": min(counts), + "maximum_task_object_count": max(counts), + "mission_structurally_required_to_identify_the_only_object": ( + task_required), + "interpretation": ( + "The sole object is the target, so the mission does not select " + "among alternatives. Mission lesion is an input ablation, not " + "evidence that language is required by the task."), + }, + "test_split_generated_or_read": False, + "decision": ( + "Retain as an implementation diagnostic; do not use as the paper's " + "task-required shared-feedback result. Move to PickupLoc."), + } + args.out.parent.mkdir(parents=True, exist_ok=True) + with open(args.out, "w", encoding="utf-8") as handle: + json.dump(report, handle, indent=2, sort_keys=True) + handle.write("\n") + print(json.dumps(report, indent=2, sort_keys=True)) + + +if __name__ == "__main__": + main() -- cgit v1.2.3