Instructions to use BiliSakura/pMF-diffusers with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use BiliSakura/pMF-diffusers with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("BiliSakura/pMF-diffusers", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- Draw Things
- DiffusionBee
Update pMF-B-32/pipeline.py
Browse files- pMF-B-32/pipeline.py +54 -87
pMF-B-32/pipeline.py
CHANGED
|
@@ -1,34 +1,16 @@
|
|
| 1 |
-
|
| 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 |
-
"""Hub custom pipeline: PMFPipeline.
|
| 16 |
-
|
| 17 |
-
Load with native Hugging Face diffusers and trust_remote_code=True.
|
| 18 |
-
"""
|
| 19 |
|
| 20 |
from __future__ import annotations
|
| 21 |
|
|
|
|
| 22 |
import json
|
| 23 |
from pathlib import Path
|
| 24 |
-
from typing import Dict, List, Optional, Tuple, Union
|
| 25 |
|
| 26 |
import torch
|
| 27 |
from diffusers.pipelines.pipeline_utils import DiffusionPipeline, ImagePipelineOutput
|
| 28 |
-
from diffusers.schedulers import FlowMatchEulerDiscreteScheduler
|
| 29 |
from diffusers.utils.torch_utils import randn_tensor
|
| 30 |
|
| 31 |
-
|
| 32 |
DEFAULT_CFG_BY_MODEL: Dict[str, Dict[str, float]] = {
|
| 33 |
"pMF-B/16": {"guidance_scale": 7.5, "guidance_interval_min": 0.1, "guidance_interval_max": 0.8},
|
| 34 |
"pMF-B/32": {"guidance_scale": 6.5, "guidance_interval_min": 0.1, "guidance_interval_max": 0.7},
|
|
@@ -48,50 +30,37 @@ RECOMMENDED_NOISE_BY_MODEL: Dict[str, float] = {
|
|
| 48 |
}
|
| 49 |
|
| 50 |
|
| 51 |
-
def _set_pmf_timesteps(
|
| 52 |
-
scheduler: FlowMatchEulerDiscreteScheduler,
|
| 53 |
-
num_inference_steps: int,
|
| 54 |
-
device: torch.device,
|
| 55 |
-
) -> torch.Tensor:
|
| 56 |
-
r"""Set linear flow sigmas from 1.0 to 0.0 for pMF sampling."""
|
| 57 |
-
flow_sigmas = torch.linspace(1.0, 0.0, num_inference_steps + 1, device=device, dtype=torch.float32)
|
| 58 |
-
scheduler.set_timesteps(sigmas=flow_sigmas.tolist(), device=device)
|
| 59 |
-
return flow_sigmas
|
| 60 |
-
|
| 61 |
-
|
| 62 |
class PMFPipeline(DiffusionPipeline):
|
| 63 |
-
r"""
|
| 64 |
-
Pipeline for ImageNet class-conditional generation with Pixel Mean Flows (pMF).
|
| 65 |
-
|
| 66 |
-
Parameters:
|
| 67 |
-
transformer ([`PMFTransformer2DModel`]):
|
| 68 |
-
Class-conditioned pMF transformer that predicts mean-flow velocity.
|
| 69 |
-
scheduler ([`FlowMatchEulerDiscreteScheduler`]):
|
| 70 |
-
Built-in flow-matching Euler scheduler.
|
| 71 |
-
id2label (`dict[int, str]`, *optional*):
|
| 72 |
-
ImageNet class id to English label mapping.
|
| 73 |
-
"""
|
| 74 |
-
|
| 75 |
model_cpu_offload_seq = "transformer"
|
| 76 |
|
| 77 |
def __init__(
|
| 78 |
self,
|
| 79 |
-
transformer,
|
| 80 |
-
scheduler,
|
| 81 |
id2label: Optional[Dict[Union[int, str], str]] = None,
|
| 82 |
-
):
|
| 83 |
super().__init__()
|
| 84 |
if scheduler is None:
|
| 85 |
-
scheduler
|
| 86 |
-
num_train_timesteps=1000,
|
| 87 |
-
shift=1.0,
|
| 88 |
-
stochastic_sampling=False,
|
| 89 |
-
)
|
| 90 |
self.register_modules(transformer=transformer, scheduler=scheduler)
|
| 91 |
self._id2label = self._normalize_id2label(id2label)
|
| 92 |
self.labels = self._build_label2id(self._id2label)
|
| 93 |
self._labels_loaded_from_model_index = bool(self._id2label)
|
| 94 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
def _ensure_labels_loaded(self) -> None:
|
| 96 |
if self._labels_loaded_from_model_index:
|
| 97 |
return
|
|
@@ -152,8 +121,8 @@ class PMFPipeline(DiffusionPipeline):
|
|
| 152 |
if isinstance(class_labels, str):
|
| 153 |
return self.get_label_ids(class_labels)
|
| 154 |
if class_labels and isinstance(class_labels[0], str):
|
| 155 |
-
return self.get_label_ids(class_labels)
|
| 156 |
-
return
|
| 157 |
|
| 158 |
def _recommended_noise_scale(self) -> float:
|
| 159 |
model_type = getattr(self.transformer.config, "model_type", None)
|
|
@@ -168,6 +137,28 @@ class PMFPipeline(DiffusionPipeline):
|
|
| 168 |
return dict(DEFAULT_CFG_BY_MODEL[model_type])
|
| 169 |
return {"guidance_scale": 7.5, "guidance_interval_min": 0.1, "guidance_interval_max": 0.8}
|
| 170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
@torch.inference_mode()
|
| 172 |
def __call__(
|
| 173 |
self,
|
|
@@ -181,33 +172,6 @@ class PMFPipeline(DiffusionPipeline):
|
|
| 181 |
output_type: Optional[str] = "pil",
|
| 182 |
return_dict: bool = True,
|
| 183 |
) -> Union[ImagePipelineOutput, Tuple]:
|
| 184 |
-
r"""
|
| 185 |
-
Generate class-conditional images with pMF.
|
| 186 |
-
|
| 187 |
-
Args:
|
| 188 |
-
class_labels (`int`, `str`, or `list`):
|
| 189 |
-
ImageNet class id(s) or label name(s).
|
| 190 |
-
num_inference_steps (`int`, *optional*, defaults to 1):
|
| 191 |
-
Number of flow steps. pMF is typically used with 1 step.
|
| 192 |
-
guidance_scale (`float`, *optional*):
|
| 193 |
-
Classifier-free guidance scale. Defaults to model-specific preset.
|
| 194 |
-
guidance_interval_min (`float`, *optional*):
|
| 195 |
-
Lower bound of the CFG interval in normalized time.
|
| 196 |
-
guidance_interval_max (`float`, *optional*):
|
| 197 |
-
Upper bound of the CFG interval in normalized time.
|
| 198 |
-
noise_scale (`float`, *optional*):
|
| 199 |
-
Initial Gaussian noise scale. Defaults to model-specific preset.
|
| 200 |
-
generator (`torch.Generator`, *optional*):
|
| 201 |
-
Random generator for reproducibility.
|
| 202 |
-
output_type (`str`, *optional*, defaults to `"pil"`):
|
| 203 |
-
Output format: `"pil"`, `"np"`, or `"pt"`.
|
| 204 |
-
return_dict (`bool`, *optional*, defaults to `True`):
|
| 205 |
-
Whether to return an [`~pipelines.ImagePipelineOutput`].
|
| 206 |
-
|
| 207 |
-
Returns:
|
| 208 |
-
[`~pipelines.ImagePipelineOutput`] or `tuple`:
|
| 209 |
-
Generated images.
|
| 210 |
-
"""
|
| 211 |
if num_inference_steps < 1:
|
| 212 |
raise ValueError("num_inference_steps must be >= 1.")
|
| 213 |
if output_type not in {"pil", "np", "pt"}:
|
|
@@ -247,15 +211,17 @@ class PMFPipeline(DiffusionPipeline):
|
|
| 247 |
t_min = torch.full((batch_size,), guidance_interval_min, device=device, dtype=dtype)
|
| 248 |
t_max = torch.full((batch_size,), guidance_interval_max, device=device, dtype=dtype)
|
| 249 |
|
| 250 |
-
|
|
|
|
|
|
|
| 251 |
|
| 252 |
for step_index in self.progress_bar(range(num_inference_steps)):
|
| 253 |
-
t =
|
| 254 |
-
t_next =
|
| 255 |
h = (t - t_next).expand(batch_size).to(device=device, dtype=dtype)
|
| 256 |
t_batch = t.expand(batch_size).to(device=device, dtype=dtype)
|
| 257 |
|
| 258 |
-
|
| 259 |
sample=latents,
|
| 260 |
timestep=t_batch,
|
| 261 |
class_labels=class_labels_t,
|
|
@@ -263,9 +229,8 @@ class PMFPipeline(DiffusionPipeline):
|
|
| 263 |
omega=omega,
|
| 264 |
guidance_interval_min=t_min,
|
| 265 |
guidance_interval_max=t_max,
|
| 266 |
-
return_dict=True,
|
| 267 |
)
|
| 268 |
-
latents = self.scheduler.step(
|
| 269 |
|
| 270 |
images_pt = ((latents.float().clamp(-1, 1) + 1.0) / 2.0).cpu()
|
| 271 |
if output_type == "pt":
|
|
@@ -283,3 +248,5 @@ class PMFPipeline(DiffusionPipeline):
|
|
| 283 |
|
| 284 |
|
| 285 |
PMFPipelineOutput = ImagePipelineOutput
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Hub custom pipeline: PMFPipeline."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
from __future__ import annotations
|
| 4 |
|
| 5 |
+
import inspect
|
| 6 |
import json
|
| 7 |
from pathlib import Path
|
| 8 |
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
| 9 |
|
| 10 |
import torch
|
| 11 |
from diffusers.pipelines.pipeline_utils import DiffusionPipeline, ImagePipelineOutput
|
|
|
|
| 12 |
from diffusers.utils.torch_utils import randn_tensor
|
| 13 |
|
|
|
|
| 14 |
DEFAULT_CFG_BY_MODEL: Dict[str, Dict[str, float]] = {
|
| 15 |
"pMF-B/16": {"guidance_scale": 7.5, "guidance_interval_min": 0.1, "guidance_interval_max": 0.8},
|
| 16 |
"pMF-B/32": {"guidance_scale": 6.5, "guidance_interval_min": 0.1, "guidance_interval_max": 0.7},
|
|
|
|
| 30 |
}
|
| 31 |
|
| 32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
class PMFPipeline(DiffusionPipeline):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
model_cpu_offload_seq = "transformer"
|
| 35 |
|
| 36 |
def __init__(
|
| 37 |
self,
|
| 38 |
+
transformer: Any,
|
| 39 |
+
scheduler: Any,
|
| 40 |
id2label: Optional[Dict[Union[int, str], str]] = None,
|
| 41 |
+
) -> None:
|
| 42 |
super().__init__()
|
| 43 |
if scheduler is None:
|
| 44 |
+
raise ValueError("PMFPipeline requires a scheduler loaded from the checkpoint.")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
self.register_modules(transformer=transformer, scheduler=scheduler)
|
| 46 |
self._id2label = self._normalize_id2label(id2label)
|
| 47 |
self.labels = self._build_label2id(self._id2label)
|
| 48 |
self._labels_loaded_from_model_index = bool(self._id2label)
|
| 49 |
|
| 50 |
+
@staticmethod
|
| 51 |
+
def prepare_extra_step_kwargs(
|
| 52 |
+
scheduler: Any,
|
| 53 |
+
generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
|
| 54 |
+
eta: float | None = None,
|
| 55 |
+
) -> Dict[str, Any]:
|
| 56 |
+
kwargs: Dict[str, Any] = {}
|
| 57 |
+
step_params = set(inspect.signature(scheduler.step).parameters.keys())
|
| 58 |
+
if "generator" in step_params:
|
| 59 |
+
kwargs["generator"] = generator
|
| 60 |
+
if eta is not None and "eta" in step_params:
|
| 61 |
+
kwargs["eta"] = eta
|
| 62 |
+
return kwargs
|
| 63 |
+
|
| 64 |
def _ensure_labels_loaded(self) -> None:
|
| 65 |
if self._labels_loaded_from_model_index:
|
| 66 |
return
|
|
|
|
| 121 |
if isinstance(class_labels, str):
|
| 122 |
return self.get_label_ids(class_labels)
|
| 123 |
if class_labels and isinstance(class_labels[0], str):
|
| 124 |
+
return self.get_label_ids(class_labels) # type: ignore[arg-type]
|
| 125 |
+
return [int(class_id) for class_id in class_labels]
|
| 126 |
|
| 127 |
def _recommended_noise_scale(self) -> float:
|
| 128 |
model_type = getattr(self.transformer.config, "model_type", None)
|
|
|
|
| 137 |
return dict(DEFAULT_CFG_BY_MODEL[model_type])
|
| 138 |
return {"guidance_scale": 7.5, "guidance_interval_min": 0.1, "guidance_interval_max": 0.8}
|
| 139 |
|
| 140 |
+
def predict_u(
|
| 141 |
+
self,
|
| 142 |
+
sample: torch.Tensor,
|
| 143 |
+
timestep: torch.Tensor,
|
| 144 |
+
class_labels: torch.Tensor,
|
| 145 |
+
h: torch.Tensor,
|
| 146 |
+
omega: torch.Tensor,
|
| 147 |
+
guidance_interval_min: torch.Tensor,
|
| 148 |
+
guidance_interval_max: torch.Tensor,
|
| 149 |
+
) -> torch.Tensor:
|
| 150 |
+
output = self.transformer(
|
| 151 |
+
sample=sample,
|
| 152 |
+
timestep=timestep,
|
| 153 |
+
class_labels=class_labels,
|
| 154 |
+
h=h,
|
| 155 |
+
omega=omega,
|
| 156 |
+
guidance_interval_min=guidance_interval_min,
|
| 157 |
+
guidance_interval_max=guidance_interval_max,
|
| 158 |
+
return_dict=True,
|
| 159 |
+
)
|
| 160 |
+
return output.u
|
| 161 |
+
|
| 162 |
@torch.inference_mode()
|
| 163 |
def __call__(
|
| 164 |
self,
|
|
|
|
| 172 |
output_type: Optional[str] = "pil",
|
| 173 |
return_dict: bool = True,
|
| 174 |
) -> Union[ImagePipelineOutput, Tuple]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
if num_inference_steps < 1:
|
| 176 |
raise ValueError("num_inference_steps must be >= 1.")
|
| 177 |
if output_type not in {"pil", "np", "pt"}:
|
|
|
|
| 211 |
t_min = torch.full((batch_size,), guidance_interval_min, device=device, dtype=dtype)
|
| 212 |
t_max = torch.full((batch_size,), guidance_interval_max, device=device, dtype=dtype)
|
| 213 |
|
| 214 |
+
self.scheduler.set_timesteps(num_inference_steps, device=device)
|
| 215 |
+
extra_step_kwargs = self.prepare_extra_step_kwargs(self.scheduler, generator=generator)
|
| 216 |
+
timesteps = self.scheduler.timesteps
|
| 217 |
|
| 218 |
for step_index in self.progress_bar(range(num_inference_steps)):
|
| 219 |
+
t = timesteps[step_index]
|
| 220 |
+
t_next = timesteps[step_index + 1]
|
| 221 |
h = (t - t_next).expand(batch_size).to(device=device, dtype=dtype)
|
| 222 |
t_batch = t.expand(batch_size).to(device=device, dtype=dtype)
|
| 223 |
|
| 224 |
+
u = self.predict_u(
|
| 225 |
sample=latents,
|
| 226 |
timestep=t_batch,
|
| 227 |
class_labels=class_labels_t,
|
|
|
|
| 229 |
omega=omega,
|
| 230 |
guidance_interval_min=t_min,
|
| 231 |
guidance_interval_max=t_max,
|
|
|
|
| 232 |
)
|
| 233 |
+
latents = self.scheduler.step(u, t, latents, **extra_step_kwargs).prev_sample
|
| 234 |
|
| 235 |
images_pt = ((latents.float().clamp(-1, 1) + 1.0) / 2.0).cpu()
|
| 236 |
if output_type == "pt":
|
|
|
|
| 248 |
|
| 249 |
|
| 250 |
PMFPipelineOutput = ImagePipelineOutput
|
| 251 |
+
|
| 252 |
+
__all__ = ["PMFPipeline", "PMFPipelineOutput"]
|