# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: OpenMDW-1.1 import importlib import os import os.path as osp import pathlib import re import sys import time from collections.abc import Iterator from contextlib import ExitStack, contextmanager from enum import IntEnum from typing import Any, Optional import torch import torch.distributed as dist import torch.distributed.checkpoint as dcp try: from filelock import SoftReadWriteLock except ImportError: # Older filelock versions in some inference containers. try: from filelock import ReadWriteLock as SoftReadWriteLock except ImportError: from filelock import FileLock class SoftReadWriteLock: """Compatibility adapter for filelock versions without read/write locks.""" def __init__(self, *args: Any, **kwargs: Any) -> None: self._lock = FileLock(*args, **kwargs) def write_lock(self) -> FileLock: return self._lock from torch.distributed.checkpoint.filesystem import FileSystemReader, FileSystemWriter from cosmos_framework.checkpoint.s3_filesystem import S3StorageReader from cosmos_framework.utils.lazy_config import instantiate from cosmos_framework.utils import log, misc from cosmos_framework.utils.config_helper import get_config_module, override from cosmos_framework.utils.easy_io import easy_io from cosmos_framework.checkpoint.dcp import CustomLoadPlanner, CustomSavePlanner, ModelWrapper from cosmos_framework.configs.base.defaults.quantization import QuantizationConfig from cosmos_framework.model.generator.utils.safetensors_loader import load_vfm_model from cosmos_framework.utils.generator.quantization import apply_quantization_inplace ################################################### # below are the load_model function for inference # ################################################### # Thus these load_model functions are designed with less dependency. def checkpoint_path_to_cached_path(path: str, cache_rootdir: Optional[str] = None) -> str: if cache_rootdir is None: homedir = os.getenv("HOME") or "" cache_rootdir = osp.join(homedir, ".cache/imaginaire4/checkpoints/") if path.startswith("s3://"): return osp.join(cache_rootdir, path.removeprefix("s3://").split("/", maxsplit=1)[1]) else: return path def _is_safetensors_checkpoint(checkpoint_path: str, credential_path: str | None) -> bool: """Return True if ``checkpoint_path`` is a directory containing any ``*.safetensors`` shard. Probes the path (local or ``s3://`` / ``gs://``) via ``easy_io`` and short-circuits on the first ``.safetensors`` entry, so the cost is O(1) listing calls regardless of shard count. Returns False for DCP checkpoints (which have ``.metadata`` + ``*.distcp`` files but no ``.safetensors``), for non-directory paths, and for any path where the listing call raises (treated as "definitely not safetensors" so the caller falls through to the legacy DCP path). """ if checkpoint_path.startswith("s3://"): backend_args: dict[str, Any] | None = { "backend": "s3", "s3_credential_path": credential_path or "", } else: backend_args = None try: listing = easy_io.list_dir_or_file( checkpoint_path, list_dir=False, list_file=True, suffix="safetensors", recursive=False, backend_args=backend_args, ) return next(iter(listing), None) is not None except Exception: return False def _is_checkpoint_cache_ready(checkpoint_path: str) -> bool: """Return True when FileSystemWriter has published its completion metadata.""" return osp.isfile(osp.join(checkpoint_path, ".metadata")) def _install_pathlib_pickle_compat() -> None: """Load DCP metadata written by Python versions that use ``pathlib._local``.""" sys.modules.setdefault("pathlib._local", pathlib) class _CheckpointCacheAction(IntEnum): LOAD_CACHE = 0 POPULATE_CACHE = 1 ERROR = 2 def _is_distributed_initialized() -> bool: return dist.is_available() and dist.is_initialized() def _dist_backend_device() -> torch.device: backend = str(dist.get_backend()).lower() if backend.endswith("nccl"): return torch.device("cuda", torch.cuda.current_device()) else: return torch.device("cpu") def _get_rank0_action(action: _CheckpointCacheAction) -> _CheckpointCacheAction: if not _is_distributed_initialized(): return action action_tensor = torch.tensor(int(action), dtype=torch.int64, device=_dist_backend_device()) # [] dist.broadcast(action_tensor, src=0) # [] return _CheckpointCacheAction(int(action_tensor.item())) def _resolve_checkpoint_cache_action( checkpoint_cache_path: str, cache_lock_path: str, exit_stack: ExitStack, ) -> _CheckpointCacheAction: assert (not _is_distributed_initialized()) or (dist.get_rank() == 0), ( "Only rank 0 should resolve checkpoint cache action" ) if _is_checkpoint_cache_ready(checkpoint_cache_path): return _CheckpointCacheAction.LOAD_CACHE cache_lock_parent = osp.dirname(cache_lock_path) if cache_lock_parent: os.makedirs(cache_lock_parent, exist_ok=True) try: cache_lock = SoftReadWriteLock( cache_lock_path, heartbeat_interval=60, stale_threshold=3 * 60, poll_interval=1, ) except TypeError: cache_lock = SoftReadWriteLock(cache_lock_path) exit_stack.enter_context(cache_lock.write_lock()) # Re-check after waiting on the inter-process lock. if _is_checkpoint_cache_ready(checkpoint_cache_path): return _CheckpointCacheAction.LOAD_CACHE return _CheckpointCacheAction.POPULATE_CACHE @contextmanager def _checkpoint_cache_group_lock( checkpoint_cache_path: str, cache_lock_path: str, ) -> Iterator[_CheckpointCacheAction]: """Coordinate checkpoint cache population across distributed ranks.""" action = _CheckpointCacheAction.ERROR rank0_error: Exception | None = None with ExitStack() as exit_stack: if not _is_distributed_initialized() or dist.get_rank() == 0: try: action = _resolve_checkpoint_cache_action(checkpoint_cache_path, cache_lock_path, exit_stack) except Exception as error: rank0_error = error action = _CheckpointCacheAction.ERROR action = _get_rank0_action(action) if action == _CheckpointCacheAction.ERROR: if rank0_error is not None: raise rank0_error raise RuntimeError("Rank 0 failed to resolve checkpoint cache action.") yield action def _reload_pretrained_reasoner_after_checkpoint_load(model: torch.nn.Module) -> None: """Re-seed the reasoner pathway after a DCP load, mirroring the LoadPretrained callback that runs during training (inference does not run training callbacks). The decision is delegated entirely to the model's own gate in ``load_pretrained_model_if_needed``: this is a no-op unless the model was built with ``exclude_reasoner_weights_from_checkpoint=True`` (and pretrained weights enabled), i.e. the case where the DCP checkpoint deliberately omits the reasoner tower so it must be re-seeded from the pretrained source. For a normal checkpoint that already contains the reasoner, the model's gate evaluates to False and nothing is reloaded. ``has_resumable_checkpoint=True`` / ``has_load_path=False`` is load-bearing: it re-seeds the reasoner from the pretrained source while skipping the understanding->generation copy (the generation pathway was already populated by the DCP load). Passing ``has_load_path=True`` would instead force a reasoner reload even for non-excluded checkpoints, clobbering any fine-tuned reasoner weights restored from the DCP. """ load_pretrained_model_if_needed = getattr(model, "load_pretrained_model_if_needed") load_pretrained_model_if_needed( has_resumable_checkpoint=True, has_load_path=False, ) def _load_model( model: torch.nn.Module, checkpoint_path: str, credential_path: str | None, enable_gcs_patch_in_boto3: bool = False, load_ema_to_reg: bool = False, keys_to_skip_loading: list[str] | None = None, ) -> None: """ Args: model: The model to load weights into checkpoint_path: Path to checkpoint (can be s3 or local path) credential_path: Path to S3 credentials (can be none if load local) enable_gcs_patch_in_boto3: Whether to enable GCS patch in boto3 for DCP loading from GCS load_ema_to_reg: Whether to load EMA weights into the regular (non-EMA) model parameters. keys_to_skip_loading: List of key substrings to skip when loading from checkpoint. Useful for loading pretrained checkpoints that are missing certain keys (e.g. action heads). """ log.info(f"Loading model from {checkpoint_path}") start_time = time.time() state_dict = ModelWrapper(model).state_dict() if any(key.startswith("net_teacher.") for key in state_dict): log.info("Dropping net_teacher.* keys from inference load target; distillation checkpoints do not save them.") state_dict = {key: value for key, value in state_dict.items() if not key.startswith("net_teacher.")} _install_pathlib_pickle_compat() if checkpoint_path.startswith("s3://"): storage_reader = S3StorageReader( credential_path=credential_path or "", path=checkpoint_path, enable_gcs_patch_in_boto3=enable_gcs_patch_in_boto3, ) else: storage_reader = FileSystemReader(checkpoint_path) load_planner = CustomLoadPlanner( load_ema_to_reg=load_ema_to_reg, keys_to_skip_loading=keys_to_skip_loading or [], ) dcp.load( state_dict=state_dict, storage_reader=storage_reader, planner=load_planner, ) log.info(f"Successfully loaded model from {checkpoint_path}") log.info(f"Time taken to load model: {time.time() - start_time:.2f} seconds") def _save_model( model: torch.nn.Module, checkpoint_path: str, save_reg_to_ema: bool = False, ) -> None: """ Args: model: The model to load weights into checkpoint_path: Path to cached checkpoint (can be s3 or local path) save_reg_to_ema: Whether to save regular (non-EMA) model parameters to EMA model parameters. """ log.info(f"Saving model to {checkpoint_path}") start_time = time.time() state_dict = ModelWrapper(model).state_dict() assert not checkpoint_path.startswith("s3://"), "Cached checkpoint path must be local path" storage_writer = FileSystemWriter(checkpoint_path) save_planner = CustomSavePlanner(save_reg_to_ema=save_reg_to_ema, dedup_save_to_lowest_rank=True) dcp.save( state_dict=state_dict, storage_writer=storage_writer, planner=save_planner, ) log.info(f"Successfully saved model to {checkpoint_path}") log.info(f"Time taken to save model: {time.time() - start_time:.2f} seconds") def load_model_from_checkpoint( experiment_name: str, checkpoint_path: Optional[str] = None, credential_path: Optional[str] = None, enable_gcs_patch_in_boto3: bool = False, config_file: str = "cosmos_framework/configs/base/config.py", load_ema_to_reg: bool = False, parallelism_config: dict[str, Any] = {}, compile_config: dict[str, Any] = {}, quantization_config: dict[str, Any] = {}, seed: int = 0, experiment_opts: list[str] = [], use_cache_checkpoint: bool = False, cache_checkpoint_rootdir: Optional[str] = None, keys_to_skip_loading: list[str] | None = None, ) -> tuple[torch.nn.Module, Any]: """ Args: experiment_name: Experiment name. checkpoint_path: Path to the checkpoint (local path or s3 URI). Two on-disk formats are auto-detected: * **DCP** (default): a directory tree containing ``.metadata`` + ``*.distcp`` shards. Loaded via :func:`torch.distributed.checkpoint.load`. The legacy "weights live under ``/model/``" convention is honored here — if ``checkpoint_path`` does not already end with ``/model``, ``/model`` is appended. * **safetensors**: a directory containing one or more ``*.safetensors`` shards in the native Cosmos3 VFM state-dict layout. Loaded via :func:`cosmos_framework.model.generator.utils.safetensors_loader.load_vfm_model`. No ``/model`` suffix is appended. credential_path: Path to credentials file (if required for remote storage). Optional. enable_gcs_patch_in_boto3: Whether to enable the boto3 patch for GCS S3-compatibility. Applies to the DCP path only; ignored for safetensors (``easy_io`` handles GCS routing internally). config_file: Path to the config file used to construct the experiment/model. load_ema_to_reg: If True, load EMA weights into the regular (non-EMA) model parameters. Only supported for DCP checkpoints — safetensors VFM checkpoints carry a single weight set with no EMA branch, so this raises ``ValueError`` when paired with a safetensors source. parallelism_config: Dictionary of parallelism configuration options. Keys are applied to ``config.model.config.parallelism``. compile_config: Dictionary of torch.compile configuration options. Keys are applied to ``config.model.config.compile``. quantization_config: Post training quantization (PTQ) config for inference. Dictionary of quantization options (e.g. ``method``, ``include_regex``, ``exclude_regex``). Quantization is applied in-place on the model parameters. Only works when model sharding (FSDP) is disabled. When ``method`` resolves to ``None``, quantization is disabled. ``mxfp8`` and ``nvfp4`` require Blackwell; ``fp8`` also supports Hopper and Ada. Valid methods are ``fp8``, ``mxfp8``, and ``nvfp4``. seed: Random seed used for initialization (if applicable). experiment_opts: Extra experiment/config override options. use_cache_checkpoint: If True, locally save & read remote checkpoints to speed up repeated loads. Be aware, the default cache path is $HOME/.cache/imaginaire4/checkpoints/. Applies to the DCP path only; for safetensors checkpoints a warning is logged and caching is skipped (the DCP write cache is not a meaningful round-trip for safetensors sources). cache_checkpoint_rootdir: Customizable root directory for checkpoint cache. Optional. keys_to_skip_loading: List of key substrings to skip when loading from checkpoint. Useful for loading pretrained checkpoints that are missing certain keys (e.g. action heads). For DCP this is forwarded as-is to ``CustomLoadPlanner`` (substring match). For safetensors each substring is escaped and wrapped as ``.*.*`` so that ``load_vfm_model``'s ``re.fullmatch``-based ``skip_patterns`` reproduces the substring semantics one-for-one. Returns: The loaded model and config """ # Ensure checkpoint_path is provided if checkpoint_path is None: raise ValueError("'checkpoint_path' must be provided.") # Detect checkpoint format BEFORE applying any DCP-specific path # rewriting (the legacy "/model" suffix only makes sense for DCP). # ``_is_safetensors_checkpoint`` is a cheap directory listing that # short-circuits on the first hit and tolerates I/O failures (returns # False) so a bad path naturally falls through to the DCP code path # and produces the same error message it always did. is_safetensors = _is_safetensors_checkpoint(checkpoint_path, credential_path) if not is_safetensors and not checkpoint_path.strip("/").endswith("model"): checkpoint_path = os.path.join(checkpoint_path, "model") config_module = get_config_module(config_file) config = importlib.import_module(config_module).make_config() config = override(config, ["--", f"experiment={experiment_name}"] + experiment_opts) if parallelism_config is not None: for key, value in parallelism_config.items(): if hasattr(config.model.config.parallelism, key): setattr(config.model.config.parallelism, key, value) else: raise ValueError(f"Key {key} not found in config.model.config.parallelism") if compile_config is not None: for key, value in compile_config.items(): if hasattr(config.model.config.compile, key): setattr(config.model.config.compile, key, value) else: raise ValueError(f"Key {key} not found in config.model.config.compile") quantization_config_obj = QuantizationConfig(**quantization_config) quantization_method = quantization_config_obj.method if quantization_method is not None: dp_shard_degree = config.model.config.parallelism.data_parallel_shard_degree if dp_shard_degree > 1: raise ValueError("Quantization is not supported for DP sharded models.") # Disable activation checkpointing for inference. config.model.config.activation_checkpointing.mode = "none" # Disable EMA for inference. config.model.config.ema.enabled = False if hasattr(config.model.config, "load_teacher_weights"): log.info("Setting load_teacher_weights=False for inference to skip teacher checkpoint download.") config.model.config.load_teacher_weights = False if getattr(config.model.config, "student_load_from", None) is not None: log.info("Setting student_load_from=None for inference to skip train-time student warm-start download.") config.model.config.student_load_from = None if ( config.model.config.exclude_reasoner_weights_from_checkpoint and not config.model.config.vlm_config.pretrained_weights.enabled ): log.info("Enabling pretrained reasoner weights because this checkpoint excludes the reasoner tower from DCP.") config.model.config.vlm_config.pretrained_weights.enabled = True config.validate() config.freeze() # type: ignore misc.set_random_seed(seed=seed, by_rank=True) torch.backends.cudnn.deterministic = config.trainer.cudnn.deterministic torch.backends.cudnn.benchmark = config.trainer.cudnn.benchmark with misc.timer("instantiate model"): model = instantiate(config.model).cuda() # type: ignore model.on_train_start() if is_safetensors: # Validate DCP-only flags up front so the caller gets a clear error # instead of a silent no-op. if load_ema_to_reg: raise ValueError( "load_ema_to_reg=True is not supported for safetensors checkpoints — " "safetensors VFM checkpoints contain a single weight set with no EMA branch." ) if use_cache_checkpoint: log.warning( "use_cache_checkpoint is ignored for safetensors checkpoints " "(the local cache is a DCP-format reshard optimization and does not " "round-trip through safetensors)." ) # Translate DCP-style substring skips into regex fullmatch patterns # so load_vfm_model's regex contract reproduces the substring semantics. skip_patterns: list[str] | None = ( [f".*{re.escape(s)}.*" for s in keys_to_skip_loading] if keys_to_skip_loading else None ) # load_vfm_model expects the Cosmos3VFMNetwork directly. In # OmniMoTModel this lives at ``.net``; for tests/standalone callers # that pass a Cosmos3VFMNetwork in directly, fall back to the model # itself. ``parallel_dims`` is populated by ``set_up_parallelism()`` # (called from ``on_train_start()`` above) — None for single-process # / non-distributed runs, which load_vfm_model accepts. vfm_network = getattr(model, "net", model) parallel_dims = getattr(model, "parallel_dims", None) log.info(f"Loading safetensors VFM checkpoint from {checkpoint_path}") start_time = time.time() load_vfm_model( model=vfm_network, checkpoint_path=checkpoint_path, credential_path=credential_path, parallel_dims=parallel_dims, skip_patterns=skip_patterns, ) log.info( f"Successfully loaded safetensors VFM checkpoint from {checkpoint_path}; " f"time taken: {time.time() - start_time:.2f} seconds" ) else: # DCP path with optional local cache reshard. def load_model(checkpoint_load_path: str) -> None: _load_model( model, checkpoint_path=checkpoint_load_path, credential_path=credential_path, enable_gcs_patch_in_boto3=enable_gcs_patch_in_boto3, load_ema_to_reg=load_ema_to_reg, keys_to_skip_loading=keys_to_skip_loading, ) checkpoint_cache_path = None if use_cache_checkpoint: checkpoint_cache_path = checkpoint_path_to_cached_path(checkpoint_path, cache_checkpoint_rootdir) if checkpoint_cache_path is None: load_model(checkpoint_path) else: cache_lock_path = f"{checkpoint_cache_path}.lock" cache_action = _CheckpointCacheAction.ERROR log.info(f"Acquiring checkpoint cache write lock: {cache_lock_path}") with _checkpoint_cache_group_lock(checkpoint_cache_path, cache_lock_path) as cache_action: if cache_action == _CheckpointCacheAction.POPULATE_CACHE: load_model(checkpoint_path) _save_model( model, checkpoint_path=checkpoint_cache_path, save_reg_to_ema=load_ema_to_reg, ) if cache_action == _CheckpointCacheAction.LOAD_CACHE: load_model(checkpoint_cache_path) _reload_pretrained_reasoner_after_checkpoint_load(model) if quantization_method is not None: # Replicated path: apply the (config-resident) recipe in place on the # unsharded (plain-tensor) params. apply_quantization_inplace(model, quantization_config_obj) return model, config