BiliSakura commited on
Commit
869ede7
·
verified ·
1 Parent(s): a43ace8

Update PixelFlow-T2I/pipeline.py

Browse files
Files changed (1) hide show
  1. PixelFlow-T2I/pipeline.py +188 -80
PixelFlow-T2I/pipeline.py CHANGED
@@ -12,14 +12,17 @@
12
  # See the License for the specific language governing permissions and
13
  # limitations under the License.
14
 
 
 
 
 
15
  import importlib
16
  import json
17
  import math
18
  import sys
19
  from pathlib import Path
20
- from typing import Any, List, Optional, Tuple, Union
21
 
22
- import numpy as np
23
  import torch
24
  import torch.nn.functional as F
25
  from einops import rearrange
@@ -27,8 +30,6 @@ from einops import rearrange
27
  from diffusers.image_processor import VaeImageProcessor
28
  from diffusers.models.embeddings import get_2d_rotary_pos_embed
29
  from diffusers.pipelines.pipeline_utils import DiffusionPipeline, ImagePipelineOutput
30
- from diffusers.schedulers import KarrasDiffusionSchedulers
31
- from diffusers.utils import replace_example_docstring
32
  from diffusers.utils.torch_utils import randn_tensor
33
 
34
 
@@ -38,29 +39,19 @@ EXAMPLE_DOC_STRING = """
38
  Examples:
39
  ```py
40
  >>> from pathlib import Path
 
41
  >>> import torch
42
- >>> from diffusers import DiffusionPipeline
43
 
44
  >>> model_dir = Path("./PixelFlow-T2I").resolve()
45
- >>> pipe = DiffusionPipeline.from_pretrained(
 
 
 
46
  ... str(model_dir),
47
  ... local_files_only=True,
48
- ... custom_pipeline=str(model_dir / "pipeline.py"),
49
- ... trust_remote_code=True,
50
  ... torch_dtype=torch.bfloat16,
51
  ... )
52
- >>> pipe = pipe.to("cuda")
53
-
54
- >>> generator = torch.Generator(device="cuda").manual_seed(42)
55
- >>> image = pipe(
56
- ... prompt="A golden retriever playing in a sunny garden",
57
- ... height=1024,
58
- ... width=1024,
59
- ... num_inference_steps=[10, 10, 10, 10],
60
- ... guidance_scale=4.0,
61
- ... generator=generator,
62
- ... ).images[0]
63
- >>> image.save("demo.png")
64
  ```
65
  """
66
 
@@ -73,14 +64,29 @@ class PixelFlowT2IPipeline(DiffusionPipeline):
73
  Parameters:
74
  transformer ([`PixelFlowTransformer2DModel`]):
75
  Text-conditioned PixelFlow transformer operating in pixel space.
76
- scheduler ([`PixelFlowScheduler`] or [`KarrasDiffusionSchedulers`]):
77
- Multi-stage flow scheduler used by PixelFlow cascade denoising.
78
  text_encoder ([`T5EncoderModel`], *optional*):
79
  Text encoder used to embed prompts.
80
  tokenizer ([`T5Tokenizer`], *optional*):
81
  Tokenizer paired with the text encoder.
82
  """
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  model_cpu_offload_seq = "text_encoder->transformer"
85
  _optional_components = ["text_encoder", "tokenizer"]
86
 
@@ -101,7 +107,29 @@ class PixelFlowT2IPipeline(DiffusionPipeline):
101
  )
102
  self.image_processor = VaeImageProcessor(vae_scale_factor=1, do_normalize=False)
103
  self.max_token_length = max_token_length
104
- self.set_progress_bar_config(disable=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
  @classmethod
107
  def from_pretrained(cls, pretrained_model_name_or_path=None, subfolder=None, **kwargs):
@@ -136,7 +164,6 @@ class PixelFlowT2IPipeline(DiffusionPipeline):
136
  variant = variant / subfolder
137
 
138
  model_kwargs = dict(kwargs)
139
- model_kwargs.pop("trust_remote_code", None)
140
  scheduler_kwargs = model_kwargs.pop("scheduler_kwargs", {})
141
  inserted = []
142
 
@@ -154,14 +181,15 @@ class PixelFlowT2IPipeline(DiffusionPipeline):
154
  transformer_cls = getattr(importlib.import_module("transformer_pixelflow"), "PixelFlowTransformer2DModel")
155
  transformer = transformer_cls.from_pretrained(str(transformer_dir), **model_kwargs)
156
 
157
- scheduler_dir = variant / "scheduler"
158
- if not (scheduler_dir / "scheduler_config.json").exists():
159
- raise FileNotFoundError(f"Expected scheduler config in {scheduler_dir}")
 
160
 
161
- _ensure_path(str(scheduler_dir))
162
  scheduler_cls = getattr(importlib.import_module("scheduling_pixelflow"), "PixelFlowScheduler")
163
  try:
164
- scheduler = scheduler_cls.from_pretrained(str(scheduler_dir), **scheduler_kwargs)
165
  except Exception:
166
  scheduler = scheduler_cls(**scheduler_kwargs)
167
 
@@ -187,6 +215,70 @@ class PixelFlowT2IPipeline(DiffusionPipeline):
187
  if comp_path in sys.path:
188
  sys.path.remove(comp_path)
189
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  @staticmethod
191
  def _read_text_encoder_name(variant_path: Path) -> str:
192
  metadata_path = variant_path / "conversion_metadata.json"
@@ -243,11 +335,12 @@ class PixelFlowT2IPipeline(DiffusionPipeline):
243
  init_factor = 2 ** (self.scheduler.num_stages - 1)
244
  coarse_height = height // init_factor
245
  coarse_width = width // init_factor
 
246
  latents = randn_tensor(
247
  (batch_size, 3, coarse_height, coarse_width),
248
  generator=generator,
249
  device=device,
250
- dtype=torch.float32,
251
  )
252
  return latents, coarse_height, coarse_width
253
 
@@ -257,15 +350,23 @@ class PixelFlowT2IPipeline(DiffusionPipeline):
257
  channels: int,
258
  height: int,
259
  width: int,
 
 
 
260
  eps: float = 1e-6,
261
  ) -> torch.Tensor:
262
  gamma = self.scheduler.gamma
263
- dist = torch.distributions.multivariate_normal.MultivariateNormal(
264
- torch.zeros(4),
265
- torch.eye(4) * (1 - gamma) + torch.ones(4, 4) * gamma + eps * torch.eye(4),
266
- )
267
  block_number = batch_size * channels * (height // 2) * (width // 2)
268
- noise = torch.stack([dist.sample() for _ in range(block_number)])
 
 
 
 
 
 
269
  return rearrange(
270
  noise,
271
  "(b c h w) (p q) -> b c (h p) (w q)",
@@ -284,6 +385,7 @@ class PixelFlowT2IPipeline(DiffusionPipeline):
284
  height: int,
285
  width: int,
286
  device: torch.device,
 
287
  ) -> torch.Tensor:
288
  latents = F.interpolate(latents, size=(height, width), mode="nearest")
289
  original_start_t = self.scheduler.original_start_t[stage_idx]
@@ -291,8 +393,12 @@ class PixelFlowT2IPipeline(DiffusionPipeline):
291
  alpha = 1 / (math.sqrt(1 - (1 / gamma)) * (1 - original_start_t) + original_start_t)
292
  beta = alpha * (1 - original_start_t) / math.sqrt(-gamma)
293
 
294
- noise = self._sample_block_noise(*latents.shape)
295
- noise = noise.to(device=device, dtype=latents.dtype)
 
 
 
 
296
  return alpha * latents + beta * noise
297
 
298
  def _prepare_rope_pos_embed(self, latents: torch.Tensor, device: torch.device) -> torch.Tensor:
@@ -415,7 +521,6 @@ class PixelFlowT2IPipeline(DiffusionPipeline):
415
  return prompt_embeds, prompt_attention_mask
416
 
417
  @torch.inference_mode()
418
- @replace_example_docstring(EXAMPLE_DOC_STRING)
419
  def __call__(
420
  self,
421
  prompt: Union[str, List[str]],
@@ -433,9 +538,6 @@ class PixelFlowT2IPipeline(DiffusionPipeline):
433
  r"""
434
  Generate text-to-image samples with PixelFlow.
435
 
436
- Examples:
437
- <!-- this section is replaced by replace_example_docstring -->
438
-
439
  Args:
440
  prompt (`str` or `list[str]`):
441
  Text prompt(s) describing the desired image.
@@ -470,65 +572,71 @@ class PixelFlowT2IPipeline(DiffusionPipeline):
470
  width = int(width or default_size)
471
  self.check_inputs(prompt_list, height, width, num_inference_steps, output_type, negative_prompt)
472
 
473
- device = self.transformer.device
474
- text_encoder_device = self.text_encoder.device if self.text_encoder is not None else device
475
  do_classifier_free_guidance = guidance_scale > 1.0
476
  stage_steps = self._normalize_stage_steps(num_inference_steps)
477
  batch_size = len(prompt_list)
 
478
 
479
  prompt_embeds, prompt_attention_mask = self.encode_prompt(
480
  prompt_list,
481
- text_encoder_device,
482
  num_images_per_prompt=num_images_per_prompt,
483
  do_classifier_free_guidance=do_classifier_free_guidance,
484
  negative_prompt=negative_prompt,
485
  )
486
- prompt_embeds = prompt_embeds.to(device)
487
- prompt_attention_mask = prompt_attention_mask.to(device)
488
 
489
  latents, height, width = self.prepare_latents(
490
  batch_size * num_images_per_prompt,
491
  height,
492
  width,
493
- device,
494
  generator,
495
  )
496
- size_tensor = torch.tensor([latents.shape[-1] // self.transformer.patch_size], dtype=torch.int32, device=device)
 
 
 
497
 
498
- autocast_enabled = device.type == "cuda"
499
  autocast_dtype = torch.bfloat16 if autocast_enabled else torch.float32
500
 
501
- with self.progress_bar(total=sum(stage_steps)) as progress_bar:
502
- for stage_idx in range(self.scheduler.num_stages):
503
- self.scheduler.set_timesteps(stage_steps[stage_idx], stage_idx, device=device, shift=shift)
504
- timesteps = self.scheduler.Timesteps
505
-
506
- if stage_idx > 0:
507
- height, width = height * 2, width * 2
508
- latents = self._upsample_latents_for_stage(latents, stage_idx, height, width, device)
509
- size_tensor = torch.tensor([latents.shape[-1] // self.transformer.patch_size], dtype=torch.int32, device=device)
510
-
511
- rope_pos = self._prepare_rope_pos_embed(latents, device)
512
-
513
- for timestep in timesteps:
514
- latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents
515
- timestep_batch = timestep.expand(latent_model_input.shape[0]).to(latent_model_input.dtype)
516
- with torch.autocast(device.type, enabled=autocast_enabled, dtype=autocast_dtype):
517
- noise_pred = self.transformer(
518
- latent_model_input,
519
- encoder_hidden_states=prompt_embeds,
520
- encoder_attention_mask=prompt_attention_mask,
521
- timestep=timestep_batch,
522
- latent_size=size_tensor,
523
- pos_embed=rope_pos,
524
- ).sample
525
-
526
- if do_classifier_free_guidance:
527
- noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
528
- noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)
529
-
530
- latents = self.scheduler.step(model_output=noise_pred, sample=latents).prev_sample
531
- progress_bar.update()
 
 
 
 
532
 
533
  image = self.decode_latents(latents, output_type=output_type)
534
  self.maybe_free_model_hooks()
 
12
  # See the License for the specific language governing permissions and
13
  # limitations under the License.
14
 
15
+ from __future__ import annotations
16
+
17
+ import inspect
18
+
19
  import importlib
20
  import json
21
  import math
22
  import sys
23
  from pathlib import Path
24
+ from typing import List, Optional, Tuple, Union, Any
25
 
 
26
  import torch
27
  import torch.nn.functional as F
28
  from einops import rearrange
 
30
  from diffusers.image_processor import VaeImageProcessor
31
  from diffusers.models.embeddings import get_2d_rotary_pos_embed
32
  from diffusers.pipelines.pipeline_utils import DiffusionPipeline, ImagePipelineOutput
 
 
33
  from diffusers.utils.torch_utils import randn_tensor
34
 
35
 
 
39
  Examples:
40
  ```py
41
  >>> from pathlib import Path
42
+ >>> import sys
43
  >>> import torch
 
44
 
45
  >>> model_dir = Path("./PixelFlow-T2I").resolve()
46
+ >>> sys.path.insert(0, str(model_dir))
47
+ >>> from pipeline import PixelFlowT2IPipeline
48
+
49
+ >>> pipe = PixelFlowT2IPipeline.from_pretrained(
50
  ... str(model_dir),
51
  ... local_files_only=True,
 
 
52
  ... torch_dtype=torch.bfloat16,
53
  ... )
54
+ >>> pipe.to("cuda")
 
 
 
 
 
 
 
 
 
 
 
55
  ```
56
  """
57
 
 
64
  Parameters:
65
  transformer ([`PixelFlowTransformer2DModel`]):
66
  Text-conditioned PixelFlow transformer operating in pixel space.
67
+ scheduler ([`PixelFlowScheduler`]):
68
+ Multi-stage flow scheduler used by PixelFlow.
69
  text_encoder ([`T5EncoderModel`], *optional*):
70
  Text encoder used to embed prompts.
71
  tokenizer ([`T5Tokenizer`], *optional*):
72
  Tokenizer paired with the text encoder.
73
  """
74
 
75
+ @staticmethod
76
+ def prepare_extra_step_kwargs(
77
+ scheduler,
78
+ generator=None,
79
+ eta: float | None = None,
80
+ ):
81
+ kwargs = {}
82
+ step_params = set(inspect.signature(scheduler.step).parameters.keys())
83
+ if "generator" in step_params:
84
+ kwargs["generator"] = generator
85
+ if eta is not None and "eta" in step_params:
86
+ kwargs["eta"] = eta
87
+ return kwargs
88
+
89
+
90
  model_cpu_offload_seq = "text_encoder->transformer"
91
  _optional_components = ["text_encoder", "tokenizer"]
92
 
 
107
  )
108
  self.image_processor = VaeImageProcessor(vae_scale_factor=1, do_normalize=False)
109
  self.max_token_length = max_token_length
110
+
111
+ @staticmethod
112
+ def _prepare_generator(
113
+ generator: Optional[Union[torch.Generator, List[torch.Generator]]],
114
+ device: torch.device,
115
+ ) -> Optional[Union[torch.Generator, List[torch.Generator]]]:
116
+ if generator is None:
117
+ return None
118
+ if isinstance(generator, list):
119
+ return [PixelFlowT2IPipeline._prepare_generator(item, device) for item in generator]
120
+
121
+ gen_device = getattr(generator, "device", torch.device("cpu"))
122
+ if gen_device.type == device.type:
123
+ return generator
124
+ new_generator = torch.Generator(device=device)
125
+ seed = int(generator.initial_seed())
126
+ return new_generator.manual_seed(seed)
127
+
128
+ def _latent_device(self) -> torch.device:
129
+ transformer_device = getattr(self.transformer, "device", None)
130
+ if transformer_device is not None:
131
+ return transformer_device
132
+ return self._execution_device
133
 
134
  @classmethod
135
  def from_pretrained(cls, pretrained_model_name_or_path=None, subfolder=None, **kwargs):
 
164
  variant = variant / subfolder
165
 
166
  model_kwargs = dict(kwargs)
 
167
  scheduler_kwargs = model_kwargs.pop("scheduler_kwargs", {})
168
  inserted = []
169
 
 
181
  transformer_cls = getattr(importlib.import_module("transformer_pixelflow"), "PixelFlowTransformer2DModel")
182
  transformer = transformer_cls.from_pretrained(str(transformer_dir), **model_kwargs)
183
 
184
+ scheduling_py = variant / "scheduling_pixelflow.py"
185
+ scheduler_cfg_dir = variant / "scheduler"
186
+ if not scheduling_py.is_file() or not (scheduler_cfg_dir / "scheduler_config.json").exists():
187
+ raise FileNotFoundError(f"Expected scheduler module at {scheduling_py} and config in {scheduler_cfg_dir}")
188
 
189
+ _ensure_path(str(variant.resolve()))
190
  scheduler_cls = getattr(importlib.import_module("scheduling_pixelflow"), "PixelFlowScheduler")
191
  try:
192
+ scheduler = scheduler_cls.from_pretrained(str(scheduler_cfg_dir), **scheduler_kwargs)
193
  except Exception:
194
  scheduler = scheduler_cls(**scheduler_kwargs)
195
 
 
215
  if comp_path in sys.path:
216
  sys.path.remove(comp_path)
217
 
218
+ def from_pretrained(cls, pretrained_model_name_or_path: str, **kwargs):
219
+ model_kwargs = dict(kwargs)
220
+ transformer_subfolder = model_kwargs.pop("transformer_subfolder", None)
221
+ scheduler_subfolder = model_kwargs.pop("scheduler_subfolder", None)
222
+ text_encoder_subfolder = model_kwargs.pop("text_encoder_subfolder", None)
223
+ tokenizer_subfolder = model_kwargs.pop("tokenizer_subfolder", None)
224
+ scheduler_kwargs = model_kwargs.pop("scheduler_kwargs", {})
225
+ base_path = Path(pretrained_model_name_or_path)
226
+
227
+ if transformer_subfolder is None and (base_path / "transformer").exists():
228
+ transformer_subfolder = "transformer"
229
+ if scheduler_subfolder is None and (base_path / "scheduler").exists():
230
+ scheduler_subfolder = "scheduler"
231
+ if text_encoder_subfolder is None and (base_path / "text_encoder").exists():
232
+ text_encoder_subfolder = "text_encoder"
233
+ if tokenizer_subfolder is None and (base_path / "tokenizer").exists():
234
+ tokenizer_subfolder = "tokenizer"
235
+
236
+ try:
237
+ return super().from_pretrained(pretrained_model_name_or_path, **kwargs)
238
+ except Exception:
239
+ if transformer_subfolder is not None:
240
+ transformer_path = str(base_path / transformer_subfolder)
241
+ else:
242
+ transformer_path = pretrained_model_name_or_path
243
+
244
+ transformer = PixelFlowTransformer2DModel.from_pretrained(transformer_path, **model_kwargs)
245
+ try:
246
+ scheduler = PixelFlowScheduler.from_pretrained(
247
+ pretrained_model_name_or_path,
248
+ subfolder=scheduler_subfolder,
249
+ **scheduler_kwargs,
250
+ )
251
+ except Exception:
252
+ scheduler = PixelFlowScheduler(**scheduler_kwargs)
253
+
254
+ text_encoder = None
255
+ tokenizer = None
256
+ if text_encoder_subfolder is not None and (base_path / text_encoder_subfolder / "config.json").exists():
257
+ from transformers import T5EncoderModel, T5Tokenizer
258
+
259
+ text_encoder = T5EncoderModel.from_pretrained(
260
+ str(base_path / text_encoder_subfolder),
261
+ **model_kwargs,
262
+ )
263
+ tokenizer = T5Tokenizer.from_pretrained(str(base_path / tokenizer_subfolder))
264
+
265
+ if text_encoder is None and tokenizer is None:
266
+ text_encoder_name = cls._read_text_encoder_name(base_path)
267
+ from transformers import T5EncoderModel, T5Tokenizer
268
+
269
+ text_encoder = T5EncoderModel.from_pretrained(text_encoder_name, **model_kwargs)
270
+ tokenizer = T5Tokenizer.from_pretrained(text_encoder_name)
271
+
272
+ pipe = cls(
273
+ transformer=transformer,
274
+ scheduler=scheduler,
275
+ text_encoder=text_encoder,
276
+ tokenizer=tokenizer,
277
+ )
278
+ if hasattr(pipe, "register_to_config"):
279
+ pipe.register_to_config(_name_or_path=str(base_path))
280
+ return pipe
281
+
282
  @staticmethod
283
  def _read_text_encoder_name(variant_path: Path) -> str:
284
  metadata_path = variant_path / "conversion_metadata.json"
 
335
  init_factor = 2 ** (self.scheduler.num_stages - 1)
336
  coarse_height = height // init_factor
337
  coarse_width = width // init_factor
338
+ latent_dtype = getattr(self.transformer, "dtype", torch.float32)
339
  latents = randn_tensor(
340
  (batch_size, 3, coarse_height, coarse_width),
341
  generator=generator,
342
  device=device,
343
+ dtype=latent_dtype,
344
  )
345
  return latents, coarse_height, coarse_width
346
 
 
350
  channels: int,
351
  height: int,
352
  width: int,
353
+ device: torch.device,
354
+ dtype: torch.dtype,
355
+ generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
356
  eps: float = 1e-6,
357
  ) -> torch.Tensor:
358
  gamma = self.scheduler.gamma
359
+ cov = torch.eye(4, dtype=torch.float32) * (1 - gamma) + torch.ones(4, 4, dtype=torch.float32) * gamma
360
+ cov = cov + eps * torch.eye(4, dtype=torch.float32)
361
+ chol = torch.linalg.cholesky(cov).to(device=device, dtype=dtype)
 
362
  block_number = batch_size * channels * (height // 2) * (width // 2)
363
+ standard = randn_tensor(
364
+ (block_number, 4),
365
+ generator=generator,
366
+ device=device,
367
+ dtype=dtype,
368
+ )
369
+ noise = standard @ chol.T
370
  return rearrange(
371
  noise,
372
  "(b c h w) (p q) -> b c (h p) (w q)",
 
385
  height: int,
386
  width: int,
387
  device: torch.device,
388
+ generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
389
  ) -> torch.Tensor:
390
  latents = F.interpolate(latents, size=(height, width), mode="nearest")
391
  original_start_t = self.scheduler.original_start_t[stage_idx]
 
393
  alpha = 1 / (math.sqrt(1 - (1 / gamma)) * (1 - original_start_t) + original_start_t)
394
  beta = alpha * (1 - original_start_t) / math.sqrt(-gamma)
395
 
396
+ noise = self._sample_block_noise(
397
+ *latents.shape,
398
+ device=device,
399
+ dtype=latents.dtype,
400
+ generator=generator,
401
+ )
402
  return alpha * latents + beta * noise
403
 
404
  def _prepare_rope_pos_embed(self, latents: torch.Tensor, device: torch.device) -> torch.Tensor:
 
521
  return prompt_embeds, prompt_attention_mask
522
 
523
  @torch.inference_mode()
 
524
  def __call__(
525
  self,
526
  prompt: Union[str, List[str]],
 
538
  r"""
539
  Generate text-to-image samples with PixelFlow.
540
 
 
 
 
541
  Args:
542
  prompt (`str` or `list[str]`):
543
  Text prompt(s) describing the desired image.
 
572
  width = int(width or default_size)
573
  self.check_inputs(prompt_list, height, width, num_inference_steps, output_type, negative_prompt)
574
 
575
+ device = self._execution_device
576
+ latent_device = self._latent_device()
577
  do_classifier_free_guidance = guidance_scale > 1.0
578
  stage_steps = self._normalize_stage_steps(num_inference_steps)
579
  batch_size = len(prompt_list)
580
+ generator = self._prepare_generator(generator, latent_device)
581
 
582
  prompt_embeds, prompt_attention_mask = self.encode_prompt(
583
  prompt_list,
584
+ device,
585
  num_images_per_prompt=num_images_per_prompt,
586
  do_classifier_free_guidance=do_classifier_free_guidance,
587
  negative_prompt=negative_prompt,
588
  )
 
 
589
 
590
  latents, height, width = self.prepare_latents(
591
  batch_size * num_images_per_prompt,
592
  height,
593
  width,
594
+ latent_device,
595
  generator,
596
  )
597
+ latents = latents.to(device=latent_device, dtype=self.transformer.dtype)
598
+ prompt_embeds = prompt_embeds.to(device=latent_device)
599
+ prompt_attention_mask = prompt_attention_mask.to(device=latent_device)
600
+ size_tensor = torch.tensor([latents.shape[-1] // self.transformer.patch_size], dtype=torch.int32, device=latent_device)
601
 
602
+ autocast_enabled = latent_device.type == "cuda"
603
  autocast_dtype = torch.bfloat16 if autocast_enabled else torch.float32
604
 
605
+ extra_step_kwargs = self.prepare_extra_step_kwargs(self.scheduler, generator=generator)
606
+
607
+ for stage_idx in range(self.scheduler.num_stages):
608
+ self.scheduler.set_timesteps(stage_steps[stage_idx], stage_idx, device=latent_device, shift=shift)
609
+ timesteps = self.scheduler.Timesteps
610
+
611
+ if stage_idx > 0:
612
+ height, width = height * 2, width * 2
613
+ latents = self._upsample_latents_for_stage(
614
+ latents, stage_idx, height, width, latent_device, generator=generator
615
+ )
616
+ latents = latents.to(dtype=self.transformer.dtype)
617
+ size_tensor = torch.tensor([latents.shape[-1] // self.transformer.patch_size], dtype=torch.int32, device=latent_device)
618
+
619
+ rope_pos = self._prepare_rope_pos_embed(latents, latent_device)
620
+
621
+ for timestep in timesteps:
622
+ latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents
623
+ latent_model_input = latent_model_input.to(device=latent_device, dtype=self.transformer.dtype)
624
+ timestep_batch = timestep.expand(latent_model_input.shape[0]).to(device=latent_device, dtype=self.transformer.dtype)
625
+ with torch.autocast(latent_device.type, enabled=autocast_enabled, dtype=autocast_dtype):
626
+ noise_pred = self.transformer(
627
+ latent_model_input,
628
+ encoder_hidden_states=prompt_embeds,
629
+ encoder_attention_mask=prompt_attention_mask,
630
+ timestep=timestep_batch,
631
+ latent_size=size_tensor,
632
+ pos_embed=rope_pos,
633
+ ).sample
634
+
635
+ if do_classifier_free_guidance:
636
+ noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
637
+ noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)
638
+
639
+ latents = self.scheduler.step(model_output=noise_pred, sample=latents, **extra_step_kwargs).prev_sample
640
 
641
  image = self.decode_latents(latents, output_type=output_type)
642
  self.maybe_free_model_hooks()