Professional Noob commited on
Update qwenimage/pipeline_qwenimage_edit_plus.py
Browse files
qwenimage/pipeline_qwenimage_edit_plus.py
CHANGED
|
@@ -166,13 +166,46 @@ def calculate_dimensions(target_area: int, ratio: float, multiple: int = 32):
|
|
| 166 |
# Optional: decoder VAE (Wan2x)
|
| 167 |
_ALT_VAE_WAN2X = None
|
| 168 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
|
| 170 |
def _get_wan2x_vae(device: torch.device, dtype: torch.dtype):
|
| 171 |
"""
|
| 172 |
Decoder-only finetune that outputs 2x resolution via pixel-shuffle.
|
| 173 |
Lazy-loaded so it doesn't impact startup unless used.
|
| 174 |
"""
|
| 175 |
-
global _ALT_VAE_WAN2X
|
| 176 |
if _ALT_VAE_WAN2X is None:
|
| 177 |
from diffusers import AutoencoderKLWan
|
| 178 |
|
|
@@ -182,7 +215,15 @@ def _get_wan2x_vae(device: torch.device, dtype: torch.dtype):
|
|
| 182 |
torch_dtype=dtype,
|
| 183 |
)
|
| 184 |
_ALT_VAE_WAN2X.eval()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 185 |
_ALT_VAE_WAN2X = _ALT_VAE_WAN2X.to(device=device, dtype=dtype)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
return _ALT_VAE_WAN2X
|
| 187 |
|
| 188 |
|
|
@@ -220,6 +261,9 @@ class QwenImageEditPlusPipeline(DiffusionPipeline, QwenImageLoraLoaderMixin):
|
|
| 220 |
self.image_processor = VaeImageProcessor(vae_scale_factor=self.vae_scale_factor * 2)
|
| 221 |
self.tokenizer_max_length = 1024
|
| 222 |
|
|
|
|
|
|
|
|
|
|
| 223 |
self.prompt_template_encode = (
|
| 224 |
"<|im_start|>system\n"
|
| 225 |
"Describe the key features of the input image (color, shape, size, texture, objects, background), "
|
|
@@ -230,6 +274,32 @@ class QwenImageEditPlusPipeline(DiffusionPipeline, QwenImageLoraLoaderMixin):
|
|
| 230 |
self.prompt_template_encode_start_idx = 64
|
| 231 |
self.default_sample_size = 128
|
| 232 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
# Copied from diffusers.pipelines.qwenimage.pipeline_qwenimage.QwenImagePipeline._extract_masked_hidden
|
| 234 |
def _extract_masked_hidden(self, hidden_states: torch.Tensor, mask: torch.Tensor):
|
| 235 |
bool_mask = mask.bool()
|
|
|
|
| 166 |
# Optional: decoder VAE (Wan2x)
|
| 167 |
_ALT_VAE_WAN2X = None
|
| 168 |
|
| 169 |
+
# Track desired tiling state for the optional decoder VAE, so it stays consistent across lazy loads.
|
| 170 |
+
_ALT_VAE_WAN2X_TILING_ENABLED = False
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def _set_vae_tiling(model: Any, enabled: bool) -> bool:
|
| 174 |
+
"""
|
| 175 |
+
Best-effort tiling toggle for a VAE-like module.
|
| 176 |
+
Returns True if a tiling method existed and was called, False otherwise.
|
| 177 |
+
"""
|
| 178 |
+
if model is None:
|
| 179 |
+
return False
|
| 180 |
+
try:
|
| 181 |
+
if enabled:
|
| 182 |
+
if hasattr(model, "enable_tiling"):
|
| 183 |
+
model.enable_tiling()
|
| 184 |
+
return True
|
| 185 |
+
if hasattr(model, "enable_vae_tiling"):
|
| 186 |
+
model.enable_vae_tiling()
|
| 187 |
+
return True
|
| 188 |
+
else:
|
| 189 |
+
if hasattr(model, "disable_tiling"):
|
| 190 |
+
model.disable_tiling()
|
| 191 |
+
return True
|
| 192 |
+
if hasattr(model, "disable_vae_tiling"):
|
| 193 |
+
model.disable_vae_tiling()
|
| 194 |
+
return True
|
| 195 |
+
except Exception as e:
|
| 196 |
+
# Don't hard-fail inference if tiling toggle fails for an alt decoder.
|
| 197 |
+
logger.warning(f"VAE tiling toggle failed on {type(model)}: {e}")
|
| 198 |
+
return False
|
| 199 |
+
return False
|
| 200 |
+
|
| 201 |
+
|
| 202 |
|
| 203 |
def _get_wan2x_vae(device: torch.device, dtype: torch.dtype):
|
| 204 |
"""
|
| 205 |
Decoder-only finetune that outputs 2x resolution via pixel-shuffle.
|
| 206 |
Lazy-loaded so it doesn't impact startup unless used.
|
| 207 |
"""
|
| 208 |
+
global _ALT_VAE_WAN2X, _ALT_VAE_WAN2X_TILING_ENABLED
|
| 209 |
if _ALT_VAE_WAN2X is None:
|
| 210 |
from diffusers import AutoencoderKLWan
|
| 211 |
|
|
|
|
| 215 |
torch_dtype=dtype,
|
| 216 |
)
|
| 217 |
_ALT_VAE_WAN2X.eval()
|
| 218 |
+
|
| 219 |
+
# Apply last requested tiling immediately on first load (if supported).
|
| 220 |
+
_set_vae_tiling(_ALT_VAE_WAN2X, _ALT_VAE_WAN2X_TILING_ENABLED)
|
| 221 |
+
|
| 222 |
_ALT_VAE_WAN2X = _ALT_VAE_WAN2X.to(device=device, dtype=dtype)
|
| 223 |
+
|
| 224 |
+
# Re-apply after moving to device, just in case.
|
| 225 |
+
_set_vae_tiling(_ALT_VAE_WAN2X, _ALT_VAE_WAN2X_TILING_ENABLED)
|
| 226 |
+
|
| 227 |
return _ALT_VAE_WAN2X
|
| 228 |
|
| 229 |
|
|
|
|
| 261 |
self.image_processor = VaeImageProcessor(vae_scale_factor=self.vae_scale_factor * 2)
|
| 262 |
self.tokenizer_max_length = 1024
|
| 263 |
|
| 264 |
+
|
| 265 |
+
# Track tiling state (applies to both primary VAE and optional decoder VAE)
|
| 266 |
+
self._vae_tiling_enabled = False
|
| 267 |
self.prompt_template_encode = (
|
| 268 |
"<|im_start|>system\n"
|
| 269 |
"Describe the key features of the input image (color, shape, size, texture, objects, background), "
|
|
|
|
| 274 |
self.prompt_template_encode_start_idx = 64
|
| 275 |
self.default_sample_size = 128
|
| 276 |
|
| 277 |
+
|
| 278 |
+
# ------------------------------------------------------------
|
| 279 |
+
# VAE tiling control (applies to both primary VAE and optional decoder VAE)
|
| 280 |
+
# ------------------------------------------------------------
|
| 281 |
+
# Expose a stable API so app.py can call pipe.enable_vae_tiling()/disable_vae_tiling()
|
| 282 |
+
# regardless of which decoder VAE is selected at runtime.
|
| 283 |
+
|
| 284 |
+
def set_vae_tiling(self, enabled: bool) -> None:
|
| 285 |
+
global _ALT_VAE_WAN2X_TILING_ENABLED, _ALT_VAE_WAN2X
|
| 286 |
+
|
| 287 |
+
enabled = bool(enabled)
|
| 288 |
+
self._vae_tiling_enabled = enabled
|
| 289 |
+
|
| 290 |
+
# 1) Primary VAE (Qwen)
|
| 291 |
+
_set_vae_tiling(getattr(self, "vae", None), enabled)
|
| 292 |
+
|
| 293 |
+
# 2) Optional decoder VAE (Wan2x): store desired global state; apply now if already loaded.
|
| 294 |
+
_ALT_VAE_WAN2X_TILING_ENABLED = enabled
|
| 295 |
+
if _ALT_VAE_WAN2X is not None:
|
| 296 |
+
_set_vae_tiling(_ALT_VAE_WAN2X, enabled)
|
| 297 |
+
|
| 298 |
+
def enable_vae_tiling(self) -> None:
|
| 299 |
+
self.set_vae_tiling(True)
|
| 300 |
+
|
| 301 |
+
def disable_vae_tiling(self) -> None:
|
| 302 |
+
self.set_vae_tiling(False)
|
| 303 |
# Copied from diffusers.pipelines.qwenimage.pipeline_qwenimage.QwenImagePipeline._extract_masked_hidden
|
| 304 |
def _extract_masked_hidden(self, hidden_states: torch.Tensor, mask: torch.Tensor):
|
| 305 |
bool_mask = mask.bool()
|