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 27d agoView on Hugging Face
9likes22kdownloads
run_tensorrt_controlnet.py1023 linesDownload Raw Back to root
1import argparse2import atexit3import inspect4import os5import time6import warnings7from typing import Any, Callable, Dict, List, Optional, Union8 9import numpy as np10import PIL.Image11import pycuda.driver as cuda12import tensorrt as trt13import torch14from PIL import Image15from pycuda.tools import make_default_context16from transformers import CLIPTokenizer17 18from diffusers import OnnxRuntimeModel, StableDiffusionImg2ImgPipeline, UniPCMultistepScheduler19from diffusers.image_processor import VaeImageProcessor20from diffusers.pipelines.pipeline_utils import DiffusionPipeline21from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput22from diffusers.schedulers import KarrasDiffusionSchedulers23from diffusers.utils import (24    deprecate,25    logging,26    replace_example_docstring,27)28from diffusers.utils.torch_utils import randn_tensor29 30 31# Initialize CUDA32cuda.init()33context = make_default_context()34device = context.get_device()35atexit.register(context.pop)36 37logger = logging.get_logger(__name__)  # pylint: disable=invalid-name38 39 40def load_engine(trt_runtime, engine_path):41    with open(engine_path, "rb") as f:42        engine_data = f.read()43    engine = trt_runtime.deserialize_cuda_engine(engine_data)44    return engine45 46 47class TensorRTModel:48    def __init__(49        self,50        trt_engine_path,51        **kwargs,52    ):53        cuda.init()54        stream = cuda.Stream()55        TRT_LOGGER = trt.Logger(trt.Logger.VERBOSE)56        trt.init_libnvinfer_plugins(TRT_LOGGER, "")57        trt_runtime = trt.Runtime(TRT_LOGGER)58        engine = load_engine(trt_runtime, trt_engine_path)59        context = engine.create_execution_context()60 61        # allocates memory for network inputs/outputs on both CPU and GPU62        host_inputs = []63        cuda_inputs = []64        host_outputs = []65        cuda_outputs = []66        bindings = []67        input_names = []68        output_names = []69 70        for binding in engine:71            datatype = engine.get_binding_dtype(binding)72            if datatype == trt.DataType.HALF:73                dtype = np.float1674            else:75                dtype = np.float3276 77            shape = tuple(engine.get_binding_shape(binding))78            host_mem = cuda.pagelocked_empty(shape, dtype)79            cuda_mem = cuda.mem_alloc(host_mem.nbytes)80            bindings.append(int(cuda_mem))81 82            if engine.binding_is_input(binding):83                host_inputs.append(host_mem)84                cuda_inputs.append(cuda_mem)85                input_names.append(binding)86            else:87                host_outputs.append(host_mem)88                cuda_outputs.append(cuda_mem)89                output_names.append(binding)90 91        self.stream = stream92        self.context = context93        self.engine = engine94 95        self.host_inputs = host_inputs96        self.cuda_inputs = cuda_inputs97        self.host_outputs = host_outputs98        self.cuda_outputs = cuda_outputs99        self.bindings = bindings100        self.batch_size = engine.max_batch_size101 102        self.input_names = input_names103        self.output_names = output_names104 105    def __call__(self, **kwargs):106        context = self.context107        stream = self.stream108        bindings = self.bindings109 110        host_inputs = self.host_inputs111        cuda_inputs = self.cuda_inputs112        host_outputs = self.host_outputs113        cuda_outputs = self.cuda_outputs114 115        for idx, input_name in enumerate(self.input_names):116            _input = kwargs[input_name]117            np.copyto(host_inputs[idx], _input)118            # transfer input data to the GPU119            cuda.memcpy_htod_async(cuda_inputs[idx], host_inputs[idx], stream)120 121        context.execute_async_v2(bindings=bindings, stream_handle=stream.handle)122 123        result = {}124        for idx, output_name in enumerate(self.output_names):125            # transfer predictions back from the GPU126            cuda.memcpy_dtoh_async(host_outputs[idx], cuda_outputs[idx], stream)127            result[output_name] = host_outputs[idx]128 129        stream.synchronize()130 131        return result132 133 134EXAMPLE_DOC_STRING = """135    Examples:136        ```py137        >>> # !pip install opencv-python transformers accelerate138        >>> from diffusers import StableDiffusionControlNetImg2ImgPipeline, ControlNetModel, UniPCMultistepScheduler139        >>> from diffusers.utils import load_image140        >>> import numpy as np141        >>> import torch142 143        >>> import cv2144        >>> from PIL import Image145 146        >>> # download an image147        >>> image = load_image(148        ...     "https://hf.co/datasets/huggingface/documentation-images/resolve/main/diffusers/input_image_vermeer.png"149        ... )150        >>> np_image = np.array(image)151 152        >>> # get canny image153        >>> np_image = cv2.Canny(np_image, 100, 200)154        >>> np_image = np_image[:, :, None]155        >>> np_image = np.concatenate([np_image, np_image, np_image], axis=2)156        >>> canny_image = Image.fromarray(np_image)157 158        >>> # load control net and stable diffusion v1-5159        >>> controlnet = ControlNetModel.from_pretrained("lllyasviel/sd-controlnet-canny", torch_dtype=torch.float16)160        >>> pipe = StableDiffusionControlNetImg2ImgPipeline.from_pretrained(161        ...     "runwayml/stable-diffusion-v1-5", controlnet=controlnet, torch_dtype=torch.float16162        ... )163 164        >>> # speed up diffusion process with faster scheduler and memory optimization165        >>> pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)166        >>> pipe.enable_model_cpu_offload()167 168        >>> # generate image169        >>> generator = torch.manual_seed(0)170        >>> image = pipe(171        ...     "futuristic-looking woman",172        ...     num_inference_steps=20,173        ...     generator=generator,174        ...     image=image,175        ...     control_image=canny_image,176        ... ).images[0]177        ```178"""179 180 181def prepare_image(image):182    if isinstance(image, torch.Tensor):183        # Batch single image184        if image.ndim == 3:185            image = image.unsqueeze(0)186 187        image = image.to(dtype=torch.float32)188    else:189        # preprocess image190        if isinstance(image, (PIL.Image.Image, np.ndarray)):191            image = [image]192 193        if isinstance(image, list) and isinstance(image[0], PIL.Image.Image):194            image = [np.array(i.convert("RGB"))[None, :] for i in image]195            image = np.concatenate(image, axis=0)196        elif isinstance(image, list) and isinstance(image[0], np.ndarray):197            image = np.concatenate([i[None, :] for i in image], axis=0)198 199        image = image.transpose(0, 3, 1, 2)200        image = torch.from_numpy(image).to(dtype=torch.float32) / 127.5 - 1.0201 202    return image203 204 205class TensorRTStableDiffusionControlNetImg2ImgPipeline(DiffusionPipeline):206    vae_encoder: OnnxRuntimeModel207    vae_decoder: OnnxRuntimeModel208    text_encoder: OnnxRuntimeModel209    tokenizer: CLIPTokenizer210    unet: TensorRTModel211    scheduler: KarrasDiffusionSchedulers212 213    def __init__(214        self,215        vae_encoder: OnnxRuntimeModel,216        vae_decoder: OnnxRuntimeModel,217        text_encoder: OnnxRuntimeModel,218        tokenizer: CLIPTokenizer,219        unet: TensorRTModel,220        scheduler: KarrasDiffusionSchedulers,221    ):222        super().__init__()223 224        self.register_modules(225            vae_encoder=vae_encoder,226            vae_decoder=vae_decoder,227            text_encoder=text_encoder,228            tokenizer=tokenizer,229            unet=unet,230            scheduler=scheduler,231        )232        self.vae_scale_factor = 2 ** (4 - 1)233        self.image_processor = VaeImageProcessor(vae_scale_factor=self.vae_scale_factor, do_convert_rgb=True)234        self.control_image_processor = VaeImageProcessor(235            vae_scale_factor=self.vae_scale_factor, do_convert_rgb=True, do_normalize=False236        )237 238    def _encode_prompt(239        self,240        prompt: Union[str, List[str]],241        num_images_per_prompt: Optional[int],242        do_classifier_free_guidance: bool,243        negative_prompt: Optional[str],244        prompt_embeds: Optional[np.ndarray] = None,245        negative_prompt_embeds: Optional[np.ndarray] = None,246    ):247        r"""248        Encodes the prompt into text encoder hidden states.249 250        Args:251            prompt (`str` or `List[str]`):252                prompt to be encoded253            num_images_per_prompt (`int`):254                number of images that should be generated per prompt255            do_classifier_free_guidance (`bool`):256                whether to use classifier free guidance or not257            negative_prompt (`str` or `List[str]`):258                The prompt or prompts not to guide the image generation. Ignored when not using guidance (i.e., ignored259                if `guidance_scale` is less than `1`).260            prompt_embeds (`np.ndarray`, *optional*):261                Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not262                provided, text embeddings will be generated from `prompt` input argument.263            negative_prompt_embeds (`np.ndarray`, *optional*):264                Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt265                weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input266                argument.267        """268        if prompt is not None and isinstance(prompt, str):269            batch_size = 1270        elif prompt is not None and isinstance(prompt, list):271            batch_size = len(prompt)272        else:273            batch_size = prompt_embeds.shape[0]274 275        if prompt_embeds is None:276            # get prompt text embeddings277            text_inputs = self.tokenizer(278                prompt,279                padding="max_length",280                max_length=self.tokenizer.model_max_length,281                truncation=True,282                return_tensors="np",283            )284            text_input_ids = text_inputs.input_ids285            untruncated_ids = self.tokenizer(prompt, padding="max_length", return_tensors="np").input_ids286 287            if not np.array_equal(text_input_ids, untruncated_ids):288                removed_text = self.tokenizer.batch_decode(289                    untruncated_ids[:, self.tokenizer.model_max_length - 1 : -1]290                )291                logger.warning(292                    "The following part of your input was truncated because CLIP can only handle sequences up to"293                    f" {self.tokenizer.model_max_length} tokens: {removed_text}"294                )295 296            prompt_embeds = self.text_encoder(input_ids=text_input_ids.astype(np.int32))[0]297 298        prompt_embeds = np.repeat(prompt_embeds, num_images_per_prompt, axis=0)299 300        # get unconditional embeddings for classifier free guidance301        if do_classifier_free_guidance and negative_prompt_embeds is None:302            uncond_tokens: List[str]303            if negative_prompt is None:304                uncond_tokens = [""] * batch_size305            elif type(prompt) is not type(negative_prompt):306                raise TypeError(307                    f"`negative_prompt` should be the same type to `prompt`, but got {type(negative_prompt)} !="308                    f" {type(prompt)}."309                )310            elif isinstance(negative_prompt, str):311                uncond_tokens = [negative_prompt] * batch_size312            elif batch_size != len(negative_prompt):313                raise ValueError(314                    f"`negative_prompt`: {negative_prompt} has batch size {len(negative_prompt)}, but `prompt`:"315                    f" {prompt} has batch size {batch_size}. Please make sure that passed `negative_prompt` matches"316                    " the batch size of `prompt`."317                )318            else:319                uncond_tokens = negative_prompt320 321            max_length = prompt_embeds.shape[1]322            uncond_input = self.tokenizer(323                uncond_tokens,324                padding="max_length",325                max_length=max_length,326                truncation=True,327                return_tensors="np",328            )329            negative_prompt_embeds = self.text_encoder(input_ids=uncond_input.input_ids.astype(np.int32))[0]330 331        if do_classifier_free_guidance:332            negative_prompt_embeds = np.repeat(negative_prompt_embeds, num_images_per_prompt, axis=0)333 334            # For classifier free guidance, we need to do two forward passes.335            # Here we concatenate the unconditional and text embeddings into a single batch336            # to avoid doing two forward passes337            prompt_embeds = np.concatenate([negative_prompt_embeds, prompt_embeds])338 339        return prompt_embeds340 341    # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.decode_latents342    def decode_latents(self, latents):343        warnings.warn(344            "The decode_latents method is deprecated and will be removed in a future version. Please"345            " use VaeImageProcessor instead",346            FutureWarning,347        )348        latents = 1 / self.vae.config.scaling_factor * latents349        image = self.vae.decode(latents, return_dict=False)[0]350        image = (image / 2 + 0.5).clamp(0, 1)351        # we always cast to float32 as this does not cause significant overhead and is compatible with bfloat16352        image = image.cpu().permute(0, 2, 3, 1).float().numpy()353        return image354 355    # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.prepare_extra_step_kwargs356    def prepare_extra_step_kwargs(self, generator, eta):357        # prepare extra kwargs for the scheduler step, since not all schedulers have the same signature358        # eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers.359        # eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502360        # and should be between [0, 1]361 362        accepts_eta = "eta" in set(inspect.signature(self.scheduler.step).parameters.keys())363        extra_step_kwargs = {}364        if accepts_eta:365            extra_step_kwargs["eta"] = eta366 367        # check if the scheduler accepts generator368        accepts_generator = "generator" in set(inspect.signature(self.scheduler.step).parameters.keys())369        if accepts_generator:370            extra_step_kwargs["generator"] = generator371        return extra_step_kwargs372 373    def check_inputs(374        self,375        num_controlnet,376        prompt,377        image,378        callback_steps,379        negative_prompt=None,380        prompt_embeds=None,381        negative_prompt_embeds=None,382        controlnet_conditioning_scale=1.0,383        control_guidance_start=0.0,384        control_guidance_end=1.0,385    ):386        if (callback_steps is None) or (387            callback_steps is not None and (not isinstance(callback_steps, int) or callback_steps <= 0)388        ):389            raise ValueError(390                f"`callback_steps` has to be a positive integer but is {callback_steps} of type"391                f" {type(callback_steps)}."392            )393 394        if prompt is not None and prompt_embeds is not None:395            raise ValueError(396                f"Cannot forward both `prompt`: {prompt} and `prompt_embeds`: {prompt_embeds}. Please make sure to"397                " only forward one of the two."398            )399        elif prompt is None and prompt_embeds is None:400            raise ValueError(401                "Provide either `prompt` or `prompt_embeds`. Cannot leave both `prompt` and `prompt_embeds` undefined."402            )403        elif prompt is not None and (not isinstance(prompt, str) and not isinstance(prompt, list)):404            raise ValueError(f"`prompt` has to be of type `str` or `list` but is {type(prompt)}")405 406        if negative_prompt is not None and negative_prompt_embeds is not None:407            raise ValueError(408                f"Cannot forward both `negative_prompt`: {negative_prompt} and `negative_prompt_embeds`:"409                f" {negative_prompt_embeds}. Please make sure to only forward one of the two."410            )411 412        if prompt_embeds is not None and negative_prompt_embeds is not None:413            if prompt_embeds.shape != negative_prompt_embeds.shape:414                raise ValueError(415                    "`prompt_embeds` and `negative_prompt_embeds` must have the same shape when passed directly, but"416                    f" got: `prompt_embeds` {prompt_embeds.shape} != `negative_prompt_embeds`"417                    f" {negative_prompt_embeds.shape}."418                )419 420        # Check `image`421        if num_controlnet == 1:422            self.check_image(image, prompt, prompt_embeds)423        elif num_controlnet > 1:424            if not isinstance(image, list):425                raise TypeError("For multiple controlnets: `image` must be type `list`")426 427            # When `image` is a nested list:428            # (e.g. [[canny_image_1, pose_image_1], [canny_image_2, pose_image_2]])429            elif any(isinstance(i, list) for i in image):430                raise ValueError("A single batch of multiple conditionings are supported at the moment.")431            elif len(image) != num_controlnet:432                raise ValueError(433                    f"For multiple controlnets: `image` must have the same length as the number of controlnets, but got {len(image)} images and {num_controlnet} ControlNets."434                )435 436            for image_ in image:437                self.check_image(image_, prompt, prompt_embeds)438        else:439            assert False440 441        # Check `controlnet_conditioning_scale`442        if num_controlnet == 1:443            if not isinstance(controlnet_conditioning_scale, float):444                raise TypeError("For single controlnet: `controlnet_conditioning_scale` must be type `float`.")445        elif num_controlnet > 1:446            if isinstance(controlnet_conditioning_scale, list):447                if any(isinstance(i, list) for i in controlnet_conditioning_scale):448                    raise ValueError("A single batch of multiple conditionings are supported at the moment.")449            elif (450                isinstance(controlnet_conditioning_scale, list)451                and len(controlnet_conditioning_scale) != num_controlnet452            ):453                raise ValueError(454                    "For multiple controlnets: When `controlnet_conditioning_scale` is specified as `list`, it must have"455                    " the same length as the number of controlnets"456                )457        else:458            assert False459 460        if len(control_guidance_start) != len(control_guidance_end):461            raise ValueError(462                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."463            )464 465        if num_controlnet > 1:466            if len(control_guidance_start) != num_controlnet:467                raise ValueError(468                    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}."469                )470 471        for start, end in zip(control_guidance_start, control_guidance_end):472            if start >= end:473                raise ValueError(474                    f"control guidance start: {start} cannot be larger or equal to control guidance end: {end}."475                )476            if start < 0.0:477                raise ValueError(f"control guidance start: {start} can't be smaller than 0.")478            if end > 1.0:479                raise ValueError(f"control guidance end: {end} can't be larger than 1.0.")480 481    # Copied from diffusers.pipelines.controlnet.pipeline_controlnet.StableDiffusionControlNetPipeline.check_image482    def check_image(self, image, prompt, prompt_embeds):483        image_is_pil = isinstance(image, PIL.Image.Image)484        image_is_tensor = isinstance(image, torch.Tensor)485        image_is_np = isinstance(image, np.ndarray)486        image_is_pil_list = isinstance(image, list) and isinstance(image[0], PIL.Image.Image)487        image_is_tensor_list = isinstance(image, list) and isinstance(image[0], torch.Tensor)488        image_is_np_list = isinstance(image, list) and isinstance(image[0], np.ndarray)489 490        if (491            not image_is_pil492            and not image_is_tensor493            and not image_is_np494            and not image_is_pil_list495            and not image_is_tensor_list496            and not image_is_np_list497        ):498            raise TypeError(499                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)}"500            )501 502        if image_is_pil:503            image_batch_size = 1504        else:505            image_batch_size = len(image)506 507        if prompt is not None and isinstance(prompt, str):508            prompt_batch_size = 1509        elif prompt is not None and isinstance(prompt, list):510            prompt_batch_size = len(prompt)511        elif prompt_embeds is not None:512            prompt_batch_size = prompt_embeds.shape[0]513 514        if image_batch_size != 1 and image_batch_size != prompt_batch_size:515            raise ValueError(516                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}"517            )518 519    # Copied from diffusers.pipelines.controlnet.pipeline_controlnet.StableDiffusionControlNetPipeline.prepare_image520    def prepare_control_image(521        self,522        image,523        width,524        height,525        batch_size,526        num_images_per_prompt,527        device,528        dtype,529        do_classifier_free_guidance=False,530        guess_mode=False,531    ):532        image = self.control_image_processor.preprocess(image, height=height, width=width).to(dtype=torch.float32)533        image_batch_size = image.shape[0]534 535        if image_batch_size == 1:536            repeat_by = batch_size537        else:538            # image batch size is the same as prompt batch size539            repeat_by = num_images_per_prompt540 541        image = image.repeat_interleave(repeat_by, dim=0)542 543        image = image.to(device=device, dtype=dtype)544 545        if do_classifier_free_guidance and not guess_mode:546            image = torch.cat([image] * 2)547 548        return image549 550    # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_img2img.StableDiffusionImg2ImgPipeline.get_timesteps551    def get_timesteps(self, num_inference_steps, strength, device):552        # get the original timestep using init_timestep553        init_timestep = min(int(num_inference_steps * strength), num_inference_steps)554 555        t_start = max(num_inference_steps - init_timestep, 0)556        timesteps = self.scheduler.timesteps[t_start * self.scheduler.order :]557 558        return timesteps, num_inference_steps - t_start559 560    def prepare_latents(self, image, timestep, batch_size, num_images_per_prompt, dtype, device, generator=None):561        if not isinstance(image, (torch.Tensor, PIL.Image.Image, list)):562            raise ValueError(563                f"`image` has to be of type `torch.Tensor`, `PIL.Image.Image` or list but is {type(image)}"564            )565 566        image = image.to(device=device, dtype=dtype)567 568        batch_size = batch_size * num_images_per_prompt569 570        if image.shape[1] == 4:571            init_latents = image572 573        else:574            _image = image.cpu().detach().numpy()575            init_latents = self.vae_encoder(sample=_image)[0]576            init_latents = torch.from_numpy(init_latents).to(device=device, dtype=dtype)577            init_latents = 0.18215 * init_latents578 579        if batch_size > init_latents.shape[0] and batch_size % init_latents.shape[0] == 0:580            # expand init_latents for batch_size581            deprecation_message = (582                f"You have passed {batch_size} text prompts (`prompt`), but only {init_latents.shape[0]} initial"583                " images (`image`). Initial images are now duplicating to match the number of text prompts. Note"584                " that this behavior is deprecated and will be removed in a version 1.0.0. Please make sure to update"585                " your script to pass as many initial images as text prompts to suppress this warning."586            )587            deprecate("len(prompt) != len(image)", "1.0.0", deprecation_message, standard_warn=False)588            additional_image_per_prompt = batch_size // init_latents.shape[0]589            init_latents = torch.cat([init_latents] * additional_image_per_prompt, dim=0)590        elif batch_size > init_latents.shape[0] and batch_size % init_latents.shape[0] != 0:591            raise ValueError(592                f"Cannot duplicate `image` of batch size {init_latents.shape[0]} to {batch_size} text prompts."593            )594        else:595            init_latents = torch.cat([init_latents], dim=0)596 597        shape = init_latents.shape598        noise = randn_tensor(shape, generator=generator, device=device, dtype=dtype)599 600        # get latents601        init_latents = self.scheduler.add_noise(init_latents, noise, timestep)602        latents = init_latents603 604        return latents605 606    @torch.no_grad()607    @replace_example_docstring(EXAMPLE_DOC_STRING)608    def __call__(609        self,610        num_controlnet: int,611        fp16: bool = True,612        prompt: Union[str, List[str]] = None,613        image: Union[614            torch.Tensor,615            PIL.Image.Image,616            np.ndarray,617            List[torch.Tensor],618            List[PIL.Image.Image],619            List[np.ndarray],620        ] = None,621        control_image: Union[622            torch.Tensor,623            PIL.Image.Image,624            np.ndarray,625            List[torch.Tensor],626            List[PIL.Image.Image],627            List[np.ndarray],628        ] = None,629        height: Optional[int] = None,630        width: Optional[int] = None,631        strength: float = 0.8,632        num_inference_steps: int = 50,633        guidance_scale: float = 7.5,634        negative_prompt: Optional[Union[str, List[str]]] = None,635        num_images_per_prompt: Optional[int] = 1,636        eta: float = 0.0,637        generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,638        latents: Optional[torch.Tensor] = None,639        prompt_embeds: Optional[torch.Tensor] = None,640        negative_prompt_embeds: Optional[torch.Tensor] = None,641        output_type: Optional[str] = "pil",642        return_dict: bool = True,643        callback: Optional[Callable[[int, int, torch.Tensor], None]] = None,644        callback_steps: int = 1,645        cross_attention_kwargs: Optional[Dict[str, Any]] = None,646        controlnet_conditioning_scale: Union[float, List[float]] = 0.8,647        guess_mode: bool = False,648        control_guidance_start: Union[float, List[float]] = 0.0,649        control_guidance_end: Union[float, List[float]] = 1.0,650    ):651        r"""652        Function invoked when calling the pipeline for generation.653 654        Args:655            prompt (`str` or `List[str]`, *optional*):656                The prompt or prompts to guide the image generation. If not defined, one has to pass `prompt_embeds`.657                instead.658            image (`torch.Tensor`, `PIL.Image.Image`, `np.ndarray`, `List[torch.Tensor]`, `List[PIL.Image.Image]`, `List[np.ndarray]`,:659                    `List[List[torch.Tensor]]`, `List[List[np.ndarray]]` or `List[List[PIL.Image.Image]]`):660                The initial image will be used as the starting point for the image generation process. Can also accept661                image latents as `image`, if passing latents directly, it will not be encoded again.662            control_image (`torch.Tensor`, `PIL.Image.Image`, `np.ndarray`, `List[torch.Tensor]`, `List[PIL.Image.Image]`, `List[np.ndarray]`,:663                    `List[List[torch.Tensor]]`, `List[List[np.ndarray]]` or `List[List[PIL.Image.Image]]`):664                The ControlNet input condition. ControlNet uses this input condition to generate guidance to Unet. If665                the type is specified as `torch.Tensor`, it is passed to ControlNet as is. `PIL.Image.Image` can666                also be accepted as an image. The dimensions of the output image defaults to `image`'s dimensions. If667                height and/or width are passed, `image` is resized according to them. If multiple ControlNets are668                specified in init, images must be passed as a list such that each element of the list can be correctly669                batched for input to a single controlnet.670            height (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):671                The height in pixels of the generated image.672            width (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):673                The width in pixels of the generated image.674            num_inference_steps (`int`, *optional*, defaults to 50):675                The number of denoising steps. More denoising steps usually lead to a higher quality image at the676                expense of slower inference.677            guidance_scale (`float`, *optional*, defaults to 7.5):678                Guidance scale as defined in [Classifier-Free Diffusion Guidance](https://arxiv.org/abs/2207.12598).679                `guidance_scale` is defined as `w` of equation 2. of [Imagen680                Paper](https://arxiv.org/pdf/2205.11487.pdf). Guidance scale is enabled by setting `guidance_scale >681                1`. Higher guidance scale encourages to generate images that are closely linked to the text `prompt`,682                usually at the expense of lower image quality.683            negative_prompt (`str` or `List[str]`, *optional*):684                The prompt or prompts not to guide the image generation. If not defined, one has to pass685                `negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is686                less than `1`).687            num_images_per_prompt (`int`, *optional*, defaults to 1):688                The number of images to generate per prompt.689            eta (`float`, *optional*, defaults to 0.0):690                Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to691                [`schedulers.DDIMScheduler`], will be ignored for others.692            generator (`torch.Generator` or `List[torch.Generator]`, *optional*):693                One or a list of [torch generator(s)](https://pytorch.org/docs/stable/generated/torch.Generator.html)694                to make generation deterministic.695            latents (`torch.Tensor`, *optional*):696                Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image697                generation. Can be used to tweak the same generation with different prompts. If not provided, a latents698                tensor will ge generated by sampling using the supplied random `generator`.699            prompt_embeds (`torch.Tensor`, *optional*):700                Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not701                provided, text embeddings will be generated from `prompt` input argument.702            negative_prompt_embeds (`torch.Tensor`, *optional*):703                Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt704                weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input705                argument.706            output_type (`str`, *optional*, defaults to `"pil"`):707                The output format of the generate image. Choose between708                [PIL](https://pillow.readthedocs.io/en/stable/): `PIL.Image.Image` or `np.array`.709            return_dict (`bool`, *optional*, defaults to `True`):710                Whether or not to return a [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] instead of a711                plain tuple.712            callback (`Callable`, *optional*):713                A function that will be called every `callback_steps` steps during inference. The function will be714                called with the following arguments: `callback(step: int, timestep: int, latents: torch.Tensor)`.715            callback_steps (`int`, *optional*, defaults to 1):716                The frequency at which the `callback` function will be called. If not specified, the callback will be717                called at every step.718            cross_attention_kwargs (`dict`, *optional*):719                A kwargs dictionary that if specified is passed along to the `AttentionProcessor` as defined under720                `self.processor` in721                [diffusers.models.attention_processor](https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/attention_processor.py).722            controlnet_conditioning_scale (`float` or `List[float]`, *optional*, defaults to 1.0):723                The outputs of the controlnet are multiplied by `controlnet_conditioning_scale` before they are added724                to the residual in the original unet. If multiple ControlNets are specified in init, you can set the725                corresponding scale as a list. Note that by default, we use a smaller conditioning scale for inpainting726                than for [`~StableDiffusionControlNetPipeline.__call__`].727            guess_mode (`bool`, *optional*, defaults to `False`):728                In this mode, the ControlNet encoder will try best to recognize the content of the input image even if729                you remove all prompts. The `guidance_scale` between 3.0 and 5.0 is recommended.730            control_guidance_start (`float` or `List[float]`, *optional*, defaults to 0.0):731                The percentage of total steps at which the controlnet starts applying.732            control_guidance_end (`float` or `List[float]`, *optional*, defaults to 1.0):733                The percentage of total steps at which the controlnet stops applying.734 735        Examples:736 737        Returns:738            [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] or `tuple`:739            [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] if `return_dict` is True, otherwise a `tuple.740            When returning a tuple, the first element is a list with the generated images, and the second element is a741            list of `bool`s denoting whether the corresponding generated image likely represents "not-safe-for-work"742            (nsfw) content, according to the `safety_checker`.743        """744        if fp16:745            torch_dtype = torch.float16746            np_dtype = np.float16747        else:748            torch_dtype = torch.float32749            np_dtype = np.float32750 751        # align format for control guidance752        if not isinstance(control_guidance_start, list) and isinstance(control_guidance_end, list):753            control_guidance_start = len(control_guidance_end) * [control_guidance_start]754        elif not isinstance(control_guidance_end, list) and isinstance(control_guidance_start, list):755            control_guidance_end = len(control_guidance_start) * [control_guidance_end]756        elif not isinstance(control_guidance_start, list) and not isinstance(control_guidance_end, list):757            mult = num_controlnet758            control_guidance_start, control_guidance_end = (759                mult * [control_guidance_start],760                mult * [control_guidance_end],761            )762 763        # 1. Check inputs. Raise error if not correct764        self.check_inputs(765            num_controlnet,766            prompt,767            control_image,768            callback_steps,769            negative_prompt,770            prompt_embeds,771            negative_prompt_embeds,772            controlnet_conditioning_scale,773            control_guidance_start,774            control_guidance_end,775        )776 777        # 2. Define call parameters778        if prompt is not None and isinstance(prompt, str):779            batch_size = 1780        elif prompt is not None and isinstance(prompt, list):781            batch_size = len(prompt)782        else:783            batch_size = prompt_embeds.shape[0]784 785        device = self._execution_device786        # here `guidance_scale` is defined analog to the guidance weight `w` of equation (2)787        # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . `guidance_scale = 1`788        # corresponds to doing no classifier free guidance.789        do_classifier_free_guidance = guidance_scale > 1.0790 791        if num_controlnet > 1 and isinstance(controlnet_conditioning_scale, float):792            controlnet_conditioning_scale = [controlnet_conditioning_scale] * num_controlnet793 794        # 3. Encode input prompt795        prompt_embeds = self._encode_prompt(796            prompt,797            num_images_per_prompt,798            do_classifier_free_guidance,799            negative_prompt,800            prompt_embeds=prompt_embeds,801            negative_prompt_embeds=negative_prompt_embeds,802        )803        # 4. Prepare image804        image = self.image_processor.preprocess(image).to(dtype=torch.float32)805 806        # 5. Prepare controlnet_conditioning_image807        if num_controlnet == 1:808            control_image = self.prepare_control_image(809                image=control_image,810                width=width,811                height=height,812                batch_size=batch_size * num_images_per_prompt,813                num_images_per_prompt=num_images_per_prompt,814                device=device,815                dtype=torch_dtype,816                do_classifier_free_guidance=do_classifier_free_guidance,817                guess_mode=guess_mode,818            )819        elif num_controlnet > 1:820            control_images = []821 822            for control_image_ in control_image:823                control_image_ = self.prepare_control_image(824                    image=control_image_,825                    width=width,826                    height=height,827                    batch_size=batch_size * num_images_per_prompt,828                    num_images_per_prompt=num_images_per_prompt,829                    device=device,830                    dtype=torch_dtype,831                    do_classifier_free_guidance=do_classifier_free_guidance,832                    guess_mode=guess_mode,833                )834 835                control_images.append(control_image_)836 837            control_image = control_images838        else:839            assert False840 841        # 5. Prepare timesteps842        self.scheduler.set_timesteps(num_inference_steps, device=device)843        timesteps, num_inference_steps = self.get_timesteps(num_inference_steps, strength, device)844        latent_timestep = timesteps[:1].repeat(batch_size * num_images_per_prompt)845 846        # 6. Prepare latent variables847        latents = self.prepare_latents(848            image,849            latent_timestep,850            batch_size,851            num_images_per_prompt,852            torch_dtype,853            device,854            generator,855        )856 857        # 7. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline858        extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)859 860        # 7.1 Create tensor stating which controlnets to keep861        controlnet_keep = []862        for i in range(len(timesteps)):863            keeps = [864                1.0 - float(i / len(timesteps) < s or (i + 1) / len(timesteps) > e)865                for s, e in zip(control_guidance_start, control_guidance_end)866            ]867            controlnet_keep.append(keeps[0] if num_controlnet == 1 else keeps)868 869        # 8. Denoising loop870        num_warmup_steps = len(timesteps) - num_inference_steps * self.scheduler.order871        with self.progress_bar(total=num_inference_steps) as progress_bar:872            for i, t in enumerate(timesteps):873                # expand the latents if we are doing classifier free guidance874                latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents875                latent_model_input = self.scheduler.scale_model_input(latent_model_input, t)876 877                if isinstance(controlnet_keep[i], list):878                    cond_scale = [c * s for c, s in zip(controlnet_conditioning_scale, controlnet_keep[i])]879                else:880                    controlnet_cond_scale = controlnet_conditioning_scale881                    if isinstance(controlnet_cond_scale, list):882                        controlnet_cond_scale = controlnet_cond_scale[0]883                    cond_scale = controlnet_cond_scale * controlnet_keep[i]884 885                # predict the noise residual886                _latent_model_input = latent_model_input.cpu().detach().numpy()887                _prompt_embeds = np.array(prompt_embeds, dtype=np_dtype)888                _t = np.array([t.cpu().detach().numpy()], dtype=np_dtype)889 890                if num_controlnet == 1:891                    control_images = np.array([control_image], dtype=np_dtype)892                else:893                    control_images = []894                    for _control_img in control_image:895                        _control_img = _control_img.cpu().detach().numpy()896                        control_images.append(_control_img)897                    control_images = np.array(control_images, dtype=np_dtype)898 899                control_scales = np.array(cond_scale, dtype=np_dtype)900                control_scales = np.resize(control_scales, (num_controlnet, 1))901 902                noise_pred = self.unet(903                    sample=_latent_model_input,904                    timestep=_t,905                    encoder_hidden_states=_prompt_embeds,906                    controlnet_conds=control_images,907                    conditioning_scales=control_scales,908                )["noise_pred"]909                noise_pred = torch.from_numpy(noise_pred).to(device)910 911                # perform guidance912                if do_classifier_free_guidance:913                    noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)914                    noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)915 916                # compute the previous noisy sample x_t -> x_t-1917                latents = self.scheduler.step(noise_pred, t, latents, **extra_step_kwargs, return_dict=False)[0]918 919                # call the callback, if provided920                if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0):921                    progress_bar.update()922                    if callback is not None and i % callback_steps == 0:923                        step_idx = i // getattr(self.scheduler, "order", 1)924                        callback(step_idx, t, latents)925 926        if not output_type == "latent":927            _latents = latents.cpu().detach().numpy() / 0.18215928            _latents = np.array(_latents, dtype=np_dtype)929            image = self.vae_decoder(latent_sample=_latents)[0]930            image = torch.from_numpy(image).to(device, dtype=torch.float32)931            has_nsfw_concept = None932        else:933            image = latents934            has_nsfw_concept = None935 936        if has_nsfw_concept is None:937            do_denormalize = [True] * image.shape[0]938        else:939            do_denormalize = [not has_nsfw for has_nsfw in has_nsfw_concept]940 941        image = self.image_processor.postprocess(image, output_type=output_type, do_denormalize=do_denormalize)942 943        if not return_dict:944            return (image, has_nsfw_concept)945 946        return StableDiffusionPipelineOutput(images=image, nsfw_content_detected=has_nsfw_concept)947 948 949if __name__ == "__main__":950    parser = argparse.ArgumentParser()951 952    parser.add_argument(953        "--sd_model",954        type=str,955        required=True,956        help="Path to the `diffusers` checkpoint to convert (either a local directory or on the Hub).",957    )958 959    parser.add_argument(960        "--onnx_model_dir",961        type=str,962        required=True,963        help="Path to the ONNX directory",964    )965 966    parser.add_argument(967        "--unet_engine_path",968        type=str,969        required=True,970        help="Path to the unet + controlnet tensorrt model",971    )972 973    parser.add_argument("--qr_img_path", type=str, required=True, help="Path to the qr code image")974 975    args = parser.parse_args()976 977    qr_image = Image.open(args.qr_img_path)978    qr_image = qr_image.resize((512, 512))979 980    # init stable diffusion pipeline981    pipeline = StableDiffusionImg2ImgPipeline.from_pretrained(args.sd_model)982    pipeline.scheduler = UniPCMultistepScheduler.from_config(pipeline.scheduler.config)983 984    provider = ["CUDAExecutionProvider", "CPUExecutionProvider"]985    onnx_pipeline = TensorRTStableDiffusionControlNetImg2ImgPipeline(986        vae_encoder=OnnxRuntimeModel.from_pretrained(987            os.path.join(args.onnx_model_dir, "vae_encoder"), provider=provider988        ),989        vae_decoder=OnnxRuntimeModel.from_pretrained(990            os.path.join(args.onnx_model_dir, "vae_decoder"), provider=provider991        ),992        text_encoder=OnnxRuntimeModel.from_pretrained(993            os.path.join(args.onnx_model_dir, "text_encoder"), provider=provider994        ),995        tokenizer=pipeline.tokenizer,996        unet=TensorRTModel(args.unet_engine_path),997        scheduler=pipeline.scheduler,998    )999    onnx_pipeline = onnx_pipeline.to("cuda")1000 1001    prompt = "a cute cat fly to the moon"1002    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"1003 1004    for i in range(10):1005        start_time = time.time()1006        image = onnx_pipeline(1007            num_controlnet=2,1008            prompt=prompt,1009            negative_prompt=negative_prompt,1010            image=qr_image,1011            control_image=[qr_image, qr_image],1012            width=512,1013            height=512,1014            strength=0.75,1015            num_inference_steps=20,1016            num_images_per_prompt=1,1017            controlnet_conditioning_scale=[0.8, 0.8],1018            control_guidance_start=[0.3, 0.3],1019            control_guidance_end=[0.9, 0.9],1020        ).images[0]1021        print(time.time() - start_time)1022        image.save("output_qr_code.png")1023