lip-forcing / lipforcing /utils /scripts.py
multimodalart's picture
multimodalart HF Staff
Initial Lip Forcing 14B streaming demo
9368ee7 verified
Raw
History Blame Contribute Delete
5.81 kB
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
import os
import argparse
import torch
from omegaconf import OmegaConf
from lipforcing.configs.config_utils import serialize_config
from lipforcing.configs import config_utils
import lipforcing.utils.logging_utils as logger
from lipforcing.utils.basic_utils import get_batch_size_total
from lipforcing.utils.distributed import ddp, world_size, is_rank0
from lipforcing.utils.io_utils import set_env_vars
from lipforcing.configs.config import BaseConfig
def parse_args(parser: argparse.ArgumentParser) -> argparse.Namespace:
parser.add_argument("--config", default="configs.config", help="Path to the config file")
parser.add_argument("--log_level", default="INFO", help="Log level (e.g. DEBUG, INFO)")
parser.add_argument(
"opts",
default=None,
nargs=argparse.REMAINDER,
help="""Modify config options at the end of the command.
For Yacs configs, use space-separated "PATH.KEY VALUE" pairs.
For python-based LazyConfig, use "path.key=value".""",
)
parser.add_argument(
"--dryrun",
action="store_true",
help="Do a dry run without training. Useful for debugging the config.",
)
args = parser.parse_args()
return args
def set_cuda_backend(deterministic: bool = True, benchmark: bool = True, tf32_enabled: bool = True):
# Initialize cuDNN.
torch.backends.cudnn.deterministic = deterministic
torch.backends.cudnn.benchmark = benchmark
# Floating-point precision settings.
torch.backends.cudnn.allow_tf32 = tf32_enabled
torch.backends.cuda.matmul.allow_tf32 = tf32_enabled
torch.backends.cuda.matmul.allow_fp16_reduced_precision_reduction = tf32_enabled
logger.critical(
f"cuDNN deterministic: {deterministic}, " f"cuDNN benchmark: {benchmark}, " f"enable TF32: {tf32_enabled}"
)
def setup(args: argparse.Namespace, evaluation: bool = False) -> BaseConfig:
if hasattr(args, "log_level"):
# set log level for logger (INFO, by default)
logger.set_log_level(args.log_level)
# Import the config from the python file
config: BaseConfig = config_utils.import_config_from_python_file(args.config)
if hasattr(args, "opts"):
# Override the config with the command line arguments
config = config_utils.override_config_with_opts(config, args.opts)
# Update checkpointer save_dir
config.trainer.checkpointer.save_dir = f"{config.log_config.save_path}/{config.trainer.checkpointer.save_dir}"
# save config
config_save_path = config.log_config.save_path
if evaluation:
config_save_path = os.path.join(config_save_path, config.eval.samples_dir)
if is_rank0():
serialize_config(config, return_type="file", path=config_save_path, filename="config.yaml")
# Check for dryrun
if getattr(args, "dryrun", False):
logger.info("Dryrun")
logger.info(OmegaConf.to_yaml(OmegaConf.load(f"{config_save_path}/config.yaml")))
logger.info(f"config.yaml is saved at {config_save_path}")
exit(0)
# distributed setup
if config.trainer.ddp or config.trainer.fsdp:
# check if ddp is available
if not torch.distributed.is_available():
raise RuntimeError("Distributed training is not available, please check your PyTorch installation.")
# initialize DDP
ddp.init()
logger.info(f"Distributed training initialized, world size: {world_size()}")
else:
logger.info("No DDP or FSDP parallelism")
# Check if we can use memory-efficient FSDP meta init
if config.model.fsdp_meta_init:
if not config.trainer.fsdp:
logger.warning("Ignoring fsdp_meta_init since FSDP is disabled.")
config.model.fsdp_meta_init = False
elif evaluation:
logger.warning("Ignoring fsdp_meta_init for evaluation/inference.")
config.model.fsdp_meta_init = False
# NOTE: fsdp_meta_init is compatible with pretrained_ckpt_path. The
# load path skips dcp.load on ranks where v.parameters() contains meta
# tensors, so only rank 0 loads weights and FSDP wrap broadcasts them
# to the other ranks via sync_module_states.
# Global batch size
if getattr(config.trainer, "batch_size_global", None) is not None:
batch_size = config.dataloader_train.batch_size * world_size()
accum_rounds = max(config.trainer.batch_size_global // batch_size, 1)
new_batch_size_global = accum_rounds * batch_size
if new_batch_size_global != config.trainer.batch_size_global:
logger.critical(
f"Requested global batch size {config.trainer.batch_size_global} is not divisible by current batch size {batch_size}. New global batch size will be {new_batch_size_global}."
)
if accum_rounds != config.trainer.grad_accum_rounds:
logger.info(
f"Changing gradient accumulation rounds from {config.trainer.grad_accum_rounds} to {accum_rounds} to match requested global batch size."
)
config.trainer.grad_accum_rounds = accum_rounds
logger.critical(
f"Global batch size: {get_batch_size_total(config)} (Batch size per GPU: {config.dataloader_train.batch_size}, Gradient accumulation rounds: {config.trainer.grad_accum_rounds}, World size: {world_size()})"
)
# Set up s3 environmental variables
set_env_vars(config.trainer.checkpointer.s3_credential)
# Set up CUDA backend
set_cuda_backend(config.trainer.cudnn.deterministic, config.trainer.cudnn.benchmark, config.trainer.tf32_enabled)
return config