Download scripts/merge_two_block_fppp_shards.py from Cccccz/Self-Forcing: direct link, hf CLI and curl.
- Browser
- Download file 4.52 kB
-
https://huggingface.co/Cccccz/Self-Forcing/resolve/main/scripts/merge_two_block_fppp_shards.py
- Command line
-
hf download hf://Cccccz/Self-Forcing/scripts/merge_two_block_fppp_shards.py
-
curl -L -o merge_two_block_fppp_shards.py https://huggingface.co/Cccccz/Self-Forcing/resolve/main/scripts/merge_two_block_fppp_shards.py
4.52 kB
| #!/usr/bin/env python3 | |
| """Merge independently evaluated two-block FPPP shards into one result set.""" | |
| from __future__ import annotations | |
| import argparse | |
| import csv | |
| import json | |
| import os | |
| import shutil | |
| from pathlib import Path | |
| from typing import Any | |
| PROMPT_IDS = list(range(80, 100)) | |
| SCHEDULE = "chunk0=FFFF; chunks1-6=FPPP" | |
| def parse_args() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--main_dir", type=Path, required=True) | |
| parser.add_argument("--shard_dir", type=Path, required=True) | |
| parser.add_argument("--sweep_dir", type=Path, required=True) | |
| return parser.parse_args() | |
| def atomic_json(path: Path, value: Any) -> None: | |
| temporary = path.with_suffix(path.suffix + ".tmp") | |
| temporary.write_text( | |
| json.dumps(value, indent=2, ensure_ascii=False) + "\n", | |
| encoding="utf-8", | |
| ) | |
| os.replace(temporary, path) | |
| def read_experiment_names(sweep_dir: Path) -> list[str]: | |
| with (sweep_dir / "summary.csv").open( | |
| "r", encoding="utf-8", newline="" | |
| ) as handle: | |
| return [row["name"] for row in csv.DictReader(handle)] | |
| def merge_pair_directories(main_dir: Path, shard_dir: Path) -> None: | |
| for source in shard_dir.glob("pair_*"): | |
| if source.is_dir(): | |
| shutil.copytree(source, main_dir / source.name, dirs_exist_ok=True) | |
| def collect_rows(main_dir: Path, names: list[str]) -> list[dict[str, Any]]: | |
| rows = [] | |
| for name in names: | |
| metrics_path = main_dir / name / "metrics.json" | |
| if not metrics_path.exists(): | |
| raise FileNotFoundError(f"Missing completed metrics: {metrics_path}") | |
| metrics = json.loads(metrics_path.read_text(encoding="utf-8")) | |
| if metrics.get("status") != "complete": | |
| raise RuntimeError(f"Incomplete metrics for {name}") | |
| if metrics.get("schedule") != SCHEDULE: | |
| raise RuntimeError(f"Unexpected schedule for {name}: {metrics.get('schedule')}") | |
| if metrics.get("prompt_ids") != PROMPT_IDS: | |
| raise RuntimeError(f"Unexpected prompt split for {name}") | |
| rows.append( | |
| { | |
| "name": metrics["name"], | |
| "source_layer_1": metrics["source_layers"][0], | |
| "source_layer_2": metrics["source_layers"][1], | |
| "pair_kind": metrics["pair_kind"], | |
| "schedule": metrics["schedule"], | |
| "num_prompts": metrics["num_prompts"], | |
| "psnr": metrics["psnr"], | |
| "ssim": metrics["ssim"], | |
| "lpips": metrics["lpips"], | |
| "rollout_psnr": metrics["rollout_psnr"], | |
| "rollout_ssim": metrics["rollout_ssim"], | |
| "rollout_lpips": metrics["rollout_lpips"], | |
| "offline_final_val_flow_mse": metrics[ | |
| "offline_final_val_flow_mse" | |
| ], | |
| "mean_generation_time_s": metrics["mean_generation_time_s"], | |
| } | |
| ) | |
| rows.sort(key=lambda row: float(row["lpips"])) | |
| return rows | |
| def write_summary(main_dir: Path, rows: list[dict[str, Any]]) -> None: | |
| destination = main_dir / "summary.csv" | |
| temporary = destination.with_suffix(".csv.tmp") | |
| with temporary.open("w", encoding="utf-8", newline="") as handle: | |
| writer = csv.DictWriter(handle, fieldnames=list(rows[0])) | |
| writer.writeheader() | |
| writer.writerows(rows) | |
| os.replace(temporary, destination) | |
| atomic_json(main_dir / "summary.json", rows) | |
| def main() -> None: | |
| args = parse_args() | |
| main_dir = args.main_dir.resolve() | |
| shard_dir = args.shard_dir.resolve() | |
| sweep_dir = args.sweep_dir.resolve() | |
| names = read_experiment_names(sweep_dir) | |
| if len(names) != 43: | |
| raise RuntimeError(f"Expected 43 experiments, found {len(names)}") | |
| merge_pair_directories(main_dir, shard_dir) | |
| rows = collect_rows(main_dir, names) | |
| write_summary(main_dir, rows) | |
| atomic_json( | |
| main_dir / "manifest.json", | |
| { | |
| "status": "complete", | |
| "architecture": "two_block_predictor", | |
| "prompt_ids": PROMPT_IDS, | |
| "experiments": names, | |
| "rollout_schedule": "FPPP", | |
| "rollout_definition": SCHEDULE, | |
| "generation_seed_reset_per_prompt": 0, | |
| "gpu_shards": {"2": 22, "4": 21}, | |
| "merged_shard_dir": str(shard_dir), | |
| }, | |
| ) | |
| print(f"[merge] {len(rows)} pairs -> {main_dir / 'summary.csv'}", flush=True) | |
| if __name__ == "__main__": | |
| main() | |