Text-to-Image
Diffusers
Safetensors
English
image-generation
class-conditional
imagenet
pixelflow
flow-matching
Instructions to use BiliSakura/PixelFlow-diffusers with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use BiliSakura/PixelFlow-diffusers with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("BiliSakura/PixelFlow-diffusers", torch_dtype=torch.bfloat16, device_map="cuda") prompt = "golden retriever" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- Draw Things
- DiffusionBee
Update PixelFlow-T2I/pipeline.py
Browse files- 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
|
| 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 |
-
>>>
|
|
|
|
|
|
|
|
|
|
| 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
|
| 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`]
|
| 77 |
-
Multi-stage flow scheduler used by PixelFlow
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 158 |
-
|
| 159 |
-
|
|
|
|
| 160 |
|
| 161 |
-
_ensure_path(str(
|
| 162 |
scheduler_cls = getattr(importlib.import_module("scheduling_pixelflow"), "PixelFlowScheduler")
|
| 163 |
try:
|
| 164 |
-
scheduler = scheduler_cls.from_pretrained(str(
|
| 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=
|
| 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 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
)
|
| 267 |
block_number = batch_size * channels * (height // 2) * (width // 2)
|
| 268 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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(
|
| 295 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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.
|
| 474 |
-
|
| 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 |
-
|
| 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 |
-
|
| 494 |
generator,
|
| 495 |
)
|
| 496 |
-
|
|
|
|
|
|
|
|
|
|
| 497 |
|
| 498 |
-
autocast_enabled =
|
| 499 |
autocast_dtype = torch.bfloat16 if autocast_enabled else torch.float32
|
| 500 |
|
| 501 |
-
|
| 502 |
-
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
|
| 506 |
-
|
| 507 |
-
|
| 508 |
-
|
| 509 |
-
|
| 510 |
-
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
|
| 514 |
-
|
| 515 |
-
|
| 516 |
-
|
| 517 |
-
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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()
|