dwehr's picture
Migrate action viewer to local Cosmos generation
9f818c5
Raw
History Blame Contribute Delete
4.01 kB
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: OpenMDW-1.1
"""FSDP2 wrapping for Cosmos3 VLM ``HFModel`` instances.
Hosts the single VLM-specific ``parallelize`` entry point used by
``vlm_model.VLMModel._init_vlm``. Lives under ``projects/cosmos3/vfm/models/``
so the FSDP wrapping concern sits next to the model class it operates on
(mirroring the layout of ``models/mot/parallelize_unified_mot.py`` for the
MoT path).
Pure parallelism plumbing — :class:`~projects.cosmos3.vfm.utils.parallelism.ParallelDims`
and its meshes — stays in ``vfm/utils/parallelism.py``.
"""
from torch.distributed.fsdp import MixedPrecisionPolicy, fully_shard
from cosmos_framework.utils import log
from cosmos_framework.configs.base.defaults.parallelism import (
PRECISION_TO_TORCH_DTYPE,
ParallelismConfig,
)
from cosmos_framework.model.vfm.hf_model import HFModel
from cosmos_framework.utils.vfm.parallelism import ParallelDims
def parallelize(
model: HFModel,
parallel_dims: ParallelDims,
parallelism_config: ParallelismConfig,
precision: str,
) -> None:
"""Apply FSDP2 to an HFModel in-place.
Uses torch.distributed.fsdp.fully_shard (FSDP2). Each transformer block is
sharded individually for fine-grained memory savings; the outer model is then
wrapped to cover remaining parameters (embeddings, layer norms, lm_head).
Supported architectures:
- Language models: ``inner.model.layers`` (standard HF LLM structure)
- Vision-language models: additionally ``inner.visual.blocks`` (Qwen3-VL)
No-op when FSDP is not needed (single-GPU or replicate-only).
Args:
model: HFModel instance (``model`` attribute must be on meta or CPU device).
parallel_dims: ParallelDims with meshes already built via
:meth:`ParallelDims.build_meshes`.
parallelism_config: Source of FSDP master dtype (``fsdp_master_dtype``;
threaded to ``MixedPrecisionPolicy.reduce_dtype``).
precision: FSDP MixedPrecisionPolicy parameter dtype
(``"bfloat16"``, ``"float16"``, or ``"float32"``).
"""
if not parallel_dims.dp_shard_enabled:
# No shard axis: dp_shard <= 1. FSDP2 (fully_shard) has nothing to do.
# For replicate-only (dp_replicate > 1, dp_shard == 1), use DDP outside
# this function.
log.info("parallelize: dp_shard <= 1 — skipping FSDP2 wrapping")
return
mp_policy = MixedPrecisionPolicy(
param_dtype=PRECISION_TO_TORCH_DTYPE[precision],
reduce_dtype=PRECISION_TO_TORCH_DTYPE[parallelism_config.fsdp_master_dtype],
)
# 2-D (dp_replicate × dp_shard) mesh for HSDP, or 1-D dp_shard sub-mesh
# for pure FSDP. In the overlay design cp does NOT fold into the FSDP
# shard axis; cp/cfgp are handled by separate meshes.
if parallel_dims.dp_replicate_enabled:
fsdp_mesh = parallel_dims.dp_mesh
else:
fsdp_mesh = parallel_dims.dp_shard_mesh
fsdp_kwargs = {"mesh": fsdp_mesh, "mp_policy": mp_policy}
inner = model.model
no_split_names = set(getattr(inner, "_no_split_modules", []))
wrapped = 0
for module in reversed(list(inner.modules())):
if type(module).__name__ in no_split_names:
fully_shard(module, **fsdp_kwargs)
wrapped += 1
log.info(f"Wrapped {wrapped} sub-modules.")
# Wrap the full inner model to cover remaining parameters
# (embed_tokens, final layer norm, lm_head, visual projector stem, etc.)
# NOTE: FSDP-2 CPU offload (offload_policy=CPUOffloadPolicy()) was never
# wired through to any active recipe and the path was untested; see the
# comment in vlm_model._init_vlm meta-materialize block (search for
# "FSDP-2 CPU offload") for how to re-enable it.
fully_shard(inner, **fsdp_kwargs)
log.info("parallelize: FSDP2 applied to HFModel.model")