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 2024 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 15import inspect16from typing import Callable, List, Optional, Union17 18import numpy as np19import PIL.Image20import torch21from packaging import version22from transformers import CLIPImageProcessor, CLIPTextModel, CLIPTokenizer23 24from diffusers import AutoencoderKL, DiffusionPipeline, UNet2DConditionModel25from diffusers.configuration_utils import FrozenDict, deprecate26from diffusers.loaders import LoraLoaderMixin, TextualInversionLoaderMixin27from diffusers.pipelines.pipeline_utils import StableDiffusionMixin28from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput29from diffusers.pipelines.stable_diffusion.safety_checker import (30 StableDiffusionSafetyChecker,31)32from diffusers.schedulers import KarrasDiffusionSchedulers33from diffusers.utils import (34 logging,35)36from diffusers.utils.torch_utils import randn_tensor37 38 39logger = logging.get_logger(__name__) # pylint: disable=invalid-name40 41 42def prepare_mask_and_masked_image(image, mask):43 """44 Prepares a pair (image, mask) to be consumed by the Stable Diffusion pipeline. This means that those inputs will be45 converted to ``torch.Tensor`` with shapes ``batch x channels x height x width`` where ``channels`` is ``3`` for the46 ``image`` and ``1`` for the ``mask``.47 The ``image`` will be converted to ``torch.float32`` and normalized to be in ``[-1, 1]``. The ``mask`` will be48 binarized (``mask > 0.5``) and cast to ``torch.float32`` too.49 Args:50 image (Union[np.array, PIL.Image, torch.Tensor]): The image to inpaint.51 It can be a ``PIL.Image``, or a ``height x width x 3`` ``np.array`` or a ``channels x height x width``52 ``torch.Tensor`` or a ``batch x channels x height x width`` ``torch.Tensor``.53 mask (_type_): The mask to apply to the image, i.e. regions to inpaint.54 It can be a ``PIL.Image``, or a ``height x width`` ``np.array`` or a ``1 x height x width``55 ``torch.Tensor`` or a ``batch x 1 x height x width`` ``torch.Tensor``.56 Raises:57 ValueError: ``torch.Tensor`` images should be in the ``[-1, 1]`` range. ValueError: ``torch.Tensor`` mask58 should be in the ``[0, 1]`` range. ValueError: ``mask`` and ``image`` should have the same spatial dimensions.59 TypeError: ``mask`` is a ``torch.Tensor`` but ``image`` is not60 (ot the other way around).61 Returns:62 tuple[torch.Tensor]: The pair (mask, masked_image) as ``torch.Tensor`` with 463 dimensions: ``batch x channels x height x width``.64 """65 if isinstance(image, torch.Tensor):66 if not isinstance(mask, torch.Tensor):67 raise TypeError(f"`image` is a torch.Tensor but `mask` (type: {type(mask)} is not")68 69 # Batch single image70 if image.ndim == 3:71 assert image.shape[0] == 3, "Image outside a batch should be of shape (3, H, W)"72 image = image.unsqueeze(0)73 74 # Batch and add channel dim for single mask75 if mask.ndim == 2:76 mask = mask.unsqueeze(0).unsqueeze(0)77 78 # Batch single mask or add channel dim79 if mask.ndim == 3:80 # Single batched mask, no channel dim or single mask not batched but channel dim81 if mask.shape[0] == 1:82 mask = mask.unsqueeze(0)83 84 # Batched masks no channel dim85 else:86 mask = mask.unsqueeze(1)87 88 assert image.ndim == 4 and mask.ndim == 4, "Image and Mask must have 4 dimensions"89 assert image.shape[-2:] == mask.shape[-2:], "Image and Mask must have the same spatial dimensions"90 assert image.shape[0] == mask.shape[0], "Image and Mask must have the same batch size"91 92 # Check image is in [-1, 1]93 if image.min() < -1 or image.max() > 1:94 raise ValueError("Image should be in [-1, 1] range")95 96 # Check mask is in [0, 1]97 if mask.min() < 0 or mask.max() > 1:98 raise ValueError("Mask should be in [0, 1] range")99 100 # Binarize mask101 mask[mask < 0.5] = 0102 mask[mask >= 0.5] = 1103 104 # Image as float32105 image = image.to(dtype=torch.float32)106 elif isinstance(mask, torch.Tensor):107 raise TypeError(f"`mask` is a torch.Tensor but `image` (type: {type(image)} is not")108 else:109 # preprocess image110 if isinstance(image, (PIL.Image.Image, np.ndarray)):111 image = [image]112 113 if isinstance(image, list) and isinstance(image[0], PIL.Image.Image):114 image = [np.array(i.convert("RGB"))[None, :] for i in image]115 image = np.concatenate(image, axis=0)116 elif isinstance(image, list) and isinstance(image[0], np.ndarray):117 image = np.concatenate([i[None, :] for i in image], axis=0)118 119 image = image.transpose(0, 3, 1, 2)120 image = torch.from_numpy(image).to(dtype=torch.float32) / 127.5 - 1.0121 122 # preprocess mask123 if isinstance(mask, (PIL.Image.Image, np.ndarray)):124 mask = [mask]125 126 if isinstance(mask, list) and isinstance(mask[0], PIL.Image.Image):127 mask = np.concatenate([np.array(m.convert("L"))[None, None, :] for m in mask], axis=0)128 mask = mask.astype(np.float32) / 255.0129 elif isinstance(mask, list) and isinstance(mask[0], np.ndarray):130 mask = np.concatenate([m[None, None, :] for m in mask], axis=0)131 132 mask[mask < 0.5] = 0133 mask[mask >= 0.5] = 1134 mask = torch.from_numpy(mask)135 136 # masked_image = image * (mask >= 0.5)137 masked_image = image138 139 return mask, masked_image140 141 142class StableDiffusionRepaintPipeline(143 DiffusionPipeline, StableDiffusionMixin, TextualInversionLoaderMixin, LoraLoaderMixin144):145 r"""146 Pipeline for text-guided image inpainting using Stable Diffusion. *This is an experimental feature*.147 This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the148 library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)149 In addition the pipeline inherits the following loading methods:150 - *Textual-Inversion*: [`loaders.TextualInversionLoaderMixin.load_textual_inversion`]151 - *LoRA*: [`loaders.LoraLoaderMixin.load_lora_weights`]152 as well as the following saving methods:153 - *LoRA*: [`loaders.LoraLoaderMixin.save_lora_weights`]154 Args:155 vae ([`AutoencoderKL`]):156 Variational Auto-Encoder (VAE) Model to encode and decode images to and from latent representations.157 text_encoder ([`CLIPTextModel`]):158 Frozen text-encoder. Stable Diffusion uses the text portion of159 [CLIP](https://huggingface.co/docs/transformers/model_doc/clip#transformers.CLIPTextModel), specifically160 the [clip-vit-large-patch14](https://huggingface.co/openai/clip-vit-large-patch14) variant.161 tokenizer (`CLIPTokenizer`):162 Tokenizer of class163 [CLIPTokenizer](https://huggingface.co/docs/transformers/v4.21.0/en/model_doc/clip#transformers.CLIPTokenizer).164 unet ([`UNet2DConditionModel`]): Conditional U-Net architecture to denoise the encoded image latents.165 scheduler ([`SchedulerMixin`]):166 A scheduler to be used in combination with `unet` to denoise the encoded image latents. Can be one of167 [`DDIMScheduler`], [`LMSDiscreteScheduler`], or [`PNDMScheduler`].168 safety_checker ([`StableDiffusionSafetyChecker`]):169 Classification module that estimates whether generated images could be considered offensive or harmful.170 Please, refer to the [model card](https://huggingface.co/runwayml/stable-diffusion-v1-5) for details.171 feature_extractor ([`CLIPImageProcessor`]):172 Model that extracts features from generated images to be used as inputs for the `safety_checker`.173 """174 175 _optional_components = ["safety_checker", "feature_extractor"]176 177 def __init__(178 self,179 vae: AutoencoderKL,180 text_encoder: CLIPTextModel,181 tokenizer: CLIPTokenizer,182 unet: UNet2DConditionModel,183 scheduler: KarrasDiffusionSchedulers,184 safety_checker: StableDiffusionSafetyChecker,185 feature_extractor: CLIPImageProcessor,186 requires_safety_checker: bool = True,187 ):188 super().__init__()189 190 if hasattr(scheduler.config, "steps_offset") and scheduler.config.steps_offset != 1:191 deprecation_message = (192 f"The configuration file of this scheduler: {scheduler} is outdated. `steps_offset`"193 f" should be set to 1 instead of {scheduler.config.steps_offset}. Please make sure "194 "to update the config accordingly as leaving `steps_offset` might led to incorrect results"195 " in future versions. If you have downloaded this checkpoint from the Hugging Face Hub,"196 " it would be very nice if you could open a Pull request for the `scheduler/scheduler_config.json`"197 " file"198 )199 deprecate("steps_offset!=1", "1.0.0", deprecation_message, standard_warn=False)200 new_config = dict(scheduler.config)201 new_config["steps_offset"] = 1202 scheduler._internal_dict = FrozenDict(new_config)203 204 if hasattr(scheduler.config, "skip_prk_steps") and scheduler.config.skip_prk_steps is False:205 deprecation_message = (206 f"The configuration file of this scheduler: {scheduler} has not set the configuration"207 " `skip_prk_steps`. `skip_prk_steps` should be set to True in the configuration file. Please make"208 " sure to update the config accordingly as not setting `skip_prk_steps` in the config might lead to"209 " incorrect results in future versions. If you have downloaded this checkpoint from the Hugging Face"210 " Hub, it would be very nice if you could open a Pull request for the"211 " `scheduler/scheduler_config.json` file"212 )213 deprecate(214 "skip_prk_steps not set",215 "1.0.0",216 deprecation_message,217 standard_warn=False,218 )219 new_config = dict(scheduler.config)220 new_config["skip_prk_steps"] = True221 scheduler._internal_dict = FrozenDict(new_config)222 223 if safety_checker is None and requires_safety_checker:224 logger.warning(225 f"You have disabled the safety checker for {self.__class__} by passing `safety_checker=None`. Ensure"226 " that you abide to the conditions of the Stable Diffusion license and do not expose unfiltered"227 " results in services or applications open to the public. Both the diffusers team and Hugging Face"228 " strongly recommend to keep the safety filter enabled in all public facing circumstances, disabling"229 " it only for use-cases that involve analyzing network behavior or auditing its results. For more"230 " information, please have a look at https://github.com/huggingface/diffusers/pull/254 ."231 )232 233 if safety_checker is not None and feature_extractor is None:234 raise ValueError(235 "Make sure to define a feature extractor when loading {self.__class__} if you want to use the safety"236 " checker. If you do not want to use the safety checker, you can pass `'safety_checker=None'` instead."237 )238 239 is_unet_version_less_0_9_0 = hasattr(unet.config, "_diffusers_version") and version.parse(240 version.parse(unet.config._diffusers_version).base_version241 ) < version.parse("0.9.0.dev0")242 is_unet_sample_size_less_64 = hasattr(unet.config, "sample_size") and unet.config.sample_size < 64243 if is_unet_version_less_0_9_0 and is_unet_sample_size_less_64:244 deprecation_message = (245 "The configuration file of the unet has set the default `sample_size` to smaller than"246 " 64 which seems highly unlikely .If you're checkpoint is a fine-tuned version of any of the"247 " following: \n- CompVis/stable-diffusion-v1-4 \n- CompVis/stable-diffusion-v1-3 \n-"248 " CompVis/stable-diffusion-v1-2 \n- CompVis/stable-diffusion-v1-1 \n- runwayml/stable-diffusion-v1-5"249 " \n- runwayml/stable-diffusion-inpainting \n you should change 'sample_size' to 64 in the"250 " configuration file. Please make sure to update the config accordingly as leaving `sample_size=32`"251 " in the config might lead to incorrect results in future versions. If you have downloaded this"252 " checkpoint from the Hugging Face Hub, it would be very nice if you could open a Pull request for"253 " the `unet/config.json` file"254 )255 deprecate("sample_size<64", "1.0.0", deprecation_message, standard_warn=False)256 new_config = dict(unet.config)257 new_config["sample_size"] = 64258 unet._internal_dict = FrozenDict(new_config)259 # Check shapes, assume num_channels_latents == 4, num_channels_mask == 1, num_channels_masked == 4260 if unet.config.in_channels != 4:261 logger.warning(262 f"You have loaded a UNet with {unet.config.in_channels} input channels, whereas by default,"263 f" {self.__class__} assumes that `pipeline.unet` has 4 input channels: 4 for `num_channels_latents`,"264 ". If you did not intend to modify"265 " this behavior, please check whether you have loaded the right checkpoint."266 )267 268 self.register_modules(269 vae=vae,270 text_encoder=text_encoder,271 tokenizer=tokenizer,272 unet=unet,273 scheduler=scheduler,274 safety_checker=safety_checker,275 feature_extractor=feature_extractor,276 )277 self.vae_scale_factor = 2 ** (len(self.vae.config.block_out_channels) - 1)278 self.register_to_config(requires_safety_checker=requires_safety_checker)279 280 # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline._encode_prompt281 def _encode_prompt(282 self,283 prompt,284 device,285 num_images_per_prompt,286 do_classifier_free_guidance,287 negative_prompt=None,288 prompt_embeds: Optional[torch.Tensor] = None,289 negative_prompt_embeds: Optional[torch.Tensor] = None,290 ):291 r"""292 Encodes the prompt into text encoder hidden states.293 Args:294 prompt (`str` or `List[str]`, *optional*):295 prompt to be encoded296 device: (`torch.device`):297 torch device298 num_images_per_prompt (`int`):299 number of images that should be generated per prompt300 do_classifier_free_guidance (`bool`):301 whether to use classifier free guidance or not302 negative_prompt (`str` or `List[str]`, *optional*):303 The prompt or prompts not to guide the image generation. If not defined, one has to pass304 `negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is305 less than `1`).306 prompt_embeds (`torch.Tensor`, *optional*):307 Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not308 provided, text embeddings will be generated from `prompt` input argument.309 negative_prompt_embeds (`torch.Tensor`, *optional*):310 Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt311 weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input312 argument.313 """314 if prompt is not None and isinstance(prompt, str):315 batch_size = 1316 elif prompt is not None and isinstance(prompt, list):317 batch_size = len(prompt)318 else:319 batch_size = prompt_embeds.shape[0]320 321 if prompt_embeds is None:322 # textual inversion: process multi-vector tokens if necessary323 if isinstance(self, TextualInversionLoaderMixin):324 prompt = self.maybe_convert_prompt(prompt, self.tokenizer)325 326 text_inputs = self.tokenizer(327 prompt,328 padding="max_length",329 max_length=self.tokenizer.model_max_length,330 truncation=True,331 return_tensors="pt",332 )333 text_input_ids = text_inputs.input_ids334 untruncated_ids = self.tokenizer(prompt, padding="longest", return_tensors="pt").input_ids335 336 if untruncated_ids.shape[-1] >= text_input_ids.shape[-1] and not torch.equal(337 text_input_ids, untruncated_ids338 ):339 removed_text = self.tokenizer.batch_decode(340 untruncated_ids[:, self.tokenizer.model_max_length - 1 : -1]341 )342 logger.warning(343 "The following part of your input was truncated because CLIP can only handle sequences up to"344 f" {self.tokenizer.model_max_length} tokens: {removed_text}"345 )346 347 if hasattr(self.text_encoder.config, "use_attention_mask") and self.text_encoder.config.use_attention_mask:348 attention_mask = text_inputs.attention_mask.to(device)349 else:350 attention_mask = None351 352 prompt_embeds = self.text_encoder(353 text_input_ids.to(device),354 attention_mask=attention_mask,355 )356 prompt_embeds = prompt_embeds[0]357 358 prompt_embeds = prompt_embeds.to(dtype=self.text_encoder.dtype, device=device)359 360 bs_embed, seq_len, _ = prompt_embeds.shape361 # duplicate text embeddings for each generation per prompt, using mps friendly method362 prompt_embeds = prompt_embeds.repeat(1, num_images_per_prompt, 1)363 prompt_embeds = prompt_embeds.view(bs_embed * num_images_per_prompt, seq_len, -1)364 365 # get unconditional embeddings for classifier free guidance366 if do_classifier_free_guidance and negative_prompt_embeds is None:367 uncond_tokens: List[str]368 if negative_prompt is None:369 uncond_tokens = [""] * batch_size370 elif type(prompt) is not type(negative_prompt):371 raise TypeError(372 f"`negative_prompt` should be the same type to `prompt`, but got {type(negative_prompt)} !="373 f" {type(prompt)}."374 )375 elif isinstance(negative_prompt, str):376 uncond_tokens = [negative_prompt]377 elif batch_size != len(negative_prompt):378 raise ValueError(379 f"`negative_prompt`: {negative_prompt} has batch size {len(negative_prompt)}, but `prompt`:"380 f" {prompt} has batch size {batch_size}. Please make sure that passed `negative_prompt` matches"381 " the batch size of `prompt`."382 )383 else:384 uncond_tokens = negative_prompt385 386 # textual inversion: process multi-vector tokens if necessary387 if isinstance(self, TextualInversionLoaderMixin):388 uncond_tokens = self.maybe_convert_prompt(uncond_tokens, self.tokenizer)389 390 max_length = prompt_embeds.shape[1]391 uncond_input = self.tokenizer(392 uncond_tokens,393 padding="max_length",394 max_length=max_length,395 truncation=True,396 return_tensors="pt",397 )398 399 if hasattr(self.text_encoder.config, "use_attention_mask") and self.text_encoder.config.use_attention_mask:400 attention_mask = uncond_input.attention_mask.to(device)401 else:402 attention_mask = None403 404 negative_prompt_embeds = self.text_encoder(405 uncond_input.input_ids.to(device),406 attention_mask=attention_mask,407 )408 negative_prompt_embeds = negative_prompt_embeds[0]409 410 if do_classifier_free_guidance:411 # duplicate unconditional embeddings for each generation per prompt, using mps friendly method412 seq_len = negative_prompt_embeds.shape[1]413 414 negative_prompt_embeds = negative_prompt_embeds.to(dtype=self.text_encoder.dtype, device=device)415 416 negative_prompt_embeds = negative_prompt_embeds.repeat(1, num_images_per_prompt, 1)417 negative_prompt_embeds = negative_prompt_embeds.view(batch_size * num_images_per_prompt, seq_len, -1)418 419 # For classifier free guidance, we need to do two forward passes.420 # Here we concatenate the unconditional and text embeddings into a single batch421 # to avoid doing two forward passes422 prompt_embeds = torch.cat([negative_prompt_embeds, prompt_embeds])423 424 return prompt_embeds425 426 # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.run_safety_checker427 def run_safety_checker(self, image, device, dtype):428 if self.safety_checker is not None:429 safety_checker_input = self.feature_extractor(self.numpy_to_pil(image), return_tensors="pt").to(device)430 image, has_nsfw_concept = self.safety_checker(431 images=image, clip_input=safety_checker_input.pixel_values.to(dtype)432 )433 else:434 has_nsfw_concept = None435 return image, has_nsfw_concept436 437 # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.prepare_extra_step_kwargs438 def prepare_extra_step_kwargs(self, generator, eta):439 # prepare extra kwargs for the scheduler step, since not all schedulers have the same signature440 # eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers.441 # eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502442 # and should be between [0, 1]443 444 accepts_eta = "eta" in set(inspect.signature(self.scheduler.step).parameters.keys())445 extra_step_kwargs = {}446 if accepts_eta:447 extra_step_kwargs["eta"] = eta448 449 # check if the scheduler accepts generator450 accepts_generator = "generator" in set(inspect.signature(self.scheduler.step).parameters.keys())451 if accepts_generator:452 extra_step_kwargs["generator"] = generator453 return extra_step_kwargs454 455 # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.decode_latents456 def decode_latents(self, latents):457 latents = 1 / self.vae.config.scaling_factor * latents458 image = self.vae.decode(latents).sample459 image = (image / 2 + 0.5).clamp(0, 1)460 # we always cast to float32 as this does not cause significant overhead and is compatible with bfloat16461 image = image.cpu().permute(0, 2, 3, 1).float().numpy()462 return image463 464 # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.check_inputs465 def check_inputs(466 self,467 prompt,468 height,469 width,470 callback_steps,471 negative_prompt=None,472 prompt_embeds=None,473 negative_prompt_embeds=None,474 ):475 if height % 8 != 0 or width % 8 != 0:476 raise ValueError(f"`height` and `width` have to be divisible by 8 but are {height} and {width}.")477 478 if (callback_steps is None) or (479 callback_steps is not None and (not isinstance(callback_steps, int) or callback_steps <= 0)480 ):481 raise ValueError(482 f"`callback_steps` has to be a positive integer but is {callback_steps} of type"483 f" {type(callback_steps)}."484 )485 486 if prompt is not None and prompt_embeds is not None:487 raise ValueError(488 f"Cannot forward both `prompt`: {prompt} and `prompt_embeds`: {prompt_embeds}. Please make sure to"489 " only forward one of the two."490 )491 elif prompt is None and prompt_embeds is None:492 raise ValueError(493 "Provide either `prompt` or `prompt_embeds`. Cannot leave both `prompt` and `prompt_embeds` undefined."494 )495 elif prompt is not None and (not isinstance(prompt, str) and not isinstance(prompt, list)):496 raise ValueError(f"`prompt` has to be of type `str` or `list` but is {type(prompt)}")497 498 if negative_prompt is not None and negative_prompt_embeds is not None:499 raise ValueError(500 f"Cannot forward both `negative_prompt`: {negative_prompt} and `negative_prompt_embeds`:"501 f" {negative_prompt_embeds}. Please make sure to only forward one of the two."502 )503 504 if prompt_embeds is not None and negative_prompt_embeds is not None:505 if prompt_embeds.shape != negative_prompt_embeds.shape:506 raise ValueError(507 "`prompt_embeds` and `negative_prompt_embeds` must have the same shape when passed directly, but"508 f" got: `prompt_embeds` {prompt_embeds.shape} != `negative_prompt_embeds`"509 f" {negative_prompt_embeds.shape}."510 )511 512 # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.prepare_latents513 def prepare_latents(514 self,515 batch_size,516 num_channels_latents,517 height,518 width,519 dtype,520 device,521 generator,522 latents=None,523 ):524 shape = (525 batch_size,526 num_channels_latents,527 height // self.vae_scale_factor,528 width // self.vae_scale_factor,529 )530 if isinstance(generator, list) and len(generator) != batch_size:531 raise ValueError(532 f"You have passed a list of generators of length {len(generator)}, but requested an effective batch"533 f" size of {batch_size}. Make sure the batch size matches the length of the generators."534 )535 536 if latents is None:537 latents = randn_tensor(shape, generator=generator, device=device, dtype=dtype)538 else:539 latents = latents.to(device)540 541 # scale the initial noise by the standard deviation required by the scheduler542 latents = latents * self.scheduler.init_noise_sigma543 return latents544 545 def prepare_mask_latents(546 self,547 mask,548 masked_image,549 batch_size,550 height,551 width,552 dtype,553 device,554 generator,555 do_classifier_free_guidance,556 ):557 # resize the mask to latents shape as we concatenate the mask to the latents558 # we do that before converting to dtype to avoid breaking in case we're using cpu_offload559 # and half precision560 mask = torch.nn.functional.interpolate(561 mask, size=(height // self.vae_scale_factor, width // self.vae_scale_factor)562 )563 mask = mask.to(device=device, dtype=dtype)564 565 masked_image = masked_image.to(device=device, dtype=dtype)566 567 # encode the mask image into latents space so we can concatenate it to the latents568 if isinstance(generator, list):569 masked_image_latents = [570 self.vae.encode(masked_image[i : i + 1]).latent_dist.sample(generator=generator[i])571 for i in range(batch_size)572 ]573 masked_image_latents = torch.cat(masked_image_latents, dim=0)574 else:575 masked_image_latents = self.vae.encode(masked_image).latent_dist.sample(generator=generator)576 masked_image_latents = self.vae.config.scaling_factor * masked_image_latents577 578 # duplicate mask and masked_image_latents for each generation per prompt, using mps friendly method579 if mask.shape[0] < batch_size:580 if not batch_size % mask.shape[0] == 0:581 raise ValueError(582 "The passed mask and the required batch size don't match. Masks are supposed to be duplicated to"583 f" a total batch size of {batch_size}, but {mask.shape[0]} masks were passed. Make sure the number"584 " of masks that you pass is divisible by the total requested batch size."585 )586 mask = mask.repeat(batch_size // mask.shape[0], 1, 1, 1)587 if masked_image_latents.shape[0] < batch_size:588 if not batch_size % masked_image_latents.shape[0] == 0:589 raise ValueError(590 "The passed images and the required batch size don't match. Images are supposed to be duplicated"591 f" to a total batch size of {batch_size}, but {masked_image_latents.shape[0]} images were passed."592 " Make sure the number of images that you pass is divisible by the total requested batch size."593 )594 masked_image_latents = masked_image_latents.repeat(batch_size // masked_image_latents.shape[0], 1, 1, 1)595 596 mask = torch.cat([mask] * 2) if do_classifier_free_guidance else mask597 masked_image_latents = (598 torch.cat([masked_image_latents] * 2) if do_classifier_free_guidance else masked_image_latents599 )600 601 # aligning device to prevent device errors when concating it with the latent model input602 masked_image_latents = masked_image_latents.to(device=device, dtype=dtype)603 return mask, masked_image_latents604 605 @torch.no_grad()606 def __call__(607 self,608 prompt: Union[str, List[str]] = None,609 image: Union[torch.Tensor, PIL.Image.Image] = None,610 mask_image: Union[torch.Tensor, PIL.Image.Image] = None,611 height: Optional[int] = None,612 width: Optional[int] = None,613 num_inference_steps: int = 50,614 jump_length: Optional[int] = 10,615 jump_n_sample: Optional[int] = 10,616 guidance_scale: float = 7.5,617 negative_prompt: Optional[Union[str, List[str]]] = None,618 num_images_per_prompt: Optional[int] = 1,619 eta: float = 0.0,620 generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,621 latents: Optional[torch.Tensor] = None,622 prompt_embeds: Optional[torch.Tensor] = None,623 negative_prompt_embeds: Optional[torch.Tensor] = None,624 output_type: Optional[str] = "pil",625 return_dict: bool = True,626 callback: Optional[Callable[[int, int, torch.Tensor], None]] = None,627 callback_steps: int = 1,628 ):629 r"""630 Function invoked when calling the pipeline for generation.631 Args:632 prompt (`str` or `List[str]`, *optional*):633 The prompt or prompts to guide the image generation. If not defined, one has to pass `prompt_embeds`.634 instead.635 image (`PIL.Image.Image`):636 `Image`, or tensor representing an image batch which will be inpainted, *i.e.* parts of the image will637 be masked out with `mask_image` and repainted according to `prompt`.638 mask_image (`PIL.Image.Image`):639 `Image`, or tensor representing an image batch, to mask `image`. White pixels in the mask will be640 repainted, while black pixels will be preserved. If `mask_image` is a PIL image, it will be converted641 to a single channel (luminance) before use. If it's a tensor, it should contain one color channel (L)642 instead of 3, so the expected shape would be `(B, H, W, 1)`.643 height (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):644 The height in pixels of the generated image.645 width (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):646 The width in pixels of the generated image.647 num_inference_steps (`int`, *optional*, defaults to 50):648 The number of denoising steps. More denoising steps usually lead to a higher quality image at the649 expense of slower inference.650 jump_length (`int`, *optional*, defaults to 10):651 The number of steps taken forward in time before going backward in time for a single jump ("j" in652 RePaint paper). Take a look at Figure 9 and 10 in https://arxiv.org/pdf/2201.09865.pdf.653 jump_n_sample (`int`, *optional*, defaults to 10):654 The number of times we will make forward time jump for a given chosen time sample. Take a look at655 Figure 9 and 10 in https://arxiv.org/pdf/2201.09865.pdf.656 guidance_scale (`float`, *optional*, defaults to 7.5):657 Guidance scale as defined in [Classifier-Free Diffusion Guidance](https://arxiv.org/abs/2207.12598).658 `guidance_scale` is defined as `w` of equation 2. of [Imagen659 Paper](https://arxiv.org/pdf/2205.11487.pdf). Guidance scale is enabled by setting `guidance_scale >660 1`. Higher guidance scale encourages to generate images that are closely linked to the text `prompt`,661 usually at the expense of lower image quality.662 negative_prompt (`str` or `List[str]`, *optional*):663 The prompt or prompts not to guide the image generation. If not defined, one has to pass664 `negative_prompt_embeds`. instead. Ignored when not using guidance (i.e., ignored if `guidance_scale`665 is less than `1`).666 num_images_per_prompt (`int`, *optional*, defaults to 1):667 The number of images to generate per prompt.668 eta (`float`, *optional*, defaults to 0.0):669 Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to670 [`schedulers.DDIMScheduler`], will be ignored for others.671 generator (`torch.Generator`, *optional*):672 One or a list of [torch generator(s)](https://pytorch.org/docs/stable/generated/torch.Generator.html)673 to make generation deterministic.674 latents (`torch.Tensor`, *optional*):675 Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image676 generation. Can be used to tweak the same generation with different prompts. If not provided, a latents677 tensor will ge generated by sampling using the supplied random `generator`.678 prompt_embeds (`torch.Tensor`, *optional*):679 Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not680 provided, text embeddings will be generated from `prompt` input argument.681 negative_prompt_embeds (`torch.Tensor`, *optional*):682 Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt683 weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input684 argument.685 output_type (`str`, *optional*, defaults to `"pil"`):686 The output format of the generate image. Choose between687 [PIL](https://pillow.readthedocs.io/en/stable/): `PIL.Image.Image` or `np.array`.688 return_dict (`bool`, *optional*, defaults to `True`):689 Whether or not to return a [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] instead of a690 plain tuple.691 callback (`Callable`, *optional*):692 A function that will be called every `callback_steps` steps during inference. The function will be693 called with the following arguments: `callback(step: int, timestep: int, latents: torch.Tensor)`.694 callback_steps (`int`, *optional*, defaults to 1):695 The frequency at which the `callback` function will be called. If not specified, the callback will be696 called at every step.697 Examples:698 ```py699 >>> import PIL700 >>> import requests701 >>> import torch702 >>> from io import BytesIO703 >>> from diffusers import StableDiffusionPipeline, RePaintScheduler704 >>> def download_image(url):705 ... response = requests.get(url)706 ... return PIL.Image.open(BytesIO(response.content)).convert("RGB")707 >>> base_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/"708 >>> img_url = base_url + "overture-creations-5sI6fQgYIuo.png"709 >>> mask_url = base_url + "overture-creations-5sI6fQgYIuo_mask.png "710 >>> init_image = download_image(img_url).resize((512, 512))711 >>> mask_image = download_image(mask_url).resize((512, 512))712 >>> pipe = DiffusionPipeline.from_pretrained(713 ... "CompVis/stable-diffusion-v1-4", torch_dtype=torch.float16, custom_pipeline="stable_diffusion_repaint",714 ... )715 >>> pipe.scheduler = RePaintScheduler.from_config(pipe.scheduler.config)716 >>> pipe = pipe.to("cuda")717 >>> prompt = "Face of a yellow cat, high resolution, sitting on a park bench"718 >>> image = pipe(prompt=prompt, image=init_image, mask_image=mask_image).images[0]719 ```720 Returns:721 [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] or `tuple`:722 [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] if `return_dict` is True, otherwise a `tuple.723 When returning a tuple, the first element is a list with the generated images, and the second element is a724 list of `bool`s denoting whether the corresponding generated image likely represents "not-safe-for-work"725 (nsfw) content, according to the `safety_checker`.726 """727 # 0. Default height and width to unet728 height = height or self.unet.config.sample_size * self.vae_scale_factor729 width = width or self.unet.config.sample_size * self.vae_scale_factor730 731 # 1. Check inputs732 self.check_inputs(733 prompt,734 height,735 width,736 callback_steps,737 negative_prompt,738 prompt_embeds,739 negative_prompt_embeds,740 )741 742 if image is None:743 raise ValueError("`image` input cannot be undefined.")744 745 if mask_image is None:746 raise ValueError("`mask_image` input cannot be undefined.")747 748 # 2. Define call parameters749 if prompt is not None and isinstance(prompt, str):750 batch_size = 1751 elif prompt is not None and isinstance(prompt, list):752 batch_size = len(prompt)753 else:754 batch_size = prompt_embeds.shape[0]755 756 device = self._execution_device757 # here `guidance_scale` is defined analog to the guidance weight `w` of equation (2)758 # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . `guidance_scale = 1`759 # corresponds to doing no classifier free guidance.760 do_classifier_free_guidance = guidance_scale > 1.0761 762 # 3. Encode input prompt763 prompt_embeds = self._encode_prompt(764 prompt,765 device,766 num_images_per_prompt,767 do_classifier_free_guidance,768 negative_prompt,769 prompt_embeds=prompt_embeds,770 negative_prompt_embeds=negative_prompt_embeds,771 )772 773 # 4. Preprocess mask and image774 mask, masked_image = prepare_mask_and_masked_image(image, mask_image)775 776 # 5. set timesteps777 self.scheduler.set_timesteps(num_inference_steps, jump_length, jump_n_sample, device)778 self.scheduler.eta = eta779 780 timesteps = self.scheduler.timesteps781 # latent_timestep = timesteps[:1].repeat(batch_size * num_images_per_prompt)782 783 # 6. Prepare latent variables784 num_channels_latents = self.vae.config.latent_channels785 latents = self.prepare_latents(786 batch_size * num_images_per_prompt,787 num_channels_latents,788 height,789 width,790 prompt_embeds.dtype,791 device,792 generator,793 latents,794 )795 796 # 7. Prepare mask latent variables797 mask, masked_image_latents = self.prepare_mask_latents(798 mask,799 masked_image,800 batch_size * num_images_per_prompt,801 height,802 width,803 prompt_embeds.dtype,804 device,805 generator,806 do_classifier_free_guidance=False, # We do not need duplicate mask and image807 )808 809 # 8. Check that sizes of mask, masked image and latents match810 # num_channels_mask = mask.shape[1]811 # num_channels_masked_image = masked_image_latents.shape[1]812 if num_channels_latents != self.unet.config.in_channels:813 raise ValueError(814 f"Incorrect configuration settings! The config of `pipeline.unet`: {self.unet.config} expects"815 f" {self.unet.config.in_channels} but received `num_channels_latents`: {num_channels_latents} "816 f" = Please verify the config of"817 " `pipeline.unet` or your `mask_image` or `image` input."818 )819 820 # 9. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline821 extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)822 823 t_last = timesteps[0] + 1824 825 # 10. Denoising loop826 with self.progress_bar(total=len(timesteps)) as progress_bar:827 for i, t in enumerate(timesteps):828 if t >= t_last:829 # compute the reverse: x_t-1 -> x_t830 latents = self.scheduler.undo_step(latents, t_last, generator)831 progress_bar.update()832 t_last = t833 continue834 835 # expand the latents if we are doing classifier free guidance836 latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents837 838 # concat latents, mask, masked_image_latents in the channel dimension839 latent_model_input = self.scheduler.scale_model_input(latent_model_input, t)840 # latent_model_input = torch.cat([latent_model_input, mask, masked_image_latents], dim=1)841 842 # predict the noise residual843 noise_pred = self.unet(latent_model_input, t, encoder_hidden_states=prompt_embeds).sample844 845 # perform guidance846 if do_classifier_free_guidance:847 noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)848 noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)849 850 # compute the previous noisy sample x_t -> x_t-1851 latents = self.scheduler.step(852 noise_pred,853 t,854 latents,855 masked_image_latents,856 mask,857 **extra_step_kwargs,858 ).prev_sample859 860 # call the callback, if provided861 progress_bar.update()862 if callback is not None and i % callback_steps == 0:863 step_idx = i // getattr(self.scheduler, "order", 1)864 callback(step_idx, t, latents)865 866 t_last = t867 868 # 11. Post-processing869 image = self.decode_latents(latents)870 871 # 12. Run safety checker872 image, has_nsfw_concept = self.run_safety_checker(image, device, prompt_embeds.dtype)873 874 # 13. Convert to PIL875 if output_type == "pil":876 image = self.numpy_to_pil(image)877 878 # Offload last model to CPU879 if hasattr(self, "final_offload_hook") and self.final_offload_hook is not None:880 self.final_offload_hook.offload()881 882 if not return_dict:883 return (image, has_nsfw_concept)884 885 return StableDiffusionPipelineOutput(images=image, nsfw_content_detected=has_nsfw_concept)886 