CoolFace
Apppublic

AstroAUmin/self-forcing

sourceHugging Faceupdated 22d agoView on Hugging Face
0likes
bidirectional_diffusion_inference.py111 linesDownload Raw Back to pipeline
1from tqdm import tqdm2from typing import List3import torch4 5from wan.utils.fm_solvers import FlowDPMSolverMultistepScheduler, get_sampling_sigmas, retrieve_timesteps6from wan.utils.fm_solvers_unipc import FlowUniPCMultistepScheduler7from utils.wan_wrapper import WanDiffusionWrapper, WanTextEncoder, WanVAEWrapper8 9 10class BidirectionalDiffusionInferencePipeline(torch.nn.Module):11    def __init__(12            self,13            args,14            device,15            generator=None,16            text_encoder=None,17            vae=None18    ):19        super().__init__()20        # Step 1: Initialize all models21        self.generator = WanDiffusionWrapper(22            **getattr(args, "model_kwargs", {}), is_causal=False) if generator is None else generator23        self.text_encoder = WanTextEncoder() if text_encoder is None else text_encoder24        self.vae = WanVAEWrapper() if vae is None else vae25 26        # Step 2: Initialize scheduler27        self.num_train_timesteps = args.num_train_timestep28        self.sampling_steps = 5029        self.sample_solver = 'unipc'30        self.shift = 8.031 32        self.args = args33 34    def inference(35        self,36        noise: torch.Tensor,37        text_prompts: List[str],38        return_latents=False39    ) -> torch.Tensor:40        """41        Perform inference on the given noise and text prompts.42        Inputs:43            noise (torch.Tensor): The input noise tensor of shape44                (batch_size, num_frames, num_channels, height, width).45            text_prompts (List[str]): The list of text prompts.46        Outputs:47            video (torch.Tensor): The generated video tensor of shape48                (batch_size, num_frames, num_channels, height, width). It is normalized to be in the range [0, 1].49        """50 51        conditional_dict = self.text_encoder(52            text_prompts=text_prompts53        )54        unconditional_dict = self.text_encoder(55            text_prompts=[self.args.negative_prompt] * len(text_prompts)56        )57 58        latents = noise59 60        sample_scheduler = self._initialize_sample_scheduler(noise)61        for _, t in enumerate(tqdm(sample_scheduler.timesteps)):62            latent_model_input = latents63            timestep = t * torch.ones([latents.shape[0], 21], device=noise.device, dtype=torch.float32)64 65            flow_pred_cond, _ = self.generator(latent_model_input, conditional_dict, timestep)66            flow_pred_uncond, _ = self.generator(latent_model_input, unconditional_dict, timestep)67 68            flow_pred = flow_pred_uncond + self.args.guidance_scale * (69                flow_pred_cond - flow_pred_uncond)70 71            temp_x0 = sample_scheduler.step(72                flow_pred.unsqueeze(0),73                t,74                latents.unsqueeze(0),75                return_dict=False)[0]76            latents = temp_x0.squeeze(0)77 78        x0 = latents79        video = self.vae.decode_to_pixel(x0)80        video = (video * 0.5 + 0.5).clamp(0, 1)81 82        del sample_scheduler83 84        if return_latents:85            return video, latents86        else:87            return video88 89    def _initialize_sample_scheduler(self, noise):90        if self.sample_solver == 'unipc':91            sample_scheduler = FlowUniPCMultistepScheduler(92                num_train_timesteps=self.num_train_timesteps,93                shift=1,94                use_dynamic_shifting=False)95            sample_scheduler.set_timesteps(96                self.sampling_steps, device=noise.device, shift=self.shift)97            self.timesteps = sample_scheduler.timesteps98        elif self.sample_solver == 'dpm++':99            sample_scheduler = FlowDPMSolverMultistepScheduler(100                num_train_timesteps=self.num_train_timesteps,101                shift=1,102                use_dynamic_shifting=False)103            sampling_sigmas = get_sampling_sigmas(self.sampling_steps, self.shift)104            self.timesteps, _ = retrieve_timesteps(105                sample_scheduler,106                device=noise.device,107                sigmas=sampling_sigmas)108        else:109            raise NotImplementedError("Unsupported solver.")110        return sample_scheduler111