linoyts HF Staff commited on
Commit
db4276e
·
verified ·
1 Parent(s): cf638e4

Eager cuda placement at startup; remove self-test

Browse files
Files changed (1) hide show
  1. app.py +16 -28
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", "lazy").lower()
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
- total = (PLACEMENT_ALLOWANCE + encode + SOURCE_ENCODE_PER_DEFAULT_CANVAS * share + denoise
 
 
 
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
- import sys
557
-
558
- if "--selftest" in sys.argv:
559
- _selftest()
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")])