dwehr's picture
Migrate action viewer to local Cosmos generation
9f818c5
Raw
History Blame Contribute Delete
4.13 kB
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: OpenMDW-1.1
"""Training callback that defers AOT compilation of the VAE tokenizer.
The actual compilation logic lives in
:meth:`~projects.cosmos3.vfm.tokenizers.wan2pt2_vae_4x16x16.Wan2pt2VAEInterface.compile_encode`.
This module provides a :class:`CompileTokenizer` callback that invokes it
at the right point during training (after ``compile_after_iterations``
steps, to avoid NCCL timeouts during CUDA/cuDNN warm-up).
Typical config usage
--------------------
.. code-block:: python
CompileTokenizer(
enabled=True,
compile_after_iterations=3,
warmup_resolutions=["256", "480", "720"],
)
"""
from collections.abc import Sequence
import torch
from cosmos_framework.utils import log
from cosmos_framework.utils.callback import Callback
from cosmos_framework.model.vfm.omni_mot_model import OmniMoTModel
class CompileTokenizer(Callback):
"""Training callback that defers AOT compilation of the VAE tokenizer.
Hooks into ``on_training_step_start``. On the
``compile_after_iterations``-th step it calls
``Wan2pt2VAEInterface.compile_encode`` to compile and load all chunk
variants. Every subsequent step is a no-op.
"""
def __init__(
self,
enabled: bool = False,
compile_after_iterations: int = 3,
warmup_resolutions: Sequence[str] | None = None,
):
"""
Args:
enabled: Master switch. When ``False`` the callback is a
complete no-op and no compilation occurs.
compile_after_iterations: How many training steps to skip
before triggering compilation. The default (3) lets CUDA
context setup and Transformer compilation finish first.
warmup_resolutions: Resolution keys (e.g. ``["256", "480", "720"]``)
to AOT-compile. Should include every resolution used in
training. Must be a non-empty list when *enabled* is ``True``.
"""
super().__init__()
self.enabled: bool = enabled
self.compile_after_iterations: int = compile_after_iterations
self.skip_counter: int = 0
self.warmup_resolutions: Sequence[str] | None = warmup_resolutions
if self.enabled:
if self.warmup_resolutions is None:
raise ValueError("warmup_resolutions must be provided when enabled, got None")
if len(self.warmup_resolutions) == 0:
raise ValueError("warmup_resolutions must be a non-empty list when enabled, got an empty list")
def on_training_step_start(
self, model: OmniMoTModel, data_batch: dict[str, torch.Tensor], iteration: int = 0
) -> None:
"""Called at the start of every training step.
On the ``compile_after_iterations``-th call, triggers AOT compilation
via ``tokenizer.compile_encode``.
Args:
model: The OmniMoTModel whose ``tokenizer_vision_gen`` will be compiled.
data_batch: Current training batch (unused, required by Callback API).
iteration: Current training iteration (unused; we track our own counter
via ``skip_counter`` because this callback may be registered after
iteration 0).
"""
if not self.enabled:
return
tokenizer = model.tokenizer_vision_gen
if isinstance(tokenizer, torch.jit.ScriptModule):
log.critical(
f"The Tokenizer model {type(tokenizer)} is a JIT model, "
"which is not compilable. The Tokenizer will not be compiled.",
rank0_only=False,
)
self.enabled = False
return
if self.skip_counter == self.compile_after_iterations:
if self.warmup_resolutions is not None:
tokenizer.compile_encode(
self.warmup_resolutions,
output_dir=self.config.job.path_local,
)
self.skip_counter += 1