CoolFace
Datasetpublic

diffusers/community-pipelines-mirror

Community Pipeline Examples For more information about community pipelines, please have a look at this issue. Community pipeline examples consist pipelines that have been added by the community. Please have a look at the following tables to get an overview of all community examples. Click on the Code Example to get a copy-and-paste ready code example that you can try out. If a community pipeline doesn't work as expected, please open an issue and ping the author on it. Please… See the full description on the dataset page: https://huggingface.co/datasets/diffusers/community-pipelines-mirror.

sourceHugging Faceupdated 29d agoView on Hugging Face
9likes22kdownloads
pipeline_null_text_inversion.py261 linesDownload Raw Back to root
1import inspect2import os3 4import numpy as np5import torch6import torch.nn.functional as nnf7from PIL import Image8from torch.optim.adam import Adam9from tqdm import tqdm10 11from diffusers import StableDiffusionPipeline12from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput13 14 15def retrieve_timesteps(16    scheduler,17    num_inference_steps=None,18    device=None,19    timesteps=None,20    **kwargs,21):22    """23    Calls the scheduler's `set_timesteps` method and retrieves timesteps from the scheduler after the call. Handles24    custom timesteps. Any kwargs will be supplied to `scheduler.set_timesteps`.25    Args:26        scheduler (`SchedulerMixin`):27            The scheduler to get timesteps from.28        num_inference_steps (`int`):29            The number of diffusion steps used when generating samples with a pre-trained model. If used,30            `timesteps` must be `None`.31        device (`str` or `torch.device`, *optional*):32            The device to which the timesteps should be moved to. If `None`, the timesteps are not moved.33        timesteps (`List[int]`, *optional*):34                Custom timesteps used to support arbitrary spacing between timesteps. If `None`, then the default35                timestep spacing strategy of the scheduler is used. If `timesteps` is passed, `num_inference_steps`36                must be `None`.37 38    Returns:39        `Tuple[torch.Tensor, int]`: A tuple where the first element is the timestep schedule from the scheduler and the40        second element is the number of inference steps.41    """42    if timesteps is not None:43        accepts_timesteps = "timesteps" in set(inspect.signature(scheduler.set_timesteps).parameters.keys())44        if not accepts_timesteps:45            raise ValueError(46                f"The current scheduler class {scheduler.__class__}'s `set_timesteps` does not support custom"47                f" timestep schedules. Please check whether you are using the correct scheduler."48            )49        scheduler.set_timesteps(timesteps=timesteps, device=device, **kwargs)50        timesteps = scheduler.timesteps51        num_inference_steps = len(timesteps)52    else:53        scheduler.set_timesteps(num_inference_steps, device=device, **kwargs)54        timesteps = scheduler.timesteps55    return timesteps, num_inference_steps56 57 58class NullTextPipeline(StableDiffusionPipeline):59    def get_noise_pred(self, latents, t, context):60        latents_input = torch.cat([latents] * 2)61        guidance_scale = 7.562        noise_pred = self.unet(latents_input, t, encoder_hidden_states=context)["sample"]63        noise_pred_uncond, noise_prediction_text = noise_pred.chunk(2)64        noise_pred = noise_pred_uncond + guidance_scale * (noise_prediction_text - noise_pred_uncond)65        latents = self.prev_step(noise_pred, t, latents)66        return latents67 68    def get_noise_pred_single(self, latents, t, context):69        noise_pred = self.unet(latents, t, encoder_hidden_states=context)["sample"]70        return noise_pred71 72    @torch.no_grad()73    def image2latent(self, image_path):74        image = Image.open(image_path).convert("RGB")75        image = np.array(image)76        image = torch.from_numpy(image).float() / 127.5 - 177        image = image.permute(2, 0, 1).unsqueeze(0).to(self.device)78        latents = self.vae.encode(image)["latent_dist"].mean79        latents = latents * 0.1821580        return latents81 82    @torch.no_grad()83    def latent2image(self, latents):84        latents = 1 / 0.18215 * latents.detach()85        image = self.vae.decode(latents)["sample"].detach()86        image = self.processor.postprocess(image, output_type="pil")[0]87        return image88 89    def prev_step(self, model_output, timestep, sample):90        prev_timestep = timestep - self.scheduler.config.num_train_timesteps // self.scheduler.num_inference_steps91        alpha_prod_t = self.scheduler.alphas_cumprod[timestep]92        alpha_prod_t_prev = (93            self.scheduler.alphas_cumprod[prev_timestep] if prev_timestep >= 0 else self.scheduler.final_alpha_cumprod94        )95        beta_prod_t = 1 - alpha_prod_t96        pred_original_sample = (sample - beta_prod_t**0.5 * model_output) / alpha_prod_t**0.597        pred_sample_direction = (1 - alpha_prod_t_prev) ** 0.5 * model_output98        prev_sample = alpha_prod_t_prev**0.5 * pred_original_sample + pred_sample_direction99        return prev_sample100 101    def next_step(self, model_output, timestep, sample):102        timestep, next_timestep = (103            min(timestep - self.scheduler.config.num_train_timesteps // self.num_inference_steps, 999),104            timestep,105        )106        alpha_prod_t = self.scheduler.alphas_cumprod[timestep] if timestep >= 0 else self.scheduler.final_alpha_cumprod107        alpha_prod_t_next = self.scheduler.alphas_cumprod[next_timestep]108        beta_prod_t = 1 - alpha_prod_t109        next_original_sample = (sample - beta_prod_t**0.5 * model_output) / alpha_prod_t**0.5110        next_sample_direction = (1 - alpha_prod_t_next) ** 0.5 * model_output111        next_sample = alpha_prod_t_next**0.5 * next_original_sample + next_sample_direction112        return next_sample113 114    def null_optimization(self, latents, context, num_inner_steps, epsilon):115        uncond_embeddings, cond_embeddings = context.chunk(2)116        uncond_embeddings_list = []117        latent_cur = latents[-1]118        bar = tqdm(total=num_inner_steps * self.num_inference_steps)119        for i in range(self.num_inference_steps):120            uncond_embeddings = uncond_embeddings.clone().detach()121            uncond_embeddings.requires_grad = True122            optimizer = Adam([uncond_embeddings], lr=1e-2 * (1.0 - i / 100.0))123            latent_prev = latents[len(latents) - i - 2]124            t = self.scheduler.timesteps[i]125            with torch.no_grad():126                noise_pred_cond = self.get_noise_pred_single(latent_cur, t, cond_embeddings)127            for j in range(num_inner_steps):128                noise_pred_uncond = self.get_noise_pred_single(latent_cur, t, uncond_embeddings)129                noise_pred = noise_pred_uncond + 7.5 * (noise_pred_cond - noise_pred_uncond)130                latents_prev_rec = self.prev_step(noise_pred, t, latent_cur)131                loss = nnf.mse_loss(latents_prev_rec, latent_prev)132                optimizer.zero_grad()133                loss.backward()134                optimizer.step()135                loss_item = loss.item()136                bar.update()137                if loss_item < epsilon + i * 2e-5:138                    break139            for j in range(j + 1, num_inner_steps):140                bar.update()141            uncond_embeddings_list.append(uncond_embeddings[:1].detach())142            with torch.no_grad():143                context = torch.cat([uncond_embeddings, cond_embeddings])144                latent_cur = self.get_noise_pred(latent_cur, t, context)145        bar.close()146        return uncond_embeddings_list147 148    @torch.no_grad()149    def ddim_inversion_loop(self, latent, context):150        self.scheduler.set_timesteps(self.num_inference_steps)151        _, cond_embeddings = context.chunk(2)152        all_latent = [latent]153        latent = latent.clone().detach()154        with torch.no_grad():155            for i in range(0, self.num_inference_steps):156                t = self.scheduler.timesteps[len(self.scheduler.timesteps) - i - 1]157                noise_pred = self.unet(latent, t, encoder_hidden_states=cond_embeddings)["sample"]158                latent = self.next_step(noise_pred, t, latent)159                all_latent.append(latent)160        return all_latent161 162    def get_context(self, prompt):163        uncond_input = self.tokenizer(164            [""], padding="max_length", max_length=self.tokenizer.model_max_length, return_tensors="pt"165        )166        uncond_embeddings = self.text_encoder(uncond_input.input_ids.to(self.device))[0]167        text_input = self.tokenizer(168            [prompt],169            padding="max_length",170            max_length=self.tokenizer.model_max_length,171            truncation=True,172            return_tensors="pt",173        )174        text_embeddings = self.text_encoder(text_input.input_ids.to(self.device))[0]175        context = torch.cat([uncond_embeddings, text_embeddings])176        return context177 178    def invert(179        self, image_path: str, prompt: str, num_inner_steps=10, early_stop_epsilon=1e-6, num_inference_steps=50180    ):181        self.num_inference_steps = num_inference_steps182        context = self.get_context(prompt)183        latent = self.image2latent(image_path)184        ddim_latents = self.ddim_inversion_loop(latent, context)185        if os.path.exists(image_path + ".pt"):186            uncond_embeddings = torch.load(image_path + ".pt")187        else:188            uncond_embeddings = self.null_optimization(ddim_latents, context, num_inner_steps, early_stop_epsilon)189            uncond_embeddings = torch.stack(uncond_embeddings, 0)190            torch.save(uncond_embeddings, image_path + ".pt")191        return ddim_latents[-1], uncond_embeddings192 193    @torch.no_grad()194    def __call__(195        self,196        prompt,197        uncond_embeddings,198        inverted_latent,199        num_inference_steps: int = 50,200        timesteps=None,201        guidance_scale=7.5,202        negative_prompt=None,203        num_images_per_prompt=1,204        generator=None,205        latents=None,206        prompt_embeds=None,207        negative_prompt_embeds=None,208        output_type="pil",209    ):210        self._guidance_scale = guidance_scale211        # 0. Default height and width to unet212        height = self.unet.config.sample_size * self.vae_scale_factor213        width = self.unet.config.sample_size * self.vae_scale_factor214        # to deal with lora scaling and other possible forward hook215        callback_steps = None216        # 1. Check inputs. Raise error if not correct217        self.check_inputs(218            prompt,219            height,220            width,221            callback_steps,222            negative_prompt,223            prompt_embeds,224            negative_prompt_embeds,225        )226        # 2. Define call parameter227        device = self._execution_device228        # 3. Encode input prompt229        prompt_embeds, _ = self.encode_prompt(230            prompt,231            device,232            num_images_per_prompt,233            self.do_classifier_free_guidance,234            negative_prompt,235            prompt_embeds=prompt_embeds,236            negative_prompt_embeds=negative_prompt_embeds,237        )238        # 4. Prepare timesteps239        timesteps, num_inference_steps = retrieve_timesteps(self.scheduler, num_inference_steps, device, timesteps)240        latents = inverted_latent241        with self.progress_bar(total=num_inference_steps) as progress_bar:242            for i, t in enumerate(timesteps):243                noise_pred_uncond = self.unet(latents, t, encoder_hidden_states=uncond_embeddings[i])["sample"]244                noise_pred = self.unet(latents, t, encoder_hidden_states=prompt_embeds)["sample"]245                noise_pred = noise_pred_uncond + guidance_scale * (noise_pred - noise_pred_uncond)246                # compute the previous noisy sample x_t -> x_t-1247                latents = self.scheduler.step(noise_pred, t, latents, return_dict=False)[0]248                progress_bar.update()249        if not output_type == "latent":250            image = self.vae.decode(latents / self.vae.config.scaling_factor, return_dict=False, generator=generator)[251                0252            ]253        else:254            image = latents255        image = self.image_processor.postprocess(256            image, output_type=output_type, do_denormalize=[True] * image.shape[0]257        )258        # Offload all models259        self.maybe_free_model_hooks()260        return StableDiffusionPipelineOutput(images=image, nsfw_content_detected=False)261