Download 14B/code/tools/precompute_dinov3_dense_nystrom_reference.py from Elastic-forcing/Elastic-forcing-code: direct link, hf CLI and curl.
- Browser
- Download file 45.2 kB
-
https://huggingface.co/Elastic-forcing/Elastic-forcing-code/resolve/main/14B/code/tools/precompute_dinov3_dense_nystrom_reference.py
- Command line
-
hf download hf://Elastic-forcing/Elastic-forcing-code/14B/code/tools/precompute_dinov3_dense_nystrom_reference.py
-
curl -L -o precompute_dinov3_dense_nystrom_reference.py https://huggingface.co/Elastic-forcing/Elastic-forcing-code/resolve/main/14B/code/tools/precompute_dinov3_dense_nystrom_reference.py
45.2 kB
| #!/usr/bin/env python3 | |
| """Build the fixed DINOv3 ViT-L/16 whole-video Nyström reference. | |
| The teacher and objective are unchanged from the paired V-JEPA2 experiment: | |
| the final latent from every row of the 1,537-video CausVid ODE LMDB is decoded | |
| with the frozen Wan VAE, then represented by a frozen DINOv3 image encoder. | |
| The DINOv3 feature map is fixed to 16 uniformly distributed source frames and | |
| an 8x8 subset of the 16x16 patch grid per frame. Frame-major concatenation | |
| therefore produces one aligned ``[16 * 64, 1024]`` matrix per video. | |
| Every torchrun rank atomically writes one indexed FP16 feature shard. Rank 0 | |
| validates and merges all shards in LMDB-index order, constructs the existing | |
| video-matrix Nyström objective (m=256, seed=0), atomically publishes the pack, | |
| and reloads the *final path* for validation. Temporary shards are removed only | |
| after that final validation succeeds; failed runs retain them for diagnosis. | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| from datetime import timedelta | |
| import gc | |
| import hashlib | |
| import json | |
| import math | |
| import os | |
| from pathlib import Path | |
| import shutil | |
| import subprocess | |
| import sys | |
| import tempfile | |
| import time | |
| from typing import Any, Dict, Iterable, Mapping, Optional, Sequence, Tuple | |
| import torch | |
| import torch.distributed as dist | |
| REPO_ROOT = Path(__file__).resolve().parents[1] | |
| if str(REPO_ROOT) not in sys.path: | |
| sys.path.insert(0, str(REPO_ROOT)) | |
| TOOL_FORMAT_VERSION = 1 | |
| MIB = 1024 ** 2 | |
| EXPECTED_TEACHER_COUNT = 1537 | |
| EXPECTED_SOURCE_COMMIT = "6876159a11b4df116f30f667f8c9888617df0751" | |
| SOURCE_NUM_FRAMES = 81 | |
| FRAME_INDICES = (0, 5, 11, 16, 21, 27, 32, 37, 43, 48, 53, 59, 64, 69, 75, 80) | |
| INPUT_SIZE = 256 | |
| PATCH_SIZE = 16 | |
| PATCH_GRID_SIZE = 16 | |
| SPATIAL_AXIS_INDICES = (0, 2, 4, 6, 9, 11, 13, 15) | |
| SPATIAL_TOKEN_INDICES = tuple( | |
| row * PATCH_GRID_SIZE + column | |
| for row in SPATIAL_AXIS_INDICES | |
| for column in SPATIAL_AXIS_INDICES | |
| ) | |
| PER_FRAME_TOKENS = 64 | |
| TOTAL_TOKENS = len(FRAME_INDICES) * PER_FRAME_TOKENS | |
| FEATURE_DIM = 1024 | |
| FORWARD_CHUNK_FRAMES = 4 | |
| NUM_LANDMARKS = 256 | |
| NYSTROM_SEED = 0 | |
| MEDIAN_MAX_SAMPLES = EXPECTED_TEACHER_COUNT | |
| KMEANS_ITERATIONS = 20 | |
| NYSTROM_RIDGE = 1.0e-6 | |
| KERNEL_CHUNK_SIZE = 32 | |
| WAN_VAE_MODEL_NAME = "Wan2.1-T2V-1.3B" | |
| WAN_VAE_MEAN = ( | |
| -0.7571, -0.7089, -0.9113, 0.1075, -0.1745, 0.9653, -0.1517, 1.5508, | |
| 0.4134, -0.0715, 0.5517, -0.3632, -0.1922, -0.9497, 0.2503, -0.2921, | |
| ) | |
| WAN_VAE_STD = ( | |
| 2.8184, 1.4541, 2.3275, 2.6558, 1.2196, 1.7708, 2.6052, 2.0743, | |
| 3.2687, 2.1526, 2.8652, 1.5579, 1.6382, 1.1253, 2.8251, 1.9160, | |
| ) | |
| def build_parser() -> argparse.ArgumentParser: | |
| parser = argparse.ArgumentParser( | |
| description=( | |
| "Build the fixed full-1537 DINOv3 ViT-L/16 video-matrix " | |
| "Nyström teacher reference." | |
| ) | |
| ) | |
| parser.add_argument("--teacher-lmdb", type=Path, required=True) | |
| parser.add_argument("--repo-path", type=Path, required=True) | |
| parser.add_argument("--weight-path", type=Path, required=True) | |
| parser.add_argument( | |
| "--source-commit", type=str, default=EXPECTED_SOURCE_COMMIT) | |
| parser.add_argument("--output", type=Path, required=True) | |
| parser.add_argument("--batch-size", type=int, default=1) | |
| parser.add_argument( | |
| "--expected-teacher-count", type=int, default=EXPECTED_TEACHER_COUNT) | |
| parser.add_argument( | |
| "--forward-chunk-frames", type=int, default=FORWARD_CHUNK_FRAMES) | |
| parser.add_argument("--num-landmarks", type=int, default=NUM_LANDMARKS) | |
| parser.add_argument("--seed", type=int, default=NYSTROM_SEED) | |
| parser.add_argument( | |
| "--median-max-samples", type=int, default=MEDIAN_MAX_SAMPLES) | |
| parser.add_argument("--bandwidth", type=float, default=None) | |
| parser.add_argument( | |
| "--kmeans-iterations", type=int, default=KMEANS_ITERATIONS) | |
| parser.add_argument("--ridge", type=float, default=NYSTROM_RIDGE) | |
| parser.add_argument("--chunk-size", type=int, default=KERNEL_CHUNK_SIZE) | |
| parser.add_argument("--tmp-dir", type=Path, default=None) | |
| parser.add_argument("--overwrite", action="store_true") | |
| parser.add_argument("--log-every", type=int, default=25) | |
| parser.add_argument("--distributed-timeout-minutes", type=int, default=360) | |
| parser.add_argument("--dry-run", action="store_true") | |
| return parser | |
| def _validate_args(args: argparse.Namespace) -> None: | |
| positive = { | |
| "batch_size": args.batch_size, | |
| "expected_teacher_count": args.expected_teacher_count, | |
| "forward_chunk_frames": args.forward_chunk_frames, | |
| "num_landmarks": args.num_landmarks, | |
| "median_max_samples": args.median_max_samples, | |
| "kmeans_iterations": args.kmeans_iterations, | |
| "chunk_size": args.chunk_size, | |
| "distributed_timeout_minutes": args.distributed_timeout_minutes, | |
| } | |
| invalid = {name: value for name, value in positive.items() if int(value) <= 0} | |
| if invalid: | |
| raise ValueError(f"arguments must be positive: {invalid}") | |
| if int(args.expected_teacher_count) != EXPECTED_TEACHER_COUNT: | |
| raise ValueError( | |
| "the canonical reference requires exactly " | |
| f"{EXPECTED_TEACHER_COUNT} teachers") | |
| if int(args.forward_chunk_frames) != FORWARD_CHUNK_FRAMES: | |
| raise ValueError( | |
| f"--forward-chunk-frames must be {FORWARD_CHUNK_FRAMES}") | |
| if int(args.num_landmarks) != NUM_LANDMARKS: | |
| raise ValueError(f"--num-landmarks must be {NUM_LANDMARKS}") | |
| if int(args.seed) != NYSTROM_SEED: | |
| raise ValueError(f"--seed must be {NYSTROM_SEED}") | |
| if int(args.median_max_samples) != MEDIAN_MAX_SAMPLES: | |
| raise ValueError( | |
| f"--median-max-samples must be {MEDIAN_MAX_SAMPLES}") | |
| if args.bandwidth is not None: | |
| raise ValueError( | |
| "the canonical reference requires median-estimated bandwidth") | |
| if int(args.kmeans_iterations) != KMEANS_ITERATIONS: | |
| raise ValueError( | |
| f"--kmeans-iterations must be {KMEANS_ITERATIONS}") | |
| if not math.isclose( | |
| float(args.ridge), NYSTROM_RIDGE, rel_tol=0.0, abs_tol=0.0 | |
| ): | |
| raise ValueError(f"--ridge must be {NYSTROM_RIDGE}") | |
| if int(args.chunk_size) != KERNEL_CHUNK_SIZE: | |
| raise ValueError(f"--chunk-size must be {KERNEL_CHUNK_SIZE}") | |
| if str(args.source_commit) != EXPECTED_SOURCE_COMMIT: | |
| raise ValueError( | |
| "--source-commit must pin the approved DINOv3 source commit " | |
| f"{EXPECTED_SOURCE_COMMIT}") | |
| if float(args.ridge) <= 0.0 or not math.isfinite(float(args.ridge)): | |
| raise ValueError("--ridge must be finite and positive") | |
| if args.bandwidth is not None and ( | |
| float(args.bandwidth) <= 0.0 | |
| or not math.isfinite(float(args.bandwidth)) | |
| ): | |
| raise ValueError("--bandwidth must be finite and positive") | |
| if int(args.log_every) < 0: | |
| raise ValueError("--log-every must be non-negative") | |
| def _git_head(repo_path: Path) -> str: | |
| try: | |
| result = subprocess.run( | |
| ["git", "-C", str(repo_path), "rev-parse", "HEAD"], | |
| check=True, | |
| capture_output=True, | |
| text=True, | |
| ) | |
| except (OSError, subprocess.CalledProcessError) as exc: | |
| raise RuntimeError( | |
| f"failed to inspect DINOv3 source checkout {repo_path}") from exc | |
| return result.stdout.strip() | |
| def _git_source_status(repo_path: Path) -> str: | |
| try: | |
| result = subprocess.run( | |
| [ | |
| "git", | |
| "-C", | |
| str(repo_path), | |
| "status", | |
| "--porcelain", | |
| "--untracked-files=all", | |
| ], | |
| check=True, | |
| capture_output=True, | |
| text=True, | |
| ) | |
| except (OSError, subprocess.CalledProcessError) as exc: | |
| raise RuntimeError( | |
| f"failed to inspect DINOv3 source worktree {repo_path}") from exc | |
| return result.stdout | |
| def _inspect_assets(args: argparse.Namespace) -> Dict[str, Any]: | |
| repo_path = args.repo_path.expanduser().resolve() | |
| weight_path = args.weight_path.expanduser().resolve() | |
| if not repo_path.is_dir(): | |
| raise FileNotFoundError(f"DINOv3 source directory not found: {repo_path}") | |
| if not weight_path.is_file(): | |
| raise FileNotFoundError(f"DINOv3 weight file not found: {weight_path}") | |
| source_commit = _git_head(repo_path) | |
| if source_commit != str(args.source_commit): | |
| raise ValueError( | |
| "DINOv3 source checkout commit mismatch: " | |
| f"{source_commit} != {args.source_commit}") | |
| source_status = _git_source_status(repo_path) | |
| if source_status.strip(): | |
| raise ValueError( | |
| "DINOv3 source checkout has worktree changes; refusing " | |
| "to build a reference from unpinned source") | |
| stat = weight_path.stat() | |
| return { | |
| "repo_path": str(repo_path), | |
| "weight_path": str(weight_path), | |
| "source_commit": source_commit, | |
| "weight_size_bytes": int(stat.st_size), | |
| "weight_mtime_ns": int(stat.st_mtime_ns), | |
| } | |
| def _inspect_lmdb(path: Path) -> Dict[str, Any]: | |
| try: | |
| import lmdb | |
| except ImportError as exc: | |
| raise ImportError( | |
| "python-lmdb is required; use the same Python environment as training" | |
| ) from exc | |
| from utils.lmdb import get_array_shape_from_lmdb | |
| resolved = path.expanduser().resolve() | |
| if not resolved.is_dir(): | |
| raise FileNotFoundError(f"teacher LMDB directory not found: {resolved}") | |
| env = lmdb.open( | |
| str(resolved), readonly=True, lock=False, readahead=False, meminit=False) | |
| try: | |
| latents_shape = tuple( | |
| int(value) for value in get_array_shape_from_lmdb(env, "latents")) | |
| prompts_shape = tuple( | |
| int(value) for value in get_array_shape_from_lmdb(env, "prompts")) | |
| finally: | |
| env.close() | |
| if len(latents_shape) != 6: | |
| raise ValueError( | |
| "teacher LMDB latents must be [N,trajectory,T,C,H,W], got " | |
| f"{latents_shape}") | |
| if prompts_shape != (latents_shape[0],): | |
| raise ValueError( | |
| f"teacher prompts/latents count mismatch: {prompts_shape} vs " | |
| f"{latents_shape}") | |
| data_path = resolved / "data.mdb" | |
| stat = data_path.stat() | |
| return { | |
| "path": str(resolved), | |
| "latents_shape": latents_shape, | |
| "prompts_shape": prompts_shape, | |
| "data_mdb_size_bytes": int(stat.st_size), | |
| "data_mdb_mtime_ns": int(stat.st_mtime_ns), | |
| } | |
| def _rank_indices(count: int, rank: int, world_size: int) -> range: | |
| return range(int(rank), int(count), int(world_size)) | |
| def _required_temp_bytes(count: int) -> int: | |
| feature_bytes = int(count) * TOTAL_TOKENS * FEATURE_DIM * 2 | |
| return int(math.ceil(feature_bytes * 1.15)) + 64 * MIB | |
| def _required_output_bytes() -> int: | |
| landmark_bytes = NUM_LANDMARKS * TOTAL_TOKENS * FEATURE_DIM * 4 | |
| return int(math.ceil(landmark_bytes * 1.25)) + 32 * MIB | |
| def _choose_temp_parent( | |
| requested: Optional[Path], required_bytes: int | |
| ) -> Tuple[Path, int]: | |
| candidates: Sequence[Path] = ( | |
| (requested.expanduser(),) | |
| if requested is not None | |
| else (Path("/dev/shm"), Path(tempfile.gettempdir())) | |
| ) | |
| errors = [] | |
| for candidate in candidates: | |
| try: | |
| candidate = candidate.resolve() | |
| if not candidate.is_dir(): | |
| errors.append(f"{candidate}: not a directory") | |
| continue | |
| if not os.access(candidate, os.W_OK | os.X_OK): | |
| errors.append(f"{candidate}: not writable") | |
| continue | |
| free = int(shutil.disk_usage(candidate).free) | |
| if free < required_bytes: | |
| errors.append( | |
| f"{candidate}: {free / MIB:.1f} MiB free, " | |
| f"{required_bytes / MIB:.1f} MiB required") | |
| continue | |
| return candidate, free | |
| except OSError as exc: | |
| errors.append(f"{candidate}: {exc}") | |
| raise RuntimeError( | |
| "no temporary shard directory has sufficient capacity: " | |
| + "; ".join(errors)) | |
| def _check_output( | |
| output: Path, *, required_bytes: int, overwrite: bool | |
| ) -> Dict[str, Any]: | |
| output = output.expanduser().resolve() | |
| if output.exists() and not overwrite: | |
| raise FileExistsError( | |
| f"output already exists: {output}; pass --overwrite to replace it") | |
| existing = output.parent | |
| while not existing.exists() and existing != existing.parent: | |
| existing = existing.parent | |
| if not existing.is_dir(): | |
| raise FileNotFoundError( | |
| f"no existing output parent for capacity check: {output.parent}") | |
| free = int(shutil.disk_usage(existing).free) | |
| if free < required_bytes: | |
| raise RuntimeError( | |
| f"output filesystem has only {free / MIB:.1f} MiB free; " | |
| f"{required_bytes / MIB:.1f} MiB required") | |
| return { | |
| "path": str(output), | |
| "capacity_parent": str(existing), | |
| "free_bytes": free, | |
| "required_bytes": required_bytes, | |
| } | |
| def _plan(args: argparse.Namespace, world_size: int) -> Dict[str, Any]: | |
| lmdb = _inspect_lmdb(args.teacher_lmdb) | |
| count = int(lmdb["latents_shape"][0]) | |
| if count != EXPECTED_TEACHER_COUNT: | |
| raise ValueError( | |
| "canonical DINOv3 reference requires the complete 1,537-row LMDB; " | |
| f"found {count} rows") | |
| if int(args.num_landmarks) > count: | |
| raise ValueError("number of landmarks exceeds teacher population") | |
| assets = _inspect_assets(args) | |
| temp_required = _required_temp_bytes(count) | |
| temp_parent, temp_free = _choose_temp_parent(args.tmp_dir, temp_required) | |
| output = _check_output( | |
| args.output, | |
| required_bytes=_required_output_bytes(), | |
| overwrite=bool(args.overwrite), | |
| ) | |
| return { | |
| "tool_format_version": TOOL_FORMAT_VERSION, | |
| "teacher_lmdb": lmdb, | |
| "assets": assets, | |
| "selected_samples": count, | |
| "world_size": int(world_size), | |
| "samples_per_rank": [ | |
| len(_rank_indices(count, rank, world_size)) | |
| for rank in range(world_size) | |
| ], | |
| "feature_geometry": { | |
| "source_num_frames": SOURCE_NUM_FRAMES, | |
| "frame_indices": list(FRAME_INDICES), | |
| "input_size": INPUT_SIZE, | |
| "patch_size": PATCH_SIZE, | |
| "patch_grid_size": PATCH_GRID_SIZE, | |
| "spatial_axis_indices": list(SPATIAL_AXIS_INDICES), | |
| "spatial_token_indices": list(SPATIAL_TOKEN_INDICES), | |
| "raw_tokens_per_frame": PATCH_GRID_SIZE ** 2, | |
| "per_frame_tokens": PER_FRAME_TOKENS, | |
| "num_tokens": TOTAL_TOKENS, | |
| "feature_dim": FEATURE_DIM, | |
| "sample_shape": [TOTAL_TOKENS, FEATURE_DIM], | |
| "concat_order": "frame_major_then_spatial_row_major", | |
| }, | |
| "num_landmarks": NUM_LANDMARKS, | |
| "temporary": { | |
| "parent": str(temp_parent), | |
| "required_bytes": temp_required, | |
| "free_bytes": temp_free, | |
| }, | |
| "output": output, | |
| } | |
| def _setup_distributed(timeout_minutes: int) -> Tuple[torch.device, int, int]: | |
| world_size = int(os.environ.get("WORLD_SIZE", "1")) | |
| rank = int(os.environ.get("RANK", "0")) | |
| local_rank = int(os.environ.get("LOCAL_RANK", "0")) | |
| if not torch.cuda.is_available(): | |
| raise RuntimeError( | |
| "reference extraction requires CUDA; use --dry-run on CPU") | |
| torch.cuda.set_device(local_rank) | |
| if world_size > 1: | |
| dist.init_process_group( | |
| backend="nccl", | |
| timeout=timedelta(minutes=int(timeout_minutes)), | |
| ) | |
| rank = dist.get_rank() | |
| world_size = dist.get_world_size() | |
| return torch.device("cuda", local_rank), rank, world_size | |
| def _barrier() -> None: | |
| if dist.is_available() and dist.is_initialized(): | |
| dist.barrier() | |
| def _broadcast_rank0_object(value: Any, rank: int) -> Any: | |
| if not (dist.is_available() and dist.is_initialized()): | |
| return value | |
| payload = [value if rank == 0 else None] | |
| dist.broadcast_object_list(payload, src=0) | |
| return payload[0] | |
| def _atomic_torch_save(value: Any, path: Path) -> None: | |
| temporary = path.with_name(f".{path.name}.tmp-{os.getpid()}") | |
| try: | |
| torch.save(value, temporary) | |
| os.replace(temporary, path) | |
| finally: | |
| if temporary.exists(): | |
| temporary.unlink() | |
| def _canonical_sha256(value: Dict[str, Any]) -> str: | |
| payload = json.dumps( | |
| value, | |
| sort_keys=True, | |
| separators=(",", ":"), | |
| ensure_ascii=True, | |
| allow_nan=False, | |
| ).encode("utf-8") | |
| return hashlib.sha256(payload).hexdigest() | |
| def _file_identity(path: Path) -> Dict[str, Any]: | |
| resolved = path.expanduser().resolve(strict=True) | |
| if not resolved.is_file(): | |
| raise ValueError(f"identity target is not a regular file: {resolved}") | |
| before = resolved.stat() | |
| digest = hashlib.sha256() | |
| with resolved.open("rb") as handle: | |
| while True: | |
| block = handle.read(8 << 20) | |
| if not block: | |
| break | |
| digest.update(block) | |
| after = resolved.stat() | |
| if ( | |
| int(before.st_size) != int(after.st_size) | |
| or int(before.st_mtime_ns) != int(after.st_mtime_ns) | |
| ): | |
| raise RuntimeError(f"identity target changed while hashing: {resolved}") | |
| return { | |
| "path": str(resolved), | |
| "size_bytes": int(after.st_size), | |
| "mtime_ns": int(after.st_mtime_ns), | |
| "sha256": digest.hexdigest(), | |
| } | |
| def _vae_identity() -> Dict[str, Any]: | |
| """Resolve the exact Wan decoder used before DINOv3 extraction.""" | |
| from utils.paths import model_path | |
| weights = model_path(WAN_VAE_MODEL_NAME) / "Wan2.1_VAE.pth" | |
| identity = { | |
| "wrapper": "utils.wan_wrapper.WanVAEWrapper", | |
| "wrapper_source": _file_identity(REPO_ROOT / "utils" / "wan_wrapper.py"), | |
| "model_name": WAN_VAE_MODEL_NAME, | |
| "weights": _file_identity(weights), | |
| "latent_channels": 16, | |
| "latent_mean": list(WAN_VAE_MEAN), | |
| "latent_std": list(WAN_VAE_STD), | |
| "mean_std_contract": "WanVAEWrapper.inline_constants.v1", | |
| "compute_dtype": "bfloat16", | |
| "decode_use_cache": False, | |
| "decode_output_range": "[-1,1]", | |
| } | |
| identity["identity_sha256"] = _canonical_sha256(identity) | |
| return identity | |
| def _validate_reference_current_assets( | |
| pack: Mapping[str, Any], | |
| *, | |
| repo_path: Path, | |
| weight_path: Path, | |
| teacher_lmdb: Path, | |
| ) -> Dict[str, Any]: | |
| """Require a validated reference to match every current production asset. | |
| Callers must first run ``load_reference_pack`` (which verifies schema and | |
| content hash). This second gate prevents a valid but stale pack from being | |
| accepted after the DINO checkpoint, Wan VAE, or teacher LMDB changes. | |
| """ | |
| if not isinstance(pack, Mapping): | |
| raise TypeError("reference pack must be a mapping") | |
| metadata = pack.get("metadata") | |
| if not isinstance(metadata, Mapping): | |
| raise ValueError("reference pack metadata is missing") | |
| feature = metadata.get("feature") | |
| reference = metadata.get("reference") | |
| if not isinstance(feature, Mapping) or not isinstance(reference, Mapping): | |
| raise ValueError("reference feature/source metadata is missing") | |
| source = reference.get("source") | |
| saved_vae = reference.get("vae") | |
| if not isinstance(source, Mapping) or not isinstance(saved_vae, Mapping): | |
| raise ValueError("reference source or Wan VAE identity is missing") | |
| from video_fd.encoders.dinov3_dense_metadata import file_sha256 | |
| resolved_repo = repo_path.expanduser().resolve(strict=True) | |
| resolved_weight = weight_path.expanduser().resolve(strict=True) | |
| current_weight_sha256 = file_sha256(resolved_weight) | |
| expected_feature_identity = { | |
| "repo_path": str(resolved_repo), | |
| "weight_path": str(resolved_weight), | |
| "weight_sha256": current_weight_sha256, | |
| } | |
| feature_mismatches = { | |
| key: {"saved": feature.get(key), "current": value} | |
| for key, value in expected_feature_identity.items() | |
| if feature.get(key) != value | |
| } | |
| if feature_mismatches: | |
| raise ValueError( | |
| "reference DINOv3 asset identity does not match current assets: " | |
| f"{feature_mismatches}") | |
| current_vae = _vae_identity() | |
| if dict(saved_vae) != current_vae: | |
| raise ValueError( | |
| "reference Wan VAE identity does not match current assets") | |
| current_lmdb = _inspect_lmdb(teacher_lmdb) | |
| expected_source_identity = { | |
| "lmdb_path": current_lmdb["path"], | |
| "latents_shape": list(current_lmdb["latents_shape"]), | |
| "prompts_shape": list(current_lmdb["prompts_shape"]), | |
| "selected_samples": int(current_lmdb["latents_shape"][0]), | |
| "data_mdb_size_bytes": int(current_lmdb["data_mdb_size_bytes"]), | |
| "data_mdb_mtime_ns": int(current_lmdb["data_mdb_mtime_ns"]), | |
| } | |
| source_mismatches = { | |
| key: {"saved": source.get(key), "current": value} | |
| for key, value in expected_source_identity.items() | |
| if source.get(key) != value | |
| } | |
| if source_mismatches: | |
| raise ValueError( | |
| "reference teacher LMDB identity does not match current assets: " | |
| f"{source_mismatches}") | |
| return { | |
| "dinov3_weight_sha256": current_weight_sha256, | |
| "vae_identity_sha256": current_vae["identity_sha256"], | |
| "teacher_lmdb": current_lmdb, | |
| } | |
| def _prompt_entry_digest(index: int, prompt: str) -> bytes: | |
| digest = hashlib.sha256() | |
| digest.update(int(index).to_bytes(8, byteorder="little", signed=False)) | |
| digest.update(b"\0") | |
| digest.update(str(prompt).encode("utf-8")) | |
| return digest.digest() | |
| def _load_dense_encoder(args: argparse.Namespace, device: torch.device): | |
| """The sole runtime boundary with the separately-owned DINOv3 adapter.""" | |
| from video_fd.encoders.dinov3_adapter import DINOv3DenseAdapter | |
| encoder = DINOv3DenseAdapter({ | |
| "name": "dinov3_dense", | |
| "repo_path": str(args.repo_path.expanduser().resolve()), | |
| "weight_path": str(args.weight_path.expanduser().resolve()), | |
| "source_commit": str(args.source_commit), | |
| "source_num_frames": SOURCE_NUM_FRAMES, | |
| "frame_indices": list(FRAME_INDICES), | |
| "input_size": INPUT_SIZE, | |
| "patch_size": PATCH_SIZE, | |
| "patch_grid_size": PATCH_GRID_SIZE, | |
| "spatial_axis_indices": list(SPATIAL_AXIS_INDICES), | |
| "forward_chunk_frames": int(args.forward_chunk_frames), | |
| "compute_dtype": "float32", | |
| }) | |
| return encoder.to(device=device, dtype=torch.float32).eval().requires_grad_(False) | |
| def _extract_rank_shard( | |
| args: argparse.Namespace, | |
| plan: Dict[str, Any], | |
| *, | |
| device: torch.device, | |
| rank: int, | |
| world_size: int, | |
| shard_path: Path, | |
| vae_identity: Dict[str, Any], | |
| ) -> None: | |
| from utils.dataset import ODERegressionLMDBDataset | |
| from utils.wan_wrapper import WanVAEWrapper | |
| selected_count = int(plan["selected_samples"]) | |
| assigned = list(_rank_indices(selected_count, rank, world_size)) | |
| dataset = ODERegressionLMDBDataset( | |
| str(args.teacher_lmdb.expanduser().resolve()), max_pair=selected_count) | |
| if len(dataset) != selected_count: | |
| raise RuntimeError( | |
| f"LMDB length changed after planning: {len(dataset)} != " | |
| f"{selected_count}") | |
| vae = ( | |
| WanVAEWrapper() | |
| .to(device=device, dtype=torch.bfloat16) | |
| .eval() | |
| .requires_grad_(False) | |
| ) | |
| if not torch.equal(vae.mean, torch.tensor(WAN_VAE_MEAN)): | |
| raise RuntimeError("WanVAEWrapper latent mean changed from the reference contract") | |
| if not torch.equal(vae.std, torch.tensor(WAN_VAE_STD)): | |
| raise RuntimeError("WanVAEWrapper latent std changed from the reference contract") | |
| encoder = _load_dense_encoder(args, device) | |
| feature_metadata = encoder.feature_metadata() | |
| if not isinstance(feature_metadata, dict): | |
| raise TypeError("DINOv3 adapter feature_metadata() must return a dict") | |
| spatial_indices = torch.tensor( | |
| SPATIAL_TOKEN_INDICES, device=device, dtype=torch.long) | |
| feature_chunks = [] | |
| index_chunks = [] | |
| prompt_digests = [] | |
| expected_tail = tuple(plan["teacher_lmdb"]["latents_shape"][1:]) | |
| started = time.monotonic() | |
| for offset in range(0, len(assigned), int(args.batch_size)): | |
| batch_indices = assigned[offset:offset + int(args.batch_size)] | |
| items = [dataset[index] for index in batch_indices] | |
| trajectories = [item["ode_latent"] for item in items] | |
| for index, trajectory in zip(batch_indices, trajectories): | |
| if tuple(trajectory.shape) != expected_tail: | |
| raise ValueError( | |
| f"LMDB row {index} shape {tuple(trajectory.shape)} != " | |
| f"{expected_tail}") | |
| if not bool(torch.isfinite(trajectory).all().item()): | |
| raise FloatingPointError( | |
| f"LMDB row {index} contains non-finite latents") | |
| latent = torch.stack( | |
| [trajectory[-1] for trajectory in trajectories], dim=0 | |
| ).to(device=device, dtype=torch.bfloat16) | |
| pixels = vae.decode_to_pixel(latent.detach()) | |
| video01 = ((pixels + 1.0) * 0.5).clamp(0.0, 1.0) | |
| if ( | |
| video01.ndim != 5 | |
| or int(video01.shape[1]) != SOURCE_NUM_FRAMES | |
| or int(video01.shape[2]) != 3 | |
| ): | |
| raise ValueError( | |
| "Wan VAE must decode [B,81,3,H,W], got " | |
| f"{tuple(video01.shape)}") | |
| features = encoder.forward_dense( | |
| video01, | |
| token_indices=spatial_indices, | |
| gradient_checkpointing=False, | |
| ).float() | |
| expected_shape = (len(batch_indices), TOTAL_TOKENS, FEATURE_DIM) | |
| if tuple(features.shape) != expected_shape: | |
| raise RuntimeError( | |
| f"DINOv3 features {tuple(features.shape)} != {expected_shape}") | |
| if not bool(torch.isfinite(features).all().item()): | |
| raise FloatingPointError( | |
| f"non-finite DINOv3 features for indices {batch_indices}") | |
| features_fp16 = features.to(dtype=torch.float16, device="cpu") | |
| if not bool(torch.isfinite(features_fp16).all().item()): | |
| raise FloatingPointError( | |
| f"FP16 conversion overflowed for indices {batch_indices}") | |
| feature_chunks.append(features_fp16) | |
| index_chunks.append(torch.tensor(batch_indices, dtype=torch.long)) | |
| prompt_digests.extend( | |
| _prompt_entry_digest(index, item["prompts"]) | |
| for index, item in zip(batch_indices, items) | |
| ) | |
| del latent, pixels, video01, features, features_fp16, items, trajectories | |
| completed = min(offset + len(batch_indices), len(assigned)) | |
| if int(args.log_every) > 0 and ( | |
| completed == len(assigned) or completed % int(args.log_every) == 0 | |
| ): | |
| print( | |
| f"[extract rank {rank}] {completed}/{len(assigned)} " | |
| f"({time.monotonic() - started:.1f}s)", | |
| flush=True, | |
| ) | |
| if feature_chunks: | |
| shard_features = torch.cat(feature_chunks, dim=0).contiguous() | |
| shard_indices = torch.cat(index_chunks, dim=0).contiguous() | |
| digest_tensor = torch.tensor( | |
| [list(value) for value in prompt_digests], dtype=torch.uint8) | |
| else: | |
| shard_features = torch.empty( | |
| 0, TOTAL_TOKENS, FEATURE_DIM, dtype=torch.float16) | |
| shard_indices = torch.empty(0, dtype=torch.long) | |
| digest_tensor = torch.empty(0, 32, dtype=torch.uint8) | |
| payload = { | |
| "shard_format_version": TOOL_FORMAT_VERSION, | |
| "rank": int(rank), | |
| "world_size": int(world_size), | |
| "indices": shard_indices, | |
| "features": shard_features, | |
| "prompt_entry_sha256": digest_tensor, | |
| "sample_shape": [TOTAL_TOKENS, FEATURE_DIM], | |
| "feature_dtype": "float16", | |
| "feature_metadata": feature_metadata, | |
| "vae_identity": vae_identity, | |
| } | |
| _atomic_torch_save(payload, shard_path) | |
| print( | |
| f"[extract rank {rank}] wrote {shard_path} " | |
| f"{tuple(shard_features.shape)}", | |
| flush=True, | |
| ) | |
| del encoder, vae, dataset, payload, feature_chunks, shard_features | |
| gc.collect() | |
| torch.cuda.empty_cache() | |
| def _load_and_merge_shards( | |
| shard_dir: Path, | |
| *, | |
| world_size: int, | |
| selected_count: int, | |
| sample_shape: Sequence[int], | |
| ) -> Tuple[torch.Tensor, str, str, Dict[str, Any], Dict[str, Any]]: | |
| feature_parts = [] | |
| index_parts = [] | |
| digest_parts = [] | |
| feature_metadata = None | |
| vae_identity = None | |
| expected_tail = tuple(int(value) for value in sample_shape) | |
| for rank in range(int(world_size)): | |
| path = shard_dir / f"rank_{rank:05d}.pt" | |
| if not path.is_file(): | |
| raise FileNotFoundError(f"missing rank shard: {path}") | |
| payload = torch.load(path, map_location="cpu", weights_only=False) | |
| if int(payload.get("shard_format_version", -1)) != TOOL_FORMAT_VERSION: | |
| raise ValueError(f"incompatible shard format in {path}") | |
| if int(payload.get("rank", -1)) != rank: | |
| raise ValueError(f"rank identity mismatch in {path}") | |
| if int(payload.get("world_size", -1)) != int(world_size): | |
| raise ValueError(f"world-size mismatch in {path}") | |
| features = payload.get("features") | |
| indices = payload.get("indices") | |
| digests = payload.get("prompt_entry_sha256") | |
| shard_feature_metadata = payload.get("feature_metadata") | |
| shard_vae_identity = payload.get("vae_identity") | |
| if ( | |
| not isinstance(features, torch.Tensor) | |
| or features.dtype != torch.float16 | |
| or features.ndim != 3 | |
| or tuple(features.shape[1:]) != expected_tail | |
| or not bool(torch.isfinite(features).all().item()) | |
| ): | |
| raise ValueError(f"invalid FP16 feature shard {path}") | |
| if ( | |
| not isinstance(indices, torch.Tensor) | |
| or indices.dtype != torch.long | |
| or tuple(indices.shape) != (features.shape[0],) | |
| ): | |
| raise ValueError(f"invalid indices in {path}") | |
| if ( | |
| not isinstance(digests, torch.Tensor) | |
| or digests.dtype != torch.uint8 | |
| or tuple(digests.shape) != (features.shape[0], 32) | |
| ): | |
| raise ValueError(f"invalid prompt hashes in {path}") | |
| if not isinstance(shard_feature_metadata, dict): | |
| raise ValueError(f"missing DINOv3 feature metadata in {path}") | |
| if feature_metadata is None: | |
| feature_metadata = shard_feature_metadata | |
| elif shard_feature_metadata != feature_metadata: | |
| raise ValueError( | |
| f"DINOv3 feature metadata differs across rank shards: {path}") | |
| if not isinstance(shard_vae_identity, dict): | |
| raise ValueError(f"missing Wan VAE identity in {path}") | |
| if vae_identity is None: | |
| vae_identity = shard_vae_identity | |
| elif shard_vae_identity != vae_identity: | |
| raise ValueError( | |
| f"Wan VAE identity differs across rank shards: {path}") | |
| feature_parts.append(features) | |
| index_parts.append(indices) | |
| digest_parts.append(digests) | |
| features = torch.cat(feature_parts, dim=0) | |
| indices = torch.cat(index_parts, dim=0) | |
| digests = torch.cat(digest_parts, dim=0) | |
| if int(features.shape[0]) != int(selected_count): | |
| raise ValueError( | |
| f"rank shards contain {features.shape[0]} samples, expected " | |
| f"{selected_count}") | |
| order = torch.argsort(indices, stable=True) | |
| indices = indices.index_select(0, order) | |
| if not torch.equal(indices, torch.arange(selected_count, dtype=torch.long)): | |
| raise ValueError( | |
| "rank shards do not cover every selected LMDB index exactly once") | |
| features = features.index_select(0, order).contiguous() | |
| digests = digests.index_select(0, order).contiguous() | |
| prompt_hash = hashlib.sha256(digests.numpy().tobytes()).hexdigest() | |
| feature_hash = hashlib.sha256( | |
| features.view(torch.uint8).numpy().tobytes()).hexdigest() | |
| if feature_metadata is None: | |
| raise ValueError("rank shards contained no DINOv3 feature metadata") | |
| if vae_identity is None: | |
| raise ValueError("rank shards contained no Wan VAE identity") | |
| return features, prompt_hash, feature_hash, feature_metadata, vae_identity | |
| def _validate_feature_metadata( | |
| args: argparse.Namespace, | |
| feature_metadata: Dict[str, Any], | |
| ) -> Dict[str, Any]: | |
| """Rebuild the canonical schema and reject even consistent bad shards.""" | |
| from video_fd.encoders.dinov3_dense_metadata import ( | |
| canonical_dinov3_dense_feature_metadata, | |
| file_sha256, | |
| ) | |
| repo_path = args.repo_path.expanduser().resolve() | |
| if _git_head(repo_path) != str(args.source_commit): | |
| raise RuntimeError("DINOv3 source commit changed during extraction") | |
| if _git_source_status(repo_path).strip(): | |
| raise RuntimeError("DINOv3 source worktree changed during extraction") | |
| current_weight_sha256 = file_sha256(args.weight_path) | |
| expected = canonical_dinov3_dense_feature_metadata( | |
| repo_path=str(repo_path), | |
| weight_path=str(args.weight_path.expanduser().resolve()), | |
| source_commit=str(args.source_commit), | |
| weight_sha256=current_weight_sha256, | |
| source_num_frames=SOURCE_NUM_FRAMES, | |
| frame_indices=list(FRAME_INDICES), | |
| input_size=INPUT_SIZE, | |
| patch_size=PATCH_SIZE, | |
| patch_grid_size=PATCH_GRID_SIZE, | |
| spatial_axis_indices=list(SPATIAL_AXIS_INDICES), | |
| spatial_token_indices=list(SPATIAL_TOKEN_INDICES), | |
| per_frame_tokens=PER_FRAME_TOKENS, | |
| num_tokens=TOTAL_TOKENS, | |
| forward_chunk_frames=FORWARD_CHUNK_FRAMES, | |
| feature_dim=FEATURE_DIM, | |
| ) | |
| if feature_metadata != expected: | |
| raise ValueError( | |
| "rank-shard DINOv3 metadata does not equal the canonical schema") | |
| return expected | |
| def _reference_metadata( | |
| args: argparse.Namespace, | |
| plan: Dict[str, Any], | |
| *, | |
| feature_metadata: Dict[str, Any], | |
| vae_identity: Dict[str, Any], | |
| prompt_index_hash: str, | |
| feature_bank_hash: str, | |
| ) -> Dict[str, Any]: | |
| feature_metadata = _validate_feature_metadata(args, feature_metadata) | |
| if vae_identity != _vae_identity(): | |
| raise RuntimeError( | |
| "Wan VAE asset or wrapper changed during teacher extraction") | |
| data_mdb = Path(plan["teacher_lmdb"]["path"]) / "data.mdb" | |
| data_stat = data_mdb.stat() | |
| if ( | |
| int(data_stat.st_size) | |
| != int(plan["teacher_lmdb"]["data_mdb_size_bytes"]) | |
| or int(data_stat.st_mtime_ns) | |
| != int(plan["teacher_lmdb"]["data_mdb_mtime_ns"]) | |
| ): | |
| raise RuntimeError("teacher LMDB changed during DINOv3 extraction") | |
| source = { | |
| "kind": "causvid_ode_teacher_lmdb_final_latent", | |
| "lmdb_path": plan["teacher_lmdb"]["path"], | |
| "latents_shape": list(plan["teacher_lmdb"]["latents_shape"]), | |
| "prompts_shape": list(plan["teacher_lmdb"]["prompts_shape"]), | |
| "selected_samples": EXPECTED_TEACHER_COUNT, | |
| "selected_index_start": 0, | |
| "selected_index_stop_exclusive": EXPECTED_TEACHER_COUNT, | |
| "trajectory_index": -1, | |
| "lmdb_storage_dtype": "float16", | |
| "data_mdb_size_bytes": int( | |
| plan["teacher_lmdb"]["data_mdb_size_bytes"]), | |
| "data_mdb_mtime_ns": int( | |
| plan["teacher_lmdb"]["data_mdb_mtime_ns"]), | |
| "prompt_index_sha256": prompt_index_hash, | |
| "feature_bank_fp16_sha256": feature_bank_hash, | |
| } | |
| source["identity_sha256"] = _canonical_sha256(source) | |
| return { | |
| "feature": feature_metadata, | |
| "reference": { | |
| "source": source, | |
| "vae": vae_identity, | |
| "extraction": { | |
| "tool": "tools/precompute_dinov3_dense_nystrom_reference.py", | |
| "tool_format_version": TOOL_FORMAT_VERSION, | |
| "world_size": int(plan["world_size"]), | |
| "vae_compute_dtype": "bfloat16", | |
| "vae_decode_use_cache": False, | |
| "decoded_pixel_transform": "((pixels+1)*0.5).clamp(0,1)", | |
| "dinov3_compute_dtype": "float32", | |
| "forward_chunk_frames": FORWARD_CHUNK_FRAMES, | |
| "rank_shard_dtype": "float16", | |
| }, | |
| "build_request": { | |
| "num_landmarks": NUM_LANDMARKS, | |
| "seed": NYSTROM_SEED, | |
| "bandwidth": ( | |
| None if args.bandwidth is None else float(args.bandwidth)), | |
| "median_max_samples": int(args.median_max_samples), | |
| "kmeans_iterations": int(args.kmeans_iterations), | |
| "ridge": float(args.ridge), | |
| "chunk_size": int(args.chunk_size), | |
| }, | |
| }, | |
| } | |
| def _build_and_save_reference( | |
| args: argparse.Namespace, | |
| plan: Dict[str, Any], | |
| shard_dir: Path, | |
| *, | |
| device: torch.device, | |
| ) -> Dict[str, Any]: | |
| from losses.video_nystrom_mmd import ( | |
| build_video_nystrom_reference, | |
| load_reference_pack, | |
| save_reference_pack, | |
| validate_reference_pack, | |
| ) | |
| features, prompt_hash, feature_hash, feature_metadata, vae_identity = ( | |
| _load_and_merge_shards( | |
| shard_dir, | |
| world_size=int(plan["world_size"]), | |
| selected_count=EXPECTED_TEACHER_COUNT, | |
| sample_shape=(TOTAL_TOKENS, FEATURE_DIM), | |
| ) | |
| ) | |
| metadata = _reference_metadata( | |
| args, | |
| plan, | |
| feature_metadata=feature_metadata, | |
| vae_identity=vae_identity, | |
| prompt_index_hash=prompt_hash, | |
| feature_bank_hash=feature_hash, | |
| ) | |
| print( | |
| f"[merge] building m={NUM_LANDMARKS} reference from " | |
| f"{tuple(features.shape)} FP16 matrices on {device}", | |
| flush=True, | |
| ) | |
| reference = features.to(device=device, non_blocking=False) | |
| pack = build_video_nystrom_reference( | |
| reference, | |
| num_landmarks=NUM_LANDMARKS, | |
| metadata=metadata, | |
| bandwidth=args.bandwidth, | |
| median_max_samples=int(args.median_max_samples), | |
| kmeans_iterations=int(args.kmeans_iterations), | |
| ridge=float(args.ridge), | |
| chunk_size=int(args.chunk_size), | |
| seed=NYSTROM_SEED, | |
| ) | |
| validate_reference_pack(pack) | |
| del reference | |
| torch.cuda.empty_cache() | |
| output = args.output.expanduser().resolve() | |
| output.parent.mkdir(parents=True, exist_ok=True) | |
| temporary = output.with_name(f".{output.name}.tmp-{os.getpid()}") | |
| try: | |
| save_reference_pack(pack, temporary) | |
| staged = load_reference_pack(temporary, map_location="cpu") | |
| validate_reference_pack(staged) | |
| if output.exists() and not bool(args.overwrite): | |
| raise FileExistsError( | |
| f"output appeared during construction: {output}") | |
| os.replace(temporary, output) | |
| finally: | |
| if temporary.exists(): | |
| temporary.unlink() | |
| # This final-path reload is the gate for temporary-shard deletion. | |
| published = load_reference_pack(output, map_location="cpu") | |
| validate_reference_pack(published) | |
| _validate_published_pack_identity(pack, published) | |
| return { | |
| "output": str(output), | |
| "samples": int(features.shape[0]), | |
| "sample_shape": list(features.shape[1:]), | |
| "num_landmarks": int(pack["landmarks"].shape[0]), | |
| "sigma": float(torch.as_tensor(pack["sigma"]).item()), | |
| "content_hash": str(pack["content_hash"]), | |
| "prompt_index_sha256": prompt_hash, | |
| "feature_bank_fp16_sha256": feature_hash, | |
| "final_path_validated": True, | |
| } | |
| def _validate_published_pack_identity( | |
| pack: Mapping[str, Any], | |
| published: Mapping[str, Any], | |
| ) -> None: | |
| """Require the final-path reload to preserve the built pack identity.""" | |
| if published.get("content_hash") != pack.get("content_hash"): | |
| raise ValueError("published reference content hash changed after rename") | |
| # The builder canonicalizes user metadata and adds its reserved ``nystrom`` | |
| # block. Compare against that exact pack payload, not the pre-build input. | |
| if published.get("metadata") != pack.get("metadata"): | |
| raise ValueError("published reference metadata changed after rename") | |
| def _remove_validated_shards( | |
| shard_dir: Path, | |
| build_summary: Dict[str, Any], | |
| ) -> None: | |
| """Delete shards only with the explicit final-path validation receipt.""" | |
| if build_summary.get("final_path_validated") is not True: | |
| raise RuntimeError( | |
| "refusing to delete shards before final reference validation") | |
| output = Path(str(build_summary.get("output", ""))).expanduser().resolve() | |
| if not output.is_file(): | |
| raise FileNotFoundError( | |
| f"refusing to delete shards; published reference is missing: {output}") | |
| shutil.rmtree(shard_dir) | |
| def _run(args: argparse.Namespace) -> None: | |
| _validate_args(args) | |
| env_world_size = int(os.environ.get("WORLD_SIZE", "1")) | |
| env_rank = int(os.environ.get("RANK", "0")) | |
| plan = _plan(args, env_world_size) | |
| if bool(args.dry_run): | |
| if env_rank == 0: | |
| print(json.dumps(plan, indent=2, sort_keys=True), flush=True) | |
| return | |
| device, rank, world_size = _setup_distributed( | |
| int(args.distributed_timeout_minutes)) | |
| if world_size != int(plan["world_size"]): | |
| raise RuntimeError( | |
| f"world size changed after planning: {world_size} != " | |
| f"{plan['world_size']}") | |
| shard_dir = None | |
| success = False | |
| validated_summary = None | |
| try: | |
| vae_result = None | |
| if rank == 0: | |
| try: | |
| vae_result = {"identity": _vae_identity(), "error": None} | |
| except Exception as exc: | |
| vae_result = { | |
| "identity": None, | |
| "error": f"{type(exc).__name__}: {exc}", | |
| } | |
| vae_result = _broadcast_rank0_object(vae_result, rank) | |
| if vae_result["error"] is not None: | |
| raise RuntimeError( | |
| "rank 0 could not resolve the Wan VAE identity: " | |
| f"{vae_result['error']}") | |
| vae_identity = vae_result["identity"] | |
| temp_result = None | |
| if rank == 0: | |
| try: | |
| created = Path(tempfile.mkdtemp( | |
| prefix="dinov3_dense_nystrom_", | |
| dir=Path(plan["temporary"]["parent"]), | |
| )) | |
| temp_result = {"path": str(created), "error": None} | |
| except Exception as exc: | |
| temp_result = { | |
| "path": None, | |
| "error": f"{type(exc).__name__}: {exc}", | |
| } | |
| temp_result = _broadcast_rank0_object(temp_result, rank) | |
| if temp_result["error"] is not None: | |
| raise RuntimeError( | |
| "rank 0 could not create shard directory: " | |
| f"{temp_result['error']}") | |
| shard_dir = Path(temp_result["path"]) | |
| _extract_rank_shard( | |
| args, | |
| plan, | |
| device=device, | |
| rank=rank, | |
| world_size=world_size, | |
| shard_path=shard_dir / f"rank_{rank:05d}.pt", | |
| vae_identity=vae_identity, | |
| ) | |
| _barrier() | |
| summary = None | |
| build_error = None | |
| if rank == 0: | |
| try: | |
| summary = _build_and_save_reference( | |
| args, plan, shard_dir, device=device) | |
| except Exception as exc: | |
| import traceback | |
| traceback.print_exc() | |
| build_error = f"{type(exc).__name__}: {exc}" | |
| outcome = _broadcast_rank0_object( | |
| {"summary": summary, "error": build_error}, rank) | |
| if outcome["error"] is not None: | |
| raise RuntimeError( | |
| f"rank 0 reference construction failed: {outcome['error']}") | |
| _barrier() | |
| validated_summary = outcome["summary"] | |
| success = True | |
| if rank == 0: | |
| print(json.dumps( | |
| {"status": "ok", **outcome["summary"]}, | |
| indent=2, | |
| sort_keys=True, | |
| ), flush=True) | |
| finally: | |
| if rank == 0 and shard_dir is not None: | |
| if success: | |
| _remove_validated_shards(shard_dir, validated_summary) | |
| print( | |
| f"[cleanup] removed validated temporary shards {shard_dir}", | |
| flush=True, | |
| ) | |
| else: | |
| print( | |
| f"[cleanup] preserving failed-run shards at {shard_dir}", | |
| flush=True, | |
| ) | |
| if dist.is_available() and dist.is_initialized(): | |
| dist.destroy_process_group() | |
| def main(argv: Optional[Iterable[str]] = None) -> None: | |
| _run(build_parser().parse_args(argv)) | |
| if __name__ == "__main__": | |
| main() | |