import gc from typing import Optional, Tuple, Union import torch from accelerate.logging import get_logger from diffusers.models.embeddings import get_3d_rotary_pos_embed logger = get_logger(__name__) def get_optimizer( params_to_optimize, optimizer_name: str = "adam", learning_rate: float = 1e-3, beta1: float = 0.9, beta2: float = 0.95, beta3: float = 0.98, epsilon: float = 1e-8, weight_decay: float = 1e-4, prodigy_decouple: bool = False, prodigy_use_bias_correction: bool = False, prodigy_safeguard_warmup: bool = False, use_8bit: bool = False, use_deepspeed: bool = False, ) -> torch.optim.Optimizer: optimizer_name = optimizer_name.lower() # Use DeepSpeed optimzer if use_deepspeed: from accelerate.utils import DummyOptim return DummyOptim( params_to_optimize, lr=learning_rate, betas=(beta1, beta2), eps=epsilon, weight_decay=weight_decay, ) # Optimizer creation supported_optimizers = ["adam", "adamw", "prodigy"] if optimizer_name not in supported_optimizers: logger.warning( f"Unsupported choice of optimizer: {optimizer_name}. Supported optimizers include {supported_optimizers}. Defaulting to `AdamW`." ) optimizer_name = "adamw" if use_8bit and optimizer_name not in ["adam", "adamw"]: logger.warning( f"use_8bit_adam is ignored when optimizer is not set to 'Adam' or 'AdamW'. Optimizer was set to {optimizer_name}." ) if use_8bit: try: import bitsandbytes as bnb except ImportError: raise ImportError( "To use 8-bit Adam, please install the bitsandbytes library: `pip install bitsandbytes`." ) if optimizer_name == "adamw": optimizer_class = bnb.optim.AdamW8bit if use_8bit else torch.optim.AdamW optimizer = optimizer_class( params_to_optimize, betas=(beta1, beta2), eps=epsilon, weight_decay=weight_decay, ) elif optimizer_name == "adam": optimizer_class = bnb.optim.Adam8bit if use_8bit else torch.optim.Adam optimizer = optimizer_class( params_to_optimize, betas=(beta1, beta2), eps=epsilon, weight_decay=weight_decay, ) elif optimizer_name == "prodigy": try: import prodigyopt except ImportError: raise ImportError("To use Prodigy, please install the prodigyopt library: `pip install prodigyopt`") optimizer_class = prodigyopt.Prodigy if learning_rate <= 0.1: logger.warning( "Learning rate is too low. When using prodigy, it's generally better to set learning rate around 1.0" ) optimizer = optimizer_class( params_to_optimize, lr=learning_rate, betas=(beta1, beta2), beta3=beta3, weight_decay=weight_decay, eps=epsilon, decouple=prodigy_decouple, use_bias_correction=prodigy_use_bias_correction, safeguard_warmup=prodigy_safeguard_warmup, ) return optimizer def get_gradient_norm(parameters): norm = 0 for param in parameters: if param.grad is None: continue local_norm = param.grad.detach().data.norm(2) norm += local_norm.item() ** 2 norm = norm**0.5 return norm # Similar to diffusers.pipelines.hunyuandit.pipeline_hunyuandit.get_resize_crop_region_for_grid def get_resize_crop_region_for_grid(src, tgt_width, tgt_height): tw = tgt_width th = tgt_height h, w = src r = h / w if r > (th / tw): resize_height = th resize_width = int(round(th / h * w)) else: resize_width = tw resize_height = int(round(tw / w * h)) crop_top = int(round((th - resize_height) / 2.0)) crop_left = int(round((tw - resize_width) / 2.0)) return (crop_top, crop_left), (crop_top + resize_height, crop_left + resize_width) def prepare_rotary_positional_embeddings( height: int, width: int, num_frames: int, vae_scale_factor_spatial: int = 8, patch_size: int = 2, attention_head_dim: int = 64, device: Optional[torch.device] = None, base_height: int = 480, base_width: int = 720, ) -> Tuple[torch.Tensor, torch.Tensor]: grid_height = height // (vae_scale_factor_spatial * patch_size) grid_width = width // (vae_scale_factor_spatial * patch_size) base_size_width = base_width // (vae_scale_factor_spatial * patch_size) base_size_height = base_height // (vae_scale_factor_spatial * patch_size) grid_crops_coords = get_resize_crop_region_for_grid((grid_height, grid_width), base_size_width, base_size_height) freqs_cos, freqs_sin = get_3d_rotary_pos_embed( embed_dim=attention_head_dim, crops_coords=grid_crops_coords, grid_size=(grid_height, grid_width), temporal_size=num_frames, ) freqs_cos = freqs_cos.to(device=device) freqs_sin = freqs_sin.to(device=device) return freqs_cos, freqs_sin def reset_memory(device: Union[str, torch.device]) -> None: gc.collect() torch.cuda.empty_cache() torch.cuda.reset_peak_memory_stats(device) torch.cuda.reset_accumulated_memory_stats(device) def print_memory(device: Union[str, torch.device]) -> None: memory_allocated = torch.cuda.memory_allocated(device) / 1024**3 max_memory_allocated = torch.cuda.max_memory_allocated(device) / 1024**3 max_memory_reserved = torch.cuda.max_memory_reserved(device) / 1024**3 print(f"{memory_allocated=:.3f} GB") print(f"{max_memory_allocated=:.3f} GB") print(f"{max_memory_reserved=:.3f} GB")