CoolFace
Datasetpublic

diffusers/community-pipelines-mirror

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

sourceHugging Faceupdated 1mo agoView on Hugging Face
9likes21kdownloads
run_onnx_controlnet.py912 linesDownload Raw Back to root
1import argparse2import inspect3import os4import time5import warnings6from typing import Any, Callable, Dict, List, Optional, Union7 8import numpy as np9import PIL.Image10import torch11from PIL import Image12from transformers import CLIPTokenizer13 14from diffusers import OnnxRuntimeModel, StableDiffusionImg2ImgPipeline, UniPCMultistepScheduler15from diffusers.image_processor import VaeImageProcessor16from diffusers.pipelines.pipeline_utils import DiffusionPipeline17from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput18from diffusers.schedulers import KarrasDiffusionSchedulers19from diffusers.utils import (20    deprecate,21    logging,22    replace_example_docstring,23)24from diffusers.utils.torch_utils import randn_tensor25 26 27logger = logging.get_logger(__name__)  # pylint: disable=invalid-name28 29 30EXAMPLE_DOC_STRING = """31    Examples:32        ```py33        >>> # !pip install opencv-python transformers accelerate34        >>> from diffusers import StableDiffusionControlNetImg2ImgPipeline, ControlNetModel, UniPCMultistepScheduler35        >>> from diffusers.utils import load_image36        >>> import numpy as np37        >>> import torch38 39        >>> import cv240        >>> from PIL import Image41 42        >>> # download an image43        >>> image = load_image(44        ...     "https://hf.co/datasets/huggingface/documentation-images/resolve/main/diffusers/input_image_vermeer.png"45        ... )46        >>> np_image = np.array(image)47 48        >>> # get canny image49        >>> np_image = cv2.Canny(np_image, 100, 200)50        >>> np_image = np_image[:, :, None]51        >>> np_image = np.concatenate([np_image, np_image, np_image], axis=2)52        >>> canny_image = Image.fromarray(np_image)53 54        >>> # load control net and stable diffusion v1-555        >>> controlnet = ControlNetModel.from_pretrained("lllyasviel/sd-controlnet-canny", torch_dtype=torch.float16)56        >>> pipe = StableDiffusionControlNetImg2ImgPipeline.from_pretrained(57        ...     "runwayml/stable-diffusion-v1-5", controlnet=controlnet, torch_dtype=torch.float1658        ... )59 60        >>> # speed up diffusion process with faster scheduler and memory optimization61        >>> pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)62        >>> pipe.enable_model_cpu_offload()63 64        >>> # generate image65        >>> generator = torch.manual_seed(0)66        >>> image = pipe(67        ...     "futuristic-looking woman",68        ...     num_inference_steps=20,69        ...     generator=generator,70        ...     image=image,71        ...     control_image=canny_image,72        ... ).images[0]73        ```74"""75 76 77def prepare_image(image):78    if isinstance(image, torch.Tensor):79        # Batch single image80        if image.ndim == 3:81            image = image.unsqueeze(0)82 83        image = image.to(dtype=torch.float32)84    else:85        # preprocess image86        if isinstance(image, (PIL.Image.Image, np.ndarray)):87            image = [image]88 89        if isinstance(image, list) and isinstance(image[0], PIL.Image.Image):90            image = [np.array(i.convert("RGB"))[None, :] for i in image]91            image = np.concatenate(image, axis=0)92        elif isinstance(image, list) and isinstance(image[0], np.ndarray):93            image = np.concatenate([i[None, :] for i in image], axis=0)94 95        image = image.transpose(0, 3, 1, 2)96        image = torch.from_numpy(image).to(dtype=torch.float32) / 127.5 - 1.097 98    return image99 100 101class OnnxStableDiffusionControlNetImg2ImgPipeline(DiffusionPipeline):102    vae_encoder: OnnxRuntimeModel103    vae_decoder: OnnxRuntimeModel104    text_encoder: OnnxRuntimeModel105    tokenizer: CLIPTokenizer106    unet: OnnxRuntimeModel107    scheduler: KarrasDiffusionSchedulers108 109    def __init__(110        self,111        vae_encoder: OnnxRuntimeModel,112        vae_decoder: OnnxRuntimeModel,113        text_encoder: OnnxRuntimeModel,114        tokenizer: CLIPTokenizer,115        unet: OnnxRuntimeModel,116        scheduler: KarrasDiffusionSchedulers,117    ):118        super().__init__()119 120        self.register_modules(121            vae_encoder=vae_encoder,122            vae_decoder=vae_decoder,123            text_encoder=text_encoder,124            tokenizer=tokenizer,125            unet=unet,126            scheduler=scheduler,127        )128        self.vae_scale_factor = 2 ** (4 - 1)129        self.image_processor = VaeImageProcessor(vae_scale_factor=self.vae_scale_factor, do_convert_rgb=True)130        self.control_image_processor = VaeImageProcessor(131            vae_scale_factor=self.vae_scale_factor, do_convert_rgb=True, do_normalize=False132        )133 134    def _encode_prompt(135        self,136        prompt: Union[str, List[str]],137        num_images_per_prompt: Optional[int],138        do_classifier_free_guidance: bool,139        negative_prompt: Optional[str],140        prompt_embeds: Optional[np.ndarray] = None,141        negative_prompt_embeds: Optional[np.ndarray] = None,142    ):143        r"""144        Encodes the prompt into text encoder hidden states.145 146        Args:147            prompt (`str` or `List[str]`):148                prompt to be encoded149            num_images_per_prompt (`int`):150                number of images that should be generated per prompt151            do_classifier_free_guidance (`bool`):152                whether to use classifier free guidance or not153            negative_prompt (`str` or `List[str]`):154                The prompt or prompts not to guide the image generation. Ignored when not using guidance (i.e., ignored155                if `guidance_scale` is less than `1`).156            prompt_embeds (`np.ndarray`, *optional*):157                Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not158                provided, text embeddings will be generated from `prompt` input argument.159            negative_prompt_embeds (`np.ndarray`, *optional*):160                Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt161                weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input162                argument.163        """164        if prompt is not None and isinstance(prompt, str):165            batch_size = 1166        elif prompt is not None and isinstance(prompt, list):167            batch_size = len(prompt)168        else:169            batch_size = prompt_embeds.shape[0]170 171        if prompt_embeds is None:172            # get prompt text embeddings173            text_inputs = self.tokenizer(174                prompt,175                padding="max_length",176                max_length=self.tokenizer.model_max_length,177                truncation=True,178                return_tensors="np",179            )180            text_input_ids = text_inputs.input_ids181            untruncated_ids = self.tokenizer(prompt, padding="max_length", return_tensors="np").input_ids182 183            if not np.array_equal(text_input_ids, untruncated_ids):184                removed_text = self.tokenizer.batch_decode(185                    untruncated_ids[:, self.tokenizer.model_max_length - 1 : -1]186                )187                logger.warning(188                    "The following part of your input was truncated because CLIP can only handle sequences up to"189                    f" {self.tokenizer.model_max_length} tokens: {removed_text}"190                )191 192            prompt_embeds = self.text_encoder(input_ids=text_input_ids.astype(np.int32))[0]193 194        prompt_embeds = np.repeat(prompt_embeds, num_images_per_prompt, axis=0)195 196        # get unconditional embeddings for classifier free guidance197        if do_classifier_free_guidance and negative_prompt_embeds is None:198            uncond_tokens: List[str]199            if negative_prompt is None:200                uncond_tokens = [""] * batch_size201            elif type(prompt) is not type(negative_prompt):202                raise TypeError(203                    f"`negative_prompt` should be the same type to `prompt`, but got {type(negative_prompt)} !="204                    f" {type(prompt)}."205                )206            elif isinstance(negative_prompt, str):207                uncond_tokens = [negative_prompt] * batch_size208            elif batch_size != len(negative_prompt):209                raise ValueError(210                    f"`negative_prompt`: {negative_prompt} has batch size {len(negative_prompt)}, but `prompt`:"211                    f" {prompt} has batch size {batch_size}. Please make sure that passed `negative_prompt` matches"212                    " the batch size of `prompt`."213                )214            else:215                uncond_tokens = negative_prompt216 217            max_length = prompt_embeds.shape[1]218            uncond_input = self.tokenizer(219                uncond_tokens,220                padding="max_length",221                max_length=max_length,222                truncation=True,223                return_tensors="np",224            )225            negative_prompt_embeds = self.text_encoder(input_ids=uncond_input.input_ids.astype(np.int32))[0]226 227        if do_classifier_free_guidance:228            negative_prompt_embeds = np.repeat(negative_prompt_embeds, num_images_per_prompt, axis=0)229 230            # For classifier free guidance, we need to do two forward passes.231            # Here we concatenate the unconditional and text embeddings into a single batch232            # to avoid doing two forward passes233            prompt_embeds = np.concatenate([negative_prompt_embeds, prompt_embeds])234 235        return prompt_embeds236 237    # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.decode_latents238    def decode_latents(self, latents):239        warnings.warn(240            "The decode_latents method is deprecated and will be removed in a future version. Please"241            " use VaeImageProcessor instead",242            FutureWarning,243        )244        latents = 1 / self.vae.config.scaling_factor * latents245        image = self.vae.decode(latents, return_dict=False)[0]246        image = (image / 2 + 0.5).clamp(0, 1)247        # we always cast to float32 as this does not cause significant overhead and is compatible with bfloat16248        image = image.cpu().permute(0, 2, 3, 1).float().numpy()249        return image250 251    # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.prepare_extra_step_kwargs252    def prepare_extra_step_kwargs(self, generator, eta):253        # prepare extra kwargs for the scheduler step, since not all schedulers have the same signature254        # eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers.255        # eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502256        # and should be between [0, 1]257 258        accepts_eta = "eta" in set(inspect.signature(self.scheduler.step).parameters.keys())259        extra_step_kwargs = {}260        if accepts_eta:261            extra_step_kwargs["eta"] = eta262 263        # check if the scheduler accepts generator264        accepts_generator = "generator" in set(inspect.signature(self.scheduler.step).parameters.keys())265        if accepts_generator:266            extra_step_kwargs["generator"] = generator267        return extra_step_kwargs268 269    def check_inputs(270        self,271        num_controlnet,272        prompt,273        image,274        callback_steps,275        negative_prompt=None,276        prompt_embeds=None,277        negative_prompt_embeds=None,278        controlnet_conditioning_scale=1.0,279        control_guidance_start=0.0,280        control_guidance_end=1.0,281    ):282        if (callback_steps is None) or (283            callback_steps is not None and (not isinstance(callback_steps, int) or callback_steps <= 0)284        ):285            raise ValueError(286                f"`callback_steps` has to be a positive integer but is {callback_steps} of type"287                f" {type(callback_steps)}."288            )289 290        if prompt is not None and prompt_embeds is not None:291            raise ValueError(292                f"Cannot forward both `prompt`: {prompt} and `prompt_embeds`: {prompt_embeds}. Please make sure to"293                " only forward one of the two."294            )295        elif prompt is None and prompt_embeds is None:296            raise ValueError(297                "Provide either `prompt` or `prompt_embeds`. Cannot leave both `prompt` and `prompt_embeds` undefined."298            )299        elif prompt is not None and (not isinstance(prompt, str) and not isinstance(prompt, list)):300            raise ValueError(f"`prompt` has to be of type `str` or `list` but is {type(prompt)}")301 302        if negative_prompt is not None and negative_prompt_embeds is not None:303            raise ValueError(304                f"Cannot forward both `negative_prompt`: {negative_prompt} and `negative_prompt_embeds`:"305                f" {negative_prompt_embeds}. Please make sure to only forward one of the two."306            )307 308        if prompt_embeds is not None and negative_prompt_embeds is not None:309            if prompt_embeds.shape != negative_prompt_embeds.shape:310                raise ValueError(311                    "`prompt_embeds` and `negative_prompt_embeds` must have the same shape when passed directly, but"312                    f" got: `prompt_embeds` {prompt_embeds.shape} != `negative_prompt_embeds`"313                    f" {negative_prompt_embeds.shape}."314                )315 316        # Check `image`317        if num_controlnet == 1:318            self.check_image(image, prompt, prompt_embeds)319        elif num_controlnet > 1:320            if not isinstance(image, list):321                raise TypeError("For multiple controlnets: `image` must be type `list`")322 323            # When `image` is a nested list:324            # (e.g. [[canny_image_1, pose_image_1], [canny_image_2, pose_image_2]])325            elif any(isinstance(i, list) for i in image):326                raise ValueError("A single batch of multiple conditionings are supported at the moment.")327            elif len(image) != num_controlnet:328                raise ValueError(329                    f"For multiple controlnets: `image` must have the same length as the number of controlnets, but got {len(image)} images and {num_controlnet} ControlNets."330                )331 332            for image_ in image:333                self.check_image(image_, prompt, prompt_embeds)334        else:335            assert False336 337        # Check `controlnet_conditioning_scale`338        if num_controlnet == 1:339            if not isinstance(controlnet_conditioning_scale, float):340                raise TypeError("For single controlnet: `controlnet_conditioning_scale` must be type `float`.")341        elif num_controlnet > 1:342            if isinstance(controlnet_conditioning_scale, list):343                if any(isinstance(i, list) for i in controlnet_conditioning_scale):344                    raise ValueError("A single batch of multiple conditionings are supported at the moment.")345            elif (346                isinstance(controlnet_conditioning_scale, list)347                and len(controlnet_conditioning_scale) != num_controlnet348            ):349                raise ValueError(350                    "For multiple controlnets: When `controlnet_conditioning_scale` is specified as `list`, it must have"351                    " the same length as the number of controlnets"352                )353        else:354            assert False355 356        if len(control_guidance_start) != len(control_guidance_end):357            raise ValueError(358                f"`control_guidance_start` has {len(control_guidance_start)} elements, but `control_guidance_end` has {len(control_guidance_end)} elements. Make sure to provide the same number of elements to each list."359            )360 361        if num_controlnet > 1:362            if len(control_guidance_start) != num_controlnet:363                raise ValueError(364                    f"`control_guidance_start`: {control_guidance_start} has {len(control_guidance_start)} elements but there are {num_controlnet} controlnets available. Make sure to provide {num_controlnet}."365                )366 367        for start, end in zip(control_guidance_start, control_guidance_end):368            if start >= end:369                raise ValueError(370                    f"control guidance start: {start} cannot be larger or equal to control guidance end: {end}."371                )372            if start < 0.0:373                raise ValueError(f"control guidance start: {start} can't be smaller than 0.")374            if end > 1.0:375                raise ValueError(f"control guidance end: {end} can't be larger than 1.0.")376 377    # Copied from diffusers.pipelines.controlnet.pipeline_controlnet.StableDiffusionControlNetPipeline.check_image378    def check_image(self, image, prompt, prompt_embeds):379        image_is_pil = isinstance(image, PIL.Image.Image)380        image_is_tensor = isinstance(image, torch.Tensor)381        image_is_np = isinstance(image, np.ndarray)382        image_is_pil_list = isinstance(image, list) and isinstance(image[0], PIL.Image.Image)383        image_is_tensor_list = isinstance(image, list) and isinstance(image[0], torch.Tensor)384        image_is_np_list = isinstance(image, list) and isinstance(image[0], np.ndarray)385 386        if (387            not image_is_pil388            and not image_is_tensor389            and not image_is_np390            and not image_is_pil_list391            and not image_is_tensor_list392            and not image_is_np_list393        ):394            raise TypeError(395                f"image must be passed and be one of PIL image, numpy array, torch tensor, list of PIL images, list of numpy arrays or list of torch tensors, but is {type(image)}"396            )397 398        if image_is_pil:399            image_batch_size = 1400        else:401            image_batch_size = len(image)402 403        if prompt is not None and isinstance(prompt, str):404            prompt_batch_size = 1405        elif prompt is not None and isinstance(prompt, list):406            prompt_batch_size = len(prompt)407        elif prompt_embeds is not None:408            prompt_batch_size = prompt_embeds.shape[0]409 410        if image_batch_size != 1 and image_batch_size != prompt_batch_size:411            raise ValueError(412                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}"413            )414 415    # Copied from diffusers.pipelines.controlnet.pipeline_controlnet.StableDiffusionControlNetPipeline.prepare_image416    def prepare_control_image(417        self,418        image,419        width,420        height,421        batch_size,422        num_images_per_prompt,423        device,424        dtype,425        do_classifier_free_guidance=False,426        guess_mode=False,427    ):428        image = self.control_image_processor.preprocess(image, height=height, width=width).to(dtype=torch.float32)429        image_batch_size = image.shape[0]430 431        if image_batch_size == 1:432            repeat_by = batch_size433        else:434            # image batch size is the same as prompt batch size435            repeat_by = num_images_per_prompt436 437        image = image.repeat_interleave(repeat_by, dim=0)438 439        image = image.to(device=device, dtype=dtype)440 441        if do_classifier_free_guidance and not guess_mode:442            image = torch.cat([image] * 2)443 444        return image445 446    # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_img2img.StableDiffusionImg2ImgPipeline.get_timesteps447    def get_timesteps(self, num_inference_steps, strength, device):448        # get the original timestep using init_timestep449        init_timestep = min(int(num_inference_steps * strength), num_inference_steps)450 451        t_start = max(num_inference_steps - init_timestep, 0)452        timesteps = self.scheduler.timesteps[t_start * self.scheduler.order :]453 454        return timesteps, num_inference_steps - t_start455 456    def prepare_latents(self, image, timestep, batch_size, num_images_per_prompt, dtype, device, generator=None):457        if not isinstance(image, (torch.Tensor, PIL.Image.Image, list)):458            raise ValueError(459                f"`image` has to be of type `torch.Tensor`, `PIL.Image.Image` or list but is {type(image)}"460            )461 462        image = image.to(device=device, dtype=dtype)463 464        batch_size = batch_size * num_images_per_prompt465 466        if image.shape[1] == 4:467            init_latents = image468 469        else:470            _image = image.cpu().detach().numpy()471            init_latents = self.vae_encoder(sample=_image)[0]472            init_latents = torch.from_numpy(init_latents).to(device=device, dtype=dtype)473            init_latents = 0.18215 * init_latents474 475        if batch_size > init_latents.shape[0] and batch_size % init_latents.shape[0] == 0:476            # expand init_latents for batch_size477            deprecation_message = (478                f"You have passed {batch_size} text prompts (`prompt`), but only {init_latents.shape[0]} initial"479                " images (`image`). Initial images are now duplicating to match the number of text prompts. Note"480                " that this behavior is deprecated and will be removed in a version 1.0.0. Please make sure to update"481                " your script to pass as many initial images as text prompts to suppress this warning."482            )483            deprecate("len(prompt) != len(image)", "1.0.0", deprecation_message, standard_warn=False)484            additional_image_per_prompt = batch_size // init_latents.shape[0]485            init_latents = torch.cat([init_latents] * additional_image_per_prompt, dim=0)486        elif batch_size > init_latents.shape[0] and batch_size % init_latents.shape[0] != 0:487            raise ValueError(488                f"Cannot duplicate `image` of batch size {init_latents.shape[0]} to {batch_size} text prompts."489            )490        else:491            init_latents = torch.cat([init_latents], dim=0)492 493        shape = init_latents.shape494        noise = randn_tensor(shape, generator=generator, device=device, dtype=dtype)495 496        # get latents497        init_latents = self.scheduler.add_noise(init_latents, noise, timestep)498        latents = init_latents499 500        return latents501 502    @torch.no_grad()503    @replace_example_docstring(EXAMPLE_DOC_STRING)504    def __call__(505        self,506        num_controlnet: int,507        fp16: bool = True,508        prompt: Union[str, List[str]] = None,509        image: Union[510            torch.Tensor,511            PIL.Image.Image,512            np.ndarray,513            List[torch.Tensor],514            List[PIL.Image.Image],515            List[np.ndarray],516        ] = None,517        control_image: Union[518            torch.Tensor,519            PIL.Image.Image,520            np.ndarray,521            List[torch.Tensor],522            List[PIL.Image.Image],523            List[np.ndarray],524        ] = None,525        height: Optional[int] = None,526        width: Optional[int] = None,527        strength: float = 0.8,528        num_inference_steps: int = 50,529        guidance_scale: float = 7.5,530        negative_prompt: Optional[Union[str, List[str]]] = None,531        num_images_per_prompt: Optional[int] = 1,532        eta: float = 0.0,533        generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,534        latents: Optional[torch.Tensor] = None,535        prompt_embeds: Optional[torch.Tensor] = None,536        negative_prompt_embeds: Optional[torch.Tensor] = None,537        output_type: Optional[str] = "pil",538        return_dict: bool = True,539        callback: Optional[Callable[[int, int, torch.Tensor], None]] = None,540        callback_steps: int = 1,541        cross_attention_kwargs: Optional[Dict[str, Any]] = None,542        controlnet_conditioning_scale: Union[float, List[float]] = 0.8,543        guess_mode: bool = False,544        control_guidance_start: Union[float, List[float]] = 0.0,545        control_guidance_end: Union[float, List[float]] = 1.0,546    ):547        r"""548        Function invoked when calling the pipeline for generation.549 550        Args:551            prompt (`str` or `List[str]`, *optional*):552                The prompt or prompts to guide the image generation. If not defined, one has to pass `prompt_embeds`.553                instead.554            image (`torch.Tensor`, `PIL.Image.Image`, `np.ndarray`, `List[torch.Tensor]`, `List[PIL.Image.Image]`, `List[np.ndarray]`,:555                    `List[List[torch.Tensor]]`, `List[List[np.ndarray]]` or `List[List[PIL.Image.Image]]`):556                The initial image will be used as the starting point for the image generation process. Can also accept557                image latents as `image`, if passing latents directly, it will not be encoded again.558            control_image (`torch.Tensor`, `PIL.Image.Image`, `np.ndarray`, `List[torch.Tensor]`, `List[PIL.Image.Image]`, `List[np.ndarray]`,:559                    `List[List[torch.Tensor]]`, `List[List[np.ndarray]]` or `List[List[PIL.Image.Image]]`):560                The ControlNet input condition. ControlNet uses this input condition to generate guidance to Unet. If561                the type is specified as `torch.Tensor`, it is passed to ControlNet as is. `PIL.Image.Image` can562                also be accepted as an image. The dimensions of the output image defaults to `image`'s dimensions. If563                height and/or width are passed, `image` is resized according to them. If multiple ControlNets are564                specified in init, images must be passed as a list such that each element of the list can be correctly565                batched for input to a single controlnet.566            height (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):567                The height in pixels of the generated image.568            width (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):569                The width in pixels of the generated image.570            num_inference_steps (`int`, *optional*, defaults to 50):571                The number of denoising steps. More denoising steps usually lead to a higher quality image at the572                expense of slower inference.573            guidance_scale (`float`, *optional*, defaults to 7.5):574                Guidance scale as defined in [Classifier-Free Diffusion Guidance](https://arxiv.org/abs/2207.12598).575                `guidance_scale` is defined as `w` of equation 2. of [Imagen576                Paper](https://arxiv.org/pdf/2205.11487.pdf). Guidance scale is enabled by setting `guidance_scale >577                1`. Higher guidance scale encourages to generate images that are closely linked to the text `prompt`,578                usually at the expense of lower image quality.579            negative_prompt (`str` or `List[str]`, *optional*):580                The prompt or prompts not to guide the image generation. If not defined, one has to pass581                `negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is582                less than `1`).583            num_images_per_prompt (`int`, *optional*, defaults to 1):584                The number of images to generate per prompt.585            eta (`float`, *optional*, defaults to 0.0):586                Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to587                [`schedulers.DDIMScheduler`], will be ignored for others.588            generator (`torch.Generator` or `List[torch.Generator]`, *optional*):589                One or a list of [torch generator(s)](https://pytorch.org/docs/stable/generated/torch.Generator.html)590                to make generation deterministic.591            latents (`torch.Tensor`, *optional*):592                Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image593                generation. Can be used to tweak the same generation with different prompts. If not provided, a latents594                tensor will ge generated by sampling using the supplied random `generator`.595            prompt_embeds (`torch.Tensor`, *optional*):596                Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not597                provided, text embeddings will be generated from `prompt` input argument.598            negative_prompt_embeds (`torch.Tensor`, *optional*):599                Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt600                weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input601                argument.602            output_type (`str`, *optional*, defaults to `"pil"`):603                The output format of the generate image. Choose between604                [PIL](https://pillow.readthedocs.io/en/stable/): `PIL.Image.Image` or `np.array`.605            return_dict (`bool`, *optional*, defaults to `True`):606                Whether or not to return a [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] instead of a607                plain tuple.608            callback (`Callable`, *optional*):609                A function that will be called every `callback_steps` steps during inference. The function will be610                called with the following arguments: `callback(step: int, timestep: int, latents: torch.Tensor)`.611            callback_steps (`int`, *optional*, defaults to 1):612                The frequency at which the `callback` function will be called. If not specified, the callback will be613                called at every step.614            cross_attention_kwargs (`dict`, *optional*):615                A kwargs dictionary that if specified is passed along to the `AttentionProcessor` as defined under616                `self.processor` in617                [diffusers.models.attention_processor](https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/attention_processor.py).618            controlnet_conditioning_scale (`float` or `List[float]`, *optional*, defaults to 1.0):619                The outputs of the controlnet are multiplied by `controlnet_conditioning_scale` before they are added620                to the residual in the original unet. If multiple ControlNets are specified in init, you can set the621                corresponding scale as a list. Note that by default, we use a smaller conditioning scale for inpainting622                than for [`~StableDiffusionControlNetPipeline.__call__`].623            guess_mode (`bool`, *optional*, defaults to `False`):624                In this mode, the ControlNet encoder will try best to recognize the content of the input image even if625                you remove all prompts. The `guidance_scale` between 3.0 and 5.0 is recommended.626            control_guidance_start (`float` or `List[float]`, *optional*, defaults to 0.0):627                The percentage of total steps at which the controlnet starts applying.628            control_guidance_end (`float` or `List[float]`, *optional*, defaults to 1.0):629                The percentage of total steps at which the controlnet stops applying.630 631        Examples:632 633        Returns:634            [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] or `tuple`:635            [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] if `return_dict` is True, otherwise a `tuple.636            When returning a tuple, the first element is a list with the generated images, and the second element is a637            list of `bool`s denoting whether the corresponding generated image likely represents "not-safe-for-work"638            (nsfw) content, according to the `safety_checker`.639        """640        if fp16:641            torch_dtype = torch.float16642            np_dtype = np.float16643        else:644            torch_dtype = torch.float32645            np_dtype = np.float32646 647        # align format for control guidance648        if not isinstance(control_guidance_start, list) and isinstance(control_guidance_end, list):649            control_guidance_start = len(control_guidance_end) * [control_guidance_start]650        elif not isinstance(control_guidance_end, list) and isinstance(control_guidance_start, list):651            control_guidance_end = len(control_guidance_start) * [control_guidance_end]652        elif not isinstance(control_guidance_start, list) and not isinstance(control_guidance_end, list):653            mult = num_controlnet654            control_guidance_start, control_guidance_end = (655                mult * [control_guidance_start],656                mult * [control_guidance_end],657            )658 659        # 1. Check inputs. Raise error if not correct660        self.check_inputs(661            num_controlnet,662            prompt,663            control_image,664            callback_steps,665            negative_prompt,666            prompt_embeds,667            negative_prompt_embeds,668            controlnet_conditioning_scale,669            control_guidance_start,670            control_guidance_end,671        )672 673        # 2. Define call parameters674        if prompt is not None and isinstance(prompt, str):675            batch_size = 1676        elif prompt is not None and isinstance(prompt, list):677            batch_size = len(prompt)678        else:679            batch_size = prompt_embeds.shape[0]680 681        device = self._execution_device682        # here `guidance_scale` is defined analog to the guidance weight `w` of equation (2)683        # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . `guidance_scale = 1`684        # corresponds to doing no classifier free guidance.685        do_classifier_free_guidance = guidance_scale > 1.0686 687        if num_controlnet > 1 and isinstance(controlnet_conditioning_scale, float):688            controlnet_conditioning_scale = [controlnet_conditioning_scale] * num_controlnet689 690        # 3. Encode input prompt691        prompt_embeds = self._encode_prompt(692            prompt,693            num_images_per_prompt,694            do_classifier_free_guidance,695            negative_prompt,696            prompt_embeds=prompt_embeds,697            negative_prompt_embeds=negative_prompt_embeds,698        )699        # 4. Prepare image700        image = self.image_processor.preprocess(image).to(dtype=torch.float32)701 702        # 5. Prepare controlnet_conditioning_image703        if num_controlnet == 1:704            control_image = self.prepare_control_image(705                image=control_image,706                width=width,707                height=height,708                batch_size=batch_size * num_images_per_prompt,709                num_images_per_prompt=num_images_per_prompt,710                device=device,711                dtype=torch_dtype,712                do_classifier_free_guidance=do_classifier_free_guidance,713                guess_mode=guess_mode,714            )715        elif num_controlnet > 1:716            control_images = []717 718            for control_image_ in control_image:719                control_image_ = self.prepare_control_image(720                    image=control_image_,721                    width=width,722                    height=height,723                    batch_size=batch_size * num_images_per_prompt,724                    num_images_per_prompt=num_images_per_prompt,725                    device=device,726                    dtype=torch_dtype,727                    do_classifier_free_guidance=do_classifier_free_guidance,728                    guess_mode=guess_mode,729                )730 731                control_images.append(control_image_)732 733            control_image = control_images734        else:735            assert False736 737        # 5. Prepare timesteps738        self.scheduler.set_timesteps(num_inference_steps, device=device)739        timesteps, num_inference_steps = self.get_timesteps(num_inference_steps, strength, device)740        latent_timestep = timesteps[:1].repeat(batch_size * num_images_per_prompt)741 742        # 6. Prepare latent variables743        latents = self.prepare_latents(744            image,745            latent_timestep,746            batch_size,747            num_images_per_prompt,748            torch_dtype,749            device,750            generator,751        )752 753        # 7. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline754        extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)755 756        # 7.1 Create tensor stating which controlnets to keep757        controlnet_keep = []758        for i in range(len(timesteps)):759            keeps = [760                1.0 - float(i / len(timesteps) < s or (i + 1) / len(timesteps) > e)761                for s, e in zip(control_guidance_start, control_guidance_end)762            ]763            controlnet_keep.append(keeps[0] if num_controlnet == 1 else keeps)764 765        # 8. Denoising loop766        num_warmup_steps = len(timesteps) - num_inference_steps * self.scheduler.order767        with self.progress_bar(total=num_inference_steps) as progress_bar:768            for i, t in enumerate(timesteps):769                # expand the latents if we are doing classifier free guidance770                latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents771                latent_model_input = self.scheduler.scale_model_input(latent_model_input, t)772 773                if isinstance(controlnet_keep[i], list):774                    cond_scale = [c * s for c, s in zip(controlnet_conditioning_scale, controlnet_keep[i])]775                else:776                    controlnet_cond_scale = controlnet_conditioning_scale777                    if isinstance(controlnet_cond_scale, list):778                        controlnet_cond_scale = controlnet_cond_scale[0]779                    cond_scale = controlnet_cond_scale * controlnet_keep[i]780 781                # predict the noise residual782                _latent_model_input = latent_model_input.cpu().detach().numpy()783                _prompt_embeds = np.array(prompt_embeds, dtype=np_dtype)784                _t = np.array([t.cpu().detach().numpy()], dtype=np_dtype)785 786                if num_controlnet == 1:787                    control_images = np.array([control_image], dtype=np_dtype)788                else:789                    control_images = []790                    for _control_img in control_image:791                        _control_img = _control_img.cpu().detach().numpy()792                        control_images.append(_control_img)793                    control_images = np.array(control_images, dtype=np_dtype)794 795                control_scales = np.array(cond_scale, dtype=np_dtype)796                control_scales = np.resize(control_scales, (num_controlnet, 1))797 798                noise_pred = self.unet(799                    sample=_latent_model_input,800                    timestep=_t,801                    encoder_hidden_states=_prompt_embeds,802                    controlnet_conds=control_images,803                    conditioning_scales=control_scales,804                )[0]805                noise_pred = torch.from_numpy(noise_pred).to(device)806 807                # perform guidance808                if do_classifier_free_guidance:809                    noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)810                    noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)811 812                # compute the previous noisy sample x_t -> x_t-1813                latents = self.scheduler.step(noise_pred, t, latents, **extra_step_kwargs, return_dict=False)[0]814 815                # call the callback, if provided816                if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0):817                    progress_bar.update()818                    if callback is not None and i % callback_steps == 0:819                        step_idx = i // getattr(self.scheduler, "order", 1)820                        callback(step_idx, t, latents)821 822        if not output_type == "latent":823            _latents = latents.cpu().detach().numpy() / 0.18215824            _latents = np.array(_latents, dtype=np_dtype)825            image = self.vae_decoder(latent_sample=_latents)[0]826            image = torch.from_numpy(image).to(device, dtype=torch.float32)827            has_nsfw_concept = None828        else:829            image = latents830            has_nsfw_concept = None831 832        if has_nsfw_concept is None:833            do_denormalize = [True] * image.shape[0]834        else:835            do_denormalize = [not has_nsfw for has_nsfw in has_nsfw_concept]836 837        image = self.image_processor.postprocess(image, output_type=output_type, do_denormalize=do_denormalize)838 839        if not return_dict:840            return (image, has_nsfw_concept)841 842        return StableDiffusionPipelineOutput(images=image, nsfw_content_detected=has_nsfw_concept)843 844 845if __name__ == "__main__":846    parser = argparse.ArgumentParser()847 848    parser.add_argument(849        "--sd_model",850        type=str,851        required=True,852        help="Path to the `diffusers` checkpoint to convert (either a local directory or on the Hub).",853    )854 855    parser.add_argument(856        "--onnx_model_dir",857        type=str,858        required=True,859        help="Path to the ONNX directory",860    )861 862    parser.add_argument("--qr_img_path", type=str, required=True, help="Path to the qr code image")863 864    args = parser.parse_args()865 866    qr_image = Image.open(args.qr_img_path)867    qr_image = qr_image.resize((512, 512))868 869    # init stable diffusion pipeline870    pipeline = StableDiffusionImg2ImgPipeline.from_pretrained(args.sd_model)871    pipeline.scheduler = UniPCMultistepScheduler.from_config(pipeline.scheduler.config)872 873    provider = ["CUDAExecutionProvider", "CPUExecutionProvider"]874    onnx_pipeline = OnnxStableDiffusionControlNetImg2ImgPipeline(875        vae_encoder=OnnxRuntimeModel.from_pretrained(876            os.path.join(args.onnx_model_dir, "vae_encoder"), provider=provider877        ),878        vae_decoder=OnnxRuntimeModel.from_pretrained(879            os.path.join(args.onnx_model_dir, "vae_decoder"), provider=provider880        ),881        text_encoder=OnnxRuntimeModel.from_pretrained(882            os.path.join(args.onnx_model_dir, "text_encoder"), provider=provider883        ),884        tokenizer=pipeline.tokenizer,885        unet=OnnxRuntimeModel.from_pretrained(os.path.join(args.onnx_model_dir, "unet"), provider=provider),886        scheduler=pipeline.scheduler,887    )888    onnx_pipeline = onnx_pipeline.to("cuda")889 890    prompt = "a cute cat fly to the moon"891    negative_prompt = "paintings, sketches, worst quality, low quality, normal quality, lowres, normal quality, monochrome, grayscale, skin spots, acnes, skin blemishes, age spot, glans, nsfw, nipples, necklace, worst quality, low quality, watermark, username, signature, multiple breasts, lowres, bad anatomy, bad hands, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, bad feet, single color, ugly, duplicate, morbid, mutilated, extra fingers, mutated hands, poorly drawn hands, poorly drawn face, mutation, deformed, ugly, blurry, bad anatomy, bad proportions, extra limbs, disfigured, bad anatomy, gross proportions, malformed limbs, missing arms, missing legs, extra arms, extra legs, mutated hands, fused fingers, too many fingers, long neck, bad body perspect"892 893    for i in range(10):894        start_time = time.time()895        image = onnx_pipeline(896            num_controlnet=2,897            prompt=prompt,898            negative_prompt=negative_prompt,899            image=qr_image,900            control_image=[qr_image, qr_image],901            width=512,902            height=512,903            strength=0.75,904            num_inference_steps=20,905            num_images_per_prompt=1,906            controlnet_conditioning_scale=[0.8, 0.8],907            control_guidance_start=[0.3, 0.3],908            control_guidance_end=[0.9, 0.9],909        ).images[0]910        print(time.time() - start_time)911        image.save("output_qr_code.png")912