Spaces:
Running on Zero
Running on Zero
Eager cuda placement at startup; remove self-test
Browse files
app.py
CHANGED
|
@@ -34,7 +34,7 @@ TURBO_REPO = os.environ.get("H3_TURBO_REPO", "lightx2v/Minimax-h3-Turbo")
|
|
| 34 |
TURBO_FILE = os.environ.get("H3_TURBO_FILE", "minimax_h3_ref2v_turbo_4step_v0.1_bf16.safetensors")
|
| 35 |
GPU_SIZE = os.environ.get("H3_GPU_SIZE", "xlarge").strip() or None
|
| 36 |
ATTENTION = os.environ.get("H3_ATTENTION", "_native_cudnn").lower()
|
| 37 |
-
PLACEMENT = os.environ.get("H3_PLACEMENT", "
|
| 38 |
|
| 39 |
FPS, FRAMES_PER_CHUNK, LATENTS_PER_CHUNK = 24, 17, 5
|
| 40 |
CANVAS_MULTIPLE = 32
|
|
@@ -101,10 +101,17 @@ def load_pipeline() -> str | None:
|
|
| 101 |
pipe.transformer_ref.set_attention_backend(ATTENTION)
|
| 102 |
try:
|
| 103 |
pipe.load_lora_weights(hf_hub_download(TURBO_REPO, TURBO_FILE), adapter_name="turbo")
|
|
|
|
| 104 |
TURBO_READY = True
|
| 105 |
print(f"[bgswap] turbo LoRA ready ({TURBO_REPO})", flush=True)
|
| 106 |
except Exception as error:
|
| 107 |
print(f"[bgswap] turbo unavailable ({type(error).__name__}: {error})", flush=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
PIPE, MANAGER = pipe, manager
|
| 109 |
print(f"[bgswap] generator ready in {time.time() - started:.0f}s", flush=True)
|
| 110 |
except Exception as error:
|
|
@@ -332,7 +339,10 @@ def get_duration(request, steps, seed, **_):
|
|
| 332 |
denoise = int(steps) * (STEP_LINEAR * sequence + STEP_QUADRATIC * sequence ** 2) * SAFETY
|
| 333 |
encode = 5 + reference_rows(references, num_frames) * 1e-3
|
| 334 |
share = (height * width * num_frames) / DEFAULT_CANVAS_PIXELS
|
| 335 |
-
|
|
|
|
|
|
|
|
|
|
| 336 |
+ DECODE_BASE + DECODE_PER_DEFAULT_CANVAS * share + 10)
|
| 337 |
duration = max(MIN_GPU_DURATION, min(MAX_GPU_DURATION, int(total)))
|
| 338 |
print(f"[bgswap] S={sequence} -> reserving {duration}s ({denoise:.0f}s denoise at {steps} steps)", flush=True)
|
|
@@ -535,30 +545,8 @@ demo = (gr.Workflow(graph=os.path.join(_HERE, "workflow.json"), bind={"generate_
|
|
| 535 |
|
| 536 |
|
| 537 |
# ----------------------------------------------------------------------------------------------------------- self-test
|
| 538 |
-
def _selftest():
|
| 539 |
-
"""Local, no network: derive a mask + reference from the prototype's existing matte/green and check shapes."""
|
| 540 |
-
base = "/home/ubuntu/ltx-h3-bgswap"
|
| 541 |
-
green = read_video(f"{base}/green.mp4")
|
| 542 |
-
matte = read_video(f"{base}/matte.mp4")
|
| 543 |
-
n = floor_frames(min(len(green), len(matte)))
|
| 544 |
-
assert n % FRAMES_PER_CHUNK == LATENTS_PER_CHUNK and n <= len(green), n
|
| 545 |
-
hard = background_mask(matte[:n], 0.0)
|
| 546 |
-
soft = background_mask(matte[:n], 0.2)
|
| 547 |
-
assert hard.shape == (n, green.shape[1], green.shape[2]), hard.shape
|
| 548 |
-
assert set(np.unique(hard)) <= {0.0, 1.0}, "hard mask must be binary"
|
| 549 |
-
assert {round(v, 3) for v in np.unique(soft).tolist()} == {0.2, 1.0}, "relight sets the subject interior to 0.2, bg to 1"
|
| 550 |
-
ref = gray_reference(green[0], matte[0])
|
| 551 |
-
assert Image.open(ref).size == (green.shape[2], green.shape[1])
|
| 552 |
-
print(f"selftest OK: n={n}, hard repaint {hard.mean()*100:.1f}%, ref {ref}")
|
| 553 |
-
|
| 554 |
-
|
| 555 |
if __name__ == "__main__":
|
| 556 |
-
|
| 557 |
-
|
| 558 |
-
|
| 559 |
-
|
| 560 |
-
else:
|
| 561 |
-
if demo is None:
|
| 562 |
-
raise SystemExit("gr.Workflow requires gradio >= 6.25")
|
| 563 |
-
load_pipeline()
|
| 564 |
-
demo.launch(show_error=True, allowed_paths=[OUTPUT_DIR, os.path.join(_HERE, "examples")])
|
|
|
|
| 34 |
TURBO_FILE = os.environ.get("H3_TURBO_FILE", "minimax_h3_ref2v_turbo_4step_v0.1_bf16.safetensors")
|
| 35 |
GPU_SIZE = os.environ.get("H3_GPU_SIZE", "xlarge").strip() or None
|
| 36 |
ATTENTION = os.environ.get("H3_ATTENTION", "_native_cudnn").lower()
|
| 37 |
+
PLACEMENT = os.environ.get("H3_PLACEMENT", "eager").lower() # eager: place on cuda at startup (ZeroGPU best practice)
|
| 38 |
|
| 39 |
FPS, FRAMES_PER_CHUNK, LATENTS_PER_CHUNK = 24, 17, 5
|
| 40 |
CANVAS_MULTIPLE = 32
|
|
|
|
| 101 |
pipe.transformer_ref.set_attention_backend(ATTENTION)
|
| 102 |
try:
|
| 103 |
pipe.load_lora_weights(hf_hub_download(TURBO_REPO, TURBO_FILE), adapter_name="turbo")
|
| 104 |
+
pipe.set_adapters(["turbo"], [1.0])
|
| 105 |
TURBO_READY = True
|
| 106 |
print(f"[bgswap] turbo LoRA ready ({TURBO_REPO})", flush=True)
|
| 107 |
except Exception as error:
|
| 108 |
print(f"[bgswap] turbo unavailable ({type(error).__name__}: {error})", flush=True)
|
| 109 |
+
# Place the whole pipeline (incl. the turbo LoRA) on cuda at startup. ZeroGPU's CUDA emulation handles
|
| 110 |
+
# `.to("cuda")` outside the GPU function and startup placement is much faster than deferring it to the first
|
| 111 |
+
# request - so the first generation is no longer penalised by a cold transfer. H3_PLACEMENT=lazy opts out.
|
| 112 |
+
if PLACEMENT != "lazy":
|
| 113 |
+
pipe.to("cuda")
|
| 114 |
+
print("[bgswap] pipeline placed on cuda at startup", flush=True)
|
| 115 |
PIPE, MANAGER = pipe, manager
|
| 116 |
print(f"[bgswap] generator ready in {time.time() - started:.0f}s", flush=True)
|
| 117 |
except Exception as error:
|
|
|
|
| 339 |
denoise = int(steps) * (STEP_LINEAR * sequence + STEP_QUADRATIC * sequence ** 2) * SAFETY
|
| 340 |
encode = 5 + reference_rows(references, num_frames) * 1e-3
|
| 341 |
share = (height * width * num_frames) / DEFAULT_CANVAS_PIXELS
|
| 342 |
+
# Only budget the cuda-transfer allowance when placement is deferred to the GPU call; eager placement pays it
|
| 343 |
+
# once at startup, off the clock, so the per-request reservation (and queue priority) improves.
|
| 344 |
+
placement = PLACEMENT_ALLOWANCE if PLACEMENT == "lazy" else 0
|
| 345 |
+
total = (placement + encode + SOURCE_ENCODE_PER_DEFAULT_CANVAS * share + denoise
|
| 346 |
+ DECODE_BASE + DECODE_PER_DEFAULT_CANVAS * share + 10)
|
| 347 |
duration = max(MIN_GPU_DURATION, min(MAX_GPU_DURATION, int(total)))
|
| 348 |
print(f"[bgswap] S={sequence} -> reserving {duration}s ({denoise:.0f}s denoise at {steps} steps)", flush=True)
|
|
|
|
| 545 |
|
| 546 |
|
| 547 |
# ----------------------------------------------------------------------------------------------------------- self-test
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 548 |
if __name__ == "__main__":
|
| 549 |
+
if demo is None:
|
| 550 |
+
raise SystemExit("gr.Workflow requires gradio >= 6.25")
|
| 551 |
+
load_pipeline()
|
| 552 |
+
demo.launch(show_error=True, allowed_paths=[OUTPUT_DIR, os.path.join(_HERE, "examples")])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|