Spaces:
Running on Zero
Running on Zero
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| from __future__ import annotations | |
| from typing import Callable, Any, TYPE_CHECKING | |
| import torch | |
| from torch.utils.data import DataLoader | |
| from lipforcing.utils import instantiate | |
| import lipforcing.utils.logging_utils as logger | |
| if TYPE_CHECKING: | |
| from lipforcing.configs.config import BaseConfig | |
| from lipforcing.trainer import Trainer | |
| from lipforcing.methods import FastGenModel | |
| class CallbackDict: | |
| def __init__(self, config: BaseConfig, trainer: Trainer): | |
| self._callbacks = {} | |
| callback_configs = config.trainer.callbacks | |
| if callback_configs: | |
| if isinstance(callback_configs, list): | |
| logger.warning(msg="The 'config.trainer.callbacks' parameter should be a dict instead of a list. ") | |
| callback_configs = {f"callback_{k}": v for k, v in enumerate(callback_configs)} | |
| for callback_name, current_callback_cfg in callback_configs.items(): | |
| if "_target_" not in current_callback_cfg: | |
| logger.critical( | |
| f"Callback {callback_name} is missing the '_target_' field. \n Skip {current_callback_cfg}" | |
| ) | |
| continue | |
| logger.critical(f"Instantiating callback {callback_name}: {current_callback_cfg}") | |
| _callback = instantiate(current_callback_cfg) | |
| assert isinstance(_callback, Callback), f"{current_callback_cfg} is not a valid callback." | |
| _callback.config = config | |
| _callback.trainer = trainer | |
| _callback.on_app_begin() | |
| self._callbacks[callback_name] = _callback | |
| def __getattr__(self, method_name: str) -> Callable: | |
| def load_state_dict(state_dict: dict[str, Any]) -> None: | |
| for name, callback in self._callbacks.items(): | |
| if name in state_dict: | |
| callback.load_state_dict(state_dict[name]) | |
| else: | |
| logger.warning(f"Callback {name} not found in checkpoint.") | |
| def state_dict() -> dict[str, Any]: | |
| return {name: self._callbacks[name].state_dict() for name in self._callbacks} | |
| def callbacks_wrapper(*args, **kwargs): | |
| for callback in self._callbacks.values(): | |
| assert hasattr(callback, method_name) | |
| method = getattr(callback, method_name) | |
| assert callable(method), f"{method_name} is not callable." | |
| method(*args, **kwargs) | |
| if method_name == "state_dict": | |
| return state_dict | |
| if method_name == "load_state_dict": | |
| return load_state_dict | |
| return callbacks_wrapper | |
| class Callback: | |
| config: "BaseConfig" | |
| trainer: "Trainer" | |
| def on_app_begin(self) -> None: | |
| pass | |
| def on_model_init_start(self, model: FastGenModel) -> None: | |
| pass | |
| def on_model_init_end(self, model: FastGenModel | torch.nn.parallel.DistributedDataParallel) -> None: | |
| pass | |
| def on_optimizer_init_start(self, model: FastGenModel) -> None: | |
| pass | |
| def on_optimizer_init_end(self, model: FastGenModel) -> None: | |
| pass | |
| def on_load_checkpoint_start(self, model: FastGenModel) -> None: | |
| pass | |
| def on_load_checkpoint_end(self, model: FastGenModel, iteration: int = 0) -> None: | |
| pass | |
| def on_dataloader_init_start(self, model: FastGenModel, iteration: int = 0) -> None: | |
| pass | |
| def on_dataloader_init_end( | |
| self, model: FastGenModel, dataloader_train: DataLoader, dataloader_val: DataLoader, iteration: int = 0 | |
| ) -> None: | |
| pass | |
| def on_train_begin(self, model: FastGenModel, iteration: int = 0) -> None: | |
| pass | |
| def on_training_step_begin( | |
| self, | |
| model: FastGenModel, | |
| iteration: int = 0, | |
| ) -> None: | |
| pass | |
| def on_training_accum_step_begin( | |
| self, | |
| model: FastGenModel, | |
| data_batch: dict[str, torch.Tensor], | |
| iteration: int = 0, | |
| accum_iter: int = 0, | |
| ) -> None: | |
| pass | |
| def on_backward_begin( | |
| self, | |
| model: FastGenModel, | |
| data_batch: dict[str, torch.Tensor], | |
| output_batch: dict[str, torch.Tensor | Callable], | |
| loss_dict: dict[str, torch.Tensor], | |
| iteration: int = 0, | |
| accum_iter: int = 0, | |
| ) -> None: | |
| pass | |
| def on_training_step_end( | |
| self, | |
| model: FastGenModel, | |
| data_batch: dict[str, torch.Tensor], | |
| output_batch: dict[str, torch.Tensor | Callable], | |
| loss_dict: dict[str, torch.Tensor], | |
| iteration: int = 0, | |
| ) -> None: | |
| pass | |
| def on_optimizer_step_begin(self, model: FastGenModel, iteration: int = 0) -> None: | |
| pass | |
| def on_train_end(self, model: FastGenModel, iteration: int = 0) -> None: | |
| pass | |
| def on_validation_begin(self, model: FastGenModel, iteration: int = 0, idx: int = 0) -> None: | |
| pass | |
| def on_validation_step_begin( | |
| self, model: FastGenModel, data_batch: dict[str, torch.Tensor], step: int = 0, iteration: int = 0, idx: int = 0 | |
| ) -> None: | |
| pass | |
| def on_validation_step_end( | |
| self, | |
| model: FastGenModel, | |
| data_batch: dict[str, torch.Tensor], | |
| output_batch: dict[str, torch.Tensor | Callable], | |
| loss_dict: dict[str, torch.Tensor], | |
| step: int = 0, | |
| iteration: int = 0, | |
| idx: int = 0, | |
| ) -> None: | |
| pass | |
| def on_validation_end(self, model: FastGenModel, iteration: int = 0, idx: int = 0) -> None: | |
| pass | |
| def on_save_checkpoint_start(self, model: FastGenModel, iteration: int = 0) -> None: | |
| pass | |
| def on_save_checkpoint_success(self, model: FastGenModel, iteration: int = 0, path: str = None) -> None: | |
| pass | |
| def on_save_checkpoint_end(self, model: FastGenModel, iteration: int = 0) -> None: | |
| pass | |
| def on_app_end(self, model: FastGenModel, iteration: int = 0) -> None: | |
| pass | |
| def state_dict(self) -> dict[str, Any]: | |
| return {} | |
| def load_state_dict(self, state_dict: dict[str, Any]) -> None: | |
| pass | |