Spaces:
Running on Zero
Running on Zero
Canvas: switch to step-distilled model + AOTI (PR#29 revendor, aokit.load + eager fallback, 16 steps no guider)
Browse files- README.md +3 -3
- app.py +73 -11
- diffusers/__init__.py +4 -0
- diffusers/experimental/README.md +5 -0
- diffusers/models/README.md +3 -0
- diffusers/models/transformers/transformer_flux3.py +30 -2
- diffusers/modular_pipelines/__init__.py +8 -1
- diffusers/modular_pipelines/flux3/__init__.py +4 -2
- diffusers/modular_pipelines/flux3/before_denoise.py +42 -3
- diffusers/modular_pipelines/flux3/denoise.py +140 -0
- diffusers/modular_pipelines/flux3/encoders.py +67 -0
- diffusers/modular_pipelines/flux3/inputs.py +67 -0
- diffusers/modular_pipelines/flux3/modular_blocks_flux3_distilled.py +333 -0
- diffusers/modular_pipelines/flux3/modular_pipeline.py +8 -0
- diffusers/modular_pipelines/modular_pipeline.py +1 -0
- diffusers/pipelines/README.md +171 -0
- diffusers/pipelines/deprecated/README.md +3 -0
- diffusers/pipelines/stable_diffusion/README.md +176 -0
- diffusers/schedulers/README.md +3 -0
- diffusers/utils/dummy_torch_and_transformers_objects.py +30 -0
- examples/cat_window.webp +0 -0
- examples/woman1.webp +0 -0
- requirements.txt +1 -0
README.md
CHANGED
|
@@ -14,7 +14,7 @@ short_description: FLUX.3 image-small bounding-box layout canvas (ZeroGPU)
|
|
| 14 |
# FLUX.3 image-small — layout-control canvas (private)
|
| 15 |
|
| 16 |
A custom-HTML canvas on top of the **diffusers-native FLUX.3 modular pipeline**
|
| 17 |
-
([`diffusers-new-model-addition-f3` PR #
|
| 18 |
on ZeroGPU.
|
| 19 |
|
| 20 |
Drag a bounding box for every element that matters, give each box an id and a
|
|
@@ -23,11 +23,11 @@ every element placed inside its box. Toggle the **Bounding boxes** overlay on th
|
|
| 23 |
result, or **Replay** to regenerate.
|
| 24 |
|
| 25 |
> **Private.** Weights are read at runtime from the private repo
|
| 26 |
-
> `diffusers-internal-dev/f3-small-
|
| 27 |
|
| 28 |
Layout control uses FLUX.3's region format: the final prompt is the scene caption
|
| 29 |
followed by a JSON list of regions, each `{"id", "bbox": [y0, x0, y1, x1] (0-1000), "desc"}`.
|
| 30 |
|
| 31 |
## Setup
|
| 32 |
|
| 33 |
-
Needs an `HF_TOKEN` secret with read access to `diffusers-internal-dev/f3-small-
|
|
|
|
| 14 |
# FLUX.3 image-small — layout-control canvas (private)
|
| 15 |
|
| 16 |
A custom-HTML canvas on top of the **diffusers-native FLUX.3 modular pipeline**
|
| 17 |
+
([`diffusers-new-model-addition-f3` PR #29](https://github.com/huggingface/diffusers-new-model-addition-f3/pull/29)), running the **step-distilled** model AOT-compiled with aokit,
|
| 18 |
on ZeroGPU.
|
| 19 |
|
| 20 |
Drag a bounding box for every element that matters, give each box an id and a
|
|
|
|
| 23 |
result, or **Replay** to regenerate.
|
| 24 |
|
| 25 |
> **Private.** Weights are read at runtime from the private repo
|
| 26 |
+
> `diffusers-internal-dev/f3-small-image-distilled` (never copied here). Keep this Space private.
|
| 27 |
|
| 28 |
Layout control uses FLUX.3's region format: the final prompt is the scene caption
|
| 29 |
followed by a JSON list of regions, each `{"id", "bbox": [y0, x0, y1, x1] (0-1000), "desc"}`.
|
| 30 |
|
| 31 |
## Setup
|
| 32 |
|
| 33 |
+
Needs an `HF_TOKEN` secret with read access to `diffusers-internal-dev/f3-small-image-distilled` and the private AOTI artifact `diffusers-modular/f3-small-image-distilled-aoti-sm120`.
|
app.py
CHANGED
|
@@ -1,9 +1,14 @@
|
|
| 1 |
"""FLUX.3 image-small — layout-control canvas (private ZeroGPU demo, diffusers modular).
|
| 2 |
|
| 3 |
A custom HTML/JS canvas on top of the diffusers-native FLUX.3 modular pipeline
|
| 4 |
-
(PR #
|
| 5 |
-
|
| 6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
Layout control uses FLUX.3's region format (see `integration-notes/flux3_examples.py`):
|
| 9 |
the final prompt is the scene caption followed by a JSON list of regions, each
|
|
@@ -23,18 +28,22 @@ import base64
|
|
| 23 |
import io
|
| 24 |
import json
|
| 25 |
import random
|
|
|
|
| 26 |
|
| 27 |
import gradio as gr
|
| 28 |
import torch
|
|
|
|
| 29 |
|
| 30 |
from diffusers import ModularPipeline
|
| 31 |
|
| 32 |
-
|
|
|
|
|
|
|
|
|
|
| 33 |
HF_TOKEN = os.environ.get("HF_TOKEN")
|
| 34 |
|
| 35 |
MAX_SEED = 2**63 - 1
|
| 36 |
-
DEFAULT_STEPS = int(os.environ.get("F3_STEPS", "
|
| 37 |
-
DEFAULT_GUIDANCE = 3.5
|
| 38 |
|
| 39 |
torch.backends.cuda.matmul.allow_tf32 = True
|
| 40 |
torch.backends.cudnn.allow_tf32 = True
|
|
@@ -50,14 +59,66 @@ RATIOS = {
|
|
| 50 |
"9:16": (768, 1344),
|
| 51 |
}
|
| 52 |
|
| 53 |
-
|
| 54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
PIPE = ModularPipeline.from_pretrained(REPO, token=HF_TOKEN)
|
| 56 |
PIPE.load_components(dtype={"vae": torch.float32, "default": torch.bfloat16}, token=HF_TOKEN)
|
| 57 |
print("[app] components loaded on CPU.", flush=True)
|
|
|
|
| 58 |
if spaces is not None:
|
| 59 |
PIPE.to("cuda")
|
| 60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
|
| 63 |
def _build_prompt(scene: str, elements: list) -> str:
|
|
@@ -88,7 +149,8 @@ def _duration(state_json, *_):
|
|
| 88 |
except Exception:
|
| 89 |
w, h = 1024, 1024
|
| 90 |
px = w * h
|
| 91 |
-
|
|
|
|
| 92 |
|
| 93 |
|
| 94 |
def _generate(state_json):
|
|
@@ -109,7 +171,7 @@ def _generate(state_json):
|
|
| 109 |
seed = st.get("seed")
|
| 110 |
seed = int(seed) if isinstance(seed, (int, float)) and seed >= 0 else random.randint(0, MAX_SEED)
|
| 111 |
|
| 112 |
-
|
| 113 |
image = PIPE(
|
| 114 |
prompt=full_prompt,
|
| 115 |
height=h,
|
|
|
|
| 1 |
"""FLUX.3 image-small — layout-control canvas (private ZeroGPU demo, diffusers modular).
|
| 2 |
|
| 3 |
A custom HTML/JS canvas on top of the diffusers-native FLUX.3 modular pipeline
|
| 4 |
+
(PR #29, vendored `diffusers/`), running the **step-distilled** flow-map model
|
| 5 |
+
(`Flux3DistilledAutoBlocks`, 16 steps, no guider / negative prompt), with its
|
| 6 |
+
transformer block stacks **AOT-compiled via aokit** for ZeroGPU (`aokit.load` +
|
| 7 |
+
a per-block eager fallback; set `F3_AOTI=0` to run eager).
|
| 8 |
+
|
| 9 |
+
You drag bounding boxes on an aspect-ratio artboard, give each box an id + a
|
| 10 |
+
description, write a one-line scene prompt, and FLUX.3 renders the scene with
|
| 11 |
+
every element placed inside its box.
|
| 12 |
|
| 13 |
Layout control uses FLUX.3's region format (see `integration-notes/flux3_examples.py`):
|
| 14 |
the final prompt is the scene caption followed by a JSON list of regions, each
|
|
|
|
| 28 |
import io
|
| 29 |
import json
|
| 30 |
import random
|
| 31 |
+
from pathlib import Path
|
| 32 |
|
| 33 |
import gradio as gr
|
| 34 |
import torch
|
| 35 |
+
from huggingface_hub import hf_hub_download
|
| 36 |
|
| 37 |
from diffusers import ModularPipeline
|
| 38 |
|
| 39 |
+
# Step-distilled FLUX.3 image model + its private AOTI artifact.
|
| 40 |
+
REPO = os.environ.get("F3_REPO", "diffusers-internal-dev/f3-small-image-distilled")
|
| 41 |
+
AOTI_REPO = os.environ.get("F3_AOTI_REPO", "diffusers-modular/f3-small-image-distilled-aoti-sm120")
|
| 42 |
+
AOTI_ENABLED = os.environ.get("F3_AOTI", "1") != "0"
|
| 43 |
HF_TOKEN = os.environ.get("HF_TOKEN")
|
| 44 |
|
| 45 |
MAX_SEED = 2**63 - 1
|
| 46 |
+
DEFAULT_STEPS = int(os.environ.get("F3_STEPS", "16")) # distilled default
|
|
|
|
| 47 |
|
| 48 |
torch.backends.cuda.matmul.allow_tf32 = True
|
| 49 |
torch.backends.cudnn.allow_tf32 = True
|
|
|
|
| 59 |
"9:16": (768, 1344),
|
| 60 |
}
|
| 61 |
|
| 62 |
+
|
| 63 |
+
def _eager_fallback(compiled, eager):
|
| 64 |
+
"""Call the AOTI graph; fall back to the eager forward on any shape it can't
|
| 65 |
+
handle (keeps odd resolutions / layouts working instead of crashing)."""
|
| 66 |
+
def forward(*args, **kwargs):
|
| 67 |
+
try:
|
| 68 |
+
return compiled(*args, **kwargs)
|
| 69 |
+
except Exception:
|
| 70 |
+
return eager(*args, **kwargs)
|
| 71 |
+
return forward
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def _load_aoti(transformer, repo, token):
|
| 75 |
+
"""aokit.load the compiled stacks, then wrap each block with an eager fallback.
|
| 76 |
+
The artifact's torch version is asserted against the runtime."""
|
| 77 |
+
import aokit
|
| 78 |
+
|
| 79 |
+
cfg = json.loads(Path(hf_hub_download(repo, "config.json", token=token)).read_text())
|
| 80 |
+
if cfg.get("torch") != torch.__version__:
|
| 81 |
+
raise RuntimeError(
|
| 82 |
+
f"AOTI artifact built for torch {cfg.get('torch')}, runtime has {torch.__version__}"
|
| 83 |
+
)
|
| 84 |
+
stack_names = list(cfg.get("stacks", {})) or [
|
| 85 |
+
"mode_blocks.image", "mode_blocks.image_cond", "txt_mode_blocks", "single_transformer_blocks",
|
| 86 |
+
]
|
| 87 |
+
|
| 88 |
+
def _blocks(name):
|
| 89 |
+
try:
|
| 90 |
+
stack = transformer.get_submodule(name)
|
| 91 |
+
except AttributeError:
|
| 92 |
+
return []
|
| 93 |
+
return list(stack) if isinstance(stack, torch.nn.ModuleList) else [stack]
|
| 94 |
+
|
| 95 |
+
eager = {name: [blk.forward for blk in _blocks(name)] for name in stack_names}
|
| 96 |
+
aokit.load(transformer, repo) # patches block.forward -> compiled (weights stay live)
|
| 97 |
+
wrapped = 0
|
| 98 |
+
for name in stack_names:
|
| 99 |
+
for blk, eager_fwd in zip(_blocks(name), eager[name]):
|
| 100 |
+
blk.forward = _eager_fallback(blk.forward, eager_fwd)
|
| 101 |
+
wrapped += 1
|
| 102 |
+
print(f"[app] AOTI loaded from {repo}: {len(stack_names)} stacks, {wrapped} blocks wrapped "
|
| 103 |
+
f"(torch {cfg.get('torch')}, {cfg.get('arch')})", flush=True)
|
| 104 |
+
return cfg
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
# ---- load the pipeline on CPU at import; place on cuda + AOTI under ZeroGPU ----
|
| 108 |
+
print(f"[app] loading distilled modular pipeline from {REPO} ...", flush=True)
|
| 109 |
PIPE = ModularPipeline.from_pretrained(REPO, token=HF_TOKEN)
|
| 110 |
PIPE.load_components(dtype={"vae": torch.float32, "default": torch.bfloat16}, token=HF_TOKEN)
|
| 111 |
print("[app] components loaded on CPU.", flush=True)
|
| 112 |
+
AOTI_LOADED = False
|
| 113 |
if spaces is not None:
|
| 114 |
PIPE.to("cuda")
|
| 115 |
+
if AOTI_ENABLED:
|
| 116 |
+
try:
|
| 117 |
+
_load_aoti(PIPE.transformer, AOTI_REPO, HF_TOKEN)
|
| 118 |
+
AOTI_LOADED = True
|
| 119 |
+
except Exception as exc: # fall back to eager if the artifact is unavailable
|
| 120 |
+
print(f"[app] AOTI unavailable, running eager: {exc!r}", flush=True)
|
| 121 |
+
print(f"[app] pipeline on cuda; ready (aoti={AOTI_LOADED}).", flush=True)
|
| 122 |
|
| 123 |
|
| 124 |
def _build_prompt(scene: str, elements: list) -> str:
|
|
|
|
| 149 |
except Exception:
|
| 150 |
w, h = 1024, 1024
|
| 151 |
px = w * h
|
| 152 |
+
# Distilled flow-map model: single forward per step (no CFG), so cheaper/step.
|
| 153 |
+
return int(min(300, 40 + DEFAULT_STEPS * 1.6 * max(1.0, px / (1024 * 1024))))
|
| 154 |
|
| 155 |
|
| 156 |
def _generate(state_json):
|
|
|
|
| 171 |
seed = st.get("seed")
|
| 172 |
seed = int(seed) if isinstance(seed, (int, float)) and seed >= 0 else random.randint(0, MAX_SEED)
|
| 173 |
|
| 174 |
+
# Distilled flow-map model has no guider / guidance.
|
| 175 |
image = PIPE(
|
| 176 |
prompt=full_prompt,
|
| 177 |
height=h,
|
diffusers/__init__.py
CHANGED
|
@@ -527,6 +527,8 @@ else:
|
|
| 527 |
"Flux2KleinModularPipeline",
|
| 528 |
"Flux2ModularPipeline",
|
| 529 |
"Flux3AutoBlocks",
|
|
|
|
|
|
|
| 530 |
"Flux3ModularPipeline",
|
| 531 |
"FluxAutoBlocks",
|
| 532 |
"FluxKontextAutoBlocks",
|
|
@@ -1386,6 +1388,8 @@ if TYPE_CHECKING or DIFFUSERS_SLOW_IMPORT:
|
|
| 1386 |
Flux2KleinModularPipeline,
|
| 1387 |
Flux2ModularPipeline,
|
| 1388 |
Flux3AutoBlocks,
|
|
|
|
|
|
|
| 1389 |
Flux3ModularPipeline,
|
| 1390 |
FluxAutoBlocks,
|
| 1391 |
FluxKontextAutoBlocks,
|
|
|
|
| 527 |
"Flux2KleinModularPipeline",
|
| 528 |
"Flux2ModularPipeline",
|
| 529 |
"Flux3AutoBlocks",
|
| 530 |
+
"Flux3DistilledAutoBlocks",
|
| 531 |
+
"Flux3DistilledModularPipeline",
|
| 532 |
"Flux3ModularPipeline",
|
| 533 |
"FluxAutoBlocks",
|
| 534 |
"FluxKontextAutoBlocks",
|
|
|
|
| 1388 |
Flux2KleinModularPipeline,
|
| 1389 |
Flux2ModularPipeline,
|
| 1390 |
Flux3AutoBlocks,
|
| 1391 |
+
Flux3DistilledAutoBlocks,
|
| 1392 |
+
Flux3DistilledModularPipeline,
|
| 1393 |
Flux3ModularPipeline,
|
| 1394 |
FluxAutoBlocks,
|
| 1395 |
FluxKontextAutoBlocks,
|
diffusers/experimental/README.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🧨 Diffusers Experimental
|
| 2 |
+
|
| 3 |
+
We are adding experimental code to support novel applications and usages of the Diffusers library.
|
| 4 |
+
Currently, the following experiments are supported:
|
| 5 |
+
* Reinforcement learning via an implementation of the [Diffuser](https://huggingface.co/papers/2205.09991) model.
|
diffusers/models/README.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Models
|
| 2 |
+
|
| 3 |
+
For more detail on the models, please refer to the [docs](https://huggingface.co/docs/diffusers/api/models/overview).
|
diffusers/models/transformers/transformer_flux3.py
CHANGED
|
@@ -346,7 +346,9 @@ class Flux3Transformer2DModel(ModelMixin, ConfigMixin, PeftAdapterMixin, Attenti
|
|
| 346 |
passes through its own per-mode transformer blocks (`mode_blocks` for the image modes, `txt_mode_blocks` for the
|
| 347 |
text context), then the text context and the active image modes are concatenated for the joint single blocks, and
|
| 348 |
only the image tokens pass through the output layers. The modulation is per mode: the image tokens are modulated by
|
| 349 |
-
the flow timestep, the reference image tokens and the text context by timestep `0`.
|
|
|
|
|
|
|
| 350 |
|
| 351 |
Args:
|
| 352 |
in_channels (`int`, defaults to `128`):
|
|
@@ -373,6 +375,9 @@ class Flux3Transformer2DModel(ModelMixin, ConfigMixin, PeftAdapterMixin, Attenti
|
|
| 373 |
The base frequency of the rotary positional embeddings.
|
| 374 |
eps (`float`, defaults to `1e-6`):
|
| 375 |
The epsilon of the layer norms and the QK norms.
|
|
|
|
|
|
|
|
|
|
| 376 |
"""
|
| 377 |
|
| 378 |
_supports_gradient_checkpointing = True
|
|
@@ -395,6 +400,7 @@ class Flux3Transformer2DModel(ModelMixin, ConfigMixin, PeftAdapterMixin, Attenti
|
|
| 395 |
axes_dims_rope: tuple[int, ...] = (32, 32, 32, 32),
|
| 396 |
rope_theta: int = 10000,
|
| 397 |
eps: float = 1e-6,
|
|
|
|
| 398 |
):
|
| 399 |
super().__init__()
|
| 400 |
|
|
@@ -410,6 +416,12 @@ class Flux3Transformer2DModel(ModelMixin, ConfigMixin, PeftAdapterMixin, Attenti
|
|
| 410 |
self.timestep_embedder = TimestepEmbedding(
|
| 411 |
in_channels=timestep_channels, time_embed_dim=self.inner_dim, sample_proj_bias=False
|
| 412 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 413 |
|
| 414 |
# 3. Modulation: one head per mode (+ text) for the per-mode blocks and for the joint blocks
|
| 415 |
self.early_stream_modulations = nn.ModuleDict(
|
|
@@ -486,6 +498,7 @@ class Flux3Transformer2DModel(ModelMixin, ConfigMixin, PeftAdapterMixin, Attenti
|
|
| 486 |
txt_ids: torch.Tensor,
|
| 487 |
image_cond_hidden_states: torch.Tensor | None = None,
|
| 488 |
image_cond_ids: torch.Tensor | None = None,
|
|
|
|
| 489 |
attention_kwargs: dict[str, Any] | None = None,
|
| 490 |
return_dict: bool = True,
|
| 491 |
) -> Transformer2DModelOutput | tuple[torch.Tensor]:
|
|
@@ -509,6 +522,9 @@ class Flux3Transformer2DModel(ModelMixin, ConfigMixin, PeftAdapterMixin, Attenti
|
|
| 509 |
VAE-encoded reference image tokens (clean conditioning content, for image-to-image generation).
|
| 510 |
image_cond_ids (`torch.Tensor` of shape `(cond_seq_len, 4)`, *optional*):
|
| 511 |
Position ids of the reference image tokens. Required with `image_cond_hidden_states`.
|
|
|
|
|
|
|
|
|
|
| 512 |
attention_kwargs (`dict`, *optional*):
|
| 513 |
A kwargs dictionary whose `scale` entry, if specified, scales the LoRA layers for this forward pass.
|
| 514 |
return_dict (`bool`, *optional*, defaults to `True`):
|
|
@@ -524,6 +540,10 @@ class Flux3Transformer2DModel(ModelMixin, ConfigMixin, PeftAdapterMixin, Attenti
|
|
| 524 |
raise ValueError("`image_cond_hidden_states` requires `image_cond_ids`.")
|
| 525 |
if image_cond_hidden_states is None and image_cond_ids is not None:
|
| 526 |
raise ValueError("`image_cond_ids` was passed without `image_cond_hidden_states`.")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 527 |
|
| 528 |
batch_size, image_seq_len = hidden_states.shape[:2]
|
| 529 |
dtype = hidden_states.dtype
|
|
@@ -531,9 +551,17 @@ class Flux3Transformer2DModel(ModelMixin, ConfigMixin, PeftAdapterMixin, Attenti
|
|
| 531 |
# 1. Timestep embeddings: the image tokens at `timestep`, the text context and the reference tokens at 0.
|
| 532 |
# Each is a per-token embedding (batch_size, seq_len, dim) since the modulation is per token.
|
| 533 |
image_temb = self.time_proj(timestep.to(dtype) * 1000)
|
| 534 |
-
image_temb = self.timestep_embedder(image_temb.to(dtype))[:, None, :]
|
| 535 |
zero_temb = self.time_proj(torch.zeros(batch_size, device=hidden_states.device, dtype=dtype))
|
| 536 |
zero_temb = self.timestep_embedder(zero_temb.to(dtype))[:, None, :]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 537 |
zero_temb_act = F.silu(zero_temb)
|
| 538 |
|
| 539 |
# 2. Text context: the two modulation sets, input projection and RoPE
|
|
|
|
| 346 |
passes through its own per-mode transformer blocks (`mode_blocks` for the image modes, `txt_mode_blocks` for the
|
| 347 |
text context), then the text context and the active image modes are concatenated for the joint single blocks, and
|
| 348 |
only the image tokens pass through the output layers. The modulation is per mode: the image tokens are modulated by
|
| 349 |
+
the flow timestep, the reference image tokens and the text context by timestep `0`. A flow-map checkpoint
|
| 350 |
+
(`flow_map=True`, the step-distilled models) additionally embeds the timestep each denoising step jumps to and adds
|
| 351 |
+
it to every mode's modulation.
|
| 352 |
|
| 353 |
Args:
|
| 354 |
in_channels (`int`, defaults to `128`):
|
|
|
|
| 375 |
The base frequency of the rotary positional embeddings.
|
| 376 |
eps (`float`, defaults to `1e-6`):
|
| 377 |
The epsilon of the layer norms and the QK norms.
|
| 378 |
+
flow_map (`bool`, defaults to `False`):
|
| 379 |
+
Whether the model is a flow map (step-distilled): adds the `target_timestep_embedder` and requires
|
| 380 |
+
`target_timestep` in the forward pass.
|
| 381 |
"""
|
| 382 |
|
| 383 |
_supports_gradient_checkpointing = True
|
|
|
|
| 400 |
axes_dims_rope: tuple[int, ...] = (32, 32, 32, 32),
|
| 401 |
rope_theta: int = 10000,
|
| 402 |
eps: float = 1e-6,
|
| 403 |
+
flow_map: bool = False,
|
| 404 |
):
|
| 405 |
super().__init__()
|
| 406 |
|
|
|
|
| 416 |
self.timestep_embedder = TimestepEmbedding(
|
| 417 |
in_channels=timestep_channels, time_embed_dim=self.inner_dim, sample_proj_bias=False
|
| 418 |
)
|
| 419 |
+
# flow map (step-distilled checkpoints): a second embedder for the timestep each step jumps to
|
| 420 |
+
self.target_timestep_embedder = (
|
| 421 |
+
TimestepEmbedding(in_channels=timestep_channels, time_embed_dim=self.inner_dim, sample_proj_bias=False)
|
| 422 |
+
if flow_map
|
| 423 |
+
else None
|
| 424 |
+
)
|
| 425 |
|
| 426 |
# 3. Modulation: one head per mode (+ text) for the per-mode blocks and for the joint blocks
|
| 427 |
self.early_stream_modulations = nn.ModuleDict(
|
|
|
|
| 498 |
txt_ids: torch.Tensor,
|
| 499 |
image_cond_hidden_states: torch.Tensor | None = None,
|
| 500 |
image_cond_ids: torch.Tensor | None = None,
|
| 501 |
+
target_timestep: torch.Tensor | None = None,
|
| 502 |
attention_kwargs: dict[str, Any] | None = None,
|
| 503 |
return_dict: bool = True,
|
| 504 |
) -> Transformer2DModelOutput | tuple[torch.Tensor]:
|
|
|
|
| 522 |
VAE-encoded reference image tokens (clean conditioning content, for image-to-image generation).
|
| 523 |
image_cond_ids (`torch.Tensor` of shape `(cond_seq_len, 4)`, *optional*):
|
| 524 |
Position ids of the reference image tokens. Required with `image_cond_hidden_states`.
|
| 525 |
+
target_timestep (`torch.Tensor` of shape `(batch_size,)`, *optional*):
|
| 526 |
+
Flow timestep in `[0, 1]` that the current denoising step jumps to. Required by, and only by, a flow-map
|
| 527 |
+
model (`flow_map=True`).
|
| 528 |
attention_kwargs (`dict`, *optional*):
|
| 529 |
A kwargs dictionary whose `scale` entry, if specified, scales the LoRA layers for this forward pass.
|
| 530 |
return_dict (`bool`, *optional*, defaults to `True`):
|
|
|
|
| 540 |
raise ValueError("`image_cond_hidden_states` requires `image_cond_ids`.")
|
| 541 |
if image_cond_hidden_states is None and image_cond_ids is not None:
|
| 542 |
raise ValueError("`image_cond_ids` was passed without `image_cond_hidden_states`.")
|
| 543 |
+
if (target_timestep is not None) != bool(self.config.flow_map):
|
| 544 |
+
raise ValueError(
|
| 545 |
+
"`target_timestep` is required by, and only by, a flow-map transformer (`flow_map=True`)."
|
| 546 |
+
)
|
| 547 |
|
| 548 |
batch_size, image_seq_len = hidden_states.shape[:2]
|
| 549 |
dtype = hidden_states.dtype
|
|
|
|
| 551 |
# 1. Timestep embeddings: the image tokens at `timestep`, the text context and the reference tokens at 0.
|
| 552 |
# Each is a per-token embedding (batch_size, seq_len, dim) since the modulation is per token.
|
| 553 |
image_temb = self.time_proj(timestep.to(dtype) * 1000)
|
| 554 |
+
image_temb = self.timestep_embedder(image_temb.to(dtype))[:, None, :]
|
| 555 |
zero_temb = self.time_proj(torch.zeros(batch_size, device=hidden_states.device, dtype=dtype))
|
| 556 |
zero_temb = self.timestep_embedder(zero_temb.to(dtype))[:, None, :]
|
| 557 |
+
if target_timestep is not None:
|
| 558 |
+
# flow map: the embedding of the timestep this step jumps to is added to every mode's embedding, so it
|
| 559 |
+
# reaches the per-mode blocks, the joint blocks and the output layer
|
| 560 |
+
target_temb = self.time_proj(target_timestep.to(dtype) * 1000)
|
| 561 |
+
target_temb = self.target_timestep_embedder(target_temb.to(dtype))[:, None, :]
|
| 562 |
+
image_temb = image_temb + target_temb
|
| 563 |
+
zero_temb = zero_temb + target_temb
|
| 564 |
+
image_temb = image_temb.expand(batch_size, image_seq_len, -1)
|
| 565 |
zero_temb_act = F.silu(zero_temb)
|
| 566 |
|
| 567 |
# 2. Text context: the two modulation sets, input projection and RoPE
|
diffusers/modular_pipelines/__init__.py
CHANGED
|
@@ -83,6 +83,8 @@ else:
|
|
| 83 |
]
|
| 84 |
_import_structure["flux3"] = [
|
| 85 |
"Flux3AutoBlocks",
|
|
|
|
|
|
|
| 86 |
"Flux3ModularPipeline",
|
| 87 |
]
|
| 88 |
_import_structure["ideogram4"] = [
|
|
@@ -172,7 +174,12 @@ if TYPE_CHECKING or DIFFUSERS_SLOW_IMPORT:
|
|
| 172 |
Flux2KleinModularPipeline,
|
| 173 |
Flux2ModularPipeline,
|
| 174 |
)
|
| 175 |
-
from .flux3 import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
from .helios import (
|
| 177 |
HeliosAutoBlocks,
|
| 178 |
HeliosModularPipeline,
|
|
|
|
| 83 |
]
|
| 84 |
_import_structure["flux3"] = [
|
| 85 |
"Flux3AutoBlocks",
|
| 86 |
+
"Flux3DistilledAutoBlocks",
|
| 87 |
+
"Flux3DistilledModularPipeline",
|
| 88 |
"Flux3ModularPipeline",
|
| 89 |
]
|
| 90 |
_import_structure["ideogram4"] = [
|
|
|
|
| 174 |
Flux2KleinModularPipeline,
|
| 175 |
Flux2ModularPipeline,
|
| 176 |
)
|
| 177 |
+
from .flux3 import (
|
| 178 |
+
Flux3AutoBlocks,
|
| 179 |
+
Flux3DistilledAutoBlocks,
|
| 180 |
+
Flux3DistilledModularPipeline,
|
| 181 |
+
Flux3ModularPipeline,
|
| 182 |
+
)
|
| 183 |
from .helios import (
|
| 184 |
HeliosAutoBlocks,
|
| 185 |
HeliosModularPipeline,
|
diffusers/modular_pipelines/flux3/__init__.py
CHANGED
|
@@ -22,7 +22,8 @@ except OptionalDependencyNotAvailable:
|
|
| 22 |
_dummy_objects.update(get_objects_from_module(dummy_torch_and_transformers_objects))
|
| 23 |
else:
|
| 24 |
_import_structure["modular_blocks_flux3"] = ["Flux3AutoBlocks"]
|
| 25 |
-
_import_structure["
|
|
|
|
| 26 |
|
| 27 |
if TYPE_CHECKING or DIFFUSERS_SLOW_IMPORT:
|
| 28 |
try:
|
|
@@ -32,7 +33,8 @@ if TYPE_CHECKING or DIFFUSERS_SLOW_IMPORT:
|
|
| 32 |
from ...utils.dummy_torch_and_transformers_objects import * # noqa F403
|
| 33 |
else:
|
| 34 |
from .modular_blocks_flux3 import Flux3AutoBlocks
|
| 35 |
-
from .
|
|
|
|
| 36 |
else:
|
| 37 |
import sys
|
| 38 |
|
|
|
|
| 22 |
_dummy_objects.update(get_objects_from_module(dummy_torch_and_transformers_objects))
|
| 23 |
else:
|
| 24 |
_import_structure["modular_blocks_flux3"] = ["Flux3AutoBlocks"]
|
| 25 |
+
_import_structure["modular_blocks_flux3_distilled"] = ["Flux3DistilledAutoBlocks"]
|
| 26 |
+
_import_structure["modular_pipeline"] = ["Flux3DistilledModularPipeline", "Flux3ModularPipeline"]
|
| 27 |
|
| 28 |
if TYPE_CHECKING or DIFFUSERS_SLOW_IMPORT:
|
| 29 |
try:
|
|
|
|
| 33 |
from ...utils.dummy_torch_and_transformers_objects import * # noqa F403
|
| 34 |
else:
|
| 35 |
from .modular_blocks_flux3 import Flux3AutoBlocks
|
| 36 |
+
from .modular_blocks_flux3_distilled import Flux3DistilledAutoBlocks
|
| 37 |
+
from .modular_pipeline import Flux3DistilledModularPipeline, Flux3ModularPipeline
|
| 38 |
else:
|
| 39 |
import sys
|
| 40 |
|
diffusers/modular_pipelines/flux3/before_denoise.py
CHANGED
|
@@ -92,9 +92,11 @@ def retrieve_timesteps(
|
|
| 92 |
class Flux3SetTimestepsStep(ModularPipelineBlocks):
|
| 93 |
model_name = "flux3"
|
| 94 |
|
| 95 |
-
def __init__(self, shift: float = 6.93):
|
| 96 |
-
# the constant timestep shift ("alpha") of the FLUX.3 sampling recipe, configured on the scheduler
|
|
|
|
| 97 |
self.shift = shift
|
|
|
|
| 98 |
super().__init__()
|
| 99 |
|
| 100 |
@property
|
|
@@ -118,7 +120,7 @@ class Flux3SetTimestepsStep(ModularPipelineBlocks):
|
|
| 118 |
@property
|
| 119 |
def inputs(self) -> list[InputParam]:
|
| 120 |
return [
|
| 121 |
-
InputParam.template("num_inference_steps"),
|
| 122 |
InputParam.template("timesteps", note="overrides `num_inference_steps` when provided"),
|
| 123 |
InputParam.template("sigmas", note="overrides `num_inference_steps` when provided"),
|
| 124 |
]
|
|
@@ -395,3 +397,40 @@ class Flux3TextRoPEInputsStep(ModularPipelineBlocks):
|
|
| 395 |
|
| 396 |
self.set_block_state(state, block_state)
|
| 397 |
return components, state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
class Flux3SetTimestepsStep(ModularPipelineBlocks):
|
| 93 |
model_name = "flux3"
|
| 94 |
|
| 95 |
+
def __init__(self, shift: float = 6.93, num_inference_steps: int = 50):
|
| 96 |
+
# the constant timestep shift ("alpha") of the FLUX.3 sampling recipe, configured on the scheduler, and the
|
| 97 |
+
# default number of steps (50; 16 for the step-distilled checkpoints)
|
| 98 |
self.shift = shift
|
| 99 |
+
self.num_inference_steps = num_inference_steps
|
| 100 |
super().__init__()
|
| 101 |
|
| 102 |
@property
|
|
|
|
| 120 |
@property
|
| 121 |
def inputs(self) -> list[InputParam]:
|
| 122 |
return [
|
| 123 |
+
InputParam.template("num_inference_steps", default=self.num_inference_steps),
|
| 124 |
InputParam.template("timesteps", note="overrides `num_inference_steps` when provided"),
|
| 125 |
InputParam.template("sigmas", note="overrides `num_inference_steps` when provided"),
|
| 126 |
]
|
|
|
|
| 397 |
|
| 398 |
self.set_block_state(state, block_state)
|
| 399 |
return components, state
|
| 400 |
+
|
| 401 |
+
|
| 402 |
+
class Flux3DistilledTextRoPEInputsStep(Flux3TextRoPEInputsStep):
|
| 403 |
+
model_name = "flux3-distilled"
|
| 404 |
+
|
| 405 |
+
@property
|
| 406 |
+
def description(self) -> str:
|
| 407 |
+
return (
|
| 408 |
+
"Step that prepares the 4D RoPE position IDs of the text tokens for the step-distilled FLUX.3 model (no "
|
| 409 |
+
"negative prompt). Place it after the text encoder step."
|
| 410 |
+
)
|
| 411 |
+
|
| 412 |
+
@property
|
| 413 |
+
def inputs(self) -> list[InputParam]:
|
| 414 |
+
return [
|
| 415 |
+
InputParam.template(
|
| 416 |
+
"prompt_embeds",
|
| 417 |
+
description="Text embeddings used to guide the generation. Can be generated from text_encoder step.",
|
| 418 |
+
),
|
| 419 |
+
]
|
| 420 |
+
|
| 421 |
+
@property
|
| 422 |
+
def intermediate_outputs(self) -> list[OutputParam]:
|
| 423 |
+
return [
|
| 424 |
+
OutputParam(
|
| 425 |
+
name="txt_ids",
|
| 426 |
+
kwargs_type="denoiser_input_fields",
|
| 427 |
+
type_hint=torch.Tensor,
|
| 428 |
+
description="4D position IDs (T, H, W, L) for text tokens, used for RoPE calculation.",
|
| 429 |
+
),
|
| 430 |
+
]
|
| 431 |
+
|
| 432 |
+
def __call__(self, components: Flux3ModularPipeline, state: PipelineState) -> PipelineState:
|
| 433 |
+
block_state = self.get_block_state(state)
|
| 434 |
+
block_state.txt_ids = self._prepare_text_ids(block_state.prompt_embeds).to(block_state.prompt_embeds.device)
|
| 435 |
+
self.set_block_state(state, block_state)
|
| 436 |
+
return components, state
|
diffusers/modular_pipelines/flux3/denoise.py
CHANGED
|
@@ -138,6 +138,76 @@ class Flux3LoopDenoiser(ModularPipelineBlocks):
|
|
| 138 |
return components, block_state
|
| 139 |
|
| 140 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
class Flux3LoopAfterDenoiser(ModularPipelineBlocks):
|
| 142 |
model_name = "flux3"
|
| 143 |
|
|
@@ -276,3 +346,73 @@ class Flux3DenoiseStep(Flux3DenoiseLoopWrapper):
|
|
| 276 |
" - `Flux3LoopAfterDenoiser`\n"
|
| 277 |
"This block supports text-to-image and image-to-image generation."
|
| 278 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
return components, block_state
|
| 139 |
|
| 140 |
|
| 141 |
+
class Flux3DistilledLoopDenoiser(ModularPipelineBlocks):
|
| 142 |
+
model_name = "flux3-distilled"
|
| 143 |
+
|
| 144 |
+
@property
|
| 145 |
+
def expected_components(self) -> list[ComponentSpec]:
|
| 146 |
+
return [ComponentSpec("transformer", Flux3Transformer2DModel)]
|
| 147 |
+
|
| 148 |
+
@property
|
| 149 |
+
def description(self) -> str:
|
| 150 |
+
return (
|
| 151 |
+
"Step within the denoising loop that predicts the velocity of the image tokens with a step-distilled "
|
| 152 |
+
"(flow-map) FLUX.3 transformer: no classifier-free guidance, and each step also passes the transformer the "
|
| 153 |
+
"timestep it jumps to. The static conditioning fields (`prompt_embeds`, `txt_ids`, `img_ids`, the "
|
| 154 |
+
"reference image tokens and their ids) arrive via `denoiser_input_fields`. "
|
| 155 |
+
"This block should be used to compose the `sub_blocks` attribute of a `LoopSequentialPipelineBlocks` "
|
| 156 |
+
"object (e.g. `Flux3DistilledDenoiseStep`)"
|
| 157 |
+
)
|
| 158 |
+
|
| 159 |
+
@property
|
| 160 |
+
def inputs(self) -> list[tuple[str, Any]]:
|
| 161 |
+
return [
|
| 162 |
+
InputParam(
|
| 163 |
+
"latents",
|
| 164 |
+
required=True,
|
| 165 |
+
type_hint=torch.Tensor,
|
| 166 |
+
description="The image latent tokens to denoise. Shape: (B, seq_len, C)",
|
| 167 |
+
),
|
| 168 |
+
InputParam.template("denoiser_input_fields"),
|
| 169 |
+
]
|
| 170 |
+
|
| 171 |
+
@property
|
| 172 |
+
def intermediate_outputs(self) -> list[OutputParam]:
|
| 173 |
+
return [OutputParam("noise_pred", type_hint=torch.Tensor, description="The predicted velocity for this step")]
|
| 174 |
+
|
| 175 |
+
@torch.no_grad()
|
| 176 |
+
def __call__(
|
| 177 |
+
self, components: Flux3ModularPipeline, block_state: BlockState, i: int, t: torch.Tensor
|
| 178 |
+
) -> PipelineState:
|
| 179 |
+
denoiser_input_fields = block_state.denoiser_input_fields
|
| 180 |
+
|
| 181 |
+
# transformer kwargs = every collected static field matching the forward signature (`img_ids`, `txt_ids`, and
|
| 182 |
+
# the `image_cond_*` fields of image-to-image generation)
|
| 183 |
+
transformer_args = set(inspect.signature(components.transformer.forward).parameters.keys())
|
| 184 |
+
transformer_kwargs = {
|
| 185 |
+
field_name: field_value
|
| 186 |
+
for field_name, field_value in denoiser_input_fields.items()
|
| 187 |
+
if field_name in transformer_args
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
latents = block_state.latents.to(components.transformer.dtype)
|
| 191 |
+
batch_size = latents.shape[0]
|
| 192 |
+
# the flow timestep in [0, 1] (scheduler timesteps are sigmas * 1000), and the one this step jumps to: the next
|
| 193 |
+
# scheduler timestep, 0 after the last
|
| 194 |
+
timesteps = block_state.timesteps
|
| 195 |
+
next_t = timesteps[i + 1] if i + 1 < len(timesteps) else torch.zeros_like(t)
|
| 196 |
+
timestep = (t / 1000).expand(batch_size).to(latents.dtype)
|
| 197 |
+
target_timestep = (next_t / 1000).expand(batch_size).to(latents.dtype)
|
| 198 |
+
|
| 199 |
+
block_state.noise_pred = components.transformer(
|
| 200 |
+
hidden_states=latents,
|
| 201 |
+
encoder_hidden_states=denoiser_input_fields["prompt_embeds"],
|
| 202 |
+
timestep=timestep,
|
| 203 |
+
target_timestep=target_timestep,
|
| 204 |
+
return_dict=False,
|
| 205 |
+
**transformer_kwargs,
|
| 206 |
+
)[0]
|
| 207 |
+
|
| 208 |
+
return components, block_state
|
| 209 |
+
|
| 210 |
+
|
| 211 |
class Flux3LoopAfterDenoiser(ModularPipelineBlocks):
|
| 212 |
model_name = "flux3"
|
| 213 |
|
|
|
|
| 346 |
" - `Flux3LoopAfterDenoiser`\n"
|
| 347 |
"This block supports text-to-image and image-to-image generation."
|
| 348 |
)
|
| 349 |
+
|
| 350 |
+
|
| 351 |
+
# auto_docstring
|
| 352 |
+
class Flux3DistilledDenoiseStep(Flux3DenoiseLoopWrapper):
|
| 353 |
+
"""
|
| 354 |
+
Denoise step that iteratively denoises the latents for the step-distilled (flow-map) FLUX.3 model.
|
| 355 |
+
Its loop logic is defined in `Flux3DenoiseLoopWrapper.__call__` method At each iteration, it runs blocks defined
|
| 356 |
+
in `sub_blocks` sequentially:
|
| 357 |
+
- `Flux3DistilledLoopDenoiser`
|
| 358 |
+
- `Flux3LoopAfterDenoiser`
|
| 359 |
+
This block supports text-to-image and image-to-image generation, without classifier-free guidance.
|
| 360 |
+
|
| 361 |
+
Components:
|
| 362 |
+
transformer (`Flux3Transformer2DModel`) scheduler (`FlowMatchEulerDiscreteScheduler`)
|
| 363 |
+
|
| 364 |
+
Inputs:
|
| 365 |
+
timesteps (`Tensor`):
|
| 366 |
+
The timesteps to use for the denoising process.
|
| 367 |
+
num_inference_steps (`int`):
|
| 368 |
+
The number of inference steps to use for the denoising process.
|
| 369 |
+
latents (`Tensor`):
|
| 370 |
+
The image latent tokens to denoise. Shape: (B, seq_len, C)
|
| 371 |
+
**denoiser_input_fields (`None`, *optional*):
|
| 372 |
+
conditional model inputs for the denoiser: e.g. prompt_embeds, negative_prompt_embeds, etc.
|
| 373 |
+
|
| 374 |
+
Outputs:
|
| 375 |
+
latents (`Tensor`):
|
| 376 |
+
The denoised latents
|
| 377 |
+
"""
|
| 378 |
+
|
| 379 |
+
model_name = "flux3-distilled"
|
| 380 |
+
"""
|
| 381 |
+
Denoise step that iteratively denoises the latents for the step-distilled (flow-map) FLUX.3 model.
|
| 382 |
+
Its loop logic is defined in `Flux3DenoiseLoopWrapper.__call__` method At each iteration, it runs blocks defined
|
| 383 |
+
in `sub_blocks` sequentially:
|
| 384 |
+
- `Flux3DistilledLoopDenoiser`
|
| 385 |
+
- `Flux3LoopAfterDenoiser`
|
| 386 |
+
This block supports text-to-image and image-to-image generation, without classifier-free guidance.
|
| 387 |
+
|
| 388 |
+
Components:
|
| 389 |
+
transformer (`Flux3Transformer2DModel`) scheduler (`FlowMatchEulerDiscreteScheduler`)
|
| 390 |
+
|
| 391 |
+
Inputs:
|
| 392 |
+
timesteps (`Tensor`):
|
| 393 |
+
The timesteps to use for the denoising process.
|
| 394 |
+
num_inference_steps (`int`):
|
| 395 |
+
The number of inference steps to use for the denoising process.
|
| 396 |
+
latents (`Tensor`):
|
| 397 |
+
The image latent tokens to denoise. Shape: (B, seq_len, C)
|
| 398 |
+
**denoiser_input_fields (`None`, *optional*):
|
| 399 |
+
conditional model inputs for the denoiser: e.g. prompt_embeds, negative_prompt_embeds, etc.
|
| 400 |
+
|
| 401 |
+
Outputs:
|
| 402 |
+
latents (`Tensor`):
|
| 403 |
+
The denoised latents
|
| 404 |
+
"""
|
| 405 |
+
|
| 406 |
+
block_classes = [Flux3DistilledLoopDenoiser(), Flux3LoopAfterDenoiser()]
|
| 407 |
+
block_names = ["denoiser", "after_denoiser"]
|
| 408 |
+
|
| 409 |
+
@property
|
| 410 |
+
def description(self) -> str:
|
| 411 |
+
return (
|
| 412 |
+
"Denoise step that iteratively denoises the latents for the step-distilled (flow-map) FLUX.3 model. \n"
|
| 413 |
+
"Its loop logic is defined in `Flux3DenoiseLoopWrapper.__call__` method \n"
|
| 414 |
+
"At each iteration, it runs blocks defined in `sub_blocks` sequentially:\n"
|
| 415 |
+
" - `Flux3DistilledLoopDenoiser`\n"
|
| 416 |
+
" - `Flux3LoopAfterDenoiser`\n"
|
| 417 |
+
"This block supports text-to-image and image-to-image generation, without classifier-free guidance."
|
| 418 |
+
)
|
diffusers/modular_pipelines/flux3/encoders.py
CHANGED
|
@@ -326,3 +326,70 @@ class Flux3TextEncoderStep(ModularPipelineBlocks):
|
|
| 326 |
|
| 327 |
self.set_block_state(state, block_state)
|
| 328 |
return components, state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
|
| 327 |
self.set_block_state(state, block_state)
|
| 328 |
return components, state
|
| 329 |
+
|
| 330 |
+
|
| 331 |
+
class Flux3DistilledTextEncoderStep(Flux3TextEncoderStep):
|
| 332 |
+
model_name = "flux3-distilled"
|
| 333 |
+
|
| 334 |
+
@property
|
| 335 |
+
def description(self) -> str:
|
| 336 |
+
return (
|
| 337 |
+
"Text Encoder step that generates text embeddings using Qwen3-VL to guide the generation with the "
|
| 338 |
+
"step-distilled FLUX.3 model, which samples without classifier-free guidance (no negative prompt). Takes "
|
| 339 |
+
f"one prompt per call; it goes through the chat template and is right-padded to a multiple of "
|
| 340 |
+
f"{self.pad_multiple} tokens."
|
| 341 |
+
)
|
| 342 |
+
|
| 343 |
+
@property
|
| 344 |
+
def inputs(self) -> list[InputParam]:
|
| 345 |
+
return [
|
| 346 |
+
InputParam.template("prompt", description="The prompt to guide the generation (one prompt per call)"),
|
| 347 |
+
InputParam.template(
|
| 348 |
+
"max_sequence_length",
|
| 349 |
+
default=8192,
|
| 350 |
+
description="Maximum number of prompt tokens; longer prompts are truncated.",
|
| 351 |
+
),
|
| 352 |
+
InputParam(
|
| 353 |
+
"text_encoder_out_layers",
|
| 354 |
+
type_hint=tuple[int],
|
| 355 |
+
default=(4, 8, 12, 16, 20, 24, 28, 32),
|
| 356 |
+
required=False,
|
| 357 |
+
description="Indices of the text-encoder hidden layers whose states are stacked to form the text embeddings",
|
| 358 |
+
),
|
| 359 |
+
]
|
| 360 |
+
|
| 361 |
+
@property
|
| 362 |
+
def intermediate_outputs(self) -> list[OutputParam]:
|
| 363 |
+
return [
|
| 364 |
+
OutputParam(
|
| 365 |
+
"prompt_embeds",
|
| 366 |
+
kwargs_type="denoiser_input_fields",
|
| 367 |
+
type_hint=torch.Tensor,
|
| 368 |
+
description="Text embeddings (stacked Qwen3-VL hidden states) used to guide the image generation",
|
| 369 |
+
),
|
| 370 |
+
]
|
| 371 |
+
|
| 372 |
+
@staticmethod
|
| 373 |
+
def check_inputs(block_state):
|
| 374 |
+
if not isinstance(block_state.prompt, str):
|
| 375 |
+
raise ValueError(
|
| 376 |
+
f"`prompt` must be a str; batched prompts are not supported, got {type(block_state.prompt).__name__}."
|
| 377 |
+
)
|
| 378 |
+
|
| 379 |
+
@torch.no_grad()
|
| 380 |
+
def __call__(self, components: Flux3ModularPipeline, state: PipelineState) -> PipelineState:
|
| 381 |
+
block_state = self.get_block_state(state)
|
| 382 |
+
self.check_inputs(block_state)
|
| 383 |
+
|
| 384 |
+
block_state.prompt_embeds = self._get_qwen3_vl_prompt_embeds(
|
| 385 |
+
text_encoder=components.text_encoder,
|
| 386 |
+
tokenizer=components.tokenizer,
|
| 387 |
+
prompt=block_state.prompt,
|
| 388 |
+
device=components._execution_device,
|
| 389 |
+
max_sequence_length=block_state.max_sequence_length,
|
| 390 |
+
pad_multiple=self.pad_multiple,
|
| 391 |
+
hidden_states_layers=block_state.text_encoder_out_layers,
|
| 392 |
+
)
|
| 393 |
+
|
| 394 |
+
self.set_block_state(state, block_state)
|
| 395 |
+
return components, state
|
diffusers/modular_pipelines/flux3/inputs.py
CHANGED
|
@@ -173,6 +173,73 @@ class Flux3TextInputStep(ModularPipelineBlocks):
|
|
| 173 |
return components, state
|
| 174 |
|
| 175 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
class Flux3ImageCondInputStep(ModularPipelineBlocks):
|
| 177 |
model_name = "flux3"
|
| 178 |
|
|
|
|
| 173 |
return components, state
|
| 174 |
|
| 175 |
|
| 176 |
+
class Flux3DistilledTextInputStep(ModularPipelineBlocks):
|
| 177 |
+
model_name = "flux3-distilled"
|
| 178 |
+
|
| 179 |
+
@property
|
| 180 |
+
def description(self) -> str:
|
| 181 |
+
return (
|
| 182 |
+
"This step:\n"
|
| 183 |
+
" 1. Determines `batch_size` from `prompt_embeds` and the compute `dtype` from the transformer\n"
|
| 184 |
+
" 2. Repeats the text embeddings to the batch size (batch_size * num_images_per_prompt)\n"
|
| 185 |
+
"For the step-distilled FLUX.3 model, which samples without classifier-free guidance (no negative "
|
| 186 |
+
"embeddings)."
|
| 187 |
+
)
|
| 188 |
+
|
| 189 |
+
@property
|
| 190 |
+
def expected_components(self) -> list[ComponentSpec]:
|
| 191 |
+
return [ComponentSpec("transformer", Flux3Transformer2DModel)]
|
| 192 |
+
|
| 193 |
+
@property
|
| 194 |
+
def inputs(self) -> list[InputParam]:
|
| 195 |
+
return [
|
| 196 |
+
InputParam.template("num_images_per_prompt"),
|
| 197 |
+
InputParam(
|
| 198 |
+
"prompt_embeds",
|
| 199 |
+
required=True,
|
| 200 |
+
kwargs_type="denoiser_input_fields",
|
| 201 |
+
type_hint=torch.Tensor,
|
| 202 |
+
description="Pre-generated text embeddings. Can be generated from text_encoder step.",
|
| 203 |
+
),
|
| 204 |
+
]
|
| 205 |
+
|
| 206 |
+
@property
|
| 207 |
+
def intermediate_outputs(self) -> list[OutputParam]:
|
| 208 |
+
return [
|
| 209 |
+
OutputParam(
|
| 210 |
+
"batch_size",
|
| 211 |
+
type_hint=int,
|
| 212 |
+
description="Number of prompts, the final batch size of model inputs should be batch_size * num_images_per_prompt",
|
| 213 |
+
),
|
| 214 |
+
OutputParam(
|
| 215 |
+
"dtype",
|
| 216 |
+
type_hint=torch.dtype,
|
| 217 |
+
description="Data type of model tensor inputs (the transformer's dtype)",
|
| 218 |
+
),
|
| 219 |
+
OutputParam(
|
| 220 |
+
"prompt_embeds",
|
| 221 |
+
type_hint=torch.Tensor,
|
| 222 |
+
kwargs_type="denoiser_input_fields",
|
| 223 |
+
description="Text embeddings used to guide the image generation",
|
| 224 |
+
),
|
| 225 |
+
]
|
| 226 |
+
|
| 227 |
+
@torch.no_grad()
|
| 228 |
+
def __call__(self, components: Flux3ModularPipeline, state: PipelineState) -> PipelineState:
|
| 229 |
+
block_state = self.get_block_state(state)
|
| 230 |
+
|
| 231 |
+
block_state.batch_size = block_state.prompt_embeds.shape[0]
|
| 232 |
+
# the denoiser consumes every tensor this chain prepares, so its dtype is the compute dtype
|
| 233 |
+
block_state.dtype = components.transformer.dtype
|
| 234 |
+
|
| 235 |
+
block_state.prompt_embeds = repeat_tensor_to_batch_size(
|
| 236 |
+
"prompt_embeds", block_state.prompt_embeds, block_state.batch_size, block_state.num_images_per_prompt
|
| 237 |
+
).to(block_state.dtype)
|
| 238 |
+
|
| 239 |
+
self.set_block_state(state, block_state)
|
| 240 |
+
return components, state
|
| 241 |
+
|
| 242 |
+
|
| 243 |
class Flux3ImageCondInputStep(ModularPipelineBlocks):
|
| 244 |
model_name = "flux3"
|
| 245 |
|
diffusers/modular_pipelines/flux3/modular_blocks_flux3_distilled.py
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2026 Black Forest Labs and The HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
from ...utils import logging
|
| 17 |
+
from ..modular_pipeline import AutoPipelineBlocks, SequentialPipelineBlocks
|
| 18 |
+
from ..modular_pipeline_utils import InsertableDict, OutputParam
|
| 19 |
+
from .before_denoise import (
|
| 20 |
+
Flux3DistilledTextRoPEInputsStep,
|
| 21 |
+
Flux3PrepareImageCondLatentsStep,
|
| 22 |
+
Flux3PrepareLatentsStep,
|
| 23 |
+
Flux3SetTimestepsStep,
|
| 24 |
+
)
|
| 25 |
+
from .decoders import Flux3DecodeStep, Flux3UnpackLatentsStep
|
| 26 |
+
from .denoise import Flux3DistilledDenoiseStep
|
| 27 |
+
from .encoders import Flux3DistilledTextEncoderStep
|
| 28 |
+
from .inputs import Flux3DistilledTextInputStep, Flux3ImageCondInputStep
|
| 29 |
+
from .modular_blocks_flux3 import Flux3AutoVaeEncoderStep
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
logger = logging.get_logger(__name__) # pylint: disable=invalid-name
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# The step-distilled (flow-map) FLUX.3 checkpoints: 16 steps and no classifier-free guidance. The text encoder,
|
| 36 |
+
# text input, text RoPE and denoise steps have distilled versions without the negative prompt; the denoise loop
|
| 37 |
+
# passes the transformer the timestep each step jumps to and runs a single pass. Everything else is shared with the
|
| 38 |
+
# base model.
|
| 39 |
+
|
| 40 |
+
###
|
| 41 |
+
### Core denoise
|
| 42 |
+
###
|
| 43 |
+
|
| 44 |
+
Flux3DistilledCoreDenoiseBlocks = InsertableDict(
|
| 45 |
+
[
|
| 46 |
+
("input", Flux3DistilledTextInputStep()),
|
| 47 |
+
("prepare_latents", Flux3PrepareLatentsStep()),
|
| 48 |
+
("set_timesteps", Flux3SetTimestepsStep(num_inference_steps=16)),
|
| 49 |
+
("prepare_rope_inputs", Flux3DistilledTextRoPEInputsStep()),
|
| 50 |
+
("denoise", Flux3DistilledDenoiseStep()),
|
| 51 |
+
("after_denoise", Flux3UnpackLatentsStep()),
|
| 52 |
+
]
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
# auto_docstring
|
| 57 |
+
class Flux3DistilledCoreDenoiseStep(SequentialPipelineBlocks):
|
| 58 |
+
"""
|
| 59 |
+
Core denoise step that performs the denoising process for the step-distilled FLUX.3 model, for text-to-image
|
| 60 |
+
generation.
|
| 61 |
+
|
| 62 |
+
Components:
|
| 63 |
+
transformer (`Flux3Transformer2DModel`) scheduler (`FlowMatchEulerDiscreteScheduler`)
|
| 64 |
+
|
| 65 |
+
Inputs:
|
| 66 |
+
num_images_per_prompt (`int`, *optional*, defaults to 1):
|
| 67 |
+
The number of images to generate per prompt.
|
| 68 |
+
prompt_embeds (`Tensor`):
|
| 69 |
+
Pre-generated text embeddings. Can be generated from text_encoder step.
|
| 70 |
+
height (`int`, *optional*, defaults to 1024):
|
| 71 |
+
The height in pixels of the generated image.
|
| 72 |
+
width (`int`, *optional*, defaults to 1024):
|
| 73 |
+
The width in pixels of the generated image.
|
| 74 |
+
latents (`Tensor`, *optional*):
|
| 75 |
+
Pre-generated noisy latents for image generation.
|
| 76 |
+
generator (`Generator`, *optional*):
|
| 77 |
+
Torch generator for deterministic generation.
|
| 78 |
+
num_inference_steps (`int`, *optional*, defaults to 16):
|
| 79 |
+
The number of denoising steps.
|
| 80 |
+
timesteps (`Tensor`, *optional*):
|
| 81 |
+
Timesteps for the denoising process. (overrides `num_inference_steps` when provided)
|
| 82 |
+
sigmas (`list`, *optional*):
|
| 83 |
+
Custom sigmas for the denoising process. (overrides `num_inference_steps` when provided)
|
| 84 |
+
**denoiser_input_fields (`None`, *optional*):
|
| 85 |
+
conditional model inputs for the denoiser: e.g. prompt_embeds, negative_prompt_embeds, etc.
|
| 86 |
+
|
| 87 |
+
Outputs:
|
| 88 |
+
latents (`Tensor`):
|
| 89 |
+
Denoised latents.
|
| 90 |
+
"""
|
| 91 |
+
|
| 92 |
+
model_name = "flux3-distilled"
|
| 93 |
+
block_classes = Flux3DistilledCoreDenoiseBlocks.values()
|
| 94 |
+
block_names = Flux3DistilledCoreDenoiseBlocks.keys()
|
| 95 |
+
|
| 96 |
+
@property
|
| 97 |
+
def description(self):
|
| 98 |
+
return (
|
| 99 |
+
"Core denoise step that performs the denoising process for the step-distilled FLUX.3 model, for "
|
| 100 |
+
"text-to-image generation."
|
| 101 |
+
)
|
| 102 |
+
|
| 103 |
+
@property
|
| 104 |
+
def outputs(self):
|
| 105 |
+
return [
|
| 106 |
+
OutputParam.template("latents"),
|
| 107 |
+
]
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
Flux3DistilledImageConditionedCoreDenoiseBlocks = InsertableDict(
|
| 111 |
+
[
|
| 112 |
+
("input", Flux3DistilledTextInputStep()),
|
| 113 |
+
("cond_input", Flux3ImageCondInputStep()),
|
| 114 |
+
("prepare_latents", Flux3PrepareLatentsStep()),
|
| 115 |
+
("prepare_image_cond_latents", Flux3PrepareImageCondLatentsStep()),
|
| 116 |
+
("set_timesteps", Flux3SetTimestepsStep(num_inference_steps=16)),
|
| 117 |
+
("prepare_rope_inputs", Flux3DistilledTextRoPEInputsStep()),
|
| 118 |
+
("denoise", Flux3DistilledDenoiseStep()),
|
| 119 |
+
("after_denoise", Flux3UnpackLatentsStep()),
|
| 120 |
+
]
|
| 121 |
+
)
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
# auto_docstring
|
| 125 |
+
class Flux3DistilledImageConditionedCoreDenoiseStep(SequentialPipelineBlocks):
|
| 126 |
+
"""
|
| 127 |
+
Core denoise step that performs the denoising process for the step-distilled FLUX.3 model with reference images
|
| 128 |
+
(image-to-image).
|
| 129 |
+
|
| 130 |
+
Components:
|
| 131 |
+
transformer (`Flux3Transformer2DModel`) scheduler (`FlowMatchEulerDiscreteScheduler`)
|
| 132 |
+
|
| 133 |
+
Inputs:
|
| 134 |
+
num_images_per_prompt (`int`, *optional*, defaults to 1):
|
| 135 |
+
The number of images to generate per prompt.
|
| 136 |
+
prompt_embeds (`Tensor`):
|
| 137 |
+
Pre-generated text embeddings. Can be generated from text_encoder step.
|
| 138 |
+
image_cond_latents (`list`):
|
| 139 |
+
Normalized packed latents of the reference images, one tensor of shape (B, C, height_i//16, width_i//16)
|
| 140 |
+
per image
|
| 141 |
+
height (`int`, *optional*):
|
| 142 |
+
The height in pixels of the generated image; defaults to the first reference image's aspect ratio at the
|
| 143 |
+
default area
|
| 144 |
+
width (`int`, *optional*):
|
| 145 |
+
The width in pixels of the generated image; defaults to the first reference image's aspect ratio at the
|
| 146 |
+
default area
|
| 147 |
+
latents (`Tensor`, *optional*):
|
| 148 |
+
Pre-generated noisy latents for image generation.
|
| 149 |
+
generator (`Generator`, *optional*):
|
| 150 |
+
Torch generator for deterministic generation.
|
| 151 |
+
num_inference_steps (`int`, *optional*, defaults to 16):
|
| 152 |
+
The number of denoising steps.
|
| 153 |
+
timesteps (`Tensor`, *optional*):
|
| 154 |
+
Timesteps for the denoising process. (overrides `num_inference_steps` when provided)
|
| 155 |
+
sigmas (`list`, *optional*):
|
| 156 |
+
Custom sigmas for the denoising process. (overrides `num_inference_steps` when provided)
|
| 157 |
+
**denoiser_input_fields (`None`, *optional*):
|
| 158 |
+
conditional model inputs for the denoiser: e.g. prompt_embeds, negative_prompt_embeds, etc.
|
| 159 |
+
|
| 160 |
+
Outputs:
|
| 161 |
+
latents (`Tensor`):
|
| 162 |
+
Denoised latents.
|
| 163 |
+
"""
|
| 164 |
+
|
| 165 |
+
model_name = "flux3-distilled"
|
| 166 |
+
block_classes = Flux3DistilledImageConditionedCoreDenoiseBlocks.values()
|
| 167 |
+
block_names = Flux3DistilledImageConditionedCoreDenoiseBlocks.keys()
|
| 168 |
+
|
| 169 |
+
@property
|
| 170 |
+
def description(self):
|
| 171 |
+
return (
|
| 172 |
+
"Core denoise step that performs the denoising process for the step-distilled FLUX.3 model with reference "
|
| 173 |
+
"images (image-to-image)."
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
@property
|
| 177 |
+
def outputs(self):
|
| 178 |
+
return [
|
| 179 |
+
OutputParam.template("latents"),
|
| 180 |
+
]
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
# auto_docstring
|
| 184 |
+
class Flux3DistilledAutoCoreDenoiseStep(AutoPipelineBlocks):
|
| 185 |
+
"""
|
| 186 |
+
Core denoise step that selects the step-distilled FLUX.3 denoising workflow by the conditioning inputs.
|
| 187 |
+
- `Flux3DistilledImageConditionedCoreDenoiseStep` is used when `image_cond_latents` is provided
|
| 188 |
+
(image-to-image).
|
| 189 |
+
- `Flux3DistilledCoreDenoiseStep` is used otherwise (text-to-image).
|
| 190 |
+
|
| 191 |
+
Components:
|
| 192 |
+
transformer (`Flux3Transformer2DModel`) scheduler (`FlowMatchEulerDiscreteScheduler`)
|
| 193 |
+
|
| 194 |
+
Inputs:
|
| 195 |
+
num_images_per_prompt (`int`, *optional*, defaults to 1):
|
| 196 |
+
The number of images to generate per prompt.
|
| 197 |
+
prompt_embeds (`Tensor`):
|
| 198 |
+
Pre-generated text embeddings. Can be generated from text_encoder step.
|
| 199 |
+
image_cond_latents (`list`, *optional*):
|
| 200 |
+
Normalized packed latents of the reference images, one tensor of shape (B, C, height_i//16, width_i//16)
|
| 201 |
+
per image
|
| 202 |
+
height (`int`, *optional*, defaults to None or 1024, depending on the workflow):
|
| 203 |
+
The height in pixels of the generated image; defaults to the first reference image's aspect ratio at the
|
| 204 |
+
default area
|
| 205 |
+
width (`int`, *optional*, defaults to None or 1024, depending on the workflow):
|
| 206 |
+
The width in pixels of the generated image; defaults to the first reference image's aspect ratio at the
|
| 207 |
+
default area
|
| 208 |
+
latents (`Tensor`):
|
| 209 |
+
Pre-generated noisy latents for image generation.
|
| 210 |
+
generator (`Generator`, *optional*):
|
| 211 |
+
Torch generator for deterministic generation.
|
| 212 |
+
num_inference_steps (`int`):
|
| 213 |
+
The number of denoising steps.
|
| 214 |
+
timesteps (`Tensor`):
|
| 215 |
+
Timesteps for the denoising process. (overrides `num_inference_steps` when provided)
|
| 216 |
+
sigmas (`list`, *optional*):
|
| 217 |
+
Custom sigmas for the denoising process. (overrides `num_inference_steps` when provided)
|
| 218 |
+
**denoiser_input_fields (`None`, *optional*):
|
| 219 |
+
conditional model inputs for the denoiser: e.g. prompt_embeds, negative_prompt_embeds, etc.
|
| 220 |
+
|
| 221 |
+
Outputs:
|
| 222 |
+
latents (`Tensor`):
|
| 223 |
+
Denoised latents.
|
| 224 |
+
"""
|
| 225 |
+
|
| 226 |
+
model_name = "flux3-distilled"
|
| 227 |
+
block_classes = [Flux3DistilledImageConditionedCoreDenoiseStep, Flux3DistilledCoreDenoiseStep]
|
| 228 |
+
block_names = ["image_conditioned", "text2image"]
|
| 229 |
+
block_trigger_inputs = ["image_cond_latents", None]
|
| 230 |
+
|
| 231 |
+
@property
|
| 232 |
+
def description(self):
|
| 233 |
+
return (
|
| 234 |
+
"Core denoise step that selects the step-distilled FLUX.3 denoising workflow by the conditioning inputs.\n"
|
| 235 |
+
" - `Flux3DistilledImageConditionedCoreDenoiseStep` is used when `image_cond_latents` is provided "
|
| 236 |
+
"(image-to-image).\n"
|
| 237 |
+
" - `Flux3DistilledCoreDenoiseStep` is used otherwise (text-to-image)."
|
| 238 |
+
)
|
| 239 |
+
|
| 240 |
+
|
| 241 |
+
###
|
| 242 |
+
### Auto blocks
|
| 243 |
+
###
|
| 244 |
+
|
| 245 |
+
DISTILLED_AUTO_BLOCKS = InsertableDict(
|
| 246 |
+
[
|
| 247 |
+
("text_encoder", Flux3DistilledTextEncoderStep()),
|
| 248 |
+
("vae_encoder", Flux3AutoVaeEncoderStep()),
|
| 249 |
+
("denoise", Flux3DistilledAutoCoreDenoiseStep()),
|
| 250 |
+
("decode", Flux3DecodeStep()),
|
| 251 |
+
]
|
| 252 |
+
)
|
| 253 |
+
|
| 254 |
+
|
| 255 |
+
# auto_docstring
|
| 256 |
+
class Flux3DistilledAutoBlocks(SequentialPipelineBlocks):
|
| 257 |
+
"""
|
| 258 |
+
Auto blocks that perform text-to-image and image-to-image generation using the step-distilled FLUX.3 model (16
|
| 259 |
+
steps, no classifier-free guidance).
|
| 260 |
+
|
| 261 |
+
Supported workflows:
|
| 262 |
+
- `text2image`: requires `prompt`
|
| 263 |
+
- `image_conditioned`: requires `prompt`, `image`
|
| 264 |
+
|
| 265 |
+
Components:
|
| 266 |
+
text_encoder (`Qwen3VLForConditionalGeneration`) tokenizer (`AutoProcessor`) image_processor
|
| 267 |
+
(`Flux3ImageProcessor`) vae (`AutoencoderKLFlux2`) transformer (`Flux3Transformer2DModel`) scheduler
|
| 268 |
+
(`FlowMatchEulerDiscreteScheduler`)
|
| 269 |
+
|
| 270 |
+
Inputs:
|
| 271 |
+
prompt (`str`):
|
| 272 |
+
The prompt to guide the generation (one prompt per call)
|
| 273 |
+
max_sequence_length (`int`, *optional*, defaults to 8192):
|
| 274 |
+
Maximum number of prompt tokens; longer prompts are truncated.
|
| 275 |
+
text_encoder_out_layers (`tuple`, *optional*, defaults to (4, 8, 12, 16, 20, 24, 28, 32)):
|
| 276 |
+
Indices of the text-encoder hidden layers whose states are stacked to form the text embeddings
|
| 277 |
+
image (`Image | list`, *optional*):
|
| 278 |
+
The reference image or images to condition the generation on; each keeps its own resolution
|
| 279 |
+
(center-cropped to the 16-pixel grid)
|
| 280 |
+
num_images_per_prompt (`int`, *optional*, defaults to 1):
|
| 281 |
+
The number of images to generate per prompt.
|
| 282 |
+
image_cond_latents (`list`, *optional*):
|
| 283 |
+
Normalized packed latents of the reference images, one tensor of shape (B, C, height_i//16, width_i//16)
|
| 284 |
+
per image
|
| 285 |
+
height (`int`, *optional*, defaults to None or 1024, depending on the workflow):
|
| 286 |
+
The height in pixels of the generated image; defaults to the first reference image's aspect ratio at the
|
| 287 |
+
default area
|
| 288 |
+
width (`int`, *optional*, defaults to None or 1024, depending on the workflow):
|
| 289 |
+
The width in pixels of the generated image; defaults to the first reference image's aspect ratio at the
|
| 290 |
+
default area
|
| 291 |
+
latents (`Tensor`):
|
| 292 |
+
Pre-generated noisy latents for image generation.
|
| 293 |
+
generator (`Generator`, *optional*):
|
| 294 |
+
Torch generator for deterministic generation.
|
| 295 |
+
num_inference_steps (`int`):
|
| 296 |
+
The number of denoising steps.
|
| 297 |
+
timesteps (`Tensor`):
|
| 298 |
+
Timesteps for the denoising process. (overrides `num_inference_steps` when provided)
|
| 299 |
+
sigmas (`list`, *optional*):
|
| 300 |
+
Custom sigmas for the denoising process. (overrides `num_inference_steps` when provided)
|
| 301 |
+
**denoiser_input_fields (`None`, *optional*):
|
| 302 |
+
conditional model inputs for the denoiser: e.g. prompt_embeds, negative_prompt_embeds, etc.
|
| 303 |
+
output_type (`str`, *optional*, defaults to pil):
|
| 304 |
+
Output format: 'pil', 'np', 'pt'.
|
| 305 |
+
|
| 306 |
+
Outputs:
|
| 307 |
+
images (`list`):
|
| 308 |
+
Generated images.
|
| 309 |
+
latents (`Tensor`):
|
| 310 |
+
Denoised latents.
|
| 311 |
+
"""
|
| 312 |
+
|
| 313 |
+
model_name = "flux3-distilled"
|
| 314 |
+
block_classes = DISTILLED_AUTO_BLOCKS.values()
|
| 315 |
+
block_names = DISTILLED_AUTO_BLOCKS.keys()
|
| 316 |
+
_workflow_map = {
|
| 317 |
+
"text2image": {"prompt": True},
|
| 318 |
+
"image_conditioned": {"prompt": True, "image": True},
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
@property
|
| 322 |
+
def description(self):
|
| 323 |
+
return (
|
| 324 |
+
"Auto blocks that perform text-to-image and image-to-image generation using the step-distilled FLUX.3 "
|
| 325 |
+
"model (16 steps, no classifier-free guidance)."
|
| 326 |
+
)
|
| 327 |
+
|
| 328 |
+
@property
|
| 329 |
+
def outputs(self):
|
| 330 |
+
return [
|
| 331 |
+
OutputParam.template("images"),
|
| 332 |
+
OutputParam.template("latents"),
|
| 333 |
+
]
|
diffusers/modular_pipelines/flux3/modular_pipeline.py
CHANGED
|
@@ -46,3 +46,11 @@ class Flux3ModularPipeline(ModularPipeline):
|
|
| 46 |
if getattr(self, "guider", None) is None:
|
| 47 |
return False
|
| 48 |
return self.guider._enabled and self.guider.num_conditions > 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
if getattr(self, "guider", None) is None:
|
| 47 |
return False
|
| 48 |
return self.guider._enabled and self.guider.num_conditions > 1
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
class Flux3DistilledModularPipeline(Flux3ModularPipeline):
|
| 52 |
+
"""
|
| 53 |
+
A ModularPipeline for the step-distilled FLUX.3 model (16 steps, no classifier-free guidance).
|
| 54 |
+
"""
|
| 55 |
+
|
| 56 |
+
default_blocks_name = "Flux3DistilledAutoBlocks"
|
diffusers/modular_pipelines/modular_pipeline.py
CHANGED
|
@@ -141,6 +141,7 @@ MODULAR_PIPELINE_MAPPING = OrderedDict(
|
|
| 141 |
("flux2", _create_default_map_fn("Flux2ModularPipeline")),
|
| 142 |
("flux2-klein", _flux2_klein_map_fn),
|
| 143 |
("flux3", _create_default_map_fn("Flux3ModularPipeline")),
|
|
|
|
| 144 |
("ideogram4", _create_default_map_fn("Ideogram4ModularPipeline")),
|
| 145 |
("krea2", _krea2_map_fn),
|
| 146 |
("qwenimage", _create_default_map_fn("QwenImageModularPipeline")),
|
|
|
|
| 141 |
("flux2", _create_default_map_fn("Flux2ModularPipeline")),
|
| 142 |
("flux2-klein", _flux2_klein_map_fn),
|
| 143 |
("flux3", _create_default_map_fn("Flux3ModularPipeline")),
|
| 144 |
+
("flux3-distilled", _create_default_map_fn("Flux3DistilledModularPipeline")),
|
| 145 |
("ideogram4", _create_default_map_fn("Ideogram4ModularPipeline")),
|
| 146 |
("krea2", _krea2_map_fn),
|
| 147 |
("qwenimage", _create_default_map_fn("QwenImageModularPipeline")),
|
diffusers/pipelines/README.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🧨 Diffusers Pipelines
|
| 2 |
+
|
| 3 |
+
Pipelines provide a simple way to run state-of-the-art diffusion models in inference.
|
| 4 |
+
Most diffusion systems consist of multiple independently-trained models and highly adaptable scheduler
|
| 5 |
+
components - all of which are needed to have a functioning end-to-end diffusion system.
|
| 6 |
+
|
| 7 |
+
As an example, [Stable Diffusion](https://huggingface.co/blog/stable_diffusion) has three independently trained models:
|
| 8 |
+
- [Autoencoder](https://github.com/huggingface/diffusers/blob/5cbed8e0d157f65d3ddc2420dfd09f2df630e978/src/diffusers/models/vae.py#L392)
|
| 9 |
+
- [Conditional Unet](https://github.com/huggingface/diffusers/blob/5cbed8e0d157f65d3ddc2420dfd09f2df630e978/src/diffusers/models/unet_2d_condition.py#L12)
|
| 10 |
+
- [CLIP text encoder](https://huggingface.co/docs/transformers/main/en/model_doc/clip#transformers.CLIPTextModel)
|
| 11 |
+
- a scheduler component, [scheduler](https://github.com/huggingface/diffusers/blob/main/src/diffusers/schedulers/scheduling_pndm.py),
|
| 12 |
+
- a [CLIPImageProcessor](https://huggingface.co/docs/transformers/main/en/model_doc/clip#transformers.CLIPImageProcessor),
|
| 13 |
+
- as well as a [safety checker](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion/safety_checker.py).
|
| 14 |
+
All of these components are necessary to run stable diffusion in inference even though they were trained
|
| 15 |
+
or created independently from each other.
|
| 16 |
+
|
| 17 |
+
To that end, we strive to offer all open-sourced, state-of-the-art diffusion system under a unified API.
|
| 18 |
+
More specifically, we strive to provide pipelines that
|
| 19 |
+
- 1. can load the officially published weights and yield 1-to-1 the same outputs as the original implementation according to the corresponding paper (*e.g.* [LDMTextToImagePipeline](https://github.com/huggingface/diffusers/tree/main/src/diffusers/pipelines/latent_diffusion), uses the officially released weights of [High-Resolution Image Synthesis with Latent Diffusion Models](https://huggingface.co/papers/2112.10752)),
|
| 20 |
+
- 2. have a simple user interface to run the model in inference (see the [Pipelines API](#pipelines-api) section),
|
| 21 |
+
- 3. are easy to understand with code that is self-explanatory and can be read along-side the official paper (see [Pipelines summary](#pipelines-summary)),
|
| 22 |
+
- 4. can easily be contributed by the community (see the [Contribution](#contribution) section).
|
| 23 |
+
|
| 24 |
+
**Note** that pipelines do not (and should not) offer any training functionality.
|
| 25 |
+
If you are looking for *official* training examples, please have a look at [examples](https://github.com/huggingface/diffusers/tree/main/examples).
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
## Pipelines Summary
|
| 29 |
+
|
| 30 |
+
The following table summarizes all officially supported pipelines, their corresponding paper, and if
|
| 31 |
+
available a colab notebook to directly try them out.
|
| 32 |
+
|
| 33 |
+
| Pipeline | Source | Tasks | Colab
|
| 34 |
+
|-------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|:---:|:---:|
|
| 35 |
+
| [dance diffusion](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/dance_diffusion) | [**Dance Diffusion**](https://github.com/Harmonai-org/sample-generator) | *Unconditional Audio Generation* |
|
| 36 |
+
| [ddpm](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/ddpm) | [**Denoising Diffusion Probabilistic Models**](https://huggingface.co/papers/2006.11239) | *Unconditional Image Generation* |
|
| 37 |
+
| [ddim](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/ddim) | [**Denoising Diffusion Implicit Models**](https://huggingface.co/papers/2010.02502) | *Unconditional Image Generation* | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/diffusers/training_example.ipynb)
|
| 38 |
+
| [latent_diffusion](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/latent_diffusion) | [**High-Resolution Image Synthesis with Latent Diffusion Models**](https://huggingface.co/papers/2112.10752) | *Text-to-Image Generation* |
|
| 39 |
+
| [latent_diffusion_uncond](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/latent_diffusion_uncond) | [**High-Resolution Image Synthesis with Latent Diffusion Models**](https://huggingface.co/papers/2112.10752) | *Unconditional Image Generation* |
|
| 40 |
+
| [pndm](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/pndm) | [**Pseudo Numerical Methods for Diffusion Models on Manifolds**](https://huggingface.co/papers/2202.09778) | *Unconditional Image Generation* |
|
| 41 |
+
| [score_sde_ve](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/score_sde_ve) | [**Score-Based Generative Modeling through Stochastic Differential Equations**](https://openreview.net/forum?id=PxTIG12RRHS) | *Unconditional Image Generation* |
|
| 42 |
+
| [score_sde_vp](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/score_sde_vp) | [**Score-Based Generative Modeling through Stochastic Differential Equations**](https://openreview.net/forum?id=PxTIG12RRHS) | *Unconditional Image Generation* |
|
| 43 |
+
| [stable_diffusion](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion) | [**Stable Diffusion**](https://stability.ai/blog/stable-diffusion-public-release) | *Text-to-Image Generation* | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/diffusers/stable_diffusion.ipynb)
|
| 44 |
+
| [stable_diffusion](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion) | [**Stable Diffusion**](https://stability.ai/blog/stable-diffusion-public-release) | *Image-to-Image Text-Guided Generation* | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/diffusers/image_2_image_using_diffusers.ipynb)
|
| 45 |
+
| [stable_diffusion](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion) | [**Stable Diffusion**](https://stability.ai/blog/stable-diffusion-public-release) | *Text-Guided Image Inpainting* | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/diffusers/in_painting_with_stable_diffusion_using_diffusers.ipynb)
|
| 46 |
+
| [stochastic_karras_ve](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stochastic_karras_ve) | [**Elucidating the Design Space of Diffusion-Based Generative Models**](https://huggingface.co/papers/2206.00364) | *Unconditional Image Generation* |
|
| 47 |
+
|
| 48 |
+
**Note**: Pipelines are simple examples of how to play around with the diffusion systems as described in the corresponding papers.
|
| 49 |
+
However, most of them can be adapted to use different scheduler components or even different model components. Some pipeline examples are shown in the [Examples](#examples) below.
|
| 50 |
+
|
| 51 |
+
## Pipelines API
|
| 52 |
+
|
| 53 |
+
Diffusion models often consist of multiple independently-trained models or other previously existing components.
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
Each model has been trained independently on a different task and the scheduler can easily be swapped out and replaced with a different one.
|
| 57 |
+
During inference, we however want to be able to easily load all components and use them in inference - even if one component, *e.g.* CLIP's text encoder, originates from a different library, such as [Transformers](https://github.com/huggingface/transformers). To that end, all pipelines provide the following functionality:
|
| 58 |
+
|
| 59 |
+
- [`from_pretrained` method](https://github.com/huggingface/diffusers/blob/5cbed8e0d157f65d3ddc2420dfd09f2df630e978/src/diffusers/pipeline_utils.py#L139) that accepts a Hugging Face Hub repository id, *e.g.* [stable-diffusion-v1-5/stable-diffusion-v1-5](https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5) or a path to a local directory, *e.g.*
|
| 60 |
+
"./stable-diffusion". To correctly retrieve which models and components should be loaded, one has to provide a `model_index.json` file, *e.g.* [stable-diffusion-v1-5/stable-diffusion-v1-5/model_index.json](https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5/blob/main/model_index.json), which defines all components that should be
|
| 61 |
+
loaded into the pipelines. More specifically, for each model/component one needs to define the format `<name>: ["<library>", "<class name>"]`. `<name>` is the attribute name given to the loaded instance of `<class name>` which can be found in the library or pipeline folder called `"<library>"`.
|
| 62 |
+
- [`save_pretrained`](https://github.com/huggingface/diffusers/blob/5cbed8e0d157f65d3ddc2420dfd09f2df630e978/src/diffusers/pipeline_utils.py#L90) that accepts a local path, *e.g.* `./stable-diffusion` under which all models/components of the pipeline will be saved. For each component/model a folder is created inside the local path that is named after the given attribute name, *e.g.* `./stable_diffusion/unet`.
|
| 63 |
+
In addition, a `model_index.json` file is created at the root of the local path, *e.g.* `./stable_diffusion/model_index.json` so that the complete pipeline can again be instantiated
|
| 64 |
+
from the local path.
|
| 65 |
+
- [`to`](https://github.com/huggingface/diffusers/blob/5cbed8e0d157f65d3ddc2420dfd09f2df630e978/src/diffusers/pipeline_utils.py#L118) which accepts a `string` or `torch.device` to move all models that are of type `torch.nn.Module` to the passed device. The behavior is fully analogous to [PyTorch's `to` method](https://pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module.to).
|
| 66 |
+
- [`__call__`] method to use the pipeline in inference. `__call__` defines inference logic of the pipeline and should ideally encompass all aspects of it, from pre-processing to forwarding tensors to the different models and schedulers, as well as post-processing. The API of the `__call__` method can strongly vary from pipeline to pipeline. *E.g.* a text-to-image pipeline, such as [`StableDiffusionPipeline`](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion.py) should accept among other things the text prompt to generate the image. A pure image generation pipeline, such as [DDPMPipeline](https://github.com/huggingface/diffusers/tree/main/src/diffusers/pipelines/ddpm) on the other hand can be run without providing any inputs. To better understand what inputs can be adapted for
|
| 67 |
+
each pipeline, one should look directly into the respective pipeline.
|
| 68 |
+
|
| 69 |
+
**Note**: All pipelines have PyTorch's autograd disabled by decorating the `__call__` method with a [`torch.no_grad`](https://pytorch.org/docs/stable/generated/torch.no_grad.html) decorator because pipelines should
|
| 70 |
+
not be used for training. If you want to store the gradients during the forward pass, we recommend writing your own pipeline, see also our [community-examples](https://github.com/huggingface/diffusers/tree/main/examples/community)
|
| 71 |
+
|
| 72 |
+
## Contribution
|
| 73 |
+
|
| 74 |
+
We are more than happy about any contribution to the officially supported pipelines 🤗. We aspire
|
| 75 |
+
all of our pipelines to be **self-contained**, **easy-to-tweak**, **beginner-friendly** and for **one-purpose-only**.
|
| 76 |
+
|
| 77 |
+
- **Self-contained**: A pipeline shall be as self-contained as possible. More specifically, this means that all functionality should be either directly defined in the pipeline file itself, should be inherited from (and only from) the [`DiffusionPipeline` class](https://github.com/huggingface/diffusers/blob/5cbed8e0d157f65d3ddc2420dfd09f2df630e978/src/diffusers/pipeline_utils.py#L56) or be directly attached to the model and scheduler components of the pipeline.
|
| 78 |
+
- **Easy-to-use**: Pipelines should be extremely easy to use - one should be able to load the pipeline and
|
| 79 |
+
use it for its designated task, *e.g.* text-to-image generation, in just a couple of lines of code. Most
|
| 80 |
+
logic including pre-processing, an unrolled diffusion loop, and post-processing should all happen inside the `__call__` method.
|
| 81 |
+
- **Easy-to-tweak**: Certain pipelines will not be able to handle all use cases and tasks that you might like them to. If you want to use a certain pipeline for a specific use case that is not yet supported, you might have to copy the pipeline file and tweak the code to your needs. We try to make the pipeline code as readable as possible so that each part –from pre-processing to diffusing to post-processing– can easily be adapted. If you would like the community to benefit from your customized pipeline, we would love to see a contribution to our [community-examples](https://github.com/huggingface/diffusers/tree/main/examples/community). If you feel that an important pipeline should be part of the official pipelines but isn't, a contribution to the [official pipelines](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines) would be even better.
|
| 82 |
+
- **One-purpose-only**: Pipelines should be used for one task and one task only. Even if two tasks are very similar from a modeling point of view, *e.g.* image2image translation and in-painting, pipelines shall be used for one task only to keep them *easy-to-tweak* and *readable*.
|
| 83 |
+
|
| 84 |
+
## Examples
|
| 85 |
+
|
| 86 |
+
### Text-to-Image generation with Stable Diffusion
|
| 87 |
+
|
| 88 |
+
```python
|
| 89 |
+
# make sure you're logged in with `hf auth login`
|
| 90 |
+
from diffusers import StableDiffusionPipeline, LMSDiscreteScheduler
|
| 91 |
+
|
| 92 |
+
pipe = StableDiffusionPipeline.from_pretrained("stable-diffusion-v1-5/stable-diffusion-v1-5")
|
| 93 |
+
pipe = pipe.to("cuda")
|
| 94 |
+
|
| 95 |
+
prompt = "a photo of an astronaut riding a horse on mars"
|
| 96 |
+
image = pipe(prompt).images[0]
|
| 97 |
+
|
| 98 |
+
image.save("astronaut_rides_horse.png")
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
### Image-to-Image text-guided generation with Stable Diffusion
|
| 102 |
+
|
| 103 |
+
The `StableDiffusionImg2ImgPipeline` lets you pass a text prompt and an initial image to condition the generation of new images.
|
| 104 |
+
|
| 105 |
+
```python
|
| 106 |
+
import requests
|
| 107 |
+
from PIL import Image
|
| 108 |
+
from io import BytesIO
|
| 109 |
+
|
| 110 |
+
from diffusers import StableDiffusionImg2ImgPipeline
|
| 111 |
+
|
| 112 |
+
# load the pipeline
|
| 113 |
+
device = "cuda"
|
| 114 |
+
pipe = StableDiffusionImg2ImgPipeline.from_pretrained(
|
| 115 |
+
"stable-diffusion-v1-5/stable-diffusion-v1-5",
|
| 116 |
+
torch_dtype=torch.float16,
|
| 117 |
+
).to(device)
|
| 118 |
+
|
| 119 |
+
# let's download an initial image
|
| 120 |
+
url = "https://raw.githubusercontent.com/CompVis/stable-diffusion/main/assets/stable-samples/img2img/sketch-mountains-input.jpg"
|
| 121 |
+
|
| 122 |
+
response = requests.get(url)
|
| 123 |
+
init_image = Image.open(BytesIO(response.content)).convert("RGB")
|
| 124 |
+
init_image = init_image.resize((768, 512))
|
| 125 |
+
|
| 126 |
+
prompt = "A fantasy landscape, trending on artstation"
|
| 127 |
+
|
| 128 |
+
images = pipe(prompt=prompt, image=init_image, strength=0.75, guidance_scale=7.5).images
|
| 129 |
+
|
| 130 |
+
images[0].save("fantasy_landscape.png")
|
| 131 |
+
```
|
| 132 |
+
You can also run this example on colab [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/diffusers/image_2_image_using_diffusers.ipynb)
|
| 133 |
+
|
| 134 |
+
### Tweak prompts reusing seeds and latents
|
| 135 |
+
|
| 136 |
+
You can generate your own latents to reproduce results, or tweak your prompt on a specific result you liked. [This notebook](https://github.com/pcuenca/diffusers-examples/blob/main/notebooks/stable-diffusion-seeds.ipynb) shows how to do it step by step. You can also run it in Google Colab [](https://colab.research.google.com/github/pcuenca/diffusers-examples/blob/main/notebooks/stable-diffusion-seeds.ipynb).
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
### In-painting using Stable Diffusion
|
| 140 |
+
|
| 141 |
+
The `StableDiffusionInpaintPipeline` lets you edit specific parts of an image by providing a mask and text prompt.
|
| 142 |
+
|
| 143 |
+
```python
|
| 144 |
+
import PIL
|
| 145 |
+
import requests
|
| 146 |
+
import torch
|
| 147 |
+
from io import BytesIO
|
| 148 |
+
|
| 149 |
+
from diffusers import StableDiffusionInpaintPipeline
|
| 150 |
+
|
| 151 |
+
def download_image(url):
|
| 152 |
+
response = requests.get(url)
|
| 153 |
+
return PIL.Image.open(BytesIO(response.content)).convert("RGB")
|
| 154 |
+
|
| 155 |
+
img_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo.png"
|
| 156 |
+
mask_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo_mask.png"
|
| 157 |
+
|
| 158 |
+
init_image = download_image(img_url).resize((512, 512))
|
| 159 |
+
mask_image = download_image(mask_url).resize((512, 512))
|
| 160 |
+
|
| 161 |
+
pipe = StableDiffusionInpaintPipeline.from_pretrained(
|
| 162 |
+
"stable-diffusion-v1-5/stable-diffusion-inpainting",
|
| 163 |
+
torch_dtype=torch.float16,
|
| 164 |
+
)
|
| 165 |
+
pipe = pipe.to("cuda")
|
| 166 |
+
|
| 167 |
+
prompt = "Face of a yellow cat, high resolution, sitting on a park bench"
|
| 168 |
+
image = pipe(prompt=prompt, image=init_image, mask_image=mask_image).images[0]
|
| 169 |
+
```
|
| 170 |
+
|
| 171 |
+
You can also run this example on colab [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/diffusers/in_painting_with_stable_diffusion_using_diffusers.ipynb)
|
diffusers/pipelines/deprecated/README.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Deprecated Pipelines
|
| 2 |
+
|
| 3 |
+
This folder contains pipelines that have very low usage as measured by model downloads, issues and PRs. While you can still use the pipelines just as before, we will stop testing the pipelines and will not accept any changes to existing files.
|
diffusers/pipelines/stable_diffusion/README.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Stable Diffusion
|
| 2 |
+
|
| 3 |
+
## Overview
|
| 4 |
+
|
| 5 |
+
Stable Diffusion was proposed in [Stable Diffusion Announcement](https://stability.ai/blog/stable-diffusion-announcement) by Patrick Esser and Robin Rombach and the Stability AI team.
|
| 6 |
+
|
| 7 |
+
The summary of the model is the following:
|
| 8 |
+
|
| 9 |
+
*Stable Diffusion is a text-to-image model that will empower billions of people to create stunning art within seconds. It is a breakthrough in speed and quality meaning that it can run on consumer GPUs. You can see some of the amazing output that has been created by this model without pre or post-processing on this page. The model itself builds upon the work of the team at CompVis and Runway in their widely used latent diffusion model combined with insights from the conditional diffusion models by our lead generative AI developer Katherine Crowson, Dall-E 2 by Open AI, Imagen by Google Brain and many others. We are delighted that AI media generation is a cooperative field and hope it can continue this way to bring the gift of creativity to all.*
|
| 10 |
+
|
| 11 |
+
## Tips:
|
| 12 |
+
|
| 13 |
+
- Stable Diffusion has the same architecture as [Latent Diffusion](https://huggingface.co/papers/2112.10752) but uses a frozen CLIP Text Encoder instead of training the text encoder jointly with the diffusion model.
|
| 14 |
+
- An in-detail explanation of the Stable Diffusion model can be found under [Stable Diffusion with 🧨 Diffusers](https://huggingface.co/blog/stable_diffusion).
|
| 15 |
+
- If you don't want to rely on the Hugging Face Hub and having to pass a authentication token, you can
|
| 16 |
+
download the weights with `git lfs install; git clone https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5` and instead pass the local path to the cloned folder to `from_pretrained` as shown below.
|
| 17 |
+
- Stable Diffusion can work with a variety of different samplers as is shown below.
|
| 18 |
+
|
| 19 |
+
## Available Pipelines:
|
| 20 |
+
|
| 21 |
+
| Pipeline | Tasks | Colab
|
| 22 |
+
|---|---|:---:|
|
| 23 |
+
| [pipeline_stable_diffusion.py](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion.py) | *Text-to-Image Generation* | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/diffusers/training_example.ipynb)
|
| 24 |
+
| [pipeline_stable_diffusion_img2img](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion_img2img.py) | *Image-to-Image Text-Guided Generation* | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/diffusers/image_2_image_using_diffusers.ipynb)
|
| 25 |
+
| [pipeline_stable_diffusion_inpaint](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion_inpaint.py) | *Text-Guided Image Inpainting* | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/diffusers/in_painting_with_stable_diffusion_using_diffusers.ipynb)
|
| 26 |
+
|
| 27 |
+
## Examples:
|
| 28 |
+
|
| 29 |
+
### Using Stable Diffusion without being logged into the Hub.
|
| 30 |
+
|
| 31 |
+
If you want to download the model weights using a single Python line, you need to be logged in via `hf auth login`.
|
| 32 |
+
|
| 33 |
+
```python
|
| 34 |
+
from diffusers import DiffusionPipeline
|
| 35 |
+
|
| 36 |
+
pipeline = DiffusionPipeline.from_pretrained("stable-diffusion-v1-5/stable-diffusion-v1-5")
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
This however can make it difficult to build applications on top of `diffusers` as you will always have to pass the token around. A potential way to solve this issue is by downloading the weights to a local path `"./stable-diffusion-v1-5"`:
|
| 40 |
+
|
| 41 |
+
```
|
| 42 |
+
git lfs install
|
| 43 |
+
git clone https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5
|
| 44 |
+
```
|
| 45 |
+
|
| 46 |
+
and simply passing the local path to `from_pretrained`:
|
| 47 |
+
|
| 48 |
+
```python
|
| 49 |
+
from diffusers import StableDiffusionPipeline
|
| 50 |
+
|
| 51 |
+
pipe = StableDiffusionPipeline.from_pretrained("./stable-diffusion-v1-5")
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
### Text-to-Image with default PLMS scheduler
|
| 55 |
+
|
| 56 |
+
```python
|
| 57 |
+
# make sure you're logged in with `hf auth login`
|
| 58 |
+
from diffusers import StableDiffusionPipeline
|
| 59 |
+
|
| 60 |
+
pipe = StableDiffusionPipeline.from_pretrained("stable-diffusion-v1-5/stable-diffusion-v1-5")
|
| 61 |
+
pipe = pipe.to("cuda")
|
| 62 |
+
|
| 63 |
+
prompt = "a photo of an astronaut riding a horse on mars"
|
| 64 |
+
image = pipe(prompt).images[0]
|
| 65 |
+
|
| 66 |
+
image.save("astronaut_rides_horse.png")
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
### Text-to-Image with DDIM scheduler
|
| 70 |
+
|
| 71 |
+
```python
|
| 72 |
+
# make sure you're logged in with `hf auth login`
|
| 73 |
+
from diffusers import StableDiffusionPipeline, DDIMScheduler
|
| 74 |
+
|
| 75 |
+
scheduler = DDIMScheduler.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="scheduler")
|
| 76 |
+
|
| 77 |
+
pipe = StableDiffusionPipeline.from_pretrained(
|
| 78 |
+
"stable-diffusion-v1-5/stable-diffusion-v1-5",
|
| 79 |
+
scheduler=scheduler,
|
| 80 |
+
).to("cuda")
|
| 81 |
+
|
| 82 |
+
prompt = "a photo of an astronaut riding a horse on mars"
|
| 83 |
+
image = pipe(prompt).images[0]
|
| 84 |
+
|
| 85 |
+
image.save("astronaut_rides_horse.png")
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
### Text-to-Image with K-LMS scheduler
|
| 89 |
+
|
| 90 |
+
```python
|
| 91 |
+
# make sure you're logged in with `hf auth login`
|
| 92 |
+
from diffusers import StableDiffusionPipeline, LMSDiscreteScheduler
|
| 93 |
+
|
| 94 |
+
lms = LMSDiscreteScheduler.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="scheduler")
|
| 95 |
+
|
| 96 |
+
pipe = StableDiffusionPipeline.from_pretrained(
|
| 97 |
+
"stable-diffusion-v1-5/stable-diffusion-v1-5",
|
| 98 |
+
scheduler=lms,
|
| 99 |
+
).to("cuda")
|
| 100 |
+
|
| 101 |
+
prompt = "a photo of an astronaut riding a horse on mars"
|
| 102 |
+
image = pipe(prompt).images[0]
|
| 103 |
+
|
| 104 |
+
image.save("astronaut_rides_horse.png")
|
| 105 |
+
```
|
| 106 |
+
|
| 107 |
+
### CycleDiffusion using Stable Diffusion and DDIM scheduler
|
| 108 |
+
|
| 109 |
+
```python
|
| 110 |
+
import requests
|
| 111 |
+
import torch
|
| 112 |
+
from PIL import Image
|
| 113 |
+
from io import BytesIO
|
| 114 |
+
|
| 115 |
+
from diffusers import CycleDiffusionPipeline, DDIMScheduler
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
# load the scheduler. CycleDiffusion only supports stochastic schedulers.
|
| 119 |
+
|
| 120 |
+
# load the pipeline
|
| 121 |
+
# make sure you're logged in with `hf auth login`
|
| 122 |
+
model_id_or_path = "CompVis/stable-diffusion-v1-4"
|
| 123 |
+
scheduler = DDIMScheduler.from_pretrained(model_id_or_path, subfolder="scheduler")
|
| 124 |
+
pipe = CycleDiffusionPipeline.from_pretrained(model_id_or_path, scheduler=scheduler).to("cuda")
|
| 125 |
+
|
| 126 |
+
# let's download an initial image
|
| 127 |
+
url = "https://raw.githubusercontent.com/ChenWu98/cycle-diffusion/main/data/dalle2/An%20astronaut%20riding%20a%20horse.png"
|
| 128 |
+
response = requests.get(url)
|
| 129 |
+
init_image = Image.open(BytesIO(response.content)).convert("RGB")
|
| 130 |
+
init_image = init_image.resize((512, 512))
|
| 131 |
+
init_image.save("horse.png")
|
| 132 |
+
|
| 133 |
+
# let's specify a prompt
|
| 134 |
+
source_prompt = "An astronaut riding a horse"
|
| 135 |
+
prompt = "An astronaut riding an elephant"
|
| 136 |
+
|
| 137 |
+
# call the pipeline
|
| 138 |
+
image = pipe(
|
| 139 |
+
prompt=prompt,
|
| 140 |
+
source_prompt=source_prompt,
|
| 141 |
+
image=init_image,
|
| 142 |
+
num_inference_steps=100,
|
| 143 |
+
eta=0.1,
|
| 144 |
+
strength=0.8,
|
| 145 |
+
guidance_scale=2,
|
| 146 |
+
source_guidance_scale=1,
|
| 147 |
+
).images[0]
|
| 148 |
+
|
| 149 |
+
image.save("horse_to_elephant.png")
|
| 150 |
+
|
| 151 |
+
# let's try another example
|
| 152 |
+
# See more samples at the original repo: https://github.com/ChenWu98/cycle-diffusion
|
| 153 |
+
url = "https://raw.githubusercontent.com/ChenWu98/cycle-diffusion/main/data/dalle2/A%20black%20colored%20car.png"
|
| 154 |
+
response = requests.get(url)
|
| 155 |
+
init_image = Image.open(BytesIO(response.content)).convert("RGB")
|
| 156 |
+
init_image = init_image.resize((512, 512))
|
| 157 |
+
init_image.save("black.png")
|
| 158 |
+
|
| 159 |
+
source_prompt = "A black colored car"
|
| 160 |
+
prompt = "A blue colored car"
|
| 161 |
+
|
| 162 |
+
# call the pipeline
|
| 163 |
+
torch.manual_seed(0)
|
| 164 |
+
image = pipe(
|
| 165 |
+
prompt=prompt,
|
| 166 |
+
source_prompt=source_prompt,
|
| 167 |
+
image=init_image,
|
| 168 |
+
num_inference_steps=100,
|
| 169 |
+
eta=0.1,
|
| 170 |
+
strength=0.85,
|
| 171 |
+
guidance_scale=3,
|
| 172 |
+
source_guidance_scale=1,
|
| 173 |
+
).images[0]
|
| 174 |
+
|
| 175 |
+
image.save("black_to_blue.png")
|
| 176 |
+
```
|
diffusers/schedulers/README.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Schedulers
|
| 2 |
+
|
| 3 |
+
For more information on the schedulers, please refer to the [docs](https://huggingface.co/docs/diffusers/api/schedulers/overview).
|
diffusers/utils/dummy_torch_and_transformers_objects.py
CHANGED
|
@@ -227,6 +227,36 @@ class Flux3AutoBlocks(metaclass=DummyObject):
|
|
| 227 |
requires_backends(cls, ["torch", "transformers"])
|
| 228 |
|
| 229 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
class Flux3ModularPipeline(metaclass=DummyObject):
|
| 231 |
_backends = ["torch", "transformers"]
|
| 232 |
|
|
|
|
| 227 |
requires_backends(cls, ["torch", "transformers"])
|
| 228 |
|
| 229 |
|
| 230 |
+
class Flux3DistilledAutoBlocks(metaclass=DummyObject):
|
| 231 |
+
_backends = ["torch", "transformers"]
|
| 232 |
+
|
| 233 |
+
def __init__(self, *args, **kwargs):
|
| 234 |
+
requires_backends(self, ["torch", "transformers"])
|
| 235 |
+
|
| 236 |
+
@classmethod
|
| 237 |
+
def from_config(cls, *args, **kwargs):
|
| 238 |
+
requires_backends(cls, ["torch", "transformers"])
|
| 239 |
+
|
| 240 |
+
@classmethod
|
| 241 |
+
def from_pretrained(cls, *args, **kwargs):
|
| 242 |
+
requires_backends(cls, ["torch", "transformers"])
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
class Flux3DistilledModularPipeline(metaclass=DummyObject):
|
| 246 |
+
_backends = ["torch", "transformers"]
|
| 247 |
+
|
| 248 |
+
def __init__(self, *args, **kwargs):
|
| 249 |
+
requires_backends(self, ["torch", "transformers"])
|
| 250 |
+
|
| 251 |
+
@classmethod
|
| 252 |
+
def from_config(cls, *args, **kwargs):
|
| 253 |
+
requires_backends(cls, ["torch", "transformers"])
|
| 254 |
+
|
| 255 |
+
@classmethod
|
| 256 |
+
def from_pretrained(cls, *args, **kwargs):
|
| 257 |
+
requires_backends(cls, ["torch", "transformers"])
|
| 258 |
+
|
| 259 |
+
|
| 260 |
class Flux3ModularPipeline(metaclass=DummyObject):
|
| 261 |
_backends = ["torch", "transformers"]
|
| 262 |
|
examples/cat_window.webp
CHANGED
|
|
Git LFS Details
|
examples/woman1.webp
CHANGED
|
|
Git LFS Details
|
requirements.txt
CHANGED
|
@@ -13,3 +13,4 @@ pillow
|
|
| 13 |
huggingface_hub>=1.31.0,<2.0
|
| 14 |
gradio==5.49.1
|
| 15 |
spaces
|
|
|
|
|
|
| 13 |
huggingface_hub>=1.31.0,<2.0
|
| 14 |
gradio==5.49.1
|
| 15 |
spaces
|
| 16 |
+
aokit
|