Update app.py
Browse files
app.py
CHANGED
|
@@ -61,6 +61,8 @@ from ltx_pipelines.utils.helpers import (
|
|
| 61 |
simple_denoising_func,
|
| 62 |
)
|
| 63 |
from ltx_pipelines.utils.media_io import decode_audio_from_file, encode_video
|
|
|
|
|
|
|
| 64 |
|
| 65 |
# Force-patch xformers attention into the LTX attention module.
|
| 66 |
from ltx_core.model.transformer import attention as _attn_mod
|
|
@@ -298,122 +300,86 @@ pipeline = LTX23DistilledA2VPipeline(
|
|
| 298 |
)
|
| 299 |
# ----------------------------------------------------------------
|
| 300 |
|
| 301 |
-
# ---- REPLACE apply_loras_to_pipeline WITH THIS IMPLEMENTATION ----
|
| 302 |
def apply_loras_to_pipeline(pose_strength: float, general_strength: float, motion_strength: float):
|
| 303 |
"""
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
|
|
|
|
|
|
|
|
|
| 310 |
"""
|
| 311 |
ledger = pipeline.model_ledger
|
| 312 |
|
| 313 |
-
# Build convenience list
|
| 314 |
-
|
| 315 |
(pose_lora_path, float(pose_strength)),
|
| 316 |
(general_lora_path, float(general_strength)),
|
| 317 |
(motion_lora_path, float(motion_strength)),
|
| 318 |
]
|
| 319 |
|
| 320 |
-
#
|
| 321 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 322 |
|
| 323 |
-
|
|
|
|
| 324 |
try:
|
| 325 |
-
#
|
| 326 |
-
if hasattr(
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
except Exception:
|
| 330 |
-
# fallback: reassign
|
| 331 |
-
try:
|
| 332 |
-
setattr(builder, "loras", [])
|
| 333 |
-
except Exception:
|
| 334 |
-
pass
|
| 335 |
-
|
| 336 |
-
# If there is an explicit builder.lora(...) helper, use it to register LoRAs.
|
| 337 |
-
if hasattr(builder, "lora"):
|
| 338 |
-
for path, strength in lora_entries:
|
| 339 |
-
try:
|
| 340 |
-
if path is None:
|
| 341 |
-
continue
|
| 342 |
-
# Always register (builder.lora should create the proper LoRA object expected by build).
|
| 343 |
-
# The builder may accept strength==0.0; if not, register only >0.0 to avoid extra work.
|
| 344 |
-
if float(strength) != 0.0:
|
| 345 |
-
builder.lora(path, float(strength))
|
| 346 |
-
except Exception as e:
|
| 347 |
-
print(f"[LoRA] builder.lora(...) failed for {path}: {type(e).__name__}: {e}")
|
| 348 |
-
else:
|
| 349 |
-
# If there's no builder.lora helper, try to append sensible objects into builder.loras.
|
| 350 |
-
# We don't know the exact LoRA object type, so we skip if we can't.
|
| 351 |
-
print("[LoRA] builder has no 'lora' helper; attempting to set builder.loras to an empty list.")
|
| 352 |
-
try:
|
| 353 |
-
setattr(builder, "loras", [])
|
| 354 |
-
except Exception:
|
| 355 |
-
pass
|
| 356 |
-
|
| 357 |
-
# Use the saved original transformer factory to (re)create a transformer using the mutated builder.
|
| 358 |
-
# The original factory should call builder.build(...) internally.
|
| 359 |
-
if "_orig_transformer_factory" in globals():
|
| 360 |
-
print("[LoRA] Rebuilding transformer from builder and hot-swapping into ledger...")
|
| 361 |
-
try:
|
| 362 |
-
new_transformer = _orig_transformer_factory()
|
| 363 |
-
# free previous cached transformer to reduce peak memory
|
| 364 |
-
global _transformer
|
| 365 |
-
try:
|
| 366 |
-
# delete previous Python ref and empty cache; underlying CUDA memory should be released when
|
| 367 |
-
# the module is garbage-collected. We proactively call torch.cuda.empty_cache().
|
| 368 |
-
del _transformer
|
| 369 |
-
except Exception:
|
| 370 |
-
pass
|
| 371 |
-
torch.cuda.empty_cache()
|
| 372 |
-
|
| 373 |
-
# install new transformer as the one returned by ledger.transformer()
|
| 374 |
-
_transformer = new_transformer
|
| 375 |
-
ledger.transformer = lambda: _transformer
|
| 376 |
-
print("[LoRA] Transformer rebuilt and hot-swapped successfully.")
|
| 377 |
-
return
|
| 378 |
-
except Exception as e:
|
| 379 |
-
print(f"[LoRA] Error while rebuilding transformer via original factory: {type(e).__name__}: {e}")
|
| 380 |
-
# fallthrough to other attempts
|
| 381 |
-
else:
|
| 382 |
-
print("[LoRA] _orig_transformer_factory is not available; cannot rebuild transformer via builder.")
|
| 383 |
except Exception as e:
|
| 384 |
-
print(f"[LoRA]
|
| 385 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 386 |
|
| 387 |
-
# 2) Try high-level APIs if present (some pipeline/ledger versions expose helpers)
|
| 388 |
-
try:
|
| 389 |
-
if hasattr(ledger, "apply_loras"):
|
| 390 |
-
print("[LoRA] Calling ledger.apply_loras(...)")
|
| 391 |
-
# Best-effort call (signature may vary across versions)
|
| 392 |
-
try:
|
| 393 |
-
ledger.apply_loras([{"path": p, "strength": s} for p, s in lora_entries if p is not None])
|
| 394 |
-
except Exception:
|
| 395 |
-
# also try a simpler form
|
| 396 |
-
ledger.apply_loras(lora_entries)
|
| 397 |
-
return
|
| 398 |
-
if hasattr(pipeline, "set_loras"):
|
| 399 |
-
print("[LoRA] Calling pipeline.set_loras(...)")
|
| 400 |
-
try:
|
| 401 |
-
pipeline.set_loras(lora_entries)
|
| 402 |
-
return
|
| 403 |
-
except Exception as e:
|
| 404 |
-
print(f"[LoRA] pipeline.set_loras failed: {type(e).__name__}: {e}")
|
| 405 |
except Exception as e:
|
| 406 |
-
|
|
|
|
|
|
|
| 407 |
|
| 408 |
-
#
|
| 409 |
try:
|
| 410 |
print("[LoRA] Falling back to pipeline.loras attribute assignment (best-effort).")
|
| 411 |
-
pipeline.loras = [(p, float(s)) for p, s in
|
| 412 |
except Exception as e:
|
| 413 |
print(f"[LoRA] Fallback pipeline.loras assignment failed: {type(e).__name__}: {e}")
|
| 414 |
-
|
| 415 |
print("[LoRA] apply_loras_to_pipeline finished (some approaches may not have taken effect).")
|
| 416 |
-
# ---- END replacement ----
|
| 417 |
|
| 418 |
# ---- REPLACE PRELOAD BLOCK START ----
|
| 419 |
# Preload all models for ZeroGPU tensor packing.
|
|
|
|
| 61 |
simple_denoising_func,
|
| 62 |
)
|
| 63 |
from ltx_pipelines.utils.media_io import decode_audio_from_file, encode_video
|
| 64 |
+
from ltx_core.loader.primitives import LoraPathStrengthAndSDOps
|
| 65 |
+
from ltx_core.loader.sd_ops import LTXV_LORA_COMFY_RENAMING_MAP
|
| 66 |
|
| 67 |
# Force-patch xformers attention into the LTX attention module.
|
| 68 |
from ltx_core.model.transformer import attention as _attn_mod
|
|
|
|
| 300 |
)
|
| 301 |
# ----------------------------------------------------------------
|
| 302 |
|
|
|
|
| 303 |
def apply_loras_to_pipeline(pose_strength: float, general_strength: float, motion_strength: float):
|
| 304 |
"""
|
| 305 |
+
Build a temporary ModelLedger configured with the requested LoRAs, build the transformer,
|
| 306 |
+
and hot-swap it into the existing ledger without recreating the pipeline object.
|
| 307 |
+
|
| 308 |
+
Strategy:
|
| 309 |
+
1. Construct LoraPathStrengthAndSDOps entries for any non-zero strengths.
|
| 310 |
+
2. Use ledger.with_loras(...) to get a temporary ledger configured with those loras.
|
| 311 |
+
3. Optionally clear the existing cached transformer to reduce peak VRAM, then build the
|
| 312 |
+
transformer from the temporary ledger and hot-swap it into the live ledger.
|
| 313 |
+
4. If anything fails, print diagnostics and leave the existing pipeline in place.
|
| 314 |
"""
|
| 315 |
ledger = pipeline.model_ledger
|
| 316 |
|
| 317 |
+
# Build convenience list and convert to the LTX primitive type (with sd_ops)
|
| 318 |
+
entries = [
|
| 319 |
(pose_lora_path, float(pose_strength)),
|
| 320 |
(general_lora_path, float(general_strength)),
|
| 321 |
(motion_lora_path, float(motion_strength)),
|
| 322 |
]
|
| 323 |
|
| 324 |
+
# Keep only nonzero strengths and valid paths (zero == disabled)
|
| 325 |
+
loras_for_builder = [
|
| 326 |
+
LoraPathStrengthAndSDOps(path, strength, LTXV_LORA_COMFY_RENAMING_MAP)
|
| 327 |
+
for path, strength in entries
|
| 328 |
+
if path is not None and float(strength) != 0.0
|
| 329 |
+
]
|
| 330 |
+
|
| 331 |
+
if len(loras_for_builder) == 0:
|
| 332 |
+
print("[LoRA] No nonzero LoRA strengths — skipping rebuild.")
|
| 333 |
+
return
|
| 334 |
+
|
| 335 |
+
try:
|
| 336 |
+
# Create a temporary ledger configured with the extra LoRAs.
|
| 337 |
+
# with_loras accepts an iterable of LoraPathStrengthAndSDOps.
|
| 338 |
+
tmp_ledger = ledger.with_loras(tuple(loras_for_builder))
|
| 339 |
+
print(f"[LoRA] Built temporary ledger with {len(loras_for_builder)} LoRA(s).")
|
| 340 |
|
| 341 |
+
# Attempt to free previously cached transformer instance to reduce peak VRAM.
|
| 342 |
+
# (We cached instances earlier and replaced ledger.<component> with lambdas returning them.)
|
| 343 |
try:
|
| 344 |
+
# If ModelLedger implements clear_vram, call it to release cached GPU tensors.
|
| 345 |
+
if hasattr(ledger, "clear_vram"):
|
| 346 |
+
ledger.clear_vram()
|
| 347 |
+
print("[LoRA] Cleared old ledger VRAM cache before building new transformer.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 348 |
except Exception as e:
|
| 349 |
+
print(f"[LoRA] Warning: ledger.clear_vram() failed: {type(e).__name__}: {e}")
|
| 350 |
+
|
| 351 |
+
# Build the new transformer from the temporary ledger (this will load & fuse LoRAs).
|
| 352 |
+
print("[LoRA] Building transformer from temporary ledger (this may take time / spike VRAM)...")
|
| 353 |
+
new_transformer = tmp_ledger.transformer() # returns an X0Model moved to device
|
| 354 |
+
print("[LoRA] New transformer built successfully.")
|
| 355 |
+
|
| 356 |
+
# Replace cached transformer instance and hot-swap ledger.transformer to return the new one.
|
| 357 |
+
global _transformer
|
| 358 |
+
try:
|
| 359 |
+
# Remove old Python ref if present to allow GC.
|
| 360 |
+
del _transformer
|
| 361 |
+
except Exception:
|
| 362 |
+
pass
|
| 363 |
+
torch.cuda.empty_cache()
|
| 364 |
+
_transformer = new_transformer
|
| 365 |
+
ledger.transformer = lambda: _transformer
|
| 366 |
+
print("[LoRA] Hot-swapped new transformer into ledger successfully.")
|
| 367 |
+
|
| 368 |
+
# Done
|
| 369 |
+
return
|
| 370 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 371 |
except Exception as e:
|
| 372 |
+
import traceback
|
| 373 |
+
print(f"[LoRA] Error during builder-based LoRA application: {type(e).__name__}: {e}")
|
| 374 |
+
print(traceback.format_exc())
|
| 375 |
|
| 376 |
+
# Final fallback (should rarely hit if above path works):
|
| 377 |
try:
|
| 378 |
print("[LoRA] Falling back to pipeline.loras attribute assignment (best-effort).")
|
| 379 |
+
pipeline.loras = [(p, float(s)) for p, s in entries if p is not None]
|
| 380 |
except Exception as e:
|
| 381 |
print(f"[LoRA] Fallback pipeline.loras assignment failed: {type(e).__name__}: {e}")
|
|
|
|
| 382 |
print("[LoRA] apply_loras_to_pipeline finished (some approaches may not have taken effect).")
|
|
|
|
| 383 |
|
| 384 |
# ---- REPLACE PRELOAD BLOCK START ----
|
| 385 |
# Preload all models for ZeroGPU tensor packing.
|