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# Inspired by: https://github.com/haofanwang/ControlNet-for-Diffusers/2 3import inspect4from typing import Any, Callable, Dict, List, Optional, Tuple, Union5 6import numpy as np7import PIL.Image8import torch9from transformers import CLIPImageProcessor, CLIPTextModel, CLIPTokenizer10 11from diffusers import AutoencoderKL, ControlNetModel, UNet2DConditionModel, logging12from diffusers.pipelines.controlnet.multicontrolnet import MultiControlNetModel13from diffusers.pipelines.pipeline_utils import DiffusionPipeline, StableDiffusionMixin14from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput, StableDiffusionSafetyChecker15from diffusers.schedulers import KarrasDiffusionSchedulers16from diffusers.utils import (17 PIL_INTERPOLATION,18 replace_example_docstring,19)20from diffusers.utils.torch_utils import randn_tensor21 22 23logger = logging.get_logger(__name__) # pylint: disable=invalid-name24 25EXAMPLE_DOC_STRING = """26 Examples:27 ```py28 >>> import numpy as np29 >>> import torch30 >>> from PIL import Image31 >>> from diffusers import ControlNetModel, UniPCMultistepScheduler32 >>> from diffusers.utils import load_image33 34 >>> input_image = load_image("https://hf.co/datasets/huggingface/documentation-images/resolve/main/diffusers/input_image_vermeer.png")35 36 >>> controlnet = ControlNetModel.from_pretrained("lllyasviel/sd-controlnet-canny", torch_dtype=torch.float16)37 38 >>> pipe_controlnet = StableDiffusionControlNetImg2ImgPipeline.from_pretrained(39 "runwayml/stable-diffusion-v1-5",40 controlnet=controlnet,41 safety_checker=None,42 torch_dtype=torch.float1643 )44 45 >>> pipe_controlnet.scheduler = UniPCMultistepScheduler.from_config(pipe_controlnet.scheduler.config)46 >>> pipe_controlnet.enable_xformers_memory_efficient_attention()47 >>> pipe_controlnet.enable_model_cpu_offload()48 49 # using image with edges for our canny controlnet50 >>> control_image = load_image(51 "https://hf.co/datasets/huggingface/documentation-images/resolve/main/diffusers/vermeer_canny_edged.png")52 53 54 >>> result_img = pipe_controlnet(controlnet_conditioning_image=control_image,55 image=input_image,56 prompt="an android robot, cyberpank, digitl art masterpiece",57 num_inference_steps=20).images[0]58 59 >>> result_img.show()60 ```61"""62 63 64def prepare_image(image):65 if isinstance(image, torch.Tensor):66 # Batch single image67 if image.ndim == 3:68 image = image.unsqueeze(0)69 70 image = image.to(dtype=torch.float32)71 else:72 # preprocess image73 if isinstance(image, (PIL.Image.Image, np.ndarray)):74 image = [image]75 76 if isinstance(image, list) and isinstance(image[0], PIL.Image.Image):77 image = [np.array(i.convert("RGB"))[None, :] for i in image]78 image = np.concatenate(image, axis=0)79 elif isinstance(image, list) and isinstance(image[0], np.ndarray):80 image = np.concatenate([i[None, :] for i in image], axis=0)81 82 image = image.transpose(0, 3, 1, 2)83 image = torch.from_numpy(image).to(dtype=torch.float32) / 127.5 - 1.084 85 return image86 87 88def prepare_controlnet_conditioning_image(89 controlnet_conditioning_image,90 width,91 height,92 batch_size,93 num_images_per_prompt,94 device,95 dtype,96 do_classifier_free_guidance,97):98 if not isinstance(controlnet_conditioning_image, torch.Tensor):99 if isinstance(controlnet_conditioning_image, PIL.Image.Image):100 controlnet_conditioning_image = [controlnet_conditioning_image]101 102 if isinstance(controlnet_conditioning_image[0], PIL.Image.Image):103 controlnet_conditioning_image = [104 np.array(i.resize((width, height), resample=PIL_INTERPOLATION["lanczos"]))[None, :]105 for i in controlnet_conditioning_image106 ]107 controlnet_conditioning_image = np.concatenate(controlnet_conditioning_image, axis=0)108 controlnet_conditioning_image = np.array(controlnet_conditioning_image).astype(np.float32) / 255.0109 controlnet_conditioning_image = controlnet_conditioning_image.transpose(0, 3, 1, 2)110 controlnet_conditioning_image = torch.from_numpy(controlnet_conditioning_image)111 elif isinstance(controlnet_conditioning_image[0], torch.Tensor):112 controlnet_conditioning_image = torch.cat(controlnet_conditioning_image, dim=0)113 114 image_batch_size = controlnet_conditioning_image.shape[0]115 116 if image_batch_size == 1:117 repeat_by = batch_size118 else:119 # image batch size is the same as prompt batch size120 repeat_by = num_images_per_prompt121 122 controlnet_conditioning_image = controlnet_conditioning_image.repeat_interleave(repeat_by, dim=0)123 124 controlnet_conditioning_image = controlnet_conditioning_image.to(device=device, dtype=dtype)125 126 if do_classifier_free_guidance:127 controlnet_conditioning_image = torch.cat([controlnet_conditioning_image] * 2)128 129 return controlnet_conditioning_image130 131 132class StableDiffusionControlNetImg2ImgPipeline(DiffusionPipeline, StableDiffusionMixin):133 """134 Inspired by: https://github.com/haofanwang/ControlNet-for-Diffusers/135 """136 137 _optional_components = ["safety_checker", "feature_extractor"]138 139 def __init__(140 self,141 vae: AutoencoderKL,142 text_encoder: CLIPTextModel,143 tokenizer: CLIPTokenizer,144 unet: UNet2DConditionModel,145 controlnet: Union[ControlNetModel, List[ControlNetModel], Tuple[ControlNetModel], MultiControlNetModel],146 scheduler: KarrasDiffusionSchedulers,147 safety_checker: StableDiffusionSafetyChecker,148 feature_extractor: CLIPImageProcessor,149 requires_safety_checker: bool = True,150 ):151 super().__init__()152 153 if safety_checker is None and requires_safety_checker:154 logger.warning(155 f"You have disabled the safety checker for {self.__class__} by passing `safety_checker=None`. Ensure"156 " that you abide to the conditions of the Stable Diffusion license and do not expose unfiltered"157 " results in services or applications open to the public. Both the diffusers team and Hugging Face"158 " strongly recommend to keep the safety filter enabled in all public facing circumstances, disabling"159 " it only for use-cases that involve analyzing network behavior or auditing its results. For more"160 " information, please have a look at https://github.com/huggingface/diffusers/pull/254 ."161 )162 163 if safety_checker is not None and feature_extractor is None:164 raise ValueError(165 "Make sure to define a feature extractor when loading {self.__class__} if you want to use the safety"166 " checker. If you do not want to use the safety checker, you can pass `'safety_checker=None'` instead."167 )168 169 if isinstance(controlnet, (list, tuple)):170 controlnet = MultiControlNetModel(controlnet)171 172 self.register_modules(173 vae=vae,174 text_encoder=text_encoder,175 tokenizer=tokenizer,176 unet=unet,177 controlnet=controlnet,178 scheduler=scheduler,179 safety_checker=safety_checker,180 feature_extractor=feature_extractor,181 )182 self.vae_scale_factor = 2 ** (len(self.vae.config.block_out_channels) - 1)183 self.register_to_config(requires_safety_checker=requires_safety_checker)184 185 def _encode_prompt(186 self,187 prompt,188 device,189 num_images_per_prompt,190 do_classifier_free_guidance,191 negative_prompt=None,192 prompt_embeds: Optional[torch.Tensor] = None,193 negative_prompt_embeds: Optional[torch.Tensor] = None,194 ):195 r"""196 Encodes the prompt into text encoder hidden states.197 198 Args:199 prompt (`str` or `List[str]`, *optional*):200 prompt to be encoded201 device: (`torch.device`):202 torch device203 num_images_per_prompt (`int`):204 number of images that should be generated per prompt205 do_classifier_free_guidance (`bool`):206 whether to use classifier free guidance or not207 negative_prompt (`str` or `List[str]`, *optional*):208 The prompt or prompts not to guide the image generation. If not defined, one has to pass209 `negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`).210 prompt_embeds (`torch.Tensor`, *optional*):211 Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not212 provided, text embeddings will be generated from `prompt` input argument.213 negative_prompt_embeds (`torch.Tensor`, *optional*):214 Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt215 weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input216 argument.217 """218 if prompt is not None and isinstance(prompt, str):219 batch_size = 1220 elif prompt is not None and isinstance(prompt, list):221 batch_size = len(prompt)222 else:223 batch_size = prompt_embeds.shape[0]224 225 if prompt_embeds is None:226 text_inputs = self.tokenizer(227 prompt,228 padding="max_length",229 max_length=self.tokenizer.model_max_length,230 truncation=True,231 return_tensors="pt",232 )233 text_input_ids = text_inputs.input_ids234 untruncated_ids = self.tokenizer(prompt, padding="longest", return_tensors="pt").input_ids235 236 if untruncated_ids.shape[-1] >= text_input_ids.shape[-1] and not torch.equal(237 text_input_ids, untruncated_ids238 ):239 removed_text = self.tokenizer.batch_decode(240 untruncated_ids[:, self.tokenizer.model_max_length - 1 : -1]241 )242 logger.warning(243 "The following part of your input was truncated because CLIP can only handle sequences up to"244 f" {self.tokenizer.model_max_length} tokens: {removed_text}"245 )246 247 if hasattr(self.text_encoder.config, "use_attention_mask") and self.text_encoder.config.use_attention_mask:248 attention_mask = text_inputs.attention_mask.to(device)249 else:250 attention_mask = None251 252 prompt_embeds = self.text_encoder(253 text_input_ids.to(device),254 attention_mask=attention_mask,255 )256 prompt_embeds = prompt_embeds[0]257 258 prompt_embeds = prompt_embeds.to(dtype=self.text_encoder.dtype, device=device)259 260 bs_embed, seq_len, _ = prompt_embeds.shape261 # duplicate text embeddings for each generation per prompt, using mps friendly method262 prompt_embeds = prompt_embeds.repeat(1, num_images_per_prompt, 1)263 prompt_embeds = prompt_embeds.view(bs_embed * num_images_per_prompt, seq_len, -1)264 265 # get unconditional embeddings for classifier free guidance266 if do_classifier_free_guidance and negative_prompt_embeds is None:267 uncond_tokens: List[str]268 if negative_prompt is None:269 uncond_tokens = [""] * batch_size270 elif type(prompt) is not type(negative_prompt):271 raise TypeError(272 f"`negative_prompt` should be the same type to `prompt`, but got {type(negative_prompt)} !="273 f" {type(prompt)}."274 )275 elif isinstance(negative_prompt, str):276 uncond_tokens = [negative_prompt]277 elif batch_size != len(negative_prompt):278 raise ValueError(279 f"`negative_prompt`: {negative_prompt} has batch size {len(negative_prompt)}, but `prompt`:"280 f" {prompt} has batch size {batch_size}. Please make sure that passed `negative_prompt` matches"281 " the batch size of `prompt`."282 )283 else:284 uncond_tokens = negative_prompt285 286 max_length = prompt_embeds.shape[1]287 uncond_input = self.tokenizer(288 uncond_tokens,289 padding="max_length",290 max_length=max_length,291 truncation=True,292 return_tensors="pt",293 )294 295 if hasattr(self.text_encoder.config, "use_attention_mask") and self.text_encoder.config.use_attention_mask:296 attention_mask = uncond_input.attention_mask.to(device)297 else:298 attention_mask = None299 300 negative_prompt_embeds = self.text_encoder(301 uncond_input.input_ids.to(device),302 attention_mask=attention_mask,303 )304 negative_prompt_embeds = negative_prompt_embeds[0]305 306 if do_classifier_free_guidance:307 # duplicate unconditional embeddings for each generation per prompt, using mps friendly method308 seq_len = negative_prompt_embeds.shape[1]309 310 negative_prompt_embeds = negative_prompt_embeds.to(dtype=self.text_encoder.dtype, device=device)311 312 negative_prompt_embeds = negative_prompt_embeds.repeat(1, num_images_per_prompt, 1)313 negative_prompt_embeds = negative_prompt_embeds.view(batch_size * num_images_per_prompt, seq_len, -1)314 315 # For classifier free guidance, we need to do two forward passes.316 # Here we concatenate the unconditional and text embeddings into a single batch317 # to avoid doing two forward passes318 prompt_embeds = torch.cat([negative_prompt_embeds, prompt_embeds])319 320 return prompt_embeds321 322 def run_safety_checker(self, image, device, dtype):323 if self.safety_checker is not None:324 safety_checker_input = self.feature_extractor(self.numpy_to_pil(image), return_tensors="pt").to(device)325 image, has_nsfw_concept = self.safety_checker(326 images=image, clip_input=safety_checker_input.pixel_values.to(dtype)327 )328 else:329 has_nsfw_concept = None330 return image, has_nsfw_concept331 332 def decode_latents(self, latents):333 latents = 1 / self.vae.config.scaling_factor * latents334 image = self.vae.decode(latents).sample335 image = (image / 2 + 0.5).clamp(0, 1)336 # we always cast to float32 as this does not cause significant overhead and is compatible with bfloat16337 image = image.cpu().permute(0, 2, 3, 1).float().numpy()338 return image339 340 def prepare_extra_step_kwargs(self, generator, eta):341 # prepare extra kwargs for the scheduler step, since not all schedulers have the same signature342 # eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers.343 # eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502344 # and should be between [0, 1]345 346 accepts_eta = "eta" in set(inspect.signature(self.scheduler.step).parameters.keys())347 extra_step_kwargs = {}348 if accepts_eta:349 extra_step_kwargs["eta"] = eta350 351 # check if the scheduler accepts generator352 accepts_generator = "generator" in set(inspect.signature(self.scheduler.step).parameters.keys())353 if accepts_generator:354 extra_step_kwargs["generator"] = generator355 return extra_step_kwargs356 357 def check_controlnet_conditioning_image(self, image, prompt, prompt_embeds):358 image_is_pil = isinstance(image, PIL.Image.Image)359 image_is_tensor = isinstance(image, torch.Tensor)360 image_is_pil_list = isinstance(image, list) and isinstance(image[0], PIL.Image.Image)361 image_is_tensor_list = isinstance(image, list) and isinstance(image[0], torch.Tensor)362 363 if not image_is_pil and not image_is_tensor and not image_is_pil_list and not image_is_tensor_list:364 raise TypeError(365 "image must be passed and be one of PIL image, torch tensor, list of PIL images, or list of torch tensors"366 )367 368 if image_is_pil:369 image_batch_size = 1370 elif image_is_tensor:371 image_batch_size = image.shape[0]372 elif image_is_pil_list:373 image_batch_size = len(image)374 elif image_is_tensor_list:375 image_batch_size = len(image)376 else:377 raise ValueError("controlnet condition image is not valid")378 379 if prompt is not None and isinstance(prompt, str):380 prompt_batch_size = 1381 elif prompt is not None and isinstance(prompt, list):382 prompt_batch_size = len(prompt)383 elif prompt_embeds is not None:384 prompt_batch_size = prompt_embeds.shape[0]385 else:386 raise ValueError("prompt or prompt_embeds are not valid")387 388 if image_batch_size != 1 and image_batch_size != prompt_batch_size:389 raise ValueError(390 f"If image batch size is not 1, image batch size must be same as prompt batch size. image batch size: {image_batch_size}, prompt batch size: {prompt_batch_size}"391 )392 393 def check_inputs(394 self,395 prompt,396 image,397 controlnet_conditioning_image,398 height,399 width,400 callback_steps,401 negative_prompt=None,402 prompt_embeds=None,403 negative_prompt_embeds=None,404 strength=None,405 controlnet_guidance_start=None,406 controlnet_guidance_end=None,407 controlnet_conditioning_scale=None,408 ):409 if height % 8 != 0 or width % 8 != 0:410 raise ValueError(f"`height` and `width` have to be divisible by 8 but are {height} and {width}.")411 412 if (callback_steps is None) or (413 callback_steps is not None and (not isinstance(callback_steps, int) or callback_steps <= 0)414 ):415 raise ValueError(416 f"`callback_steps` has to be a positive integer but is {callback_steps} of type"417 f" {type(callback_steps)}."418 )419 420 if prompt is not None and prompt_embeds is not None:421 raise ValueError(422 f"Cannot forward both `prompt`: {prompt} and `prompt_embeds`: {prompt_embeds}. Please make sure to"423 " only forward one of the two."424 )425 elif prompt is None and prompt_embeds is None:426 raise ValueError(427 "Provide either `prompt` or `prompt_embeds`. Cannot leave both `prompt` and `prompt_embeds` undefined."428 )429 elif prompt is not None and (not isinstance(prompt, str) and not isinstance(prompt, list)):430 raise ValueError(f"`prompt` has to be of type `str` or `list` but is {type(prompt)}")431 432 if negative_prompt is not None and negative_prompt_embeds is not None:433 raise ValueError(434 f"Cannot forward both `negative_prompt`: {negative_prompt} and `negative_prompt_embeds`:"435 f" {negative_prompt_embeds}. Please make sure to only forward one of the two."436 )437 438 if prompt_embeds is not None and negative_prompt_embeds is not None:439 if prompt_embeds.shape != negative_prompt_embeds.shape:440 raise ValueError(441 "`prompt_embeds` and `negative_prompt_embeds` must have the same shape when passed directly, but"442 f" got: `prompt_embeds` {prompt_embeds.shape} != `negative_prompt_embeds`"443 f" {negative_prompt_embeds.shape}."444 )445 446 # check controlnet condition image447 448 if isinstance(self.controlnet, ControlNetModel):449 self.check_controlnet_conditioning_image(controlnet_conditioning_image, prompt, prompt_embeds)450 elif isinstance(self.controlnet, MultiControlNetModel):451 if not isinstance(controlnet_conditioning_image, list):452 raise TypeError("For multiple controlnets: `image` must be type `list`")453 454 if len(controlnet_conditioning_image) != len(self.controlnet.nets):455 raise ValueError(456 "For multiple controlnets: `image` must have the same length as the number of controlnets."457 )458 459 for image_ in controlnet_conditioning_image:460 self.check_controlnet_conditioning_image(image_, prompt, prompt_embeds)461 else:462 assert False463 464 # Check `controlnet_conditioning_scale`465 466 if isinstance(self.controlnet, ControlNetModel):467 if not isinstance(controlnet_conditioning_scale, float):468 raise TypeError("For single controlnet: `controlnet_conditioning_scale` must be type `float`.")469 elif isinstance(self.controlnet, MultiControlNetModel):470 if isinstance(controlnet_conditioning_scale, list) and len(controlnet_conditioning_scale) != len(471 self.controlnet.nets472 ):473 raise ValueError(474 "For multiple controlnets: When `controlnet_conditioning_scale` is specified as `list`, it must have"475 " the same length as the number of controlnets"476 )477 else:478 assert False479 480 if isinstance(image, torch.Tensor):481 if image.ndim != 3 and image.ndim != 4:482 raise ValueError("`image` must have 3 or 4 dimensions")483 484 if image.ndim == 3:485 image_batch_size = 1486 image_channels, image_height, image_width = image.shape487 elif image.ndim == 4:488 image_batch_size, image_channels, image_height, image_width = image.shape489 else:490 assert False491 492 if image_channels != 3:493 raise ValueError("`image` must have 3 channels")494 495 if image.min() < -1 or image.max() > 1:496 raise ValueError("`image` should be in range [-1, 1]")497 498 if self.vae.config.latent_channels != self.unet.config.in_channels:499 raise ValueError(500 f"The config of `pipeline.unet` expects {self.unet.config.in_channels} but received"501 f" latent channels: {self.vae.config.latent_channels},"502 f" Please verify the config of `pipeline.unet` and the `pipeline.vae`"503 )504 505 if strength < 0 or strength > 1:506 raise ValueError(f"The value of `strength` should in [0.0, 1.0] but is {strength}")507 508 if controlnet_guidance_start < 0 or controlnet_guidance_start > 1:509 raise ValueError(510 f"The value of `controlnet_guidance_start` should in [0.0, 1.0] but is {controlnet_guidance_start}"511 )512 513 if controlnet_guidance_end < 0 or controlnet_guidance_end > 1:514 raise ValueError(515 f"The value of `controlnet_guidance_end` should in [0.0, 1.0] but is {controlnet_guidance_end}"516 )517 518 if controlnet_guidance_start > controlnet_guidance_end:519 raise ValueError(520 "The value of `controlnet_guidance_start` should be less than `controlnet_guidance_end`, but got"521 f" `controlnet_guidance_start` {controlnet_guidance_start} >= `controlnet_guidance_end` {controlnet_guidance_end}"522 )523 524 def get_timesteps(self, num_inference_steps, strength, device):525 # get the original timestep using init_timestep526 init_timestep = min(int(num_inference_steps * strength), num_inference_steps)527 528 t_start = max(num_inference_steps - init_timestep, 0)529 timesteps = self.scheduler.timesteps[t_start:]530 531 return timesteps, num_inference_steps - t_start532 533 def prepare_latents(self, image, timestep, batch_size, num_images_per_prompt, dtype, device, generator=None):534 if not isinstance(image, (torch.Tensor, PIL.Image.Image, list)):535 raise ValueError(536 f"`image` has to be of type `torch.Tensor`, `PIL.Image.Image` or list but is {type(image)}"537 )538 539 image = image.to(device=device, dtype=dtype)540 541 batch_size = batch_size * num_images_per_prompt542 if isinstance(generator, list) and len(generator) != batch_size:543 raise ValueError(544 f"You have passed a list of generators of length {len(generator)}, but requested an effective batch"545 f" size of {batch_size}. Make sure the batch size matches the length of the generators."546 )547 548 if isinstance(generator, list):549 init_latents = [550 self.vae.encode(image[i : i + 1]).latent_dist.sample(generator[i]) for i in range(batch_size)551 ]552 init_latents = torch.cat(init_latents, dim=0)553 else:554 init_latents = self.vae.encode(image).latent_dist.sample(generator)555 556 init_latents = self.vae.config.scaling_factor * init_latents557 558 if batch_size > init_latents.shape[0] and batch_size % init_latents.shape[0] == 0:559 raise ValueError(560 f"Cannot duplicate `image` of batch size {init_latents.shape[0]} to {batch_size} text prompts."561 )562 else:563 init_latents = torch.cat([init_latents], dim=0)564 565 shape = init_latents.shape566 noise = randn_tensor(shape, generator=generator, device=device, dtype=dtype)567 568 # get latents569 init_latents = self.scheduler.add_noise(init_latents, noise, timestep)570 latents = init_latents571 572 return latents573 574 def _default_height_width(self, height, width, image):575 if isinstance(image, list):576 image = image[0]577 578 if height is None:579 if isinstance(image, PIL.Image.Image):580 height = image.height581 elif isinstance(image, torch.Tensor):582 height = image.shape[3]583 584 height = (height // 8) * 8 # round down to nearest multiple of 8585 586 if width is None:587 if isinstance(image, PIL.Image.Image):588 width = image.width589 elif isinstance(image, torch.Tensor):590 width = image.shape[2]591 592 width = (width // 8) * 8 # round down to nearest multiple of 8593 594 return height, width595 596 @torch.no_grad()597 @replace_example_docstring(EXAMPLE_DOC_STRING)598 def __call__(599 self,600 prompt: Union[str, List[str]] = None,601 image: Union[torch.Tensor, PIL.Image.Image] = None,602 controlnet_conditioning_image: Union[603 torch.Tensor, PIL.Image.Image, List[torch.Tensor], List[PIL.Image.Image]604 ] = None,605 strength: float = 0.8,606 height: Optional[int] = None,607 width: Optional[int] = None,608 num_inference_steps: int = 50,609 guidance_scale: float = 7.5,610 negative_prompt: Optional[Union[str, List[str]]] = None,611 num_images_per_prompt: Optional[int] = 1,612 eta: float = 0.0,613 generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,614 latents: Optional[torch.Tensor] = None,615 prompt_embeds: Optional[torch.Tensor] = None,616 negative_prompt_embeds: Optional[torch.Tensor] = None,617 output_type: Optional[str] = "pil",618 return_dict: bool = True,619 callback: Optional[Callable[[int, int, torch.Tensor], None]] = None,620 callback_steps: int = 1,621 cross_attention_kwargs: Optional[Dict[str, Any]] = None,622 controlnet_conditioning_scale: Union[float, List[float]] = 1.0,623 controlnet_guidance_start: float = 0.0,624 controlnet_guidance_end: float = 1.0,625 ):626 r"""627 Function invoked when calling the pipeline for generation.628 629 Args:630 prompt (`str` or `List[str]`, *optional*):631 The prompt or prompts to guide the image generation. If not defined, one has to pass `prompt_embeds`.632 instead.633 image (`torch.Tensor` or `PIL.Image.Image`):634 `Image`, or tensor representing an image batch which will be inpainted, *i.e.* parts of the image will635 be masked out with `mask_image` and repainted according to `prompt`.636 controlnet_conditioning_image (`torch.Tensor`, `PIL.Image.Image`, `List[torch.Tensor]` or `List[PIL.Image.Image]`):637 The ControlNet input condition. ControlNet uses this input condition to generate guidance to Unet. If638 the type is specified as `torch.Tensor`, it is passed to ControlNet as is. PIL.Image.Image` can639 also be accepted as an image. The control image is automatically resized to fit the output image.640 strength (`float`, *optional*):641 Conceptually, indicates how much to transform the reference `image`. Must be between 0 and 1. `image`642 will be used as a starting point, adding more noise to it the larger the `strength`. The number of643 denoising steps depends on the amount of noise initially added. When `strength` is 1, added noise will644 be maximum and the denoising process will run for the full number of iterations specified in645 `num_inference_steps`. A value of 1, therefore, essentially ignores `image`.646 height (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):647 The height in pixels of the generated image.648 width (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):649 The width in pixels of the generated image.650 num_inference_steps (`int`, *optional*, defaults to 50):651 The number of denoising steps. More denoising steps usually lead to a higher quality image at the652 expense of slower inference.653 guidance_scale (`float`, *optional*, defaults to 7.5):654 Guidance scale as defined in [Classifier-Free Diffusion Guidance](https://arxiv.org/abs/2207.12598).655 `guidance_scale` is defined as `w` of equation 2. of [Imagen656 Paper](https://arxiv.org/pdf/2205.11487.pdf). Guidance scale is enabled by setting `guidance_scale >657 1`. Higher guidance scale encourages to generate images that are closely linked to the text `prompt`,658 usually at the expense of lower image quality.659 negative_prompt (`str` or `List[str]`, *optional*):660 The prompt or prompts not to guide the image generation. If not defined, one has to pass661 `negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`).662 num_images_per_prompt (`int`, *optional*, defaults to 1):663 The number of images to generate per prompt.664 eta (`float`, *optional*, defaults to 0.0):665 Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to666 [`schedulers.DDIMScheduler`], will be ignored for others.667 generator (`torch.Generator` or `List[torch.Generator]`, *optional*):668 One or a list of [torch generator(s)](https://pytorch.org/docs/stable/generated/torch.Generator.html)669 to make generation deterministic.670 latents (`torch.Tensor`, *optional*):671 Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image672 generation. Can be used to tweak the same generation with different prompts. If not provided, a latents673 tensor will ge generated by sampling using the supplied random `generator`.674 prompt_embeds (`torch.Tensor`, *optional*):675 Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not676 provided, text embeddings will be generated from `prompt` input argument.677 negative_prompt_embeds (`torch.Tensor`, *optional*):678 Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt679 weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input680 argument.681 output_type (`str`, *optional*, defaults to `"pil"`):682 The output format of the generate image. Choose between683 [PIL](https://pillow.readthedocs.io/en/stable/): `PIL.Image.Image` or `np.array`.684 return_dict (`bool`, *optional*, defaults to `True`):685 Whether or not to return a [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] instead of a686 plain tuple.687 callback (`Callable`, *optional*):688 A function that will be called every `callback_steps` steps during inference. The function will be689 called with the following arguments: `callback(step: int, timestep: int, latents: torch.Tensor)`.690 callback_steps (`int`, *optional*, defaults to 1):691 The frequency at which the `callback` function will be called. If not specified, the callback will be692 called at every step.693 cross_attention_kwargs (`dict`, *optional*):694 A kwargs dictionary that if specified is passed along to the `AttentionProcessor` as defined under695 `self.processor` in696 [diffusers.models.attention_processor](https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/attention_processor.py).697 controlnet_conditioning_scale (`float`, *optional*, defaults to 1.0):698 The outputs of the controlnet are multiplied by `controlnet_conditioning_scale` before they are added699 to the residual in the original unet.700 controlnet_guidance_start ('float', *optional*, defaults to 0.0):701 The percentage of total steps the controlnet starts applying. Must be between 0 and 1.702 controlnet_guidance_end ('float', *optional*, defaults to 1.0):703 The percentage of total steps the controlnet ends applying. Must be between 0 and 1. Must be greater704 than `controlnet_guidance_start`.705 706 Examples:707 708 Returns:709 [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] or `tuple`:710 [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] if `return_dict` is True, otherwise a `tuple.711 When returning a tuple, the first element is a list with the generated images, and the second element is a712 list of `bool`s denoting whether the corresponding generated image likely represents "not-safe-for-work"713 (nsfw) content, according to the `safety_checker`.714 """715 # 0. Default height and width to unet716 height, width = self._default_height_width(height, width, controlnet_conditioning_image)717 718 # 1. Check inputs. Raise error if not correct719 self.check_inputs(720 prompt,721 image,722 controlnet_conditioning_image,723 height,724 width,725 callback_steps,726 negative_prompt,727 prompt_embeds,728 negative_prompt_embeds,729 strength,730 controlnet_guidance_start,731 controlnet_guidance_end,732 controlnet_conditioning_scale,733 )734 735 # 2. Define call parameters736 if prompt is not None and isinstance(prompt, str):737 batch_size = 1738 elif prompt is not None and isinstance(prompt, list):739 batch_size = len(prompt)740 else:741 batch_size = prompt_embeds.shape[0]742 743 device = self._execution_device744 # here `guidance_scale` is defined analog to the guidance weight `w` of equation (2)745 # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . `guidance_scale = 1`746 # corresponds to doing no classifier free guidance.747 do_classifier_free_guidance = guidance_scale > 1.0748 749 if isinstance(self.controlnet, MultiControlNetModel) and isinstance(controlnet_conditioning_scale, float):750 controlnet_conditioning_scale = [controlnet_conditioning_scale] * len(self.controlnet.nets)751 752 # 3. Encode input prompt753 prompt_embeds = self._encode_prompt(754 prompt,755 device,756 num_images_per_prompt,757 do_classifier_free_guidance,758 negative_prompt,759 prompt_embeds=prompt_embeds,760 negative_prompt_embeds=negative_prompt_embeds,761 )762 763 # 4. Prepare image, and controlnet_conditioning_image764 image = prepare_image(image)765 766 # condition image(s)767 if isinstance(self.controlnet, ControlNetModel):768 controlnet_conditioning_image = prepare_controlnet_conditioning_image(769 controlnet_conditioning_image=controlnet_conditioning_image,770 width=width,771 height=height,772 batch_size=batch_size * num_images_per_prompt,773 num_images_per_prompt=num_images_per_prompt,774 device=device,775 dtype=self.controlnet.dtype,776 do_classifier_free_guidance=do_classifier_free_guidance,777 )778 elif isinstance(self.controlnet, MultiControlNetModel):779 controlnet_conditioning_images = []780 781 for image_ in controlnet_conditioning_image:782 image_ = prepare_controlnet_conditioning_image(783 controlnet_conditioning_image=image_,784 width=width,785 height=height,786 batch_size=batch_size * num_images_per_prompt,787 num_images_per_prompt=num_images_per_prompt,788 device=device,789 dtype=self.controlnet.dtype,790 do_classifier_free_guidance=do_classifier_free_guidance,791 )792 793 controlnet_conditioning_images.append(image_)794 795 controlnet_conditioning_image = controlnet_conditioning_images796 else:797 assert False798 799 # 5. Prepare timesteps800 self.scheduler.set_timesteps(num_inference_steps, device=device)801 timesteps, num_inference_steps = self.get_timesteps(num_inference_steps, strength, device)802 latent_timestep = timesteps[:1].repeat(batch_size * num_images_per_prompt)803 804 # 6. Prepare latent variables805 if latents is None:806 latents = self.prepare_latents(807 image,808 latent_timestep,809 batch_size,810 num_images_per_prompt,811 prompt_embeds.dtype,812 device,813 generator,814 )815 816 # 7. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline817 extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)818 819 # 8. Denoising loop820 num_warmup_steps = len(timesteps) - num_inference_steps * self.scheduler.order821 with self.progress_bar(total=num_inference_steps) as progress_bar:822 for i, t in enumerate(timesteps):823 # expand the latents if we are doing classifier free guidance824 latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents825 826 latent_model_input = self.scheduler.scale_model_input(latent_model_input, t)827 828 # compute the percentage of total steps we are at829 current_sampling_percent = i / len(timesteps)830 831 if (832 current_sampling_percent < controlnet_guidance_start833 or current_sampling_percent > controlnet_guidance_end834 ):835 # do not apply the controlnet836 down_block_res_samples = None837 mid_block_res_sample = None838 else:839 # apply the controlnet840 down_block_res_samples, mid_block_res_sample = self.controlnet(841 latent_model_input,842 t,843 encoder_hidden_states=prompt_embeds,844 controlnet_cond=controlnet_conditioning_image,845 conditioning_scale=controlnet_conditioning_scale,846 return_dict=False,847 )848 849 # predict the noise residual850 noise_pred = self.unet(851 latent_model_input,852 t,853 encoder_hidden_states=prompt_embeds,854 cross_attention_kwargs=cross_attention_kwargs,855 down_block_additional_residuals=down_block_res_samples,856 mid_block_additional_residual=mid_block_res_sample,857 ).sample858 859 # perform guidance860 if do_classifier_free_guidance:861 noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)862 noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)863 864 # compute the previous noisy sample x_t -> x_t-1865 latents = self.scheduler.step(noise_pred, t, latents, **extra_step_kwargs).prev_sample866 867 # call the callback, if provided868 if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0):869 progress_bar.update()870 if callback is not None and i % callback_steps == 0:871 step_idx = i // getattr(self.scheduler, "order", 1)872 callback(step_idx, t, latents)873 874 # If we do sequential model offloading, let's offload unet and controlnet875 # manually for max memory savings876 if hasattr(self, "final_offload_hook") and self.final_offload_hook is not None:877 self.unet.to("cpu")878 self.controlnet.to("cpu")879 torch.cuda.empty_cache()880 881 if output_type == "latent":882 image = latents883 has_nsfw_concept = None884 elif output_type == "pil":885 # 8. Post-processing886 image = self.decode_latents(latents)887 888 # 9. Run safety checker889 image, has_nsfw_concept = self.run_safety_checker(image, device, prompt_embeds.dtype)890 891 # 10. Convert to PIL892 image = self.numpy_to_pil(image)893 else:894 # 8. Post-processing895 image = self.decode_latents(latents)896 897 # 9. Run safety checker898 image, has_nsfw_concept = self.run_safety_checker(image, device, prompt_embeds.dtype)899 900 # Offload last model to CPU901 if hasattr(self, "final_offload_hook") and self.final_offload_hook is not None:902 self.final_offload_hook.offload()903 904 if not return_dict:905 return (image, has_nsfw_concept)906 907 return StableDiffusionPipelineOutput(images=image, nsfw_content_detected=has_nsfw_concept)908 