dagloop5 commited on
Commit
3039fec
·
verified ·
1 Parent(s): fc8c94a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -95
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
- Rebuild the transformer with the requested LoRA strengths and hot-swap into the ledger.
305
- Strategy (in order):
306
- 1. If the ledger/builder object exists and exposes 'lora' + 'loras' + the original transformer factory,
307
- mutate builder.loras (clear and append .lora(...)) and call the saved original factory to rebuild.
308
- 2. If a dedicated ledger.apply_loras or pipeline.set_loras exists, try calling them.
309
- 3. Fallback: set pipeline.loras attribute (best-effort, may be ignored).
 
 
 
310
  """
311
  ledger = pipeline.model_ledger
312
 
313
- # Build convenience list (paths may be None if download failed)
314
- lora_entries = [
315
  (pose_lora_path, float(pose_strength)),
316
  (general_lora_path, float(general_strength)),
317
  (motion_lora_path, float(motion_strength)),
318
  ]
319
 
320
- # 1) Preferred: mutate the builder used by the ledger, then call the original transformer factory.
321
- builder = getattr(ledger, "builder", None) or getattr(ledger, "_builder", None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
 
323
- if builder is not None:
 
324
  try:
325
- # Clear existing builder.loras if present.
326
- if hasattr(builder, "loras") and isinstance(getattr(builder, "loras"), list):
327
- try:
328
- builder.loras.clear()
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] Unexpected error while manipulating builder: {type(e).__name__}: {e}")
385
- # proceed to fallbacks below
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- print(f"[LoRA] Exception when trying high-level apply APIs: {type(e).__name__}: {e}")
 
 
407
 
408
- # 3) Fallback: set pipeline.loras attribute (best-effort, may not be used)
409
  try:
410
  print("[LoRA] Falling back to pipeline.loras attribute assignment (best-effort).")
411
- pipeline.loras = [(p, float(s)) for p, s in lora_entries if p is not None]
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.