diffusers/community-pipelines-mirror
Community Pipeline Examples For more information about community pipelines, please have a look at this issue. Community pipeline examples consist pipelines that have been added by the community. Please have a look at the following tables to get an overview of all community examples. Click on the Code Example to get a copy-and-paste ready code example that you can try out. If a community pipeline doesn't work as expected, please open an issue and ping the author on it. Please… See the full description on the dataset page: https://huggingface.co/datasets/diffusers/community-pipelines-mirror.
922k
1#2# Copyright 2025 The HuggingFace Inc. team.3# SPDX-FileCopyrightText: Copyright (c) 1993-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.4# SPDX-License-Identifier: Apache-2.05#6# Licensed under the Apache License, Version 2.0 (the "License");7# you may not use this file except in compliance with the License.8# You may obtain a copy of the License at9#10# http://www.apache.org/licenses/LICENSE-2.011#12# Unless required by applicable law or agreed to in writing, software13# distributed under the License is distributed on an "AS IS" BASIS,14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.15# See the License for the specific language governing permissions and16# limitations under the License.17 18import gc19import os20from collections import OrderedDict21from typing import List, Optional, Tuple, Union22 23import numpy as np24import onnx25import onnx_graphsurgeon as gs26import PIL.Image27import tensorrt as trt28import torch29from cuda import cudart30from huggingface_hub import snapshot_download31from huggingface_hub.utils import validate_hf_hub_args32from onnx import shape_inference33from packaging import version34from polygraphy import cuda35from polygraphy.backend.common import bytes_from_path36from polygraphy.backend.onnx.loader import fold_constants37from polygraphy.backend.trt import (38 CreateConfig,39 Profile,40 engine_from_bytes,41 engine_from_network,42 network_from_onnx_path,43 save_engine,44)45from transformers import CLIPImageProcessor, CLIPTextModel, CLIPTokenizer, CLIPVisionModelWithProjection46 47from diffusers import DiffusionPipeline48from diffusers.configuration_utils import FrozenDict, deprecate49from diffusers.image_processor import VaeImageProcessor50from diffusers.models import AutoencoderKL, UNet2DConditionModel51from diffusers.pipelines.stable_diffusion import (52 StableDiffusionPipelineOutput,53 StableDiffusionSafetyChecker,54)55from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_img2img import retrieve_latents56from diffusers.schedulers import DDIMScheduler57from diffusers.utils import logging58 59 60"""61Installation instructions62python3 -m pip install --upgrade transformers diffusers>=0.16.063python3 -m pip install --upgrade tensorrt~=10.2.064python3 -m pip install --upgrade polygraphy>=0.47.0 onnx-graphsurgeon --extra-index-url https://pypi.ngc.nvidia.com65python3 -m pip install onnxruntime66"""67 68TRT_LOGGER = trt.Logger(trt.Logger.ERROR)69logger = logging.get_logger(__name__) # pylint: disable=invalid-name70 71# Map of numpy dtype -> torch dtype72numpy_to_torch_dtype_dict = {73 np.uint8: torch.uint8,74 np.int8: torch.int8,75 np.int16: torch.int16,76 np.int32: torch.int32,77 np.int64: torch.int64,78 np.float16: torch.float16,79 np.float32: torch.float32,80 np.float64: torch.float64,81 np.complex64: torch.complex64,82 np.complex128: torch.complex128,83}84if np.version.full_version >= "1.24.0":85 numpy_to_torch_dtype_dict[np.bool_] = torch.bool86else:87 numpy_to_torch_dtype_dict[np.bool] = torch.bool88 89# Map of torch dtype -> numpy dtype90torch_to_numpy_dtype_dict = {value: key for (key, value) in numpy_to_torch_dtype_dict.items()}91 92 93def preprocess_image(image):94 """95 image: torch.Tensor96 """97 w, h = image.size98 w, h = (x - x % 32 for x in (w, h)) # resize to integer multiple of 3299 image = image.resize((w, h))100 image = np.array(image).astype(np.float32) / 255.0101 image = image[None].transpose(0, 3, 1, 2)102 image = torch.from_numpy(image).contiguous()103 return 2.0 * image - 1.0104 105 106class Engine:107 def __init__(self, engine_path):108 self.engine_path = engine_path109 self.engine = None110 self.context = None111 self.buffers = OrderedDict()112 self.tensors = OrderedDict()113 114 def __del__(self):115 [buf.free() for buf in self.buffers.values() if isinstance(buf, cuda.DeviceArray)]116 del self.engine117 del self.context118 del self.buffers119 del self.tensors120 121 def build(122 self,123 onnx_path,124 fp16,125 input_profile=None,126 enable_all_tactics=False,127 timing_cache=None,128 ):129 logger.warning(f"Building TensorRT engine for {onnx_path}: {self.engine_path}")130 p = Profile()131 if input_profile:132 for name, dims in input_profile.items():133 assert len(dims) == 3134 p.add(name, min=dims[0], opt=dims[1], max=dims[2])135 136 extra_build_args = {}137 if not enable_all_tactics:138 extra_build_args["tactic_sources"] = []139 140 engine = engine_from_network(141 network_from_onnx_path(onnx_path, flags=[trt.OnnxParserFlag.NATIVE_INSTANCENORM]),142 config=CreateConfig(fp16=fp16, profiles=[p], load_timing_cache=timing_cache, **extra_build_args),143 save_timing_cache=timing_cache,144 )145 save_engine(engine, path=self.engine_path)146 147 def load(self):148 logger.warning(f"Loading TensorRT engine: {self.engine_path}")149 self.engine = engine_from_bytes(bytes_from_path(self.engine_path))150 151 def activate(self):152 self.context = self.engine.create_execution_context()153 154 def allocate_buffers(self, shape_dict=None, device="cuda"):155 for binding in range(self.engine.num_io_tensors):156 name = self.engine.get_tensor_name(binding)157 if shape_dict and name in shape_dict:158 shape = shape_dict[name]159 else:160 shape = self.engine.get_tensor_shape(name)161 dtype = trt.nptype(self.engine.get_tensor_dtype(name))162 if self.engine.get_tensor_mode(name) == trt.TensorIOMode.INPUT:163 self.context.set_input_shape(name, shape)164 tensor = torch.empty(tuple(shape), dtype=numpy_to_torch_dtype_dict[dtype]).to(device=device)165 self.tensors[name] = tensor166 167 def infer(self, feed_dict, stream):168 for name, buf in feed_dict.items():169 self.tensors[name].copy_(buf)170 for name, tensor in self.tensors.items():171 self.context.set_tensor_address(name, tensor.data_ptr())172 noerror = self.context.execute_async_v3(stream)173 if not noerror:174 raise ValueError("ERROR: inference failed.")175 176 return self.tensors177 178 179class Optimizer:180 def __init__(self, onnx_graph):181 self.graph = gs.import_onnx(onnx_graph)182 183 def cleanup(self, return_onnx=False):184 self.graph.cleanup().toposort()185 if return_onnx:186 return gs.export_onnx(self.graph)187 188 def select_outputs(self, keep, names=None):189 self.graph.outputs = [self.graph.outputs[o] for o in keep]190 if names:191 for i, name in enumerate(names):192 self.graph.outputs[i].name = name193 194 def fold_constants(self, return_onnx=False):195 onnx_graph = fold_constants(gs.export_onnx(self.graph), allow_onnxruntime_shape_inference=True)196 self.graph = gs.import_onnx(onnx_graph)197 if return_onnx:198 return onnx_graph199 200 def infer_shapes(self, return_onnx=False):201 onnx_graph = gs.export_onnx(self.graph)202 if onnx_graph.ByteSize() > 2147483648:203 raise TypeError("ERROR: model size exceeds supported 2GB limit")204 else:205 onnx_graph = shape_inference.infer_shapes(onnx_graph)206 207 self.graph = gs.import_onnx(onnx_graph)208 if return_onnx:209 return onnx_graph210 211 212class BaseModel:213 def __init__(self, model, fp16=False, device="cuda", max_batch_size=16, embedding_dim=768, text_maxlen=77):214 self.model = model215 self.name = "SD Model"216 self.fp16 = fp16217 self.device = device218 219 self.min_batch = 1220 self.max_batch = max_batch_size221 self.min_image_shape = 256 # min image resolution: 256x256222 self.max_image_shape = 1024 # max image resolution: 1024x1024223 self.min_latent_shape = self.min_image_shape // 8224 self.max_latent_shape = self.max_image_shape // 8225 226 self.embedding_dim = embedding_dim227 self.text_maxlen = text_maxlen228 229 def get_model(self):230 return self.model231 232 def get_input_names(self):233 pass234 235 def get_output_names(self):236 pass237 238 def get_dynamic_axes(self):239 return None240 241 def get_sample_input(self, batch_size, image_height, image_width):242 pass243 244 def get_input_profile(self, batch_size, image_height, image_width, static_batch, static_shape):245 return None246 247 def get_shape_dict(self, batch_size, image_height, image_width):248 return None249 250 def optimize(self, onnx_graph):251 opt = Optimizer(onnx_graph)252 opt.cleanup()253 opt.fold_constants()254 opt.infer_shapes()255 onnx_opt_graph = opt.cleanup(return_onnx=True)256 return onnx_opt_graph257 258 def check_dims(self, batch_size, image_height, image_width):259 assert batch_size >= self.min_batch and batch_size <= self.max_batch260 assert image_height % 8 == 0 or image_width % 8 == 0261 latent_height = image_height // 8262 latent_width = image_width // 8263 assert latent_height >= self.min_latent_shape and latent_height <= self.max_latent_shape264 assert latent_width >= self.min_latent_shape and latent_width <= self.max_latent_shape265 return (latent_height, latent_width)266 267 def get_minmax_dims(self, batch_size, image_height, image_width, static_batch, static_shape):268 min_batch = batch_size if static_batch else self.min_batch269 max_batch = batch_size if static_batch else self.max_batch270 latent_height = image_height // 8271 latent_width = image_width // 8272 min_image_height = image_height if static_shape else self.min_image_shape273 max_image_height = image_height if static_shape else self.max_image_shape274 min_image_width = image_width if static_shape else self.min_image_shape275 max_image_width = image_width if static_shape else self.max_image_shape276 min_latent_height = latent_height if static_shape else self.min_latent_shape277 max_latent_height = latent_height if static_shape else self.max_latent_shape278 min_latent_width = latent_width if static_shape else self.min_latent_shape279 max_latent_width = latent_width if static_shape else self.max_latent_shape280 return (281 min_batch,282 max_batch,283 min_image_height,284 max_image_height,285 min_image_width,286 max_image_width,287 min_latent_height,288 max_latent_height,289 min_latent_width,290 max_latent_width,291 )292 293 294def getOnnxPath(model_name, onnx_dir, opt=True):295 return os.path.join(onnx_dir, model_name + (".opt" if opt else "") + ".onnx")296 297 298def getEnginePath(model_name, engine_dir):299 return os.path.join(engine_dir, model_name + ".plan")300 301 302def build_engines(303 models: dict,304 engine_dir,305 onnx_dir,306 onnx_opset,307 opt_image_height,308 opt_image_width,309 opt_batch_size=1,310 force_engine_rebuild=False,311 static_batch=False,312 static_shape=True,313 enable_all_tactics=False,314 timing_cache=None,315):316 built_engines = {}317 if not os.path.isdir(onnx_dir):318 os.makedirs(onnx_dir)319 if not os.path.isdir(engine_dir):320 os.makedirs(engine_dir)321 322 # Export models to ONNX323 for model_name, model_obj in models.items():324 engine_path = getEnginePath(model_name, engine_dir)325 if force_engine_rebuild or not os.path.exists(engine_path):326 logger.warning("Building Engines...")327 logger.warning("Engine build can take a while to complete")328 onnx_path = getOnnxPath(model_name, onnx_dir, opt=False)329 onnx_opt_path = getOnnxPath(model_name, onnx_dir)330 if force_engine_rebuild or not os.path.exists(onnx_opt_path):331 if force_engine_rebuild or not os.path.exists(onnx_path):332 logger.warning(f"Exporting model: {onnx_path}")333 model = model_obj.get_model()334 with torch.inference_mode(), torch.autocast("cuda"):335 inputs = model_obj.get_sample_input(opt_batch_size, opt_image_height, opt_image_width)336 torch.onnx.export(337 model,338 inputs,339 onnx_path,340 export_params=True,341 opset_version=onnx_opset,342 do_constant_folding=True,343 input_names=model_obj.get_input_names(),344 output_names=model_obj.get_output_names(),345 dynamic_axes=model_obj.get_dynamic_axes(),346 )347 del model348 torch.cuda.empty_cache()349 gc.collect()350 else:351 logger.warning(f"Found cached model: {onnx_path}")352 353 # Optimize onnx354 if force_engine_rebuild or not os.path.exists(onnx_opt_path):355 logger.warning(f"Generating optimizing model: {onnx_opt_path}")356 onnx_opt_graph = model_obj.optimize(onnx.load(onnx_path))357 onnx.save(onnx_opt_graph, onnx_opt_path)358 else:359 logger.warning(f"Found cached optimized model: {onnx_opt_path} ")360 361 # Build TensorRT engines362 for model_name, model_obj in models.items():363 engine_path = getEnginePath(model_name, engine_dir)364 engine = Engine(engine_path)365 onnx_path = getOnnxPath(model_name, onnx_dir, opt=False)366 onnx_opt_path = getOnnxPath(model_name, onnx_dir)367 368 if force_engine_rebuild or not os.path.exists(engine.engine_path):369 engine.build(370 onnx_opt_path,371 fp16=True,372 input_profile=model_obj.get_input_profile(373 opt_batch_size,374 opt_image_height,375 opt_image_width,376 static_batch=static_batch,377 static_shape=static_shape,378 ),379 timing_cache=timing_cache,380 )381 built_engines[model_name] = engine382 383 # Load and activate TensorRT engines384 for model_name, model_obj in models.items():385 engine = built_engines[model_name]386 engine.load()387 engine.activate()388 389 return built_engines390 391 392def runEngine(engine, feed_dict, stream):393 return engine.infer(feed_dict, stream)394 395 396class CLIP(BaseModel):397 def __init__(self, model, device, max_batch_size, embedding_dim):398 super(CLIP, self).__init__(399 model=model, device=device, max_batch_size=max_batch_size, embedding_dim=embedding_dim400 )401 self.name = "CLIP"402 403 def get_input_names(self):404 return ["input_ids"]405 406 def get_output_names(self):407 return ["text_embeddings", "pooler_output"]408 409 def get_dynamic_axes(self):410 return {"input_ids": {0: "B"}, "text_embeddings": {0: "B"}}411 412 def get_input_profile(self, batch_size, image_height, image_width, static_batch, static_shape):413 self.check_dims(batch_size, image_height, image_width)414 min_batch, max_batch, _, _, _, _, _, _, _, _ = self.get_minmax_dims(415 batch_size, image_height, image_width, static_batch, static_shape416 )417 return {418 "input_ids": [(min_batch, self.text_maxlen), (batch_size, self.text_maxlen), (max_batch, self.text_maxlen)]419 }420 421 def get_shape_dict(self, batch_size, image_height, image_width):422 self.check_dims(batch_size, image_height, image_width)423 return {424 "input_ids": (batch_size, self.text_maxlen),425 "text_embeddings": (batch_size, self.text_maxlen, self.embedding_dim),426 }427 428 def get_sample_input(self, batch_size, image_height, image_width):429 self.check_dims(batch_size, image_height, image_width)430 return torch.zeros(batch_size, self.text_maxlen, dtype=torch.int32, device=self.device)431 432 def optimize(self, onnx_graph):433 opt = Optimizer(onnx_graph)434 opt.select_outputs([0]) # delete graph output#1435 opt.cleanup()436 opt.fold_constants()437 opt.infer_shapes()438 opt.select_outputs([0], names=["text_embeddings"]) # rename network output439 opt_onnx_graph = opt.cleanup(return_onnx=True)440 return opt_onnx_graph441 442 443def make_CLIP(model, device, max_batch_size, embedding_dim, inpaint=False):444 return CLIP(model, device=device, max_batch_size=max_batch_size, embedding_dim=embedding_dim)445 446 447class UNet(BaseModel):448 def __init__(449 self, model, fp16=False, device="cuda", max_batch_size=16, embedding_dim=768, text_maxlen=77, unet_dim=4450 ):451 super(UNet, self).__init__(452 model=model,453 fp16=fp16,454 device=device,455 max_batch_size=max_batch_size,456 embedding_dim=embedding_dim,457 text_maxlen=text_maxlen,458 )459 self.unet_dim = unet_dim460 self.name = "UNet"461 462 def get_input_names(self):463 return ["sample", "timestep", "encoder_hidden_states"]464 465 def get_output_names(self):466 return ["latent"]467 468 def get_dynamic_axes(self):469 return {470 "sample": {0: "2B", 2: "H", 3: "W"},471 "encoder_hidden_states": {0: "2B"},472 "latent": {0: "2B", 2: "H", 3: "W"},473 }474 475 def get_input_profile(self, batch_size, image_height, image_width, static_batch, static_shape):476 latent_height, latent_width = self.check_dims(batch_size, image_height, image_width)477 (478 min_batch,479 max_batch,480 _,481 _,482 _,483 _,484 min_latent_height,485 max_latent_height,486 min_latent_width,487 max_latent_width,488 ) = self.get_minmax_dims(batch_size, image_height, image_width, static_batch, static_shape)489 return {490 "sample": [491 (2 * min_batch, self.unet_dim, min_latent_height, min_latent_width),492 (2 * batch_size, self.unet_dim, latent_height, latent_width),493 (2 * max_batch, self.unet_dim, max_latent_height, max_latent_width),494 ],495 "encoder_hidden_states": [496 (2 * min_batch, self.text_maxlen, self.embedding_dim),497 (2 * batch_size, self.text_maxlen, self.embedding_dim),498 (2 * max_batch, self.text_maxlen, self.embedding_dim),499 ],500 }501 502 def get_shape_dict(self, batch_size, image_height, image_width):503 latent_height, latent_width = self.check_dims(batch_size, image_height, image_width)504 return {505 "sample": (2 * batch_size, self.unet_dim, latent_height, latent_width),506 "encoder_hidden_states": (2 * batch_size, self.text_maxlen, self.embedding_dim),507 "latent": (2 * batch_size, 4, latent_height, latent_width),508 }509 510 def get_sample_input(self, batch_size, image_height, image_width):511 latent_height, latent_width = self.check_dims(batch_size, image_height, image_width)512 dtype = torch.float16 if self.fp16 else torch.float32513 return (514 torch.randn(515 2 * batch_size, self.unet_dim, latent_height, latent_width, dtype=torch.float32, device=self.device516 ),517 torch.tensor([1.0], dtype=torch.float32, device=self.device),518 torch.randn(2 * batch_size, self.text_maxlen, self.embedding_dim, dtype=dtype, device=self.device),519 )520 521 522def make_UNet(model, device, max_batch_size, embedding_dim, inpaint=False):523 return UNet(524 model,525 fp16=True,526 device=device,527 max_batch_size=max_batch_size,528 embedding_dim=embedding_dim,529 unet_dim=(9 if inpaint else 4),530 )531 532 533class VAE(BaseModel):534 def __init__(self, model, device, max_batch_size, embedding_dim):535 super(VAE, self).__init__(536 model=model, device=device, max_batch_size=max_batch_size, embedding_dim=embedding_dim537 )538 self.name = "VAE decoder"539 540 def get_input_names(self):541 return ["latent"]542 543 def get_output_names(self):544 return ["images"]545 546 def get_dynamic_axes(self):547 return {"latent": {0: "B", 2: "H", 3: "W"}, "images": {0: "B", 2: "8H", 3: "8W"}}548 549 def get_input_profile(self, batch_size, image_height, image_width, static_batch, static_shape):550 latent_height, latent_width = self.check_dims(batch_size, image_height, image_width)551 (552 min_batch,553 max_batch,554 _,555 _,556 _,557 _,558 min_latent_height,559 max_latent_height,560 min_latent_width,561 max_latent_width,562 ) = self.get_minmax_dims(batch_size, image_height, image_width, static_batch, static_shape)563 return {564 "latent": [565 (min_batch, 4, min_latent_height, min_latent_width),566 (batch_size, 4, latent_height, latent_width),567 (max_batch, 4, max_latent_height, max_latent_width),568 ]569 }570 571 def get_shape_dict(self, batch_size, image_height, image_width):572 latent_height, latent_width = self.check_dims(batch_size, image_height, image_width)573 return {574 "latent": (batch_size, 4, latent_height, latent_width),575 "images": (batch_size, 3, image_height, image_width),576 }577 578 def get_sample_input(self, batch_size, image_height, image_width):579 latent_height, latent_width = self.check_dims(batch_size, image_height, image_width)580 return torch.randn(batch_size, 4, latent_height, latent_width, dtype=torch.float32, device=self.device)581 582 583def make_VAE(model, device, max_batch_size, embedding_dim, inpaint=False):584 return VAE(model, device=device, max_batch_size=max_batch_size, embedding_dim=embedding_dim)585 586 587class TorchVAEEncoder(torch.nn.Module):588 def __init__(self, model):589 super().__init__()590 self.vae_encoder = model591 592 def forward(self, x):593 return retrieve_latents(self.vae_encoder.encode(x))594 595 596class VAEEncoder(BaseModel):597 def __init__(self, model, device, max_batch_size, embedding_dim):598 super(VAEEncoder, self).__init__(599 model=model, device=device, max_batch_size=max_batch_size, embedding_dim=embedding_dim600 )601 self.name = "VAE encoder"602 603 def get_model(self):604 vae_encoder = TorchVAEEncoder(self.model)605 return vae_encoder606 607 def get_input_names(self):608 return ["images"]609 610 def get_output_names(self):611 return ["latent"]612 613 def get_dynamic_axes(self):614 return {"images": {0: "B", 2: "8H", 3: "8W"}, "latent": {0: "B", 2: "H", 3: "W"}}615 616 def get_input_profile(self, batch_size, image_height, image_width, static_batch, static_shape):617 assert batch_size >= self.min_batch and batch_size <= self.max_batch618 min_batch = batch_size if static_batch else self.min_batch619 max_batch = batch_size if static_batch else self.max_batch620 self.check_dims(batch_size, image_height, image_width)621 (622 min_batch,623 max_batch,624 min_image_height,625 max_image_height,626 min_image_width,627 max_image_width,628 _,629 _,630 _,631 _,632 ) = self.get_minmax_dims(batch_size, image_height, image_width, static_batch, static_shape)633 634 return {635 "images": [636 (min_batch, 3, min_image_height, min_image_width),637 (batch_size, 3, image_height, image_width),638 (max_batch, 3, max_image_height, max_image_width),639 ]640 }641 642 def get_shape_dict(self, batch_size, image_height, image_width):643 latent_height, latent_width = self.check_dims(batch_size, image_height, image_width)644 return {645 "images": (batch_size, 3, image_height, image_width),646 "latent": (batch_size, 4, latent_height, latent_width),647 }648 649 def get_sample_input(self, batch_size, image_height, image_width):650 self.check_dims(batch_size, image_height, image_width)651 return torch.randn(batch_size, 3, image_height, image_width, dtype=torch.float32, device=self.device)652 653 654def make_VAEEncoder(model, device, max_batch_size, embedding_dim, inpaint=False):655 return VAEEncoder(model, device=device, max_batch_size=max_batch_size, embedding_dim=embedding_dim)656 657 658class TensorRTStableDiffusionImg2ImgPipeline(DiffusionPipeline):659 r"""660 Pipeline for image-to-image generation using TensorRT accelerated Stable Diffusion.661 662 This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the663 library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)664 665 Args:666 vae ([`AutoencoderKL`]):667 Variational Auto-Encoder (VAE) Model to encode and decode images to and from latent representations.668 text_encoder ([`CLIPTextModel`]):669 Frozen text-encoder. Stable Diffusion uses the text portion of670 [CLIP](https://huggingface.co/docs/transformers/model_doc/clip#transformers.CLIPTextModel), specifically671 the [clip-vit-large-patch14](https://huggingface.co/openai/clip-vit-large-patch14) variant.672 tokenizer (`CLIPTokenizer`):673 Tokenizer of class674 [CLIPTokenizer](https://huggingface.co/docs/transformers/v4.21.0/en/model_doc/clip#transformers.CLIPTokenizer).675 unet ([`UNet2DConditionModel`]): Conditional U-Net architecture to denoise the encoded image latents.676 scheduler ([`SchedulerMixin`]):677 A scheduler to be used in combination with `unet` to denoise the encoded image latents. Can be one of678 [`DDIMScheduler`], [`LMSDiscreteScheduler`], or [`PNDMScheduler`].679 safety_checker ([`StableDiffusionSafetyChecker`]):680 Classification module that estimates whether generated images could be considered offensive or harmful.681 Please, refer to the [model card](https://huggingface.co/runwayml/stable-diffusion-v1-5) for details.682 feature_extractor ([`CLIPImageProcessor`]):683 Model that extracts features from generated images to be used as inputs for the `safety_checker`.684 """685 686 _optional_components = ["safety_checker", "feature_extractor", "image_encoder"]687 688 def __init__(689 self,690 vae: AutoencoderKL,691 text_encoder: CLIPTextModel,692 tokenizer: CLIPTokenizer,693 unet: UNet2DConditionModel,694 scheduler: DDIMScheduler,695 safety_checker: StableDiffusionSafetyChecker,696 feature_extractor: CLIPImageProcessor,697 image_encoder: CLIPVisionModelWithProjection = None,698 requires_safety_checker: bool = True,699 stages=["clip", "unet", "vae", "vae_encoder"],700 image_height: int = 512,701 image_width: int = 512,702 max_batch_size: int = 16,703 # ONNX export parameters704 onnx_opset: int = 17,705 onnx_dir: str = "onnx",706 # TensorRT engine build parameters707 engine_dir: str = "engine",708 force_engine_rebuild: bool = False,709 timing_cache: str = "timing_cache",710 ):711 super().__init__()712 713 if scheduler is not None and getattr(scheduler.config, "steps_offset", 1) != 1:714 deprecation_message = (715 f"The configuration file of this scheduler: {scheduler} is outdated. `steps_offset`"716 f" should be set to 1 instead of {scheduler.config.steps_offset}. Please make sure "717 "to update the config accordingly as leaving `steps_offset` might led to incorrect results"718 " in future versions. If you have downloaded this checkpoint from the Hugging Face Hub,"719 " it would be very nice if you could open a Pull request for the `scheduler/scheduler_config.json`"720 " file"721 )722 deprecate("steps_offset!=1", "1.0.0", deprecation_message, standard_warn=False)723 new_config = dict(scheduler.config)724 new_config["steps_offset"] = 1725 scheduler._internal_dict = FrozenDict(new_config)726 727 if scheduler is not None and getattr(scheduler.config, "clip_sample", False) is True:728 deprecation_message = (729 f"The configuration file of this scheduler: {scheduler} has not set the configuration `clip_sample`."730 " `clip_sample` should be set to False in the configuration file. Please make sure to update the"731 " config accordingly as not setting `clip_sample` in the config might lead to incorrect results in"732 " future versions. If you have downloaded this checkpoint from the Hugging Face Hub, it would be very"733 " nice if you could open a Pull request for the `scheduler/scheduler_config.json` file"734 )735 deprecate("clip_sample not set", "1.0.0", deprecation_message, standard_warn=False)736 new_config = dict(scheduler.config)737 new_config["clip_sample"] = False738 scheduler._internal_dict = FrozenDict(new_config)739 740 if safety_checker is None and requires_safety_checker:741 logger.warning(742 f"You have disabled the safety checker for {self.__class__} by passing `safety_checker=None`. Ensure"743 " that you abide to the conditions of the Stable Diffusion license and do not expose unfiltered"744 " results in services or applications open to the public. Both the diffusers team and Hugging Face"745 " strongly recommend to keep the safety filter enabled in all public facing circumstances, disabling"746 " it only for use-cases that involve analyzing network behavior or auditing its results. For more"747 " information, please have a look at https://github.com/huggingface/diffusers/pull/254 ."748 )749 750 if safety_checker is not None and feature_extractor is None:751 raise ValueError(752 "Make sure to define a feature extractor when loading {self.__class__} if you want to use the safety"753 " checker. If you do not want to use the safety checker, you can pass `'safety_checker=None'` instead."754 )755 756 is_unet_version_less_0_9_0 = (757 unet is not None758 and hasattr(unet.config, "_diffusers_version")759 and version.parse(version.parse(unet.config._diffusers_version).base_version) < version.parse("0.9.0.dev0")760 )761 is_unet_sample_size_less_64 = (762 unet is not None and hasattr(unet.config, "sample_size") and unet.config.sample_size < 64763 )764 if is_unet_version_less_0_9_0 and is_unet_sample_size_less_64:765 deprecation_message = (766 "The configuration file of the unet has set the default `sample_size` to smaller than"767 " 64 which seems highly unlikely. If your checkpoint is a fine-tuned version of any of the"768 " following: \n- CompVis/stable-diffusion-v1-4 \n- CompVis/stable-diffusion-v1-3 \n-"769 " CompVis/stable-diffusion-v1-2 \n- CompVis/stable-diffusion-v1-1 \n- runwayml/stable-diffusion-v1-5"770 " \n- runwayml/stable-diffusion-inpainting \n you should change 'sample_size' to 64 in the"771 " configuration file. Please make sure to update the config accordingly as leaving `sample_size=32`"772 " in the config might lead to incorrect results in future versions. If you have downloaded this"773 " checkpoint from the Hugging Face Hub, it would be very nice if you could open a Pull request for"774 " the `unet/config.json` file"775 )776 deprecate("sample_size<64", "1.0.0", deprecation_message, standard_warn=False)777 new_config = dict(unet.config)778 new_config["sample_size"] = 64779 unet._internal_dict = FrozenDict(new_config)780 781 self.register_modules(782 vae=vae,783 text_encoder=text_encoder,784 tokenizer=tokenizer,785 unet=unet,786 scheduler=scheduler,787 safety_checker=safety_checker,788 feature_extractor=feature_extractor,789 image_encoder=image_encoder,790 )791 792 self.stages = stages793 self.image_height, self.image_width = image_height, image_width794 self.inpaint = False795 self.onnx_opset = onnx_opset796 self.onnx_dir = onnx_dir797 self.engine_dir = engine_dir798 self.force_engine_rebuild = force_engine_rebuild799 self.timing_cache = timing_cache800 self.build_static_batch = False801 self.build_dynamic_shape = False802 803 self.max_batch_size = max_batch_size804 # TODO: Restrict batch size to 4 for larger image dimensions as a WAR for TensorRT limitation.805 if self.build_dynamic_shape or self.image_height > 512 or self.image_width > 512:806 self.max_batch_size = 4807 808 self.stream = None # loaded in loadResources()809 self.models = {} # loaded in __loadModels()810 self.engine = {} # loaded in build_engines()811 812 self.vae.forward = self.vae.decode813 self.vae_scale_factor = 2 ** (len(self.vae.config.block_out_channels) - 1) if getattr(self, "vae", None) else 8814 self.image_processor = VaeImageProcessor(vae_scale_factor=self.vae_scale_factor)815 self.register_to_config(requires_safety_checker=requires_safety_checker)816 817 def __loadModels(self):818 # Load pipeline models819 self.embedding_dim = self.text_encoder.config.hidden_size820 models_args = {821 "device": self.torch_device,822 "max_batch_size": self.max_batch_size,823 "embedding_dim": self.embedding_dim,824 "inpaint": self.inpaint,825 }826 if "clip" in self.stages:827 self.models["clip"] = make_CLIP(self.text_encoder, **models_args)828 if "unet" in self.stages:829 self.models["unet"] = make_UNet(self.unet, **models_args)830 if "vae" in self.stages:831 self.models["vae"] = make_VAE(self.vae, **models_args)832 if "vae_encoder" in self.stages:833 self.models["vae_encoder"] = make_VAEEncoder(self.vae, **models_args)834 835 # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.run_safety_checker836 def run_safety_checker(837 self, image: Union[torch.Tensor, PIL.Image.Image], device: torch.device, dtype: torch.dtype838 ) -> Tuple[Union[torch.Tensor, PIL.Image.Image], Optional[bool]]:839 r"""840 Runs the safety checker on the given image.841 Args:842 image (Union[torch.Tensor, PIL.Image.Image]): The input image to be checked.843 device (torch.device): The device to run the safety checker on.844 dtype (torch.dtype): The data type of the input image.845 Returns:846 (image, has_nsfw_concept) Tuple[Union[torch.Tensor, PIL.Image.Image], Optional[bool]]: A tuple containing the processed image and847 a boolean indicating whether the image has a NSFW (Not Safe for Work) concept.848 """849 if self.safety_checker is None:850 has_nsfw_concept = None851 else:852 if torch.is_tensor(image):853 feature_extractor_input = self.image_processor.postprocess(image, output_type="pil")854 else:855 feature_extractor_input = self.image_processor.numpy_to_pil(image)856 safety_checker_input = self.feature_extractor(feature_extractor_input, return_tensors="pt").to(device)857 image, has_nsfw_concept = self.safety_checker(858 images=image, clip_input=safety_checker_input.pixel_values.to(dtype)859 )860 return image, has_nsfw_concept861 862 @classmethod863 @validate_hf_hub_args864 def set_cached_folder(cls, pretrained_model_name_or_path: Optional[Union[str, os.PathLike]], **kwargs):865 cache_dir = kwargs.pop("cache_dir", None)866 proxies = kwargs.pop("proxies", None)867 local_files_only = kwargs.pop("local_files_only", False)868 token = kwargs.pop("token", None)869 revision = kwargs.pop("revision", None)870 871 cls.cached_folder = (872 pretrained_model_name_or_path873 if os.path.isdir(pretrained_model_name_or_path)874 else snapshot_download(875 pretrained_model_name_or_path,876 cache_dir=cache_dir,877 proxies=proxies,878 local_files_only=local_files_only,879 token=token,880 revision=revision,881 )882 )883 884 def to(self, torch_device: Optional[Union[str, torch.device]] = None, silence_dtype_warnings: bool = False):885 super().to(torch_device, silence_dtype_warnings=silence_dtype_warnings)886 887 self.onnx_dir = os.path.join(self.cached_folder, self.onnx_dir)888 self.engine_dir = os.path.join(self.cached_folder, self.engine_dir)889 self.timing_cache = os.path.join(self.cached_folder, self.timing_cache)890 891 # set device892 self.torch_device = self._execution_device893 logger.warning(f"Running inference on device: {self.torch_device}")894 895 # load models896 self.__loadModels()897 898 # build engines899 self.engine = build_engines(900 self.models,901 self.engine_dir,902 self.onnx_dir,903 self.onnx_opset,904 opt_image_height=self.image_height,905 opt_image_width=self.image_width,906 force_engine_rebuild=self.force_engine_rebuild,907 static_batch=self.build_static_batch,908 static_shape=not self.build_dynamic_shape,909 timing_cache=self.timing_cache,910 )911 912 return self913 914 def __initialize_timesteps(self, timesteps, strength):915 self.scheduler.set_timesteps(timesteps)916 offset = self.scheduler.steps_offset if hasattr(self.scheduler, "steps_offset") else 0917 init_timestep = int(timesteps * strength) + offset918 init_timestep = min(init_timestep, timesteps)919 t_start = max(timesteps - init_timestep + offset, 0)920 timesteps = self.scheduler.timesteps[t_start:].to(self.torch_device)921 return timesteps, t_start922 923 def __preprocess_images(self, batch_size, images=()):924 init_images = []925 for image in images:926 image = image.to(self.torch_device).float()927 image = image.repeat(batch_size, 1, 1, 1)928 init_images.append(image)929 return tuple(init_images)930 931 def __encode_image(self, init_image):932 init_latents = runEngine(self.engine["vae_encoder"], {"images": init_image}, self.stream)["latent"]933 init_latents = 0.18215 * init_latents934 return init_latents935 936 def __encode_prompt(self, prompt, negative_prompt):937 r"""938 Encodes the prompt into text encoder hidden states.939 940 Args:941 prompt (`str` or `List[str]`, *optional*):942 prompt to be encoded943 negative_prompt (`str` or `List[str]`, *optional*):944 The prompt or prompts not to guide the image generation. If not defined, one has to pass945 `negative_prompt_embeds`. instead. If not defined, one has to pass `negative_prompt_embeds`. instead.946 Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`).947 """948 # Tokenize prompt949 text_input_ids = (950 self.tokenizer(951 prompt,952 padding="max_length",953 max_length=self.tokenizer.model_max_length,954 truncation=True,955 return_tensors="pt",956 )957 .input_ids.type(torch.int32)958 .to(self.torch_device)959 )960 961 # NOTE: output tensor for CLIP must be cloned because it will be overwritten when called again for negative prompt962 text_embeddings = runEngine(self.engine["clip"], {"input_ids": text_input_ids}, self.stream)[963 "text_embeddings"964 ].clone()965 966 # Tokenize negative prompt967 uncond_input_ids = (968 self.tokenizer(969 negative_prompt,970 padding="max_length",971 max_length=self.tokenizer.model_max_length,972 truncation=True,973 return_tensors="pt",974 )975 .input_ids.type(torch.int32)976 .to(self.torch_device)977 )978 uncond_embeddings = runEngine(self.engine["clip"], {"input_ids": uncond_input_ids}, self.stream)[979 "text_embeddings"980 ]981 982 # Concatenate the unconditional and text embeddings into a single batch to avoid doing two forward passes for classifier free guidance983 text_embeddings = torch.cat([uncond_embeddings, text_embeddings]).to(dtype=torch.float16)984 985 return text_embeddings986 987 def __denoise_latent(988 self, latents, text_embeddings, timesteps=None, step_offset=0, mask=None, masked_image_latents=None989 ):990 if not isinstance(timesteps, torch.Tensor):991 timesteps = self.scheduler.timesteps992 for step_index, timestep in enumerate(timesteps):993 # Expand the latents if we are doing classifier free guidance994 latent_model_input = torch.cat([latents] * 2)995 latent_model_input = self.scheduler.scale_model_input(latent_model_input, timestep)996 if isinstance(mask, torch.Tensor):997 latent_model_input = torch.cat([latent_model_input, mask, masked_image_latents], dim=1)998 999 # Predict the noise residual1000 timestep_float = timestep.float() if timestep.dtype != torch.float32 else timestep1001 1002 noise_pred = runEngine(1003 self.engine["unet"],1004 {"sample": latent_model_input, "timestep": timestep_float, "encoder_hidden_states": text_embeddings},1005 self.stream,1006 )["latent"]1007 1008 # Perform guidance1009 noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)1010 noise_pred = noise_pred_uncond + self._guidance_scale * (noise_pred_text - noise_pred_uncond)1011 1012 latents = self.scheduler.step(noise_pred, timestep, latents).prev_sample1013 1014 latents = 1.0 / 0.18215 * latents1015 return latents1016 1017 def __decode_latent(self, latents):1018 images = runEngine(self.engine["vae"], {"latent": latents}, self.stream)["images"]1019 images = (images / 2 + 0.5).clamp(0, 1)1020 return images.cpu().permute(0, 2, 3, 1).float().numpy()1021 1022 def __loadResources(self, image_height, image_width, batch_size):1023 self.stream = cudart.cudaStreamCreate()[1]1024 1025 # Allocate buffers for TensorRT engine bindings1026 for model_name, obj in self.models.items():1027 self.engine[model_name].allocate_buffers(1028 shape_dict=obj.get_shape_dict(batch_size, image_height, image_width), device=self.torch_device1029 )1030 1031 @torch.no_grad()1032 def __call__(1033 self,1034 prompt: Union[str, List[str]] = None,1035 image: Union[torch.Tensor, PIL.Image.Image] = None,1036 strength: float = 0.8,1037 num_inference_steps: int = 50,1038 guidance_scale: float = 7.5,1039 negative_prompt: Optional[Union[str, List[str]]] = None,1040 generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,1041 ):1042 r"""1043 Function invoked when calling the pipeline for generation.1044 1045 Args:1046 prompt (`str` or `List[str]`, *optional*):1047 The prompt or prompts to guide the image generation. If not defined, one has to pass `prompt_embeds`.1048 instead.1049 image (`PIL.Image.Image`):1050 `Image`, or tensor representing an image batch which will be inpainted, *i.e.* parts of the image will1051 be masked out with `mask_image` and repainted according to `prompt`.1052 strength (`float`, *optional*, defaults to 0.8):1053 Conceptually, indicates how much to transform the reference `image`. Must be between 0 and 1. `image`1054 will be used as a starting point, adding more noise to it the larger the `strength`. The number of1055 denoising steps depends on the amount of noise initially added. When `strength` is 1, added noise will1056 be maximum and the denoising process will run for the full number of iterations specified in1057 `num_inference_steps`. A value of 1, therefore, essentially ignores `image`.1058 num_inference_steps (`int`, *optional*, defaults to 50):1059 The number of denoising steps. More denoising steps usually lead to a higher quality image at the1060 expense of slower inference.1061 guidance_scale (`float`, *optional*, defaults to 7.5):1062 Guidance scale as defined in [Classifier-Free Diffusion Guidance](https://huggingface.co/papers/2207.12598).1063 `guidance_scale` is defined as `w` of equation 2. of [Imagen1064 Paper](https://huggingface.co/papers/2205.11487). Guidance scale is enabled by setting `guidance_scale >1065 1`. Higher guidance scale encourages to generate images that are closely linked to the text `prompt`,1066 usually at the expense of lower image quality.1067 negative_prompt (`str` or `List[str]`, *optional*):1068 The prompt or prompts not to guide the image generation. If not defined, one has to pass1069 `negative_prompt_embeds`. instead. If not defined, one has to pass `negative_prompt_embeds`. instead.1070 Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`).1071 generator (`torch.Generator` or `List[torch.Generator]`, *optional*):1072 One or a list of [torch generator(s)](https://pytorch.org/docs/stable/generated/torch.Generator.html)1073 to make generation deterministic.1074 1075 """1076 self.generator = generator1077 self.denoising_steps = num_inference_steps1078 self._guidance_scale = guidance_scale1079 1080 # Pre-compute latent input scales and linear multistep coefficients1081 self.scheduler.set_timesteps(self.denoising_steps, device=self.torch_device)1082 1083 # Define call parameters1084 if prompt is not None and isinstance(prompt, str):1085 batch_size = 11086 prompt = [prompt]1087 elif prompt is not None and isinstance(prompt, list):1088 batch_size = len(prompt)1089 else:1090 raise ValueError(f"Expected prompt to be of type list or str but got {type(prompt)}")1091 1092 if negative_prompt is None:1093 negative_prompt = [""] * batch_size1094 1095 if negative_prompt is not None and isinstance(negative_prompt, str):1096 negative_prompt = [negative_prompt]1097 1098 assert len(prompt) == len(negative_prompt)1099 1100 if batch_size > self.max_batch_size:1101 raise ValueError(1102 f"Batch size {len(prompt)} is larger than allowed {self.max_batch_size}. If dynamic shape is used, then maximum batch size is 4"1103 )1104 1105 # load resources1106 self.__loadResources(self.image_height, self.image_width, batch_size)1107 1108 with torch.inference_mode(), torch.autocast("cuda"), trt.Runtime(TRT_LOGGER):1109 # Initialize timesteps1110 timesteps, t_start = self.__initialize_timesteps(self.denoising_steps, strength)1111 latent_timestep = timesteps[:1].repeat(batch_size)1112 1113 # Pre-process input image1114 if isinstance(image, PIL.Image.Image):1115 image = preprocess_image(image)1116 init_image = self.__preprocess_images(batch_size, (image,))[0]1117 1118 # VAE encode init image1119 init_latents = self.__encode_image(init_image)1120 1121 # Add noise to latents using timesteps1122 noise = torch.randn(1123 init_latents.shape, generator=self.generator, device=self.torch_device, dtype=torch.float321124 )1125 latents = self.scheduler.add_noise(init_latents, noise, latent_timestep)1126 1127 # CLIP text encoder1128 text_embeddings = self.__encode_prompt(prompt, negative_prompt)1129 1130 # UNet denoiser1131 latents = self.__denoise_latent(latents, text_embeddings, timesteps=timesteps, step_offset=t_start)1132 1133 # VAE decode latent1134 images = self.__decode_latent(latents)1135 1136 images, has_nsfw_concept = self.run_safety_checker(images, self.torch_device, text_embeddings.dtype)1137 images = self.numpy_to_pil(images)1138 return StableDiffusionPipelineOutput(images=images, nsfw_content_detected=has_nsfw_concept)1139 