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.
922k
1# Copyright 2023 Long Lian, the GLIGEN Authors, and The HuggingFace Team. All rights reserved.2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7# http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14 15# This is a single file implementation of LMD+. See README.md for examples.16 17import ast18import gc19import inspect20import math21import warnings22from collections.abc import Iterable23from typing import Any, Callable, Dict, List, Optional, Union24 25import torch26import torch.nn.functional as F27from packaging import version28from transformers import CLIPImageProcessor, CLIPTextModel, CLIPTokenizer, CLIPVisionModelWithProjection29 30from diffusers.configuration_utils import FrozenDict31from diffusers.image_processor import PipelineImageInput, VaeImageProcessor32from diffusers.loaders import FromSingleFileMixin, IPAdapterMixin, LoraLoaderMixin, TextualInversionLoaderMixin33from diffusers.models import AutoencoderKL, UNet2DConditionModel34from diffusers.models.attention import Attention, GatedSelfAttentionDense35from diffusers.models.attention_processor import AttnProcessor2_036from diffusers.models.lora import adjust_lora_scale_text_encoder37from diffusers.pipelines import DiffusionPipeline38from diffusers.pipelines.stable_diffusion.pipeline_output import StableDiffusionPipelineOutput39from diffusers.pipelines.stable_diffusion.safety_checker import StableDiffusionSafetyChecker40from diffusers.schedulers import KarrasDiffusionSchedulers41from diffusers.utils import (42 USE_PEFT_BACKEND,43 deprecate,44 logging,45 replace_example_docstring,46 scale_lora_layers,47 unscale_lora_layers,48)49from diffusers.utils.torch_utils import randn_tensor50 51 52EXAMPLE_DOC_STRING = """53 Examples:54 ```py55 >>> import torch56 >>> from diffusers import DiffusionPipeline57 58 >>> pipe = DiffusionPipeline.from_pretrained(59 ... "longlian/lmd_plus",60 ... custom_pipeline="llm_grounded_diffusion",61 ... custom_revision="main",62 ... variant="fp16", torch_dtype=torch.float1663 ... )64 >>> pipe.enable_model_cpu_offload()65 66 >>> # Generate an image described by the prompt and67 >>> # insert objects described by text at the region defined by bounding boxes68 >>> prompt = "a waterfall and a modern high speed train in a beautiful forest with fall foliage"69 >>> boxes = [[0.1387, 0.2051, 0.4277, 0.7090], [0.4980, 0.4355, 0.8516, 0.7266]]70 >>> phrases = ["a waterfall", "a modern high speed train"]71 72 >>> images = pipe(73 ... prompt=prompt,74 ... phrases=phrases,75 ... boxes=boxes,76 ... gligen_scheduled_sampling_beta=0.4,77 ... output_type="pil",78 ... num_inference_steps=50,79 ... lmd_guidance_kwargs={}80 ... ).images81 82 >>> images[0].save("./lmd_plus_generation.jpg")83 84 >>> # Generate directly from a text prompt and an LLM response85 >>> prompt = "a waterfall and a modern high speed train in a beautiful forest with fall foliage"86 >>> phrases, boxes, bg_prompt, neg_prompt = pipe.parse_llm_response(\"""87 [('a waterfall', [71, 105, 148, 258]), ('a modern high speed train', [255, 223, 181, 149])]88 Background prompt: A beautiful forest with fall foliage89 Negative prompt:90 \""")91 92 >> images = pipe(93 ... prompt=prompt,94 ... negative_prompt=neg_prompt,95 ... phrases=phrases,96 ... boxes=boxes,97 ... gligen_scheduled_sampling_beta=0.4,98 ... output_type="pil",99 ... num_inference_steps=50,100 ... lmd_guidance_kwargs={}101 ... ).images102 103 >>> images[0].save("./lmd_plus_generation.jpg")104 105images[0]106 107 ```108"""109 110logger = logging.get_logger(__name__) # pylint: disable=invalid-name111 112# All keys in Stable Diffusion models: [('down', 0, 0, 0), ('down', 0, 1, 0), ('down', 1, 0, 0), ('down', 1, 1, 0), ('down', 2, 0, 0), ('down', 2, 1, 0), ('mid', 0, 0, 0), ('up', 1, 0, 0), ('up', 1, 1, 0), ('up', 1, 2, 0), ('up', 2, 0, 0), ('up', 2, 1, 0), ('up', 2, 2, 0), ('up', 3, 0, 0), ('up', 3, 1, 0), ('up', 3, 2, 0)]113# Note that the first up block is `UpBlock2D` rather than `CrossAttnUpBlock2D` and does not have attention. The last index is always 0 in our case since we have one `BasicTransformerBlock` in each `Transformer2DModel`.114DEFAULT_GUIDANCE_ATTN_KEYS = [115 ("mid", 0, 0, 0),116 ("up", 1, 0, 0),117 ("up", 1, 1, 0),118 ("up", 1, 2, 0),119]120 121 122def convert_attn_keys(key):123 """Convert the attention key from tuple format to the torch state format"""124 125 if key[0] == "mid":126 assert key[1] == 0, f"mid block only has one block but the index is {key[1]}"127 return f"{key[0]}_block.attentions.{key[2]}.transformer_blocks.{key[3]}.attn2.processor"128 129 return f"{key[0]}_blocks.{key[1]}.attentions.{key[2]}.transformer_blocks.{key[3]}.attn2.processor"130 131 132DEFAULT_GUIDANCE_ATTN_KEYS = [convert_attn_keys(key) for key in DEFAULT_GUIDANCE_ATTN_KEYS]133 134 135def scale_proportion(obj_box, H, W):136 # Separately rounding box_w and box_h to allow shift invariant box sizes. Otherwise box sizes may change when both coordinates being rounded end with ".5".137 x_min, y_min = round(obj_box[0] * W), round(obj_box[1] * H)138 box_w, box_h = round((obj_box[2] - obj_box[0]) * W), round((obj_box[3] - obj_box[1]) * H)139 x_max, y_max = x_min + box_w, y_min + box_h140 141 x_min, y_min = max(x_min, 0), max(y_min, 0)142 x_max, y_max = min(x_max, W), min(y_max, H)143 144 return x_min, y_min, x_max, y_max145 146 147# Adapted from the parent class `AttnProcessor2_0`148class AttnProcessorWithHook(AttnProcessor2_0):149 def __init__(150 self,151 attn_processor_key,152 hidden_size,153 cross_attention_dim,154 hook=None,155 fast_attn=True,156 enabled=True,157 ):158 super().__init__()159 self.attn_processor_key = attn_processor_key160 self.hidden_size = hidden_size161 self.cross_attention_dim = cross_attention_dim162 self.hook = hook163 self.fast_attn = fast_attn164 self.enabled = enabled165 166 def __call__(167 self,168 attn: Attention,169 hidden_states,170 encoder_hidden_states=None,171 attention_mask=None,172 temb=None,173 scale: float = 1.0,174 ):175 residual = hidden_states176 177 if attn.spatial_norm is not None:178 hidden_states = attn.spatial_norm(hidden_states, temb)179 180 input_ndim = hidden_states.ndim181 182 if input_ndim == 4:183 batch_size, channel, height, width = hidden_states.shape184 hidden_states = hidden_states.view(batch_size, channel, height * width).transpose(1, 2)185 186 batch_size, sequence_length, _ = (187 hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape188 )189 190 if attention_mask is not None:191 attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size)192 193 if attn.group_norm is not None:194 hidden_states = attn.group_norm(hidden_states.transpose(1, 2)).transpose(1, 2)195 196 args = () if USE_PEFT_BACKEND else (scale,)197 query = attn.to_q(hidden_states, *args)198 199 if encoder_hidden_states is None:200 encoder_hidden_states = hidden_states201 elif attn.norm_cross:202 encoder_hidden_states = attn.norm_encoder_hidden_states(encoder_hidden_states)203 204 key = attn.to_k(encoder_hidden_states, *args)205 value = attn.to_v(encoder_hidden_states, *args)206 207 inner_dim = key.shape[-1]208 head_dim = inner_dim // attn.heads209 210 if (self.hook is not None and self.enabled) or not self.fast_attn:211 query_batch_dim = attn.head_to_batch_dim(query)212 key_batch_dim = attn.head_to_batch_dim(key)213 value_batch_dim = attn.head_to_batch_dim(value)214 attention_probs = attn.get_attention_scores(query_batch_dim, key_batch_dim, attention_mask)215 216 if self.hook is not None and self.enabled:217 # Call the hook with query, key, value, and attention maps218 self.hook(219 self.attn_processor_key,220 query_batch_dim,221 key_batch_dim,222 value_batch_dim,223 attention_probs,224 )225 226 if self.fast_attn:227 query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)228 229 key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)230 value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)231 232 if attention_mask is not None:233 # scaled_dot_product_attention expects attention_mask shape to be234 # (batch, heads, source_length, target_length)235 attention_mask = attention_mask.view(batch_size, attn.heads, -1, attention_mask.shape[-1])236 237 # the output of sdp = (batch, num_heads, seq_len, head_dim)238 # TODO: add support for attn.scale when we move to Torch 2.1239 hidden_states = F.scaled_dot_product_attention(240 query,241 key,242 value,243 attn_mask=attention_mask,244 dropout_p=0.0,245 is_causal=False,246 )247 hidden_states = hidden_states.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)248 hidden_states = hidden_states.to(query.dtype)249 else:250 hidden_states = torch.bmm(attention_probs, value)251 hidden_states = attn.batch_to_head_dim(hidden_states)252 253 # linear proj254 hidden_states = attn.to_out[0](hidden_states, *args)255 # dropout256 hidden_states = attn.to_out[1](hidden_states)257 258 if input_ndim == 4:259 hidden_states = hidden_states.transpose(-1, -2).reshape(batch_size, channel, height, width)260 261 if attn.residual_connection:262 hidden_states = hidden_states + residual263 264 hidden_states = hidden_states / attn.rescale_output_factor265 266 return hidden_states267 268 269class LLMGroundedDiffusionPipeline(270 DiffusionPipeline, TextualInversionLoaderMixin, LoraLoaderMixin, IPAdapterMixin, FromSingleFileMixin271):272 r"""273 Pipeline for layout-grounded text-to-image generation using LLM-grounded Diffusion (LMD+): https://arxiv.org/pdf/2305.13655.pdf.274 275 This model inherits from [`StableDiffusionPipeline`] and aims at implementing the pipeline with minimal modifications. Check the superclass documentation for the generic methods276 implemented for all pipelines (downloading, saving, running on a particular device, etc.).277 278 This is a simplified implementation that does not perform latent or attention transfer from single object generation to overall generation. The final image is generated directly with attention and adapters control.279 280 Args:281 vae ([`AutoencoderKL`]):282 Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations.283 text_encoder ([`~transformers.CLIPTextModel`]):284 Frozen text-encoder ([clip-vit-large-patch14](https://huggingface.co/openai/clip-vit-large-patch14)).285 tokenizer ([`~transformers.CLIPTokenizer`]):286 A `CLIPTokenizer` to tokenize text.287 unet ([`UNet2DConditionModel`]):288 A `UNet2DConditionModel` to denoise the encoded image latents.289 scheduler ([`SchedulerMixin`]):290 A scheduler to be used in combination with `unet` to denoise the encoded image latents. Can be one of291 [`DDIMScheduler`], [`LMSDiscreteScheduler`], or [`PNDMScheduler`].292 safety_checker ([`StableDiffusionSafetyChecker`]):293 Classification module that estimates whether generated images could be considered offensive or harmful.294 Please refer to the [model card](https://huggingface.co/runwayml/stable-diffusion-v1-5) for more details295 about a model's potential harms.296 feature_extractor ([`~transformers.CLIPImageProcessor`]):297 A `CLIPImageProcessor` to extract features from generated images; used as inputs to the `safety_checker`.298 requires_safety_checker (bool):299 Whether a safety checker is needed for this pipeline.300 """301 302 model_cpu_offload_seq = "text_encoder->unet->vae"303 _optional_components = ["safety_checker", "feature_extractor", "image_encoder"]304 _exclude_from_cpu_offload = ["safety_checker"]305 _callback_tensor_inputs = ["latents", "prompt_embeds", "negative_prompt_embeds"]306 307 objects_text = "Objects: "308 bg_prompt_text = "Background prompt: "309 bg_prompt_text_no_trailing_space = bg_prompt_text.rstrip()310 neg_prompt_text = "Negative prompt: "311 neg_prompt_text_no_trailing_space = neg_prompt_text.rstrip()312 313 def __init__(314 self,315 vae: AutoencoderKL,316 text_encoder: CLIPTextModel,317 tokenizer: CLIPTokenizer,318 unet: UNet2DConditionModel,319 scheduler: KarrasDiffusionSchedulers,320 safety_checker: StableDiffusionSafetyChecker,321 feature_extractor: CLIPImageProcessor,322 image_encoder: CLIPVisionModelWithProjection = None,323 requires_safety_checker: bool = True,324 ):325 # This is copied from StableDiffusionPipeline, with hook initizations for LMD+.326 super().__init__()327 328 if hasattr(scheduler.config, "steps_offset") and scheduler.config.steps_offset != 1:329 deprecation_message = (330 f"The configuration file of this scheduler: {scheduler} is outdated. `steps_offset`"331 f" should be set to 1 instead of {scheduler.config.steps_offset}. Please make sure "332 "to update the config accordingly as leaving `steps_offset` might led to incorrect results"333 " in future versions. If you have downloaded this checkpoint from the Hugging Face Hub,"334 " it would be very nice if you could open a Pull request for the `scheduler/scheduler_config.json`"335 " file"336 )337 deprecate("steps_offset!=1", "1.0.0", deprecation_message, standard_warn=False)338 new_config = dict(scheduler.config)339 new_config["steps_offset"] = 1340 scheduler._internal_dict = FrozenDict(new_config)341 342 if hasattr(scheduler.config, "clip_sample") and scheduler.config.clip_sample is True:343 deprecation_message = (344 f"The configuration file of this scheduler: {scheduler} has not set the configuration `clip_sample`."345 " `clip_sample` should be set to False in the configuration file. Please make sure to update the"346 " config accordingly as not setting `clip_sample` in the config might lead to incorrect results in"347 " future versions. If you have downloaded this checkpoint from the Hugging Face Hub, it would be very"348 " nice if you could open a Pull request for the `scheduler/scheduler_config.json` file"349 )350 deprecate("clip_sample not set", "1.0.0", deprecation_message, standard_warn=False)351 new_config = dict(scheduler.config)352 new_config["clip_sample"] = False353 scheduler._internal_dict = FrozenDict(new_config)354 355 if safety_checker is None and requires_safety_checker:356 logger.warning(357 f"You have disabled the safety checker for {self.__class__} by passing `safety_checker=None`. Ensure"358 " that you abide to the conditions of the Stable Diffusion license and do not expose unfiltered"359 " results in services or applications open to the public. Both the diffusers team and Hugging Face"360 " strongly recommend to keep the safety filter enabled in all public facing circumstances, disabling"361 " it only for use-cases that involve analyzing network behavior or auditing its results. For more"362 " information, please have a look at https://github.com/huggingface/diffusers/pull/254 ."363 )364 365 if safety_checker is not None and feature_extractor is None:366 raise ValueError(367 "Make sure to define a feature extractor when loading {self.__class__} if you want to use the safety"368 " checker. If you do not want to use the safety checker, you can pass `'safety_checker=None'` instead."369 )370 371 is_unet_version_less_0_9_0 = hasattr(unet.config, "_diffusers_version") and version.parse(372 version.parse(unet.config._diffusers_version).base_version373 ) < version.parse("0.9.0.dev0")374 is_unet_sample_size_less_64 = hasattr(unet.config, "sample_size") and unet.config.sample_size < 64375 if is_unet_version_less_0_9_0 and is_unet_sample_size_less_64:376 deprecation_message = (377 "The configuration file of the unet has set the default `sample_size` to smaller than"378 " 64 which seems highly unlikely. If your checkpoint is a fine-tuned version of any of the"379 " following: \n- CompVis/stable-diffusion-v1-4 \n- CompVis/stable-diffusion-v1-3 \n-"380 " CompVis/stable-diffusion-v1-2 \n- CompVis/stable-diffusion-v1-1 \n- runwayml/stable-diffusion-v1-5"381 " \n- runwayml/stable-diffusion-inpainting \n you should change 'sample_size' to 64 in the"382 " configuration file. Please make sure to update the config accordingly as leaving `sample_size=32`"383 " in the config might lead to incorrect results in future versions. If you have downloaded this"384 " checkpoint from the Hugging Face Hub, it would be very nice if you could open a Pull request for"385 " the `unet/config.json` file"386 )387 deprecate("sample_size<64", "1.0.0", deprecation_message, standard_warn=False)388 new_config = dict(unet.config)389 new_config["sample_size"] = 64390 unet._internal_dict = FrozenDict(new_config)391 392 self.register_modules(393 vae=vae,394 text_encoder=text_encoder,395 tokenizer=tokenizer,396 unet=unet,397 scheduler=scheduler,398 safety_checker=safety_checker,399 feature_extractor=feature_extractor,400 image_encoder=image_encoder,401 )402 self.vae_scale_factor = 2 ** (len(self.vae.config.block_out_channels) - 1)403 self.image_processor = VaeImageProcessor(vae_scale_factor=self.vae_scale_factor)404 self.register_to_config(requires_safety_checker=requires_safety_checker)405 406 # Initialize the attention hooks for LLM-grounded Diffusion407 self.register_attn_hooks(unet)408 self._saved_attn = None409 410 def attn_hook(self, name, query, key, value, attention_probs):411 if name in DEFAULT_GUIDANCE_ATTN_KEYS:412 self._saved_attn[name] = attention_probs413 414 @classmethod415 def convert_box(cls, box, height, width):416 # box: x, y, w, h (in 512 format) -> x_min, y_min, x_max, y_max417 x_min, y_min = box[0] / width, box[1] / height418 w_box, h_box = box[2] / width, box[3] / height419 420 x_max, y_max = x_min + w_box, y_min + h_box421 422 return x_min, y_min, x_max, y_max423 424 @classmethod425 def _parse_response_with_negative(cls, text):426 if not text:427 raise ValueError("LLM response is empty")428 429 if cls.objects_text in text:430 text = text.split(cls.objects_text)[1]431 432 text_split = text.split(cls.bg_prompt_text_no_trailing_space)433 if len(text_split) == 2:434 gen_boxes, text_rem = text_split435 else:436 raise ValueError(f"LLM response is incomplete: {text}")437 438 text_split = text_rem.split(cls.neg_prompt_text_no_trailing_space)439 440 if len(text_split) == 2:441 bg_prompt, neg_prompt = text_split442 else:443 raise ValueError(f"LLM response is incomplete: {text}")444 445 try:446 gen_boxes = ast.literal_eval(gen_boxes)447 except SyntaxError as e:448 # Sometimes the response is in plain text449 if "No objects" in gen_boxes or gen_boxes.strip() == "":450 gen_boxes = []451 else:452 raise e453 bg_prompt = bg_prompt.strip()454 neg_prompt = neg_prompt.strip()455 456 # LLM may return "None" to mean no negative prompt provided.457 if neg_prompt == "None":458 neg_prompt = ""459 460 return gen_boxes, bg_prompt, neg_prompt461 462 @classmethod463 def parse_llm_response(cls, response, canvas_height=512, canvas_width=512):464 # Infer from spec465 gen_boxes, bg_prompt, neg_prompt = cls._parse_response_with_negative(text=response)466 467 gen_boxes = sorted(gen_boxes, key=lambda gen_box: gen_box[0])468 469 phrases = [name for name, _ in gen_boxes]470 boxes = [cls.convert_box(box, height=canvas_height, width=canvas_width) for _, box in gen_boxes]471 472 return phrases, boxes, bg_prompt, neg_prompt473 474 def check_inputs(475 self,476 prompt,477 height,478 width,479 callback_steps,480 phrases,481 boxes,482 negative_prompt=None,483 prompt_embeds=None,484 negative_prompt_embeds=None,485 phrase_indices=None,486 ):487 if height % 8 != 0 or width % 8 != 0:488 raise ValueError(f"`height` and `width` have to be divisible by 8 but are {height} and {width}.")489 490 if (callback_steps is None) or (491 callback_steps is not None and (not isinstance(callback_steps, int) or callback_steps <= 0)492 ):493 raise ValueError(494 f"`callback_steps` has to be a positive integer but is {callback_steps} of type"495 f" {type(callback_steps)}."496 )497 498 if prompt is not None and prompt_embeds is not None:499 raise ValueError(500 f"Cannot forward both `prompt`: {prompt} and `prompt_embeds`: {prompt_embeds}. Please make sure to"501 " only forward one of the two."502 )503 elif prompt is None and prompt_embeds is None:504 raise ValueError(505 "Provide either `prompt` or `prompt_embeds`. Cannot leave both `prompt` and `prompt_embeds` undefined."506 )507 elif prompt is not None and (not isinstance(prompt, str) and not isinstance(prompt, list)):508 raise ValueError(f"`prompt` has to be of type `str` or `list` but is {type(prompt)}")509 elif prompt is None and phrase_indices is None:510 raise ValueError("If the prompt is None, the phrase_indices cannot be None")511 512 if negative_prompt is not None and negative_prompt_embeds is not None:513 raise ValueError(514 f"Cannot forward both `negative_prompt`: {negative_prompt} and `negative_prompt_embeds`:"515 f" {negative_prompt_embeds}. Please make sure to only forward one of the two."516 )517 518 if prompt_embeds is not None and negative_prompt_embeds is not None:519 if prompt_embeds.shape != negative_prompt_embeds.shape:520 raise ValueError(521 "`prompt_embeds` and `negative_prompt_embeds` must have the same shape when passed directly, but"522 f" got: `prompt_embeds` {prompt_embeds.shape} != `negative_prompt_embeds`"523 f" {negative_prompt_embeds.shape}."524 )525 526 if len(phrases) != len(boxes):527 ValueError(528 "length of `phrases` and `boxes` has to be same, but"529 f" got: `phrases` {len(phrases)} != `boxes` {len(boxes)}"530 )531 532 def register_attn_hooks(self, unet):533 """Registering hooks to obtain the attention maps for guidance"""534 535 attn_procs = {}536 537 for name in unet.attn_processors.keys():538 # Only obtain the queries and keys from cross-attention539 if name.endswith("attn1.processor") or name.endswith("fuser.attn.processor"):540 # Keep the same attn_processors for self-attention (no hooks for self-attention)541 attn_procs[name] = unet.attn_processors[name]542 continue543 544 cross_attention_dim = None if name.endswith("attn1.processor") else unet.config.cross_attention_dim545 546 if name.startswith("mid_block"):547 hidden_size = unet.config.block_out_channels[-1]548 elif name.startswith("up_blocks"):549 block_id = int(name[len("up_blocks.")])550 hidden_size = list(reversed(unet.config.block_out_channels))[block_id]551 elif name.startswith("down_blocks"):552 block_id = int(name[len("down_blocks.")])553 hidden_size = unet.config.block_out_channels[block_id]554 555 attn_procs[name] = AttnProcessorWithHook(556 attn_processor_key=name,557 hidden_size=hidden_size,558 cross_attention_dim=cross_attention_dim,559 hook=self.attn_hook,560 fast_attn=True,561 # Not enabled by default562 enabled=False,563 )564 565 unet.set_attn_processor(attn_procs)566 567 def enable_fuser(self, enabled=True):568 for module in self.unet.modules():569 if isinstance(module, GatedSelfAttentionDense):570 module.enabled = enabled571 572 def enable_attn_hook(self, enabled=True):573 for module in self.unet.attn_processors.values():574 if isinstance(module, AttnProcessorWithHook):575 module.enabled = enabled576 577 def get_token_map(self, prompt, padding="do_not_pad", verbose=False):578 """Get a list of mapping: prompt index to str (prompt in a list of token str)"""579 fg_prompt_tokens = self.tokenizer([prompt], padding=padding, max_length=77, return_tensors="np")580 input_ids = fg_prompt_tokens["input_ids"][0]581 582 token_map = []583 for ind, item in enumerate(input_ids.tolist()):584 token = self.tokenizer._convert_id_to_token(item)585 586 if verbose:587 logger.info(f"{ind}, {token} ({item})")588 589 token_map.append(token)590 591 return token_map592 593 def get_phrase_indices(594 self,595 prompt,596 phrases,597 token_map=None,598 add_suffix_if_not_found=False,599 verbose=False,600 ):601 for obj in phrases:602 # Suffix the prompt with object name for attention guidance if object is not in the prompt, using "|" to separate the prompt and the suffix603 if obj not in prompt:604 prompt += "| " + obj605 606 if token_map is None:607 # We allow using a pre-computed token map.608 token_map = self.get_token_map(prompt=prompt, padding="do_not_pad", verbose=verbose)609 token_map_str = " ".join(token_map)610 611 phrase_indices = []612 613 for obj in phrases:614 phrase_token_map = self.get_token_map(prompt=obj, padding="do_not_pad", verbose=verbose)615 # Remove <bos> and <eos> in substr616 phrase_token_map = phrase_token_map[1:-1]617 phrase_token_map_len = len(phrase_token_map)618 phrase_token_map_str = " ".join(phrase_token_map)619 620 if verbose:621 logger.info(622 "Full str:",623 token_map_str,624 "Substr:",625 phrase_token_map_str,626 "Phrase:",627 phrases,628 )629 630 # Count the number of token before substr631 # The substring comes with a trailing space that needs to be removed by minus one in the index.632 obj_first_index = len(token_map_str[: token_map_str.index(phrase_token_map_str) - 1].split(" "))633 634 obj_position = list(range(obj_first_index, obj_first_index + phrase_token_map_len))635 phrase_indices.append(obj_position)636 637 if add_suffix_if_not_found:638 return phrase_indices, prompt639 640 return phrase_indices641 642 def add_ca_loss_per_attn_map_to_loss(643 self,644 loss,645 attn_map,646 object_number,647 bboxes,648 phrase_indices,649 fg_top_p=0.2,650 bg_top_p=0.2,651 fg_weight=1.0,652 bg_weight=1.0,653 ):654 # b is the number of heads, not batch655 b, i, j = attn_map.shape656 H = W = int(math.sqrt(i))657 for obj_idx in range(object_number):658 obj_loss = 0659 mask = torch.zeros(size=(H, W), device="cuda")660 obj_boxes = bboxes[obj_idx]661 662 # We support two level (one box per phrase) and three level (multiple boxes per phrase)663 if not isinstance(obj_boxes[0], Iterable):664 obj_boxes = [obj_boxes]665 666 for obj_box in obj_boxes:667 # x_min, y_min, x_max, y_max = int(obj_box[0] * W), int(obj_box[1] * H), int(obj_box[2] * W), int(obj_box[3] * H)668 x_min, y_min, x_max, y_max = scale_proportion(obj_box, H=H, W=W)669 mask[y_min:y_max, x_min:x_max] = 1670 671 for obj_position in phrase_indices[obj_idx]:672 # Could potentially optimize to compute this for loop in batch.673 # Could crop the ref cross attention before saving to save memory.674 675 ca_map_obj = attn_map[:, :, obj_position].reshape(b, H, W)676 677 # shape: (b, H * W)678 ca_map_obj = attn_map[:, :, obj_position] # .reshape(b, H, W)679 k_fg = (mask.sum() * fg_top_p).long().clamp_(min=1)680 k_bg = ((1 - mask).sum() * bg_top_p).long().clamp_(min=1)681 682 mask_1d = mask.view(1, -1)683 684 # Max-based loss function685 686 # Take the topk over spatial dimension, and then take the sum over heads dim687 # The mean is over k_fg and k_bg dimension, so we don't need to sum and divide on our own.688 obj_loss += (1 - (ca_map_obj * mask_1d).topk(k=k_fg).values.mean(dim=1)).sum(dim=0) * fg_weight689 obj_loss += ((ca_map_obj * (1 - mask_1d)).topk(k=k_bg).values.mean(dim=1)).sum(dim=0) * bg_weight690 691 loss += obj_loss / len(phrase_indices[obj_idx])692 693 return loss694 695 def compute_ca_loss(696 self,697 saved_attn,698 bboxes,699 phrase_indices,700 guidance_attn_keys,701 verbose=False,702 **kwargs,703 ):704 """705 The `saved_attn` is supposed to be passed to `save_attn_to_dict` in `cross_attention_kwargs` prior to computing ths loss.706 `AttnProcessor` will put attention maps into the `save_attn_to_dict`.707 708 `index` is the timestep.709 `ref_ca_word_token_only`: This has precedence over `ref_ca_last_token_only` (i.e., if both are enabled, we take the token from word rather than the last token).710 `ref_ca_last_token_only`: `ref_ca_saved_attn` comes from the attention map of the last token of the phrase in single object generation, so we apply it only to the last token of the phrase in overall generation if this is set to True. If set to False, `ref_ca_saved_attn` will be applied to all the text tokens.711 """712 loss = torch.tensor(0).float().cuda()713 object_number = len(bboxes)714 if object_number == 0:715 return loss716 717 for attn_key in guidance_attn_keys:718 # We only have 1 cross attention for mid.719 720 attn_map_integrated = saved_attn[attn_key]721 if not attn_map_integrated.is_cuda:722 attn_map_integrated = attn_map_integrated.cuda()723 # Example dimension: [20, 64, 77]724 attn_map = attn_map_integrated.squeeze(dim=0)725 726 loss = self.add_ca_loss_per_attn_map_to_loss(727 loss, attn_map, object_number, bboxes, phrase_indices, **kwargs728 )729 730 num_attn = len(guidance_attn_keys)731 732 if num_attn > 0:733 loss = loss / (object_number * num_attn)734 735 return loss736 737 @torch.no_grad()738 @replace_example_docstring(EXAMPLE_DOC_STRING)739 def __call__(740 self,741 prompt: Union[str, List[str]] = None,742 height: Optional[int] = None,743 width: Optional[int] = None,744 num_inference_steps: int = 50,745 guidance_scale: float = 7.5,746 gligen_scheduled_sampling_beta: float = 0.3,747 phrases: List[str] = None,748 boxes: List[List[float]] = None,749 negative_prompt: Optional[Union[str, List[str]]] = None,750 num_images_per_prompt: Optional[int] = 1,751 eta: float = 0.0,752 generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,753 latents: Optional[torch.FloatTensor] = None,754 prompt_embeds: Optional[torch.FloatTensor] = None,755 negative_prompt_embeds: Optional[torch.FloatTensor] = None,756 ip_adapter_image: Optional[PipelineImageInput] = None,757 output_type: Optional[str] = "pil",758 return_dict: bool = True,759 callback: Optional[Callable[[int, int, torch.FloatTensor], None]] = None,760 callback_steps: int = 1,761 cross_attention_kwargs: Optional[Dict[str, Any]] = None,762 clip_skip: Optional[int] = None,763 lmd_guidance_kwargs: Optional[Dict[str, Any]] = {},764 phrase_indices: Optional[List[int]] = None,765 ):766 r"""767 The call function to the pipeline for generation.768 769 Args:770 prompt (`str` or `List[str]`, *optional*):771 The prompt or prompts to guide image generation. If not defined, you need to pass `prompt_embeds`.772 height (`int`, *optional*, defaults to `self.unet.config.sample_size * self.vae_scale_factor`):773 The height in pixels of the generated image.774 width (`int`, *optional*, defaults to `self.unet.config.sample_size * self.vae_scale_factor`):775 The width in pixels of the generated image.776 num_inference_steps (`int`, *optional*, defaults to 50):777 The number of denoising steps. More denoising steps usually lead to a higher quality image at the778 expense of slower inference.779 guidance_scale (`float`, *optional*, defaults to 7.5):780 A higher guidance scale value encourages the model to generate images closely linked to the text781 `prompt` at the expense of lower image quality. Guidance scale is enabled when `guidance_scale > 1`.782 phrases (`List[str]`):783 The phrases to guide what to include in each of the regions defined by the corresponding784 `boxes`. There should only be one phrase per bounding box.785 boxes (`List[List[float]]`):786 The bounding boxes that identify rectangular regions of the image that are going to be filled with the787 content described by the corresponding `phrases`. Each rectangular box is defined as a788 `List[float]` of 4 elements `[xmin, ymin, xmax, ymax]` where each value is between [0,1].789 gligen_scheduled_sampling_beta (`float`, defaults to 0.3):790 Scheduled Sampling factor from [GLIGEN: Open-Set Grounded Text-to-Image791 Generation](https://arxiv.org/pdf/2301.07093.pdf). Scheduled Sampling factor is only varied for792 scheduled sampling during inference for improved quality and controllability.793 negative_prompt (`str` or `List[str]`, *optional*):794 The prompt or prompts to guide what to not include in image generation. If not defined, you need to795 pass `negative_prompt_embeds` instead. Ignored when not using guidance (`guidance_scale < 1`).796 num_images_per_prompt (`int`, *optional*, defaults to 1):797 The number of images to generate per prompt.798 eta (`float`, *optional*, defaults to 0.0):799 Corresponds to parameter eta (η) from the [DDIM](https://arxiv.org/abs/2010.02502) paper. Only applies800 to the [`~schedulers.DDIMScheduler`], and is ignored in other schedulers.801 generator (`torch.Generator` or `List[torch.Generator]`, *optional*):802 A [`torch.Generator`](https://pytorch.org/docs/stable/generated/torch.Generator.html) to make803 generation deterministic.804 latents (`torch.FloatTensor`, *optional*):805 Pre-generated noisy latents sampled from a Gaussian distribution, to be used as inputs for image806 generation. Can be used to tweak the same generation with different prompts. If not provided, a latents807 tensor is generated by sampling using the supplied random `generator`.808 prompt_embeds (`torch.FloatTensor`, *optional*):809 Pre-generated text embeddings. Can be used to easily tweak text inputs (prompt weighting). If not810 provided, text embeddings are generated from the `prompt` input argument.811 negative_prompt_embeds (`torch.FloatTensor`, *optional*):812 Pre-generated negative text embeddings. Can be used to easily tweak text inputs (prompt weighting). If813 not provided, `negative_prompt_embeds` are generated from the `negative_prompt` input argument.814 ip_adapter_image: (`PipelineImageInput`, *optional*): Optional image input to work with IP Adapters.815 output_type (`str`, *optional*, defaults to `"pil"`):816 The output format of the generated image. Choose between `PIL.Image` or `np.array`.817 return_dict (`bool`, *optional*, defaults to `True`):818 Whether or not to return a [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] instead of a819 plain tuple.820 callback (`Callable`, *optional*):821 A function that calls every `callback_steps` steps during inference. The function is called with the822 following arguments: `callback(step: int, timestep: int, latents: torch.FloatTensor)`.823 callback_steps (`int`, *optional*, defaults to 1):824 The frequency at which the `callback` function is called. If not specified, the callback is called at825 every step.826 cross_attention_kwargs (`dict`, *optional*):827 A kwargs dictionary that if specified is passed along to the [`AttentionProcessor`] as defined in828 [`self.processor`](https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/attention_processor.py).829 guidance_rescale (`float`, *optional*, defaults to 0.0):830 Guidance rescale factor from [Common Diffusion Noise Schedules and Sample Steps are831 Flawed](https://arxiv.org/pdf/2305.08891.pdf). Guidance rescale factor should fix overexposure when832 using zero terminal SNR.833 clip_skip (`int`, *optional*):834 Number of layers to be skipped from CLIP while computing the prompt embeddings. A value of 1 means that835 the output of the pre-final layer will be used for computing the prompt embeddings.836 lmd_guidance_kwargs (`dict`, *optional*):837 A kwargs dictionary that if specified is passed along to `latent_lmd_guidance` function. Useful keys include `loss_scale` (the guidance strength), `loss_threshold` (when loss is lower than this value, the guidance is not applied anymore), `max_iter` (the number of iterations of guidance for each step), and `guidance_timesteps` (the number of diffusion timesteps to apply guidance on). See `latent_lmd_guidance` for implementation details.838 phrase_indices (`list` of `list`, *optional*): The indices of the tokens of each phrase in the overall prompt. If omitted, the pipeline will match the first token subsequence. The pipeline will append the missing phrases to the end of the prompt by default.839 Examples:840 841 Returns:842 [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] or `tuple`:843 If `return_dict` is `True`, [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] is returned,844 otherwise a `tuple` is returned where the first element is a list with the generated images and the845 second element is a list of `bool`s indicating whether the corresponding generated image contains846 "not-safe-for-work" (nsfw) content.847 """848 # 0. Default height and width to unet849 height = height or self.unet.config.sample_size * self.vae_scale_factor850 width = width or self.unet.config.sample_size * self.vae_scale_factor851 852 # 1. Check inputs. Raise error if not correct853 self.check_inputs(854 prompt,855 height,856 width,857 callback_steps,858 phrases,859 boxes,860 negative_prompt,861 prompt_embeds,862 negative_prompt_embeds,863 phrase_indices,864 )865 866 # 2. Define call parameters867 if prompt is not None and isinstance(prompt, str):868 batch_size = 1869 if phrase_indices is None:870 phrase_indices, prompt = self.get_phrase_indices(prompt, phrases, add_suffix_if_not_found=True)871 elif prompt is not None and isinstance(prompt, list):872 batch_size = len(prompt)873 if phrase_indices is None:874 phrase_indices = []875 prompt_parsed = []876 for prompt_item in prompt:877 (878 phrase_indices_parsed_item,879 prompt_parsed_item,880 ) = self.get_phrase_indices(prompt_item, add_suffix_if_not_found=True)881 phrase_indices.append(phrase_indices_parsed_item)882 prompt_parsed.append(prompt_parsed_item)883 prompt = prompt_parsed884 else:885 batch_size = prompt_embeds.shape[0]886 887 device = self._execution_device888 # here `guidance_scale` is defined analog to the guidance weight `w` of equation (2)889 # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . `guidance_scale = 1`890 # corresponds to doing no classifier free guidance.891 do_classifier_free_guidance = guidance_scale > 1.0892 893 # 3. Encode input prompt894 prompt_embeds, negative_prompt_embeds = self.encode_prompt(895 prompt,896 device,897 num_images_per_prompt,898 do_classifier_free_guidance,899 negative_prompt,900 prompt_embeds=prompt_embeds,901 negative_prompt_embeds=negative_prompt_embeds,902 clip_skip=clip_skip,903 )904 905 cond_prompt_embeds = prompt_embeds906 907 # For classifier free guidance, we need to do two forward passes.908 # Here we concatenate the unconditional and text embeddings into a single batch909 # to avoid doing two forward passes910 if do_classifier_free_guidance:911 prompt_embeds = torch.cat([negative_prompt_embeds, prompt_embeds])912 913 if ip_adapter_image is not None:914 image_embeds, negative_image_embeds = self.encode_image(ip_adapter_image, device, num_images_per_prompt)915 if self.do_classifier_free_guidance:916 image_embeds = torch.cat([negative_image_embeds, image_embeds])917 918 # 4. Prepare timesteps919 self.scheduler.set_timesteps(num_inference_steps, device=device)920 timesteps = self.scheduler.timesteps921 922 # 5. Prepare latent variables923 num_channels_latents = self.unet.config.in_channels924 latents = self.prepare_latents(925 batch_size * num_images_per_prompt,926 num_channels_latents,927 height,928 width,929 prompt_embeds.dtype,930 device,931 generator,932 latents,933 )934 935 # 5.1 Prepare GLIGEN variables936 max_objs = 30937 if len(boxes) > max_objs:938 warnings.warn(939 f"More that {max_objs} objects found. Only first {max_objs} objects will be processed.",940 FutureWarning,941 )942 phrases = phrases[:max_objs]943 boxes = boxes[:max_objs]944 945 n_objs = len(boxes)946 if n_objs:947 # prepare batched input to the PositionNet (boxes, phrases, mask)948 # Get tokens for phrases from pre-trained CLIPTokenizer949 tokenizer_inputs = self.tokenizer(phrases, padding=True, return_tensors="pt").to(device)950 # For the token, we use the same pre-trained text encoder951 # to obtain its text feature952 _text_embeddings = self.text_encoder(**tokenizer_inputs).pooler_output953 954 # For each entity, described in phrases, is denoted with a bounding box,955 # we represent the location information as (xmin,ymin,xmax,ymax)956 cond_boxes = torch.zeros(max_objs, 4, device=device, dtype=self.text_encoder.dtype)957 if n_objs:958 cond_boxes[:n_objs] = torch.tensor(boxes)959 text_embeddings = torch.zeros(960 max_objs,961 self.unet.config.cross_attention_dim,962 device=device,963 dtype=self.text_encoder.dtype,964 )965 if n_objs:966 text_embeddings[:n_objs] = _text_embeddings967 # Generate a mask for each object that is entity described by phrases968 masks = torch.zeros(max_objs, device=device, dtype=self.text_encoder.dtype)969 masks[:n_objs] = 1970 971 repeat_batch = batch_size * num_images_per_prompt972 cond_boxes = cond_boxes.unsqueeze(0).expand(repeat_batch, -1, -1).clone()973 text_embeddings = text_embeddings.unsqueeze(0).expand(repeat_batch, -1, -1).clone()974 masks = masks.unsqueeze(0).expand(repeat_batch, -1).clone()975 if do_classifier_free_guidance:976 repeat_batch = repeat_batch * 2977 cond_boxes = torch.cat([cond_boxes] * 2)978 text_embeddings = torch.cat([text_embeddings] * 2)979 masks = torch.cat([masks] * 2)980 masks[: repeat_batch // 2] = 0981 if cross_attention_kwargs is None:982 cross_attention_kwargs = {}983 cross_attention_kwargs["gligen"] = {984 "boxes": cond_boxes,985 "positive_embeddings": text_embeddings,986 "masks": masks,987 }988 989 num_grounding_steps = int(gligen_scheduled_sampling_beta * len(timesteps))990 self.enable_fuser(True)991 992 # 6. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline993 extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)994 995 # 6.1 Add image embeds for IP-Adapter996 added_cond_kwargs = {"image_embeds": image_embeds} if ip_adapter_image is not None else None997 998 loss_attn = torch.tensor(10000.0)999 1000 # 7. Denoising loop1001 num_warmup_steps = len(timesteps) - num_inference_steps * self.scheduler.order1002 with self.progress_bar(total=num_inference_steps) as progress_bar:1003 for i, t in enumerate(timesteps):1004 # Scheduled sampling1005 if i == num_grounding_steps:1006 self.enable_fuser(False)1007 1008 if latents.shape[1] != 4:1009 latents = torch.randn_like(latents[:, :4])1010 1011 # 7.1 Perform LMD guidance1012 if boxes:1013 latents, loss_attn = self.latent_lmd_guidance(1014 cond_prompt_embeds,1015 index=i,1016 boxes=boxes,1017 phrase_indices=phrase_indices,1018 t=t,1019 latents=latents,1020 loss=loss_attn,1021 **lmd_guidance_kwargs,1022 )1023 1024 # expand the latents if we are doing classifier free guidance1025 latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents1026 latent_model_input = self.scheduler.scale_model_input(latent_model_input, t)1027 1028 # predict the noise residual1029 noise_pred = self.unet(1030 latent_model_input,1031 t,1032 encoder_hidden_states=prompt_embeds,1033 cross_attention_kwargs=cross_attention_kwargs,1034 added_cond_kwargs=added_cond_kwargs,1035 ).sample1036 1037 # perform guidance1038 if do_classifier_free_guidance:1039 noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)1040 noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)1041 1042 # compute the previous noisy sample x_t -> x_t-11043 latents = self.scheduler.step(noise_pred, t, latents, **extra_step_kwargs).prev_sample1044 1045 # call the callback, if provided1046 if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0):1047 progress_bar.update()1048 if callback is not None and i % callback_steps == 0:1049 step_idx = i // getattr(self.scheduler, "order", 1)1050 callback(step_idx, t, latents)1051 1052 if not output_type == "latent":1053 image = self.vae.decode(latents / self.vae.config.scaling_factor, return_dict=False)[0]1054 image, has_nsfw_concept = self.run_safety_checker(image, device, prompt_embeds.dtype)1055 else:1056 image = latents1057 has_nsfw_concept = None1058 1059 if has_nsfw_concept is None:1060 do_denormalize = [True] * image.shape[0]1061 else:1062 do_denormalize = [not has_nsfw for has_nsfw in has_nsfw_concept]1063 1064 image = self.image_processor.postprocess(image, output_type=output_type, do_denormalize=do_denormalize)1065 1066 # Offload last model to CPU1067 if hasattr(self, "final_offload_hook") and self.final_offload_hook is not None:1068 self.final_offload_hook.offload()1069 1070 if not return_dict:1071 return (image, has_nsfw_concept)1072 1073 return StableDiffusionPipelineOutput(images=image, nsfw_content_detected=has_nsfw_concept)1074 1075 @torch.set_grad_enabled(True)1076 def latent_lmd_guidance(1077 self,1078 cond_embeddings,1079 index,1080 boxes,1081 phrase_indices,1082 t,1083 latents,1084 loss,1085 *,1086 loss_scale=20,1087 loss_threshold=5.0,1088 max_iter=[3] * 5 + [2] * 5 + [1] * 5,1089 guidance_timesteps=15,1090 cross_attention_kwargs=None,1091 guidance_attn_keys=DEFAULT_GUIDANCE_ATTN_KEYS,1092 verbose=False,1093 clear_cache=False,1094 unet_additional_kwargs={},1095 guidance_callback=None,1096 **kwargs,1097 ):1098 scheduler, unet = self.scheduler, self.unet1099 1100 iteration = 01101 1102 if index < guidance_timesteps:1103 if isinstance(max_iter, list):1104 max_iter = max_iter[index]1105 1106 if verbose:1107 logger.info(1108 f"time index {index}, loss: {loss.item()/loss_scale:.3f} (de-scaled with scale {loss_scale:.1f}), loss threshold: {loss_threshold:.3f}"1109 )1110 1111 try:1112 self.enable_attn_hook(enabled=True)1113 1114 while (1115 loss.item() / loss_scale > loss_threshold and iteration < max_iter and index < guidance_timesteps1116 ):1117 self._saved_attn = {}1118 1119 latents.requires_grad_(True)1120 latent_model_input = latents1121 latent_model_input = scheduler.scale_model_input(latent_model_input, t)1122 1123 unet(1124 latent_model_input,1125 t,1126 encoder_hidden_states=cond_embeddings,1127 cross_attention_kwargs=cross_attention_kwargs,1128 **unet_additional_kwargs,1129 )1130 1131 # update latents with guidance1132 loss = (1133 self.compute_ca_loss(1134 saved_attn=self._saved_attn,1135 bboxes=boxes,1136 phrase_indices=phrase_indices,1137 guidance_attn_keys=guidance_attn_keys,1138 verbose=verbose,1139 **kwargs,1140 )1141 * loss_scale1142 )1143 1144 if torch.isnan(loss):1145 raise RuntimeError("**Loss is NaN**")1146 1147 # This callback allows visualizations.1148 if guidance_callback is not None:1149 guidance_callback(self, latents, loss, iteration, index)1150 1151 self._saved_attn = None1152 1153 grad_cond = torch.autograd.grad(loss.requires_grad_(True), [latents])[0]1154 1155 latents.requires_grad_(False)1156 1157 # Scaling with classifier guidance1158 alpha_prod_t = scheduler.alphas_cumprod[t]1159 # Classifier guidance: https://arxiv.org/pdf/2105.05233.pdf1160 # DDIM: https://arxiv.org/pdf/2010.02502.pdf1161 scale = (1 - alpha_prod_t) ** (0.5)1162 latents = latents - scale * grad_cond1163 1164 iteration += 11165 1166 if clear_cache:1167 gc.collect()1168 torch.cuda.empty_cache()1169 1170 if verbose:1171 logger.info(1172 f"time index {index}, loss: {loss.item()/loss_scale:.3f}, loss threshold: {loss_threshold:.3f}, iteration: {iteration}"1173 )1174 1175 finally:1176 self.enable_attn_hook(enabled=False)1177 1178 return latents, loss1179 1180 # Below are methods copied from StableDiffusionPipeline1181 # The design choice of not inheriting from StableDiffusionPipeline is discussed here: https://github.com/huggingface/diffusers/pull/5993#issuecomment-18342585171182 1183 # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.enable_vae_slicing1184 def enable_vae_slicing(self):1185 r"""1186 Enable sliced VAE decoding. When this option is enabled, the VAE will split the input tensor in slices to1187 compute decoding in several steps. This is useful to save some memory and allow larger batch sizes.1188 """1189 self.vae.enable_slicing()1190 1191 # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.disable_vae_slicing1192 def disable_vae_slicing(self):1193 r"""1194 Disable sliced VAE decoding. If `enable_vae_slicing` was previously enabled, this method will go back to1195 computing decoding in one step.1196 """1197 self.vae.disable_slicing()1198 1199 # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.enable_vae_tiling1200 def enable_vae_tiling(self):