Spaces:
Running on Zero
Running on Zero
Idiomatic ZeroGPU startup packing for the transformer
Browse files
app.py
CHANGED
|
@@ -18,7 +18,7 @@ CONDITIONER_SPACE = os.environ.get("H3_CONDITIONER", "diffusers-internal-dev/min
|
|
| 18 |
# `lazy` moves all 72.16 GiB onto the card on the first GPU call and leaves it there; `offload` hands placement to
|
| 19 |
# `ComponentsManager.enable_auto_cpu_offload` instead. Neither puts anything on the card at *startup*, which is
|
| 20 |
# deliberate — see `load_models`: the 150 GB storage quota, not the 95 GiB card, is what rules that out here.
|
| 21 |
-
PLACEMENT = os.environ.get("H3_PLACEMENT", "
|
| 22 |
# cuDNN's fused attention is 10-20% faster than the SDPA default on this pool and needs nothing installed.
|
| 23 |
ATTENTION = os.environ.get("H3_ATTENTION", "_native_cudnn").lower()
|
| 24 |
GPU_DURATION = int(os.environ.get("H3_GPU_DURATION", "900"))
|
|
@@ -122,6 +122,15 @@ def load_models() -> str | None:
|
|
| 122 |
|
| 123 |
h3_aoti.maybe_load(pipe.transformer)
|
| 124 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
if PLACEMENT == "offload":
|
| 126 |
manager.enable_auto_cpu_offload(device="cuda")
|
| 127 |
_arm_decode_hooks(pipe)
|
|
@@ -189,7 +198,7 @@ def encode_remote(prompt, image_path, last_image_path, canvas, num_frames):
|
|
| 189 |
# gpu_seconds = A + B * steps * tokens + C * steps * tokens^2, where tokens is the packed video row count.
|
| 190 |
# PLACEMENT_ALLOWANCE covers the one-time 72 GiB lazy .to("cuda") a cold worker pays inside its first call.
|
| 191 |
_DUR_A, _DUR_B, _DUR_C = -6.023, 2.0877e-4, 2.1221e-9
|
| 192 |
-
_PLACEMENT_ALLOWANCE, _PAD =
|
| 193 |
|
| 194 |
|
| 195 |
def get_duration(prompt_embeds, text_token_tags, image, last_image, height, width, num_frames, steps, seed, *a, **k):
|
|
@@ -212,9 +221,12 @@ def _generate(prompt_embeds, text_token_tags, image, last_image, height, width,
|
|
| 212 |
import torch
|
| 213 |
|
| 214 |
if PLACEMENT == "lazy":
|
| 215 |
-
# 72.16 GiB across PCIe on the first request of a worker, a no-op walk on every one after it.
|
| 216 |
-
# placement is not an option here — see `load_models` — and this is what buys the offload-free denoise loop.
|
| 217 |
PIPE.to("cuda")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 218 |
|
| 219 |
state = PIPE(
|
| 220 |
prompt_embeds=prompt_embeds.to("cuda"),
|
|
|
|
| 18 |
# `lazy` moves all 72.16 GiB onto the card on the first GPU call and leaves it there; `offload` hands placement to
|
| 19 |
# `ComponentsManager.enable_auto_cpu_offload` instead. Neither puts anything on the card at *startup*, which is
|
| 20 |
# deliberate — see `load_models`: the 150 GB storage quota, not the 95 GiB card, is what rules that out here.
|
| 21 |
+
PLACEMENT = os.environ.get("H3_PLACEMENT", "pack").lower()
|
| 22 |
# cuDNN's fused attention is 10-20% faster than the SDPA default on this pool and needs nothing installed.
|
| 23 |
ATTENTION = os.environ.get("H3_ATTENTION", "_native_cudnn").lower()
|
| 24 |
GPU_DURATION = int(os.environ.get("H3_GPU_DURATION", "900"))
|
|
|
|
| 122 |
|
| 123 |
h3_aoti.maybe_load(pipe.transformer)
|
| 124 |
|
| 125 |
+
if PLACEMENT == "pack":
|
| 126 |
+
# Idiomatic ZeroGPU startup placement, scoped to the transformer only. `spaces` packs every
|
| 127 |
+
# startup-resident CUDA tensor into a second on-disk copy; packing all 77.3 GB (transformer + fp32
|
| 128 |
+
# VAEs) busts the 150 GB storage quota (77.3 + 77.3 + shards), but the 61.7 GB transformer alone
|
| 129 |
+
# packs to ~123 GB total and fits. The VAEs (~10 GB) take the lazy path on first GPU call, ~2 s.
|
| 130 |
+
# With AoTI the packed transformer pairs with the precompiled blocks: no placement, no compile,
|
| 131 |
+
# first request runs at steady state.
|
| 132 |
+
pipe.transformer.to("cuda")
|
| 133 |
+
|
| 134 |
if PLACEMENT == "offload":
|
| 135 |
manager.enable_auto_cpu_offload(device="cuda")
|
| 136 |
_arm_decode_hooks(pipe)
|
|
|
|
| 198 |
# gpu_seconds = A + B * steps * tokens + C * steps * tokens^2, where tokens is the packed video row count.
|
| 199 |
# PLACEMENT_ALLOWANCE covers the one-time 72 GiB lazy .to("cuda") a cold worker pays inside its first call.
|
| 200 |
_DUR_A, _DUR_B, _DUR_C = -6.023, 2.0877e-4, 2.1221e-9
|
| 201 |
+
_PLACEMENT_ALLOWANCE, _PAD = 12, 10 # pack mode: only the ~10 GB VAEs move on a cold worker
|
| 202 |
|
| 203 |
|
| 204 |
def get_duration(prompt_embeds, text_token_tags, image, last_image, height, width, num_frames, steps, seed, *a, **k):
|
|
|
|
| 221 |
import torch
|
| 222 |
|
| 223 |
if PLACEMENT == "lazy":
|
| 224 |
+
# 72.16 GiB across PCIe on the first request of a worker, a no-op walk on every one after it.
|
|
|
|
| 225 |
PIPE.to("cuda")
|
| 226 |
+
elif PLACEMENT == "pack":
|
| 227 |
+
# Transformer was packed at startup; only the ~10 GB of fp32 VAEs walk across on a cold worker.
|
| 228 |
+
PIPE.vae.to("cuda")
|
| 229 |
+
PIPE.audio_vae.to("cuda")
|
| 230 |
|
| 231 |
state = PIPE(
|
| 232 |
prompt_embeds=prompt_embeds.to("cuda"),
|