DFAGWE/infinitetalk2
0
1# Copyright 2024-2025 The Alibaba Wan Team Authors. All rights reserved.2import gc3from inspect import ArgSpec4import logging5import json6import math7import importlib8import os9import random10import sys11import types12from contextlib import contextmanager13from functools import partial14from PIL import Image15 16import numpy as np17import torch18import torch.cuda.amp as amp19import torch.distributed as dist20import torchvision.transforms as transforms21import torch.nn.functional as F22import torch.nn as nn23from tqdm import tqdm24from diffusers.models.modeling_utils import no_init_weights, ContextManagers25import accelerate26 27from .distributed.fsdp import shard_model28from .modules.clip import CLIPModel29from .modules.multitalk_model import WanModel, WanLayerNorm, WanRMSNorm30from .modules.t5 import T5EncoderModel, T5LayerNorm, T5RelativeEmbedding31from .modules.vae import WanVAE, CausalConv3d, RMS_norm, Upsample32from .utils.multitalk_utils import MomentumBuffer, adaptive_projected_guidance, match_and_blend_colors33from src.vram_management import AutoWrappedQLinear, AutoWrappedLinear, AutoWrappedModule, enable_vram_management34from wan.utils.utils import convert_video_to_h264, extract_specific_frames, get_video_codec35from wan.wan_lora import WanLoraWrapper36 37from safetensors.torch import load_file38from optimum.quanto import quantize, freeze, qint8,requantize39import optimum.quanto.nn.qlinear as qlinear40 41def torch_gc():42 torch.cuda.empty_cache()43 torch.cuda.ipc_collect()44 45def to_param_dtype_fp32only(model, param_dtype):46 for module in model.modules():47 for name, param in module.named_parameters(recurse=False):48 if param.dtype == torch.float32 and param.__class__.__name__ not in ['WeightQBytesTensor']:49 param.data = param.data.to(param_dtype)50 for name, buf in module.named_buffers(recurse=False):51 if buf.dtype == torch.float32 and buf.__class__.__name__ not in ['WeightQBytesTensor']:52 module._buffers[name] = buf.to(param_dtype)53 54def resize_and_centercrop(cond_image, target_size):55 """56 Resize image or tensor to the target size without padding.57 """58 59 # Get the original size60 if isinstance(cond_image, torch.Tensor):61 _, orig_h, orig_w = cond_image.shape62 else:63 orig_h, orig_w = cond_image.height, cond_image.width64 65 target_h, target_w = target_size66 67 # Calculate the scaling factor for resizing68 scale_h = target_h / orig_h69 scale_w = target_w / orig_w70 71 # Compute the final size72 scale = max(scale_h, scale_w)73 final_h = math.ceil(scale * orig_h)74 final_w = math.ceil(scale * orig_w)75 76 # Resize77 if isinstance(cond_image, torch.Tensor):78 if len(cond_image.shape) == 3:79 cond_image = cond_image[None]80 resized_tensor = nn.functional.interpolate(cond_image, size=(final_h, final_w), mode='nearest').contiguous() 81 # crop82 cropped_tensor = transforms.functional.center_crop(resized_tensor, target_size) 83 cropped_tensor = cropped_tensor.squeeze(0)84 else:85 resized_image = cond_image.resize((final_w, final_h), resample=Image.BILINEAR)86 resized_image = np.array(resized_image)87 # tensor and crop88 resized_tensor = torch.from_numpy(resized_image)[None, ...].permute(0, 3, 1, 2).contiguous()89 cropped_tensor = transforms.functional.center_crop(resized_tensor, target_size)90 cropped_tensor = cropped_tensor[:, :, None, :, :] 91 92 return cropped_tensor93 94 95def timestep_transform(96 t,97 shift=5.0,98 num_timesteps=1000,99):100 t = t / num_timesteps101 # shift the timestep based on ratio102 new_t = shift * t / (1 + (shift - 1) * t)103 new_t = new_t * num_timesteps104 return new_t105 106 107 108class InfiniteTalkPipeline:109 110 def __init__(111 self,112 config,113 checkpoint_dir,114 quant_dir=None,115 device_id=0,116 rank=0,117 t5_fsdp=False,118 dit_fsdp=False,119 use_usp=False,120 t5_cpu=False,121 init_on_cpu=True,122 num_timesteps=1000,123 use_timestep_transform=True,124 lora_dir=None,125 lora_scales=None,126 quant = None,127 dit_path = None,128 infinitetalk_dir=None,129 ):130 r"""131 Initializes the image-to-video generation model components.132 133 Args:134 config (EasyDict):135 Object containing model parameters initialized from config.py136 checkpoint_dir (`str`):137 Path to directory containing model checkpoints138 device_id (`int`, *optional*, defaults to 0):139 Id of target GPU device140 rank (`int`, *optional*, defaults to 0):141 Process rank for distributed training142 t5_fsdp (`bool`, *optional*, defaults to False):143 Enable FSDP sharding for T5 model144 dit_fsdp (`bool`, *optional*, defaults to False):145 Enable FSDP sharding for DiT model146 use_usp (`bool`, *optional*, defaults to False):147 Enable distribution strategy of USP.148 t5_cpu (`bool`, *optional*, defaults to False):149 Whether to place T5 model on CPU. Only works without t5_fsdp.150 init_on_cpu (`bool`, *optional*, defaults to True):151 Enable initializing Transformer Model on CPU. Only works without FSDP or USP.152 quant (`str`, *optional*, defaults to None):153 Quantization type, must be 'int8' or 'fp8'.154 """155 if quant is not None and quant not in ("int8", "fp8"):156 raise ValueError("quant must be 'int8', 'fp8', or None(default fp32 model)")157 self.device = torch.device(f"cuda:{device_id}")158 self.config = config159 self.rank = rank160 self.use_usp = use_usp161 self.t5_cpu = t5_cpu162 163 self.num_train_timesteps = config.num_train_timesteps164 self.param_dtype = config.param_dtype165 166 shard_fn = partial(shard_model, device_id=device_id)167 168 self.text_encoder = T5EncoderModel(169 text_len=config.text_len,170 dtype=config.t5_dtype,171 device=torch.device('cpu'),172 checkpoint_path=os.path.join(checkpoint_dir, config.t5_checkpoint),173 tokenizer_path=os.path.join(checkpoint_dir, config.t5_tokenizer),174 shard_fn=shard_fn if t5_fsdp else None,175 quant=quant,176 quant_dir=os.path.dirname(quant_dir) if quant_dir is not None else None,177 )178 179 self.vae_stride = config.vae_stride180 self.patch_size = config.patch_size181 self.vae = WanVAE(182 vae_pth=os.path.join(checkpoint_dir, config.vae_checkpoint),183 device=self.device)184 185 self.clip = CLIPModel(186 dtype=config.clip_dtype,187 device=self.device,188 checkpoint_path=os.path.join(checkpoint_dir,189 config.clip_checkpoint),190 tokenizer_path=os.path.join(checkpoint_dir, config.clip_tokenizer))191 192 logging.info(f"Creating WanModel from {checkpoint_dir}")193 194 if quant is not None:195 logging.info(f"Loading Quantized MultiTalk from {quant_dir}")196 with torch.device('meta'):197 wan_config = json.load(open(os.path.join(checkpoint_dir, "config.json")))198 self.model = WanModel(weight_init=False,**wan_config)199 torch_gc()200 model_state_dict = load_file(quant_dir)201 map_json_path = os.path.join(quant_dir.replace('safetensors', 'json'))202 self.model.init_freqs()203 with open(map_json_path, "r") as f:204 quantization_map = json.load(f)205 requantize(self.model, model_state_dict, quantization_map, device='cpu')206 else:207 if dit_path is None:208 init_contexts = [no_init_weights()]209 init_contexts.append(accelerate.init_empty_weights())210 wan_config = json.load(open(os.path.join(checkpoint_dir, "config.json")))211 self.model = WanModel(weight_init=False,**wan_config).to(dtype=self.param_dtype)212 weight_files = [f"{checkpoint_dir}/diffusion_pytorch_model-00001-of-00007.safetensors", 213 f"{checkpoint_dir}/diffusion_pytorch_model-00002-of-00007.safetensors", 214 f"{checkpoint_dir}/diffusion_pytorch_model-00003-of-00007.safetensors", 215 f"{checkpoint_dir}/diffusion_pytorch_model-00004-of-00007.safetensors",216 f"{checkpoint_dir}/diffusion_pytorch_model-00005-of-00007.safetensors", 217 f"{checkpoint_dir}/diffusion_pytorch_model-00006-of-00007.safetensors", 218 f"{checkpoint_dir}/diffusion_pytorch_model-00007-of-00007.safetensors",219 f"{infinitetalk_dir}"]220 merged_state_dict = {}221 for weight_file in weight_files:222 sd = load_file(weight_file)223 merged_state_dict.update(sd)224 self.model.load_state_dict(merged_state_dict)225 226 else:227 init_contexts = [no_init_weights()]228 init_contexts.append(accelerate.init_empty_weights())229 with ContextManagers(init_contexts):230 wan_config = json.load(open(os.path.join(checkpoint_dir, "config.json")))231 self.model = WanModel(weight_init=False,**wan_config)232 checkpoint_weights = torch.load(dit_path, map_location='cpu')233 self.model.load_state_dict(checkpoint_weights['state_dict'])234 logging.info(f"loading infinitetalk weights {checkpoint_dir}")235 236 self.model.eval().requires_grad_(False)237 238 to_param_dtype_fp32only(self.model, self.param_dtype)239 if lora_dir is not None and quant is None :240 lora_wrapper = WanLoraWrapper(self.model)241 for lora_path, lora_scale in zip(lora_dir, lora_scales):242 lora_name = lora_wrapper.load_lora(lora_path)243 lora_wrapper.apply_lora(lora_name, lora_scale, param_dtype=self.param_dtype, device=self.device)244 245 246 247 248 if t5_fsdp or dit_fsdp or use_usp:249 init_on_cpu = False250 if use_usp:251 from xfuser.core.distributed import get_sequence_parallel_world_size252 253 from .distributed.xdit_context_parallel import (254 usp_dit_forward_multitalk,255 usp_attn_forward_multitalk,256 usp_crossattn_multi_forward_multitalk257 )258 for block in self.model.blocks:259 block.self_attn.forward = types.MethodType(260 usp_attn_forward_multitalk, block.self_attn)261 block.audio_cross_attn.forward = types.MethodType(262 usp_crossattn_multi_forward_multitalk, block.audio_cross_attn)263 self.model.forward = types.MethodType(usp_dit_forward_multitalk, self.model)264 self.sp_size = get_sequence_parallel_world_size()265 else:266 self.sp_size = 1267 268 269 270 if dist.is_initialized():271 dist.barrier()272 if dit_fsdp:273 self.model = shard_fn(self.model)274 else:275 if not init_on_cpu:276 self.model.to(self.device)277 278 self.sample_neg_prompt = config.sample_neg_prompt279 self.num_timesteps = num_timesteps280 self.use_timestep_transform = use_timestep_transform281 282 self.cpu_offload = False283 self.model_names = ["model"]284 self.vram_management = False285 286 def add_noise(287 self,288 original_samples: torch.FloatTensor,289 noise: torch.FloatTensor,290 timesteps: torch.IntTensor,291 ) -> torch.FloatTensor:292 """293 compatible with diffusers add_noise()294 """295 timesteps = timesteps.float() / self.num_timesteps296 timesteps = timesteps.view(timesteps.shape + (1,) * (len(noise.shape)-1))297 298 return (1 - timesteps) * original_samples + timesteps * noise299 300 def enable_vram_management(self, num_persistent_param_in_dit=None):301 dtype = next(iter(self.model.parameters())).dtype302 enable_vram_management(303 self.model,304 module_map={305 qlinear.QLinear: AutoWrappedQLinear,306 torch.nn.Linear: AutoWrappedLinear,307 torch.nn.Conv3d: AutoWrappedModule,308 torch.nn.LayerNorm: AutoWrappedModule,309 WanLayerNorm: AutoWrappedModule,310 WanRMSNorm: AutoWrappedModule,311 },312 module_config=dict(313 offload_dtype=dtype,314 offload_device="cpu",315 onload_dtype=dtype,316 onload_device=self.device,317 computation_dtype=self.param_dtype,318 computation_device=self.device,319 ),320 max_num_param=num_persistent_param_in_dit,321 overflow_module_config=dict(322 offload_dtype=dtype,323 offload_device="cpu",324 onload_dtype=dtype,325 onload_device="cpu",326 computation_dtype=self.param_dtype,327 computation_device=self.device,328 ),329 )330 self.enable_cpu_offload()331 332 def enable_cpu_offload(self):333 self.cpu_offload = True334 335 def load_models_to_device(self, loadmodel_names=[]):336 # only load models to device if cpu_offload is enabled337 if not self.cpu_offload:338 return339 # offload the unneeded models to cpu340 for model_name in self.model_names:341 if model_name not in loadmodel_names:342 model = getattr(self, model_name)343 344 if not isinstance(model, nn.Module):345 model = model.model346 347 if model is not None:348 if (349 hasattr(model, "vram_management_enabled")350 and model.vram_management_enabled351 ):352 for module in model.modules():353 if hasattr(module, "offload"):354 module.offload()355 else:356 model.cpu()357 # load the needed models to device358 for model_name in loadmodel_names:359 model = getattr(self, model_name)360 if not isinstance(model, nn.Module):361 model = model.model362 if model is not None:363 if (364 hasattr(model, "vram_management_enabled")365 and model.vram_management_enabled366 ):367 for module in model.modules():368 if hasattr(module, "onload"):369 module.onload()370 else:371 model.to(self.device)372 # fresh the cuda cache373 torch.cuda.empty_cache()374 375 376 def generate_infinitetalk(self,377 input_data,378 size_buckget='infinitetalk-480',379 motion_frame=25,380 frame_num=81,381 shift=5.0,382 sampling_steps=40,383 text_guide_scale=5.0,384 audio_guide_scale=4.0,385 n_prompt="",386 seed=-1,387 offload_model=True,388 max_frames_num=1000,389 face_scale=0.05,390 progress=True,391 color_correction_strength=0.0,392 extra_args=None):393 r"""394 Generates video frames from input image and text prompt using diffusion process.395 396 Args:397 frame_num (`int`, *optional*, defaults to 81):398 How many frames to sample from a video. The number should be 4n+1399 shift (`float`, *optional*, defaults to 5.0):400 Noise schedule shift parameter. Affects temporal dynamics401 [NOTE]: If you want to generate a 480p video, it is recommended to set the shift value to 3.0.402 sampling_steps (`int`, *optional*, defaults to 40):403 Number of diffusion sampling steps. Higher values improve quality but slow generation404 n_prompt (`str`, *optional*, defaults to ""):405 Negative prompt for content exclusion. If not given, use `config.sample_neg_prompt`406 seed (`int`, *optional*, defaults to -1):407 Random seed for noise generation. If -1, use random seed408 offload_model (`bool`, *optional*, defaults to True):409 If True, offloads models to CPU during generation to save VRAM410 """411 412 # init teacache413 if extra_args.use_teacache:414 self.model.teacache_init(415 sample_steps=sampling_steps,416 teacache_thresh=extra_args.teacache_thresh,417 model_scale=extra_args.size,418 )419 else:420 self.model.disable_teacache()421 422 input_prompt = input_data['prompt']423 cond_file_path = input_data['cond_video']424 codec = get_video_codec(cond_file_path)425 if codec == 'av1':426 output_video_path = 'tmp/' + '_input_h264.mp4'427 print(f"Converting {cond_file_path} from AV1 to H.264...")428 convert_video_to_h264(cond_file_path, output_video_path)429 print(f"Conversion complete! Saved as {output_video_path}")430 cond_file_path = output_video_path431 else:432 print("No conversion needed.")433 cond_image = extract_specific_frames(cond_file_path, 0)434 # cond_image = Image.fromarray(cond_image)435 436 437 # decide a proper size438 bucket_config_module = importlib.import_module("wan.utils.multitalk_utils")439 if size_buckget == 'infinitetalk-480':440 bucket_config = getattr(bucket_config_module, 'ASPECT_RATIO_627')441 elif size_buckget == 'infinitetalk-720':442 bucket_config = getattr(bucket_config_module, 'ASPECT_RATIO_960')443 444 src_h, src_w = cond_image.height, cond_image.width445 ratio = src_h / src_w446 closest_bucket = sorted(list(bucket_config.keys()), key=lambda x: abs(float(x)-ratio))[0]447 target_h, target_w = bucket_config[closest_bucket][0]448 cond_image = resize_and_centercrop(cond_image, (target_h, target_w))449 cond_image = cond_image / 255450 cond_image = (cond_image - 0.5) * 2 # normalization451 cond_image = cond_image.to(self.device) # 1 C 1 H W452 453 # Store the original image for color reference if strength > 0454 original_color_reference = None455 if color_correction_strength > 0.0:456 original_color_reference = cond_image.clone()457 458 459 # read audio embeddings460 audio_embedding_path_1 = input_data['cond_audio']['person1']461 if len(input_data['cond_audio']) == 1:462 HUMAN_NUMBER = 1463 audio_embedding_path_2 = None464 else:465 HUMAN_NUMBER = 2466 audio_embedding_path_2 = input_data['cond_audio']['person2']467 468 469 full_audio_embs = [] 470 audio_embedding_paths = [audio_embedding_path_1, audio_embedding_path_2]471 for human_idx in range(HUMAN_NUMBER): 472 audio_embedding_path = audio_embedding_paths[human_idx]473 if not os.path.exists(audio_embedding_path):474 continue475 full_audio_emb = torch.load(audio_embedding_path)476 if torch.isnan(full_audio_emb).any():477 continue478 if full_audio_emb.shape[0] <= frame_num:479 continue480 full_audio_embs.append(full_audio_emb) 481 482 assert len(full_audio_embs) == HUMAN_NUMBER, f"Aduio file not exists or length not satisfies frame nums."483 484 # preprocess text embedding485 if n_prompt == "":486 n_prompt = self.sample_neg_prompt487 if not self.t5_cpu:488 self.text_encoder.model.to(self.device)489 context, context_null = self.text_encoder([input_prompt, n_prompt], self.device)490 if offload_model:491 self.text_encoder.model.cpu()492 else:493 context = self.text_encoder([input_prompt], torch.device('cpu'))494 context_null = self.text_encoder([n_prompt], torch.device('cpu'))495 context = [t.to(self.device) for t in context]496 context_null = [t.to(self.device) for t in context_null]497 498 torch_gc()499 # prepare params for video generation500 indices = (torch.arange(2 * 2 + 1) - 2) * 1 501 clip_length = frame_num502 is_first_clip = True503 arrive_last_frame = False504 cur_motion_frames_num = 1505 audio_start_idx = 0506 audio_end_idx = audio_start_idx + clip_length507 gen_video_list = []508 torch_gc()509 510 # set random seed and init noise511 seed = seed if seed >= 0 else random.randint(0, 99999999)512 torch.manual_seed(seed)513 torch.cuda.manual_seed_all(seed)514 np.random.seed(seed)515 random.seed(seed)516 torch.backends.cudnn.deterministic = True517 518 # start video generation iteratively519 while True:520 audio_embs = []521 # split audio with window size522 for human_idx in range(HUMAN_NUMBER): 523 center_indices = torch.arange(524 audio_start_idx,525 audio_end_idx,526 1,527 ).unsqueeze(528 1529 ) + indices.unsqueeze(0)530 center_indices = torch.clamp(center_indices, min=0, max=full_audio_embs[human_idx].shape[0]-1)531 audio_emb = full_audio_embs[human_idx][center_indices][None,...].to(self.device)532 audio_embs.append(audio_emb)533 audio_embs = torch.concat(audio_embs, dim=0).to(self.param_dtype)534 torch_gc()535 536 h, w = cond_image.shape[-2], cond_image.shape[-1]537 lat_h, lat_w = h // self.vae_stride[1], w // self.vae_stride[2]538 max_seq_len = ((frame_num - 1) // self.vae_stride[0] + 1) * lat_h * lat_w // (539 self.patch_size[1] * self.patch_size[2])540 max_seq_len = int(math.ceil(max_seq_len / self.sp_size)) * self.sp_size541 542 543 544 noise = torch.randn(545 16, (frame_num - 1) // 4 + 1,546 lat_h,547 lat_w,548 dtype=torch.float32,549 device=self.device) 550 551 # get mask552 msk = torch.ones(1, frame_num, lat_h, lat_w, device=self.device)553 msk[:, 1:] = 0554 msk = torch.concat([555 torch.repeat_interleave(msk[:, 0:1], repeats=4, dim=1), msk[:, 1:]556 ],557 dim=1)558 msk = msk.view(1, msk.shape[1] // 4, 4, lat_h, lat_w)559 msk = msk.transpose(1, 2).to(self.param_dtype) # B 4 T H W560 561 with torch.no_grad():562 # get clip embedding563 self.clip.model.to(self.device)564 clip_context = self.clip.visual(cond_image[:, :, -1:, :, :]).to(self.param_dtype) 565 if offload_model:566 self.clip.model.cpu()567 torch_gc()568 569 # zero padding and vae encode570 video_frames = torch.zeros(1, cond_image.shape[1], frame_num-cond_image.shape[2], target_h, target_w).to(self.device)571 padding_frames_pixels_values = torch.concat([cond_image, video_frames], dim=2)572 y = self.vae.encode(padding_frames_pixels_values) 573 y = torch.stack(y).to(self.param_dtype) # B C T H W574 cur_motion_frames_latent_num = int(1 + (cur_motion_frames_num-1) // 4)575 576 if is_first_clip:577 latent_motion_frames = self.vae.encode(cond_image)[0]578 else:579 latent_motion_frames = self.vae.encode(cond_frame)[0]580 581 y = torch.concat([msk, y], dim=1) # B 4+C T H W582 torch_gc()583 584 585 # construct human mask586 human_masks = []587 if HUMAN_NUMBER==1:588 background_mask = torch.ones([src_h, src_w])589 human_mask1 = torch.ones([src_h, src_w])590 human_mask2 = torch.ones([src_h, src_w])591 human_masks = [human_mask1, human_mask2, background_mask]592 elif HUMAN_NUMBER==2:593 if 'bbox' in input_data:594 assert len(input_data['bbox']) == len(input_data['cond_audio']), f"The number of target bbox should be the same with cond_audio"595 background_mask = torch.zeros([src_h, src_w])596 for _, person_bbox in input_data['bbox'].items():597 x_min, y_min, x_max, y_max = person_bbox598 human_mask = torch.zeros([src_h, src_w])599 human_mask[int(x_min):int(x_max), int(y_min):int(y_max)] = 1600 background_mask += human_mask601 human_masks.append(human_mask)602 else:603 x_min, x_max = int(src_h * face_scale), int(src_h * (1 - face_scale))604 background_mask = torch.zeros([src_h, src_w])605 background_mask = torch.zeros([src_h, src_w])606 human_mask1 = torch.zeros([src_h, src_w])607 human_mask2 = torch.zeros([src_h, src_w])608 lefty_min, lefty_max = int((src_w//2) * face_scale), int((src_w//2) * (1 - face_scale))609 righty_min, righty_max = int((src_w//2) * face_scale + (src_w//2)), int((src_w//2) * (1 - face_scale) + (src_w//2))610 human_mask1[x_min:x_max, lefty_min:lefty_max] = 1611 human_mask2[x_min:x_max, righty_min:righty_max] = 1612 background_mask += human_mask1613 background_mask += human_mask2614 human_masks = [human_mask1, human_mask2]615 background_mask = torch.where(background_mask > 0, torch.tensor(0), torch.tensor(1))616 human_masks.append(background_mask)617 618 ref_target_masks = torch.stack(human_masks, dim=0).to(self.device)619 # resize and centercrop for ref_target_masks 620 ref_target_masks = resize_and_centercrop(ref_target_masks, (target_h, target_w))621 622 _, _, _,lat_h, lat_w = y.shape623 ref_target_masks = F.interpolate(ref_target_masks.unsqueeze(0), size=(lat_h, lat_w), mode='nearest').squeeze() 624 ref_target_masks = (ref_target_masks > 0) 625 ref_target_masks = ref_target_masks.float().to(self.device)626 627 torch_gc()628 629 @contextmanager630 def noop_no_sync():631 yield632 633 no_sync = getattr(self.model, 'no_sync', noop_no_sync)634 635 # evaluation mode636 with torch.no_grad(), no_sync():637 638 # prepare timesteps639 timesteps = list(np.linspace(self.num_timesteps, 1, sampling_steps, dtype=np.float32))640 timesteps.append(0.)641 timesteps = [torch.tensor([t], device=self.device) for t in timesteps]642 if self.use_timestep_transform:643 timesteps = [timestep_transform(t, shift=shift, num_timesteps=self.num_timesteps) for t in timesteps]644 645 # sample videos646 latent = noise647 648 # prepare condition and uncondition configs649 arg_c = {650 'context': [context],651 'clip_fea': clip_context,652 'seq_len': max_seq_len,653 'y': y,654 'audio': audio_embs,655 'ref_target_masks': ref_target_masks656 }657 658 659 arg_null_text = {660 'context': [context_null],661 'clip_fea': clip_context,662 'seq_len': max_seq_len,663 'y': y,664 'audio': audio_embs,665 'ref_target_masks': ref_target_masks666 }667 668 arg_null_audio = {669 'context': [context],670 'clip_fea': clip_context,671 'seq_len': max_seq_len,672 'y': y,673 'audio': torch.zeros_like(audio_embs)[-1:],674 'ref_target_masks': ref_target_masks675 }676 677 678 arg_null = {679 'context': [context_null],680 'clip_fea': clip_context,681 'seq_len': max_seq_len,682 'y': y,683 'audio': torch.zeros_like(audio_embs)[-1:],684 'ref_target_masks': ref_target_masks685 }686 687 torch_gc()688 if not self.vram_management:689 self.model.to(self.device)690 else:691 self.load_models_to_device(["model"])692 693 # injecting motion frames694 if not is_first_clip:695 latent_motion_frames = latent_motion_frames.to(latent.dtype).to(self.device)696 motion_add_noise = torch.randn_like(latent_motion_frames).contiguous()697 add_latent = self.add_noise(latent_motion_frames, motion_add_noise, timesteps[0])698 _, T_m, _, _ = add_latent.shape699 latent[:, :T_m] = add_latent700 701 # infer with APG702 # refer https://arxiv.org/abs/2410.02416 703 if extra_args.use_apg: 704 text_momentumbuffer = MomentumBuffer(extra_args.apg_momentum) 705 audio_momentumbuffer = MomentumBuffer(extra_args.apg_momentum) 706 707 708 progress_wrap = partial(tqdm, total=len(timesteps)-1) if progress else (lambda x: x)709 for i in progress_wrap(range(len(timesteps)-1)):710 timestep = timesteps[i]711 latent[:, :cur_motion_frames_latent_num] = latent_motion_frames712 latent_model_input = [latent.to(self.device)]713 714 # inference with CFG strategy715 noise_pred_cond = self.model(716 latent_model_input, t=timestep, **arg_c)[0] 717 torch_gc()718 719 if math.isclose(text_guide_scale, 1.0):720 noise_pred_drop_audio = self.model(721 latent_model_input, t=timestep, **arg_null_audio)[0] 722 torch_gc()723 else:724 noise_pred_drop_text = self.model(725 latent_model_input, t=timestep, **arg_null_text)[0] 726 torch_gc()727 noise_pred_uncond = self.model(728 latent_model_input, t=timestep, **arg_null)[0] 729 torch_gc()730 731 if extra_args.use_apg:732 # correct update direction733 if math.isclose(text_guide_scale, 1.0):734 diff_uncond_audio = noise_pred_cond - noise_pred_drop_audio735 noise_pred = noise_pred_cond + (audio_guide_scale - 1)* adaptive_projected_guidance(diff_uncond_audio, 736 noise_pred_cond, 737 momentum_buffer=audio_momentumbuffer, 738 norm_threshold=extra_args.apg_norm_threshold)739 else:740 diff_uncond_text = noise_pred_cond - noise_pred_drop_text741 diff_uncond_audio = noise_pred_drop_text - noise_pred_uncond742 noise_pred = noise_pred_cond + (text_guide_scale - 1) * adaptive_projected_guidance(diff_uncond_text, 743 noise_pred_cond, 744 momentum_buffer=text_momentumbuffer, 745 norm_threshold=extra_args.apg_norm_threshold) \746 + (audio_guide_scale - 1) * adaptive_projected_guidance(diff_uncond_audio, 747 noise_pred_cond, 748 momentum_buffer=audio_momentumbuffer, 749 norm_threshold=extra_args.apg_norm_threshold)750 else:751 # vanilla CFG strategy752 if math.isclose(text_guide_scale, 1.0):753 noise_pred = noise_pred_drop_audio + audio_guide_scale* (noise_pred_cond - noise_pred_drop_audio) 754 else:755 noise_pred = noise_pred_uncond + text_guide_scale * (756 noise_pred_cond - noise_pred_drop_text) + \757 audio_guide_scale * (noise_pred_drop_text - noise_pred_uncond) 758 noise_pred = -noise_pred 759 760 # update latent761 dt = timesteps[i] - timesteps[i + 1]762 dt = dt / self.num_timesteps763 latent = latent + noise_pred * dt[:, None, None, None]764 765 # injecting motion frames766 if not is_first_clip:767 latent_motion_frames = latent_motion_frames.to(latent.dtype).to(self.device)768 motion_add_noise = torch.randn_like(latent_motion_frames).contiguous()769 add_latent = self.add_noise(latent_motion_frames, motion_add_noise, timesteps[i+1])770 _, T_m, _, _ = add_latent.shape771 latent[:, :T_m] = add_latent772 773 latent[:, :cur_motion_frames_latent_num] = latent_motion_frames774 x0 = [latent.to(self.device)] 775 del latent_model_input, timestep776 777 if offload_model: 778 if not self.vram_management:779 self.model.cpu()780 torch_gc()781 782 videos = self.vae.decode(x0)783 784 # cache generated samples785 videos = torch.stack(videos).cpu() # B C T H W786 # >>> START OF COLOR CORRECTION STEP <<<787 if color_correction_strength > 0.0 and original_color_reference is not None:788 videos = match_and_blend_colors(videos, original_color_reference, color_correction_strength)789 # >>> END OF COLOR CORRECTION STEP <<<790 791 if is_first_clip:792 gen_video_list.append(videos)793 else:794 gen_video_list.append(videos[:, :, cur_motion_frames_num:])795 796 # decide whether is done797 if arrive_last_frame: break798 799 # update next condition frames800 is_first_clip = False801 cur_motion_frames_num = motion_frame802 803 cond_frame = videos[:, :, -cur_motion_frames_num:].to(torch.float32).to(self.device)804 audio_start_idx += (frame_num - cur_motion_frames_num)805 audio_end_idx = audio_start_idx + clip_length806 807 cond_image = extract_specific_frames(cond_file_path, audio_start_idx)808 # cond_image = Image.fromarray(cond_image)809 cond_image = resize_and_centercrop(cond_image, (target_h, target_w))810 cond_image = cond_image / 255811 cond_image = (cond_image - 0.5) * 2 # normalization812 cond_image = cond_image.to(self.device) # 1 C 1 H W813 814 # Repeat audio emb815 if audio_end_idx >= min(max_frames_num, len(full_audio_embs[0])):816 arrive_last_frame = True817 miss_lengths = []818 source_frames = []819 for human_inx in range(HUMAN_NUMBER):820 source_frame = len(full_audio_embs[human_inx])821 source_frames.append(source_frame)822 if audio_end_idx >= len(full_audio_embs[human_inx]):823 miss_length = audio_end_idx - len(full_audio_embs[human_inx]) + 3 824 add_audio_emb = torch.flip(full_audio_embs[human_inx][-1*miss_length:], dims=[0])825 full_audio_embs[human_inx] = torch.cat([full_audio_embs[human_inx], add_audio_emb], dim=0)826 miss_lengths.append(miss_length)827 else:828 miss_lengths.append(0)829 830 831 if max_frames_num <= frame_num: break832 833 torch_gc()834 if offload_model: 835 torch.cuda.synchronize()836 if dist.is_initialized():837 dist.barrier()838 839 gen_video_samples = torch.cat(gen_video_list, dim=2)[:, :, :int(max_frames_num)] 840 gen_video_samples = gen_video_samples.to(torch.float32)841 if max_frames_num > frame_num and sum(miss_lengths) > 0:842 # split video frames843 # gen_video_samples = gen_video_samples[:, :, :-1*miss_lengths[0]]844 gen_video_samples = gen_video_samples[:, :, :full_audio_emb.shape[0]]845 846 if dist.is_initialized():847 dist.barrier()848 849 del noise, latent850 torch_gc()851 852 return gen_video_samples[0] if self.rank == 0 else None853 854 855 856 