| |
| """Aggregate ablation summaries across multiple seeds.""" |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import csv |
| import json |
| import statistics |
| from pathlib import Path |
| from typing import Dict, List |
|
|
|
|
| def parse_args() -> argparse.Namespace: |
| parser = argparse.ArgumentParser(description="Aggregate ablation CSV files across seeds.") |
| parser.add_argument("--results-pattern", required=True, help="Pattern with {seed} placeholder") |
| parser.add_argument("--seeds", type=int, nargs="+", default=[1, 3, 5, 7, 11]) |
| parser.add_argument("--output-dir", required=True) |
| parser.add_argument( |
| "--variant-order", |
| nargs="*", |
| default=["Full", "w/o Verification", "w/o Feedback", "w/o Co-Attention", "Text-only", "Vision-only", "w/o Text", "w/o Image"], |
| ) |
| return parser.parse_args() |
|
|
|
|
| def agg(values: List[float]) -> tuple[float, float]: |
| if not values: |
| return float("nan"), float("nan") |
| if len(values) == 1: |
| return values[0], 0.0 |
| return float(statistics.mean(values)), float(statistics.stdev(values)) |
|
|
|
|
| def main() -> None: |
| args = parse_args() |
| metric_map: Dict[str, Dict[str, List[float]]] = {} |
| f1_key = "" |
|
|
| for seed in args.seeds: |
| path = Path(args.results_pattern.format(seed=seed)) |
| if not path.exists(): |
| raise FileNotFoundError(f"Missing ablation CSV for seed {seed}: {path}") |
| with path.open("r", encoding="utf-8") as f: |
| rows = list(csv.DictReader(f)) |
| if not rows: |
| continue |
| if not f1_key: |
| f1_candidates = [k for k in rows[0].keys() if k.startswith("f1_")] |
| if not f1_candidates: |
| raise RuntimeError(f"Could not find F1 column in {path}") |
| f1_key = f1_candidates[0] |
| for row in rows: |
| variant = row["variant"] |
| metric_map.setdefault(variant, {"accuracy": [], f1_key: []}) |
| metric_map[variant]["accuracy"].append(float(row["accuracy"])) |
| metric_map[variant][f1_key].append(float(row[f1_key])) |
|
|
| ordered_variants: List[str] = [] |
| for variant in args.variant_order: |
| if variant in metric_map: |
| ordered_variants.append(variant) |
| for variant in metric_map.keys(): |
| if variant not in ordered_variants: |
| ordered_variants.append(variant) |
|
|
| output_dir = Path(args.output_dir) |
| output_dir.mkdir(parents=True, exist_ok=True) |
|
|
| rows_out: List[Dict[str, object]] = [] |
| for variant in ordered_variants: |
| acc_mean, acc_std = agg(metric_map[variant]["accuracy"]) |
| f1_mean, f1_std = agg(metric_map[variant][f1_key]) |
| rows_out.append( |
| { |
| "variant": variant, |
| "accuracy_mean": acc_mean, |
| "accuracy_std": acc_std, |
| f"{f1_key}_mean": f1_mean, |
| f"{f1_key}_std": f1_std, |
| "n_seeds": len(metric_map[variant]["accuracy"]), |
| "accuracy_pm": f"{acc_mean * 100.0:.2f} ± {acc_std * 100.0:.2f}", |
| "f1_pm": f"{f1_mean * 100.0:.2f} ± {f1_std * 100.0:.2f}", |
| } |
| ) |
|
|
| csv_path = output_dir / "ablation_multiseed_aggregate.csv" |
| with csv_path.open("w", encoding="utf-8", newline="") as f: |
| fieldnames = [ |
| "variant", |
| "accuracy_mean", |
| "accuracy_std", |
| f"{f1_key}_mean", |
| f"{f1_key}_std", |
| "n_seeds", |
| "accuracy_pm", |
| "f1_pm", |
| ] |
| writer = csv.DictWriter(f, fieldnames=fieldnames) |
| writer.writeheader() |
| for row in rows_out: |
| writer.writerow(row) |
|
|
| md_lines = [ |
| f"| Variant | Accuracy (%) | {f1_key} (%) | n |", |
| "|---|---:|---:|---:|", |
| ] |
| for row in rows_out: |
| md_lines.append( |
| "| {variant} | {acc} | {f1} | {n} |".format( |
| variant=row["variant"], |
| acc=row["accuracy_pm"], |
| f1=row["f1_pm"], |
| n=int(row["n_seeds"]), |
| ) |
| ) |
| md_path = output_dir / "ablation_multiseed_aggregate.md" |
| md_path.write_text("\n".join(md_lines) + "\n", encoding="utf-8") |
|
|
| json_path = output_dir / "ablation_multiseed_aggregate.json" |
| json_path.write_text(json.dumps(rows_out, indent=2), encoding="utf-8") |
|
|
| print(f"Saved CSV: {csv_path}") |
| print(f"Saved MD: {md_path}") |
| print(f"Saved JSON:{json_path}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|