comdoleger commited on
Commit
b19b71c
·
verified ·
1 Parent(s): 58ca204

Upload extensions_built_in/diffusion_models/hidream/src/pipelines/hidream_image/pipeline_hidream_image.py with huggingface_hub

Browse files
extensions_built_in/diffusion_models/hidream/src/pipelines/hidream_image/pipeline_hidream_image.py ADDED
@@ -0,0 +1,737 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import inspect
2
+ from typing import Any, Callable, Dict, List, Optional, Union
3
+ import math
4
+ import einops
5
+ import torch
6
+ from transformers import (
7
+ CLIPTextModelWithProjection,
8
+ CLIPTokenizer,
9
+ T5EncoderModel,
10
+ T5Tokenizer,
11
+ LlamaForCausalLM,
12
+ PreTrainedTokenizerFast
13
+ )
14
+
15
+ from diffusers.image_processor import VaeImageProcessor
16
+ from diffusers.loaders import FromSingleFileMixin
17
+ from diffusers.models.autoencoders import AutoencoderKL
18
+ from diffusers.schedulers import FlowMatchEulerDiscreteScheduler
19
+ from diffusers.utils import (
20
+ USE_PEFT_BACKEND,
21
+ is_torch_xla_available,
22
+ logging,
23
+ )
24
+ from diffusers.utils.torch_utils import randn_tensor
25
+ from diffusers.pipelines.pipeline_utils import DiffusionPipeline
26
+ from .pipeline_output import HiDreamImagePipelineOutput
27
+ from ...models.transformers.transformer_hidream_image import HiDreamImageTransformer2DModel
28
+ from ...schedulers.fm_solvers_unipc import FlowUniPCMultistepScheduler
29
+
30
+ if is_torch_xla_available():
31
+ import torch_xla.core.xla_model as xm
32
+
33
+ XLA_AVAILABLE = True
34
+ else:
35
+ XLA_AVAILABLE = False
36
+
37
+ logger = logging.get_logger(__name__) # pylint: disable=invalid-name
38
+
39
+ # Copied from diffusers.pipelines.flux.pipeline_flux.calculate_shift
40
+ def calculate_shift(
41
+ image_seq_len,
42
+ base_seq_len: int = 256,
43
+ max_seq_len: int = 4096,
44
+ base_shift: float = 0.5,
45
+ max_shift: float = 1.15,
46
+ ):
47
+ m = (max_shift - base_shift) / (max_seq_len - base_seq_len)
48
+ b = base_shift - m * base_seq_len
49
+ mu = image_seq_len * m + b
50
+ return mu
51
+
52
+ # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.retrieve_timesteps
53
+ def retrieve_timesteps(
54
+ scheduler,
55
+ num_inference_steps: Optional[int] = None,
56
+ device: Optional[Union[str, torch.device]] = None,
57
+ timesteps: Optional[List[int]] = None,
58
+ sigmas: Optional[List[float]] = None,
59
+ **kwargs,
60
+ ):
61
+ r"""
62
+ Calls the scheduler's `set_timesteps` method and retrieves timesteps from the scheduler after the call. Handles
63
+ custom timesteps. Any kwargs will be supplied to `scheduler.set_timesteps`.
64
+
65
+ Args:
66
+ scheduler (`SchedulerMixin`):
67
+ The scheduler to get timesteps from.
68
+ num_inference_steps (`int`):
69
+ The number of diffusion steps used when generating samples with a pre-trained model. If used, `timesteps`
70
+ must be `None`.
71
+ device (`str` or `torch.device`, *optional*):
72
+ The device to which the timesteps should be moved to. If `None`, the timesteps are not moved.
73
+ timesteps (`List[int]`, *optional*):
74
+ Custom timesteps used to override the timestep spacing strategy of the scheduler. If `timesteps` is passed,
75
+ `num_inference_steps` and `sigmas` must be `None`.
76
+ sigmas (`List[float]`, *optional*):
77
+ Custom sigmas used to override the timestep spacing strategy of the scheduler. If `sigmas` is passed,
78
+ `num_inference_steps` and `timesteps` must be `None`.
79
+
80
+ Returns:
81
+ `Tuple[torch.Tensor, int]`: A tuple where the first element is the timestep schedule from the scheduler and the
82
+ second element is the number of inference steps.
83
+ """
84
+ if timesteps is not None and sigmas is not None:
85
+ raise ValueError("Only one of `timesteps` or `sigmas` can be passed. Please choose one to set custom values")
86
+ if timesteps is not None:
87
+ accepts_timesteps = "timesteps" in set(inspect.signature(scheduler.set_timesteps).parameters.keys())
88
+ if not accepts_timesteps:
89
+ raise ValueError(
90
+ f"The current scheduler class {scheduler.__class__}'s `set_timesteps` does not support custom"
91
+ f" timestep schedules. Please check whether you are using the correct scheduler."
92
+ )
93
+ scheduler.set_timesteps(timesteps=timesteps, device=device, **kwargs)
94
+ timesteps = scheduler.timesteps
95
+ num_inference_steps = len(timesteps)
96
+ elif sigmas is not None:
97
+ accept_sigmas = "sigmas" in set(inspect.signature(scheduler.set_timesteps).parameters.keys())
98
+ if not accept_sigmas:
99
+ raise ValueError(
100
+ f"The current scheduler class {scheduler.__class__}'s `set_timesteps` does not support custom"
101
+ f" sigmas schedules. Please check whether you are using the correct scheduler."
102
+ )
103
+ scheduler.set_timesteps(sigmas=sigmas, device=device, **kwargs)
104
+ timesteps = scheduler.timesteps
105
+ num_inference_steps = len(timesteps)
106
+ else:
107
+ scheduler.set_timesteps(num_inference_steps, device=device, **kwargs)
108
+ timesteps = scheduler.timesteps
109
+ return timesteps, num_inference_steps
110
+
111
+ class HiDreamImagePipeline(DiffusionPipeline, FromSingleFileMixin):
112
+ model_cpu_offload_seq = "text_encoder->text_encoder_2->text_encoder_3->text_encoder_4->image_encoder->transformer->vae"
113
+ _optional_components = ["image_encoder", "feature_extractor"]
114
+ _callback_tensor_inputs = ["latents", "prompt_embeds"]
115
+
116
+ def __init__(
117
+ self,
118
+ scheduler: FlowMatchEulerDiscreteScheduler,
119
+ vae: AutoencoderKL,
120
+ text_encoder: CLIPTextModelWithProjection,
121
+ tokenizer: CLIPTokenizer,
122
+ text_encoder_2: CLIPTextModelWithProjection,
123
+ tokenizer_2: CLIPTokenizer,
124
+ text_encoder_3: T5EncoderModel,
125
+ tokenizer_3: T5Tokenizer,
126
+ text_encoder_4: LlamaForCausalLM,
127
+ tokenizer_4: PreTrainedTokenizerFast,
128
+ transformer: HiDreamImageTransformer2DModel,
129
+ aggressive_unloading: bool = False,
130
+ ):
131
+ super().__init__()
132
+
133
+ self.register_modules(
134
+ vae=vae,
135
+ text_encoder=text_encoder,
136
+ text_encoder_2=text_encoder_2,
137
+ text_encoder_3=text_encoder_3,
138
+ text_encoder_4=text_encoder_4,
139
+ tokenizer=tokenizer,
140
+ tokenizer_2=tokenizer_2,
141
+ tokenizer_3=tokenizer_3,
142
+ tokenizer_4=tokenizer_4,
143
+ scheduler=scheduler,
144
+ transformer=transformer,
145
+ )
146
+ self.vae_scale_factor = (
147
+ 2 ** (len(self.vae.config.block_out_channels) - 1) if hasattr(self, "vae") and self.vae is not None else 8
148
+ )
149
+ # HiDreamImage latents are turned into 2x2 patches and packed. This means the latent width and height has to be divisible
150
+ # by the patch size. So the vae scale factor is multiplied by the patch size to account for this
151
+ self.image_processor = VaeImageProcessor(vae_scale_factor=self.vae_scale_factor * 2)
152
+ self.default_sample_size = 128
153
+ self.tokenizer_4.pad_token = self.tokenizer_4.eos_token
154
+ self.aggressive_unloading = aggressive_unloading
155
+
156
+ def _get_t5_prompt_embeds(
157
+ self,
158
+ prompt: Union[str, List[str]] = None,
159
+ num_images_per_prompt: int = 1,
160
+ max_sequence_length: int = 128,
161
+ device: Optional[torch.device] = None,
162
+ dtype: Optional[torch.dtype] = None,
163
+ ):
164
+ device = device or self._execution_device
165
+ dtype = dtype or self.text_encoder_3.dtype
166
+
167
+ prompt = [prompt] if isinstance(prompt, str) else prompt
168
+ batch_size = len(prompt)
169
+
170
+ text_inputs = self.tokenizer_3(
171
+ prompt,
172
+ padding="max_length",
173
+ max_length=min(max_sequence_length, self.tokenizer_3.model_max_length),
174
+ truncation=True,
175
+ add_special_tokens=True,
176
+ return_tensors="pt",
177
+ )
178
+ text_input_ids = text_inputs.input_ids
179
+ attention_mask = text_inputs.attention_mask
180
+ untruncated_ids = self.tokenizer_3(prompt, padding="longest", return_tensors="pt").input_ids
181
+
182
+ if untruncated_ids.shape[-1] >= text_input_ids.shape[-1] and not torch.equal(text_input_ids, untruncated_ids):
183
+ removed_text = self.tokenizer_3.batch_decode(untruncated_ids[:, min(max_sequence_length, self.tokenizer_3.model_max_length) - 1 : -1])
184
+ logger.warning(
185
+ "The following part of your input was truncated because `max_sequence_length` is set to "
186
+ f" {min(max_sequence_length, self.tokenizer_3.model_max_length)} tokens: {removed_text}"
187
+ )
188
+
189
+ prompt_embeds = self.text_encoder_3(text_input_ids.to(device), attention_mask=attention_mask.to(device))[0]
190
+ prompt_embeds = prompt_embeds.to(dtype=dtype, device=device)
191
+ _, seq_len, _ = prompt_embeds.shape
192
+
193
+ # duplicate text embeddings and attention mask for each generation per prompt, using mps friendly method
194
+ prompt_embeds = prompt_embeds.repeat(1, num_images_per_prompt, 1)
195
+ prompt_embeds = prompt_embeds.view(batch_size * num_images_per_prompt, seq_len, -1)
196
+ return prompt_embeds
197
+
198
+ def _get_clip_prompt_embeds(
199
+ self,
200
+ tokenizer,
201
+ text_encoder,
202
+ prompt: Union[str, List[str]],
203
+ num_images_per_prompt: int = 1,
204
+ max_sequence_length: int = 128,
205
+ device: Optional[torch.device] = None,
206
+ dtype: Optional[torch.dtype] = None,
207
+ ):
208
+ device = device or self._execution_device
209
+ dtype = dtype or text_encoder.dtype
210
+
211
+ prompt = [prompt] if isinstance(prompt, str) else prompt
212
+ batch_size = len(prompt)
213
+
214
+ text_inputs = tokenizer(
215
+ prompt,
216
+ padding="max_length",
217
+ max_length=min(max_sequence_length, 218),
218
+ truncation=True,
219
+ return_tensors="pt",
220
+ )
221
+
222
+ text_input_ids = text_inputs.input_ids
223
+ untruncated_ids = tokenizer(prompt, padding="longest", return_tensors="pt").input_ids
224
+ if untruncated_ids.shape[-1] >= text_input_ids.shape[-1] and not torch.equal(text_input_ids, untruncated_ids):
225
+ removed_text = tokenizer.batch_decode(untruncated_ids[:, 218 - 1 : -1])
226
+ logger.warning(
227
+ "The following part of your input was truncated because CLIP can only handle sequences up to"
228
+ f" {218} tokens: {removed_text}"
229
+ )
230
+ prompt_embeds = text_encoder(text_input_ids.to(device), output_hidden_states=True)
231
+
232
+ # Use pooled output of CLIPTextModel
233
+ prompt_embeds = prompt_embeds[0]
234
+ prompt_embeds = prompt_embeds.to(dtype=dtype, device=device)
235
+
236
+ # duplicate text embeddings for each generation per prompt, using mps friendly method
237
+ prompt_embeds = prompt_embeds.repeat(1, num_images_per_prompt)
238
+ prompt_embeds = prompt_embeds.view(batch_size * num_images_per_prompt, -1)
239
+
240
+ return prompt_embeds
241
+
242
+ def _get_llama3_prompt_embeds(
243
+ self,
244
+ prompt: Union[str, List[str]] = None,
245
+ num_images_per_prompt: int = 1,
246
+ max_sequence_length: int = 128,
247
+ device: Optional[torch.device] = None,
248
+ dtype: Optional[torch.dtype] = None,
249
+ ):
250
+ device = device or self._execution_device
251
+ dtype = dtype or self.text_encoder_4.dtype
252
+
253
+ prompt = [prompt] if isinstance(prompt, str) else prompt
254
+ batch_size = len(prompt)
255
+
256
+ text_inputs = self.tokenizer_4(
257
+ prompt,
258
+ padding="max_length",
259
+ max_length=min(max_sequence_length, self.tokenizer_4.model_max_length),
260
+ truncation=True,
261
+ add_special_tokens=True,
262
+ return_tensors="pt",
263
+ )
264
+ text_input_ids = text_inputs.input_ids
265
+ attention_mask = text_inputs.attention_mask
266
+ untruncated_ids = self.tokenizer_4(prompt, padding="longest", return_tensors="pt").input_ids
267
+
268
+ if untruncated_ids.shape[-1] >= text_input_ids.shape[-1] and not torch.equal(text_input_ids, untruncated_ids):
269
+ removed_text = self.tokenizer_4.batch_decode(untruncated_ids[:, min(max_sequence_length, self.tokenizer_4.model_max_length) - 1 : -1])
270
+ logger.warning(
271
+ "The following part of your input was truncated because `max_sequence_length` is set to "
272
+ f" {min(max_sequence_length, self.tokenizer_4.model_max_length)} tokens: {removed_text}"
273
+ )
274
+
275
+ outputs = self.text_encoder_4(
276
+ text_input_ids.to(device),
277
+ attention_mask=attention_mask.to(device),
278
+ output_hidden_states=True,
279
+ output_attentions=True
280
+ )
281
+
282
+ prompt_embeds = outputs.hidden_states[1:]
283
+ prompt_embeds = torch.stack(prompt_embeds, dim=0)
284
+ _, _, seq_len, dim = prompt_embeds.shape
285
+
286
+ # duplicate text embeddings and attention mask for each generation per prompt, using mps friendly method
287
+ prompt_embeds = prompt_embeds.repeat(1, 1, num_images_per_prompt, 1)
288
+ prompt_embeds = prompt_embeds.view(-1, batch_size * num_images_per_prompt, seq_len, dim)
289
+ return prompt_embeds
290
+
291
+ def encode_prompt(
292
+ self,
293
+ prompt: Union[str, List[str]],
294
+ prompt_2: Union[str, List[str]],
295
+ prompt_3: Union[str, List[str]],
296
+ prompt_4: Union[str, List[str]],
297
+ device: Optional[torch.device] = None,
298
+ dtype: Optional[torch.dtype] = None,
299
+ num_images_per_prompt: int = 1,
300
+ do_classifier_free_guidance: bool = True,
301
+ negative_prompt: Optional[Union[str, List[str]]] = None,
302
+ negative_prompt_2: Optional[Union[str, List[str]]] = None,
303
+ negative_prompt_3: Optional[Union[str, List[str]]] = None,
304
+ negative_prompt_4: Optional[Union[str, List[str]]] = None,
305
+ prompt_embeds: Optional[List[torch.FloatTensor]] = None,
306
+ negative_prompt_embeds: Optional[torch.FloatTensor] = None,
307
+ pooled_prompt_embeds: Optional[torch.FloatTensor] = None,
308
+ negative_pooled_prompt_embeds: Optional[torch.FloatTensor] = None,
309
+ max_sequence_length: int = 128,
310
+ lora_scale: Optional[float] = None,
311
+ ):
312
+ prompt = [prompt] if isinstance(prompt, str) else prompt
313
+ if prompt is not None:
314
+ batch_size = len(prompt)
315
+ else:
316
+ batch_size = prompt_embeds[0].shape[0]
317
+
318
+ prompt_embeds, pooled_prompt_embeds = self._encode_prompt(
319
+ prompt = prompt,
320
+ prompt_2 = prompt_2,
321
+ prompt_3 = prompt_3,
322
+ prompt_4 = prompt_4,
323
+ device = device,
324
+ dtype = dtype,
325
+ num_images_per_prompt = num_images_per_prompt,
326
+ prompt_embeds = prompt_embeds,
327
+ pooled_prompt_embeds = pooled_prompt_embeds,
328
+ max_sequence_length = max_sequence_length,
329
+ )
330
+
331
+ if do_classifier_free_guidance and negative_prompt_embeds is None:
332
+ negative_prompt = negative_prompt or ""
333
+ negative_prompt_2 = negative_prompt_2 or negative_prompt
334
+ negative_prompt_3 = negative_prompt_3 or negative_prompt
335
+ negative_prompt_4 = negative_prompt_4 or negative_prompt
336
+
337
+ # normalize str to list
338
+ negative_prompt = batch_size * [negative_prompt] if isinstance(negative_prompt, str) else negative_prompt
339
+ negative_prompt_2 = (
340
+ batch_size * [negative_prompt_2] if isinstance(negative_prompt_2, str) else negative_prompt_2
341
+ )
342
+ negative_prompt_3 = (
343
+ batch_size * [negative_prompt_3] if isinstance(negative_prompt_3, str) else negative_prompt_3
344
+ )
345
+ negative_prompt_4 = (
346
+ batch_size * [negative_prompt_4] if isinstance(negative_prompt_4, str) else negative_prompt_4
347
+ )
348
+
349
+ if prompt is not None and type(prompt) is not type(negative_prompt):
350
+ raise TypeError(
351
+ f"`negative_prompt` should be the same type to `prompt`, but got {type(negative_prompt)} !="
352
+ f" {type(prompt)}."
353
+ )
354
+ elif batch_size != len(negative_prompt):
355
+ raise ValueError(
356
+ f"`negative_prompt`: {negative_prompt} has batch size {len(negative_prompt)}, but `prompt`:"
357
+ f" {prompt} has batch size {batch_size}. Please make sure that passed `negative_prompt` matches"
358
+ " the batch size of `prompt`."
359
+ )
360
+
361
+ negative_prompt_embeds, negative_pooled_prompt_embeds = self._encode_prompt(
362
+ prompt = negative_prompt,
363
+ prompt_2 = negative_prompt_2,
364
+ prompt_3 = negative_prompt_3,
365
+ prompt_4 = negative_prompt_4,
366
+ device = device,
367
+ dtype = dtype,
368
+ num_images_per_prompt = num_images_per_prompt,
369
+ prompt_embeds = negative_prompt_embeds,
370
+ pooled_prompt_embeds = negative_pooled_prompt_embeds,
371
+ max_sequence_length = max_sequence_length,
372
+ )
373
+ return prompt_embeds, negative_prompt_embeds, pooled_prompt_embeds, negative_pooled_prompt_embeds
374
+
375
+ def _encode_prompt(
376
+ self,
377
+ prompt: Union[str, List[str]],
378
+ prompt_2: Union[str, List[str]],
379
+ prompt_3: Union[str, List[str]],
380
+ prompt_4: Union[str, List[str]],
381
+ device: Optional[torch.device] = None,
382
+ dtype: Optional[torch.dtype] = None,
383
+ num_images_per_prompt: int = 1,
384
+ prompt_embeds: Optional[List[torch.FloatTensor]] = None,
385
+ pooled_prompt_embeds: Optional[torch.FloatTensor] = None,
386
+ max_sequence_length: int = 128,
387
+ ):
388
+ device = device or self._execution_device
389
+
390
+ if prompt_embeds is None:
391
+ prompt_2 = prompt_2 or prompt
392
+ prompt_2 = [prompt_2] if isinstance(prompt_2, str) else prompt_2
393
+
394
+ prompt_3 = prompt_3 or prompt
395
+ prompt_3 = [prompt_3] if isinstance(prompt_3, str) else prompt_3
396
+
397
+ prompt_4 = prompt_4 or prompt
398
+ prompt_4 = [prompt_4] if isinstance(prompt_4, str) else prompt_4
399
+
400
+ pooled_prompt_embeds_1 = self._get_clip_prompt_embeds(
401
+ self.tokenizer,
402
+ self.text_encoder,
403
+ prompt = prompt,
404
+ num_images_per_prompt = num_images_per_prompt,
405
+ max_sequence_length = max_sequence_length,
406
+ device = device,
407
+ dtype = dtype,
408
+ )
409
+
410
+ pooled_prompt_embeds_2 = self._get_clip_prompt_embeds(
411
+ self.tokenizer_2,
412
+ self.text_encoder_2,
413
+ prompt = prompt_2,
414
+ num_images_per_prompt = num_images_per_prompt,
415
+ max_sequence_length = max_sequence_length,
416
+ device = device,
417
+ dtype = dtype,
418
+ )
419
+
420
+ pooled_prompt_embeds = torch.cat([pooled_prompt_embeds_1, pooled_prompt_embeds_2], dim=-1)
421
+
422
+ t5_prompt_embeds = self._get_t5_prompt_embeds(
423
+ prompt = prompt_3,
424
+ num_images_per_prompt = num_images_per_prompt,
425
+ max_sequence_length = max_sequence_length,
426
+ device = device,
427
+ dtype = dtype
428
+ )
429
+ llama3_prompt_embeds = self._get_llama3_prompt_embeds(
430
+ prompt = prompt_4,
431
+ num_images_per_prompt = num_images_per_prompt,
432
+ max_sequence_length = max_sequence_length,
433
+ device = device,
434
+ dtype = dtype
435
+ )
436
+ prompt_embeds = [t5_prompt_embeds, llama3_prompt_embeds]
437
+
438
+ return prompt_embeds, pooled_prompt_embeds
439
+
440
+ def enable_vae_slicing(self):
441
+ r"""
442
+ Enable sliced VAE decoding. When this option is enabled, the VAE will split the input tensor in slices to
443
+ compute decoding in several steps. This is useful to save some memory and allow larger batch sizes.
444
+ """
445
+ self.vae.enable_slicing()
446
+
447
+ def disable_vae_slicing(self):
448
+ r"""
449
+ Disable sliced VAE decoding. If `enable_vae_slicing` was previously enabled, this method will go back to
450
+ computing decoding in one step.
451
+ """
452
+ self.vae.disable_slicing()
453
+
454
+ def enable_vae_tiling(self):
455
+ r"""
456
+ Enable tiled VAE decoding. When this option is enabled, the VAE will split the input tensor into tiles to
457
+ compute decoding and encoding in several steps. This is useful for saving a large amount of memory and to allow
458
+ processing larger images.
459
+ """
460
+ self.vae.enable_tiling()
461
+
462
+ def disable_vae_tiling(self):
463
+ r"""
464
+ Disable tiled VAE decoding. If `enable_vae_tiling` was previously enabled, this method will go back to
465
+ computing decoding in one step.
466
+ """
467
+ self.vae.disable_tiling()
468
+
469
+ def prepare_latents(
470
+ self,
471
+ batch_size,
472
+ num_channels_latents,
473
+ height,
474
+ width,
475
+ dtype,
476
+ device,
477
+ generator,
478
+ latents=None,
479
+ ):
480
+ # VAE applies 8x compression on images but we must also account for packing which requires
481
+ # latent height and width to be divisible by 2.
482
+ height = 2 * (int(height) // (self.vae_scale_factor * 2))
483
+ width = 2 * (int(width) // (self.vae_scale_factor * 2))
484
+
485
+ shape = (batch_size, num_channels_latents, height, width)
486
+
487
+ if latents is None:
488
+ latents = randn_tensor(shape, generator=generator, device=device, dtype=dtype)
489
+ else:
490
+ if latents.shape != shape:
491
+ raise ValueError(f"Unexpected latents shape, got {latents.shape}, expected {shape}")
492
+ latents = latents.to(device)
493
+ return latents
494
+
495
+ @property
496
+ def guidance_scale(self):
497
+ return self._guidance_scale
498
+
499
+ @property
500
+ def do_classifier_free_guidance(self):
501
+ return self._guidance_scale > 1
502
+
503
+ @property
504
+ def joint_attention_kwargs(self):
505
+ return self._joint_attention_kwargs
506
+
507
+ @property
508
+ def num_timesteps(self):
509
+ return self._num_timesteps
510
+
511
+ @property
512
+ def interrupt(self):
513
+ return self._interrupt
514
+
515
+ @torch.no_grad()
516
+ def __call__(
517
+ self,
518
+ prompt: Union[str, List[str]] = None,
519
+ prompt_2: Optional[Union[str, List[str]]] = None,
520
+ prompt_3: Optional[Union[str, List[str]]] = None,
521
+ prompt_4: Optional[Union[str, List[str]]] = None,
522
+ height: Optional[int] = None,
523
+ width: Optional[int] = None,
524
+ num_inference_steps: int = 50,
525
+ sigmas: Optional[List[float]] = None,
526
+ guidance_scale: float = 5.0,
527
+ negative_prompt: Optional[Union[str, List[str]]] = None,
528
+ negative_prompt_2: Optional[Union[str, List[str]]] = None,
529
+ negative_prompt_3: Optional[Union[str, List[str]]] = None,
530
+ negative_prompt_4: Optional[Union[str, List[str]]] = None,
531
+ num_images_per_prompt: Optional[int] = 1,
532
+ generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
533
+ latents: Optional[torch.FloatTensor] = None,
534
+ prompt_embeds: Optional[torch.FloatTensor] = None,
535
+ negative_prompt_embeds: Optional[torch.FloatTensor] = None,
536
+ pooled_prompt_embeds: Optional[torch.FloatTensor] = None,
537
+ negative_pooled_prompt_embeds: Optional[torch.FloatTensor] = None,
538
+ output_type: Optional[str] = "pil",
539
+ return_dict: bool = True,
540
+ joint_attention_kwargs: Optional[Dict[str, Any]] = None,
541
+ callback_on_step_end: Optional[Callable[[int, int, Dict], None]] = None,
542
+ callback_on_step_end_tensor_inputs: List[str] = ["latents"],
543
+ max_sequence_length: int = 128,
544
+ ):
545
+ height = height or self.default_sample_size * self.vae_scale_factor
546
+ width = width or self.default_sample_size * self.vae_scale_factor
547
+
548
+ division = self.vae_scale_factor * 2
549
+ S_max = (self.default_sample_size * self.vae_scale_factor) ** 2
550
+ scale = S_max / (width * height)
551
+ scale = math.sqrt(scale)
552
+ width, height = int(width * scale // division * division), int(height * scale // division * division)
553
+
554
+ self._guidance_scale = guidance_scale
555
+ self._joint_attention_kwargs = joint_attention_kwargs
556
+ self._interrupt = False
557
+
558
+ # 2. Define call parameters
559
+ if prompt is not None and isinstance(prompt, str):
560
+ batch_size = 1
561
+ elif prompt is not None and isinstance(prompt, list):
562
+ batch_size = len(prompt)
563
+ else:
564
+ batch_size = prompt_embeds[0].shape[0]
565
+
566
+ device = self._execution_device
567
+
568
+ lora_scale = (
569
+ self.joint_attention_kwargs.get("scale", None) if self.joint_attention_kwargs is not None else None
570
+ )
571
+ (
572
+ prompt_embeds,
573
+ negative_prompt_embeds,
574
+ pooled_prompt_embeds,
575
+ negative_pooled_prompt_embeds,
576
+ ) = self.encode_prompt(
577
+ prompt=prompt,
578
+ prompt_2=prompt_2,
579
+ prompt_3=prompt_3,
580
+ prompt_4=prompt_4,
581
+ negative_prompt=negative_prompt,
582
+ negative_prompt_2=negative_prompt_2,
583
+ negative_prompt_3=negative_prompt_3,
584
+ negative_prompt_4=negative_prompt_4,
585
+ do_classifier_free_guidance=self.do_classifier_free_guidance,
586
+ prompt_embeds=prompt_embeds,
587
+ negative_prompt_embeds=negative_prompt_embeds,
588
+ pooled_prompt_embeds=pooled_prompt_embeds,
589
+ negative_pooled_prompt_embeds=negative_pooled_prompt_embeds,
590
+ device=device,
591
+ num_images_per_prompt=num_images_per_prompt,
592
+ max_sequence_length=max_sequence_length,
593
+ lora_scale=lora_scale,
594
+ )
595
+
596
+ if self.do_classifier_free_guidance:
597
+ prompt_embeds_arr = []
598
+ for n, p in zip(negative_prompt_embeds, prompt_embeds):
599
+ if len(n.shape) == 3:
600
+ prompt_embeds_arr.append(torch.cat([n, p], dim=0))
601
+ else:
602
+ prompt_embeds_arr.append(torch.cat([n, p], dim=1))
603
+ prompt_embeds = prompt_embeds_arr
604
+ pooled_prompt_embeds = torch.cat([negative_pooled_prompt_embeds, pooled_prompt_embeds], dim=0)
605
+
606
+ # 4. Prepare latent variables
607
+ num_channels_latents = self.transformer.config.in_channels
608
+ latents = self.prepare_latents(
609
+ batch_size * num_images_per_prompt,
610
+ num_channels_latents,
611
+ height,
612
+ width,
613
+ pooled_prompt_embeds.dtype,
614
+ device,
615
+ generator,
616
+ latents,
617
+ )
618
+
619
+ if latents.shape[-2] != latents.shape[-1]:
620
+ B, C, H, W = latents.shape
621
+ pH, pW = H // self.transformer.config.patch_size, W // self.transformer.config.patch_size
622
+
623
+ img_sizes = torch.tensor([pH, pW], dtype=torch.int64).reshape(-1)
624
+ img_ids = torch.zeros(pH, pW, 3)
625
+ img_ids[..., 1] = img_ids[..., 1] + torch.arange(pH)[:, None]
626
+ img_ids[..., 2] = img_ids[..., 2] + torch.arange(pW)[None, :]
627
+ img_ids = img_ids.reshape(pH * pW, -1)
628
+ img_ids_pad = torch.zeros(self.transformer.max_seq, 3)
629
+ img_ids_pad[:pH*pW, :] = img_ids
630
+
631
+ img_sizes = img_sizes.unsqueeze(0).to(latents.device)
632
+ img_ids = img_ids_pad.unsqueeze(0).to(latents.device)
633
+ if self.do_classifier_free_guidance:
634
+ img_sizes = img_sizes.repeat(2 * B, 1)
635
+ img_ids = img_ids.repeat(2 * B, 1, 1)
636
+ else:
637
+ img_sizes = img_ids = None
638
+
639
+ # 5. Prepare timesteps
640
+ mu = calculate_shift(self.transformer.max_seq)
641
+ scheduler_kwargs = {"mu": mu}
642
+ if isinstance(self.scheduler, FlowUniPCMultistepScheduler):
643
+ self.scheduler.set_timesteps(num_inference_steps, device=device, shift=math.exp(mu))
644
+ timesteps = self.scheduler.timesteps
645
+ else:
646
+ timesteps, num_inference_steps = retrieve_timesteps(
647
+ self.scheduler,
648
+ num_inference_steps,
649
+ device,
650
+ sigmas=sigmas,
651
+ **scheduler_kwargs,
652
+ )
653
+ num_warmup_steps = max(len(timesteps) - num_inference_steps * self.scheduler.order, 0)
654
+ self._num_timesteps = len(timesteps)
655
+
656
+ # 6. Denoising loop
657
+ with self.progress_bar(total=num_inference_steps) as progress_bar:
658
+ for i, t in enumerate(timesteps):
659
+ if self.interrupt:
660
+ continue
661
+
662
+ # expand the latents if we are doing classifier free guidance
663
+ latent_model_input = torch.cat([latents] * 2) if self.do_classifier_free_guidance else latents
664
+ # broadcast to batch dimension in a way that's compatible with ONNX/Core ML
665
+ timestep = t.expand(latent_model_input.shape[0])
666
+
667
+ if latent_model_input.shape[-2] != latent_model_input.shape[-1]:
668
+ B, C, H, W = latent_model_input.shape
669
+ patch_size = self.transformer.config.patch_size
670
+ pH, pW = H // patch_size, W // patch_size
671
+ out = torch.zeros(
672
+ (B, C, self.transformer.max_seq, patch_size * patch_size),
673
+ dtype=latent_model_input.dtype,
674
+ device=latent_model_input.device
675
+ )
676
+ latent_model_input = einops.rearrange(latent_model_input, 'B C (H p1) (W p2) -> B C (H W) (p1 p2)', p1=patch_size, p2=patch_size)
677
+ out[:, :, 0:pH*pW] = latent_model_input
678
+ latent_model_input = out
679
+
680
+ noise_pred = self.transformer(
681
+ hidden_states = latent_model_input,
682
+ timesteps = timestep,
683
+ encoder_hidden_states = prompt_embeds,
684
+ pooled_embeds = pooled_prompt_embeds,
685
+ img_sizes = img_sizes,
686
+ img_ids = img_ids,
687
+ return_dict = False,
688
+ )[0]
689
+ noise_pred = -noise_pred
690
+
691
+ # perform guidance
692
+ if self.do_classifier_free_guidance:
693
+ noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
694
+ noise_pred = noise_pred_uncond + self.guidance_scale * (noise_pred_text - noise_pred_uncond)
695
+
696
+ # compute the previous noisy sample x_t -> x_t-1
697
+ latents_dtype = latents.dtype
698
+ latents = self.scheduler.step(noise_pred, t, latents, return_dict=False)[0]
699
+
700
+ if latents.dtype != latents_dtype:
701
+ if torch.backends.mps.is_available():
702
+ # some platforms (eg. apple mps) misbehave due to a pytorch bug: https://github.com/pytorch/pytorch/pull/99272
703
+ latents = latents.to(latents_dtype)
704
+
705
+ if callback_on_step_end is not None:
706
+ callback_kwargs = {}
707
+ for k in callback_on_step_end_tensor_inputs:
708
+ callback_kwargs[k] = locals()[k]
709
+ callback_outputs = callback_on_step_end(self, i, t, callback_kwargs)
710
+
711
+ latents = callback_outputs.pop("latents", latents)
712
+ prompt_embeds = callback_outputs.pop("prompt_embeds", prompt_embeds)
713
+ negative_prompt_embeds = callback_outputs.pop("negative_prompt_embeds", negative_prompt_embeds)
714
+
715
+ # call the callback, if provided
716
+ if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0):
717
+ progress_bar.update()
718
+
719
+ if XLA_AVAILABLE:
720
+ xm.mark_step()
721
+
722
+ if output_type == "latent":
723
+ image = latents
724
+
725
+ else:
726
+ latents = (latents / self.vae.config.scaling_factor) + self.vae.config.shift_factor
727
+
728
+ image = self.vae.decode(latents, return_dict=False)[0]
729
+ image = self.image_processor.postprocess(image, output_type=output_type)
730
+
731
+ # Offload all models
732
+ self.maybe_free_model_hooks()
733
+
734
+ if not return_dict:
735
+ return (image,)
736
+
737
+ return HiDreamImagePipelineOutput(images=image)