Spaces:
Running on Zero
Running on Zero
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| # ----------------------------------------------------------------------------- | |
| # Copyright (c) Facebook, Inc. and its affiliates. | |
| # | |
| # See licenses/detectron2/LICENSE for more details. | |
| # ----------------------------------------------------------------------------- | |
| from collections import abc | |
| from omegaconf import DictConfig, ListConfig | |
| from dataclasses import is_dataclass | |
| import torch | |
| import contextlib | |
| from lipforcing.utils.registry import locate, _convert_target_to_string | |
| import lipforcing.utils.logging_utils as logger | |
| from lipforcing.utils import global_vars | |
| def expand_like(x: torch.Tensor, target: torch.Tensor) -> torch.Tensor: | |
| """Expands the input tensor `x` to have the same | |
| number of dimensions as the `target` tensor. | |
| Pads `x` with singleton dimensions on the end. | |
| # Example | |
| ``` | |
| x = torch.ones(5) | |
| target = torch.ones(5, 10, 30, 1, 10) | |
| x = expand_like(x, target) | |
| print(x.shape) # <- [5, 1, 1, 1, 1] | |
| ``` | |
| Args: | |
| x (torch.Tensor): The input tensor to expand. | |
| target (torch.Tensor): The target tensor whose shape length | |
| will be matched. | |
| Returns: | |
| torch.Tensor: The expanded tensor `x` with trailing singleton | |
| dimensions. | |
| """ | |
| x = torch.atleast_1d(x) | |
| while len(x.shape) < len(target.shape): | |
| x = x[..., None] | |
| return x | |
| def instantiate(cfg, *args, **kwargs): | |
| """ | |
| Recursively instantiate objects defined in dictionaries by | |
| "_target_" and arguments. | |
| Args: | |
| cfg: a dict-like object with "_target_" that defines the caller, and | |
| other keys that define the arguments | |
| Returns: | |
| object instantiated by cfg | |
| """ | |
| if isinstance(cfg, ListConfig): | |
| lst = [instantiate(x) for x in cfg] | |
| return ListConfig(lst, flags={"allow_objects": True}) | |
| if isinstance(cfg, list): | |
| # Specialize for list, because many classes take | |
| # list[objects] as arguments, such as ResNet, DatasetMapper | |
| return [instantiate(x) for x in cfg] | |
| if isinstance(cfg, abc.Mapping) and "_target_" in cfg: | |
| # conceptually equivalent to hydra.utils.instantiate(cfg) with _convert_=all, | |
| # but faster: https://github.com/facebookresearch/hydra/issues/1200 | |
| cfg = {k: instantiate(v) for k, v in cfg.items()} | |
| cls = cfg.pop("_target_") | |
| cls = instantiate(cls) | |
| if isinstance(cls, str): | |
| cls_name = cls | |
| cls = locate(cls_name) | |
| assert cls is not None, cls_name | |
| else: | |
| try: | |
| cls_name = cls.__module__ + "." + cls.__qualname__ | |
| except Exception: | |
| # target could be anything, so the above could fail | |
| cls_name = str(cls) | |
| assert callable(cls), f"_target_ {cls} does not define a callable object" | |
| try: | |
| additional_kwargs = {} | |
| additional_kwargs.update(cfg) | |
| additional_kwargs.update(kwargs) | |
| return cls(*args, **additional_kwargs) | |
| except TypeError: | |
| logger.error(f"Error when instantiating {cls_name}!") | |
| raise | |
| return cfg # return as-is if don't know what to do | |
| class LazyCall: | |
| """ | |
| Wrap a callable so that when it's called, the call will not be executed, | |
| but returns a dict that describes the call. | |
| LazyCall object has to be called with only keyword arguments. Positional | |
| arguments are not yet supported. | |
| Examples: | |
| :: | |
| from lipforcing.utils import instantiate, LazyCall | |
| layer_cfg = LazyCall(nn.Conv2d)(in_channels=32, out_channels=32) | |
| layer_cfg.out_channels = 64 # can edit it afterwards | |
| layer = instantiate(layer_cfg) | |
| """ | |
| def __init__(self, target): | |
| if not (callable(target) or isinstance(target, (str, abc.Mapping))): | |
| raise TypeError(f"target of LazyCall must be a callable or defines a callable! Got {target}") | |
| self._target = target | |
| def __call__(self, **kwargs): | |
| if is_dataclass(self._target): | |
| # omegaconf object cannot hold dataclass type | |
| # https://github.com/omry/omegaconf/issues/784 | |
| target = _convert_target_to_string(self._target) | |
| else: | |
| target = self._target | |
| kwargs["_target_"] = target | |
| return DictConfig(content=kwargs, flags={"allow_objects": True}) | |
| def set_global_vars(config: dict | DictConfig | None = None): | |
| config = config or {} | |
| # update all keys that exist in global_vars | |
| update_config = {k: v for k, v in config.items() if k in global_vars.__all__} | |
| logger.debug(f"Setting global variables {update_config}") | |
| global_vars.__dict__.update(update_config) | |
| # log keys that do not exist in global_vars | |
| ignore_keys = [k for k in config.keys() if k not in global_vars.__all__] | |
| if len(ignore_keys) > 0: | |
| logger.warning(f"Ignoring keys {ignore_keys} since they are not found in global_vars.") | |
| def set_temp_global_vars(config): | |
| # Handle string "None" from command line parsing | |
| if config == "None": | |
| config = None | |
| original_global_vars = {k: global_vars.__dict__[k] for k in global_vars.__all__} | |
| try: | |
| set_global_vars(config) | |
| yield | |
| finally: | |
| logger.debug(f"Resetting global variables to {original_global_vars}") | |
| global_vars.__dict__.update(original_global_vars) | |