Update app.py
Browse files
app.py
CHANGED
|
@@ -293,66 +293,158 @@ pipeline = LTX23DistilledA2VPipeline(
|
|
| 293 |
distilled_checkpoint_path=checkpoint_path,
|
| 294 |
spatial_upsampler_path=spatial_upsampler_path,
|
| 295 |
gemma_root=gemma_root,
|
| 296 |
-
|
| 297 |
-
loras=[
|
| 298 |
-
(pose_lora_path, 0.0),
|
| 299 |
-
(general_lora_path, 0.0),
|
| 300 |
-
(motion_lora_path, 0.0),
|
| 301 |
-
],
|
| 302 |
quantization=QuantizationPolicy.fp8_cast(), # keep FP8 quantization unchanged
|
| 303 |
)
|
| 304 |
# ----------------------------------------------------------------
|
| 305 |
|
| 306 |
-
# ----
|
| 307 |
def apply_loras_to_pipeline(pose_strength: float, general_strength: float, motion_strength: float):
|
| 308 |
"""
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
|
|
|
|
|
|
|
|
|
| 312 |
"""
|
| 313 |
-
|
| 314 |
-
|
|
|
|
|
|
|
| 315 |
(pose_lora_path, float(pose_strength)),
|
| 316 |
(general_lora_path, float(general_strength)),
|
| 317 |
(motion_lora_path, float(motion_strength)),
|
| 318 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 319 |
try:
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 324 |
return
|
| 325 |
-
|
| 326 |
-
# Alternative: pipeline may have helper 'set_loras' or similar
|
| 327 |
if hasattr(pipeline, "set_loras"):
|
| 328 |
-
print("[LoRA]
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
|
| 336 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 337 |
except Exception as e:
|
| 338 |
-
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
# --------
|
| 342 |
|
|
|
|
| 343 |
# Preload all models for ZeroGPU tensor packing.
|
| 344 |
print("Preloading all models (including Gemma and audio components)...")
|
| 345 |
ledger = pipeline.model_ledger
|
| 346 |
-
_transformer = ledger.transformer()
|
| 347 |
-
_video_encoder = ledger.video_encoder()
|
| 348 |
-
_video_decoder = ledger.video_decoder()
|
| 349 |
-
_audio_encoder = ledger.audio_encoder()
|
| 350 |
-
_audio_decoder = ledger.audio_decoder()
|
| 351 |
-
_vocoder = ledger.vocoder()
|
| 352 |
-
_spatial_upsampler = ledger.spatial_upsampler()
|
| 353 |
-
_text_encoder = ledger.text_encoder()
|
| 354 |
-
_embeddings_processor = ledger.gemma_embeddings_processor()
|
| 355 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 356 |
ledger.transformer = lambda: _transformer
|
| 357 |
ledger.video_encoder = lambda: _video_encoder
|
| 358 |
ledger.video_decoder = lambda: _video_decoder
|
|
@@ -362,7 +454,9 @@ ledger.vocoder = lambda: _vocoder
|
|
| 362 |
ledger.spatial_upsampler = lambda: _spatial_upsampler
|
| 363 |
ledger.text_encoder = lambda: _text_encoder
|
| 364 |
ledger.gemma_embeddings_processor = lambda: _embeddings_processor
|
|
|
|
| 365 |
print("All models preloaded (including Gemma text encoder and audio encoder)!")
|
|
|
|
| 366 |
|
| 367 |
print("=" * 80)
|
| 368 |
print("Pipeline ready!")
|
|
|
|
| 293 |
distilled_checkpoint_path=checkpoint_path,
|
| 294 |
spatial_upsampler_path=spatial_upsampler_path,
|
| 295 |
gemma_root=gemma_root,
|
| 296 |
+
loras=[],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 297 |
quantization=QuantizationPolicy.fp8_cast(), # keep FP8 quantization unchanged
|
| 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.
|
| 420 |
print("Preloading all models (including Gemma and audio components)...")
|
| 421 |
ledger = pipeline.model_ledger
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 422 |
|
| 423 |
+
# Save the original factory methods so we can rebuild individual components later.
|
| 424 |
+
# These are bound callables on ledger that will call the builder when invoked.
|
| 425 |
+
_orig_transformer_factory = ledger.transformer
|
| 426 |
+
_orig_video_encoder_factory = ledger.video_encoder
|
| 427 |
+
_orig_video_decoder_factory = ledger.video_decoder
|
| 428 |
+
_orig_audio_encoder_factory = ledger.audio_encoder
|
| 429 |
+
_orig_audio_decoder_factory = ledger.audio_decoder
|
| 430 |
+
_orig_vocoder_factory = ledger.vocoder
|
| 431 |
+
_orig_spatial_upsampler_factory = ledger.spatial_upsampler
|
| 432 |
+
_orig_text_encoder_factory = ledger.text_encoder
|
| 433 |
+
_orig_gemma_embeddings_factory = ledger.gemma_embeddings_processor
|
| 434 |
+
|
| 435 |
+
# Call the original factories once to create the cached instances we will serve by default.
|
| 436 |
+
_transformer = _orig_transformer_factory()
|
| 437 |
+
_video_encoder = _orig_video_encoder_factory()
|
| 438 |
+
_video_decoder = _orig_video_decoder_factory()
|
| 439 |
+
_audio_encoder = _orig_audio_encoder_factory()
|
| 440 |
+
_audio_decoder = _orig_audio_decoder_factory()
|
| 441 |
+
_vocoder = _orig_vocoder_factory()
|
| 442 |
+
_spatial_upsampler = _orig_spatial_upsampler_factory()
|
| 443 |
+
_text_encoder = _orig_text_encoder_factory()
|
| 444 |
+
_embeddings_processor = _orig_gemma_embeddings_factory()
|
| 445 |
+
|
| 446 |
+
# Replace ledger methods with lightweight lambdas that return the cached instances.
|
| 447 |
+
# We keep the original factories above so we can call them later to rebuild components.
|
| 448 |
ledger.transformer = lambda: _transformer
|
| 449 |
ledger.video_encoder = lambda: _video_encoder
|
| 450 |
ledger.video_decoder = lambda: _video_decoder
|
|
|
|
| 454 |
ledger.spatial_upsampler = lambda: _spatial_upsampler
|
| 455 |
ledger.text_encoder = lambda: _text_encoder
|
| 456 |
ledger.gemma_embeddings_processor = lambda: _embeddings_processor
|
| 457 |
+
|
| 458 |
print("All models preloaded (including Gemma text encoder and audio encoder)!")
|
| 459 |
+
# ---- REPLACE PRELOAD BLOCK END ----
|
| 460 |
|
| 461 |
print("=" * 80)
|
| 462 |
print("Pipeline ready!")
|