Spaces:
Running on Zero
Running on Zero
Commit ·
a104380
1
Parent(s): 5ed2ecb
Use sequential CPU offload instead of moving full pipeline to GPU at once
Browse filespipe.to(device) staged all ~37GB of weights (transformer + text_encoder +
vae) onto GPU simultaneously, which OOM'd on smaller MIG slices (e.g. the
47GB 2g.48gb partition ZeroGPU sometimes hands out). enable_model_cpu_offload
uses the pipeline's declared model_cpu_offload_seq to keep only the active
component resident on GPU at a time.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
app.py
CHANGED
|
@@ -402,12 +402,14 @@ def _infer_gpu(pil_images, prompt, seed, guidance_scale, steps, width, height, m
|
|
| 402 |
print(f"[infer] GPU: {p.name}, total={p.total_memory/1024**3:.1f}GB, cap={p.major}.{p.minor}")
|
| 403 |
torch.cuda.reset_peak_memory_stats()
|
| 404 |
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
|
|
|
|
|
|
| 411 |
|
| 412 |
print(f"[infer] {len(pil_images)} image(s) pre-decoded, output={width}x{height}, seed={seed}")
|
| 413 |
|
|
@@ -450,8 +452,9 @@ def _infer_gpu(pil_images, prompt, seed, guidance_scale, steps, width, height, m
|
|
| 450 |
timer.print_timings()
|
| 451 |
raise
|
| 452 |
finally:
|
| 453 |
-
|
| 454 |
-
|
|
|
|
| 455 |
gc.collect()
|
| 456 |
torch.cuda.empty_cache()
|
| 457 |
print(f"[infer] ===== END t={time.perf_counter()-t0:.1f}s =====")
|
|
|
|
| 402 |
print(f"[infer] GPU: {p.name}, total={p.total_memory/1024**3:.1f}GB, cap={p.major}.{p.minor}")
|
| 403 |
torch.cuda.reset_peak_memory_stats()
|
| 404 |
|
| 405 |
+
# Sequential offload: only the component currently doing work (text_encoder,
|
| 406 |
+
# then transformer, then vae — see model_cpu_offload_seq) sits on GPU at a
|
| 407 |
+
# time, instead of the full ~37GB pipeline resident simultaneously. Needed
|
| 408 |
+
# to fit on smaller MIG slices (e.g. the 47GB 2g.48gb partition) without OOM.
|
| 409 |
+
if getattr(pipe.transformer, "_hf_hook", None) is None:
|
| 410 |
+
pipe.enable_model_cpu_offload(device=device)
|
| 411 |
+
print(f"[infer] enabled sequential cpu offload on {device}")
|
| 412 |
+
print(f"[infer] {_gpu_mem_str(_cuda_ok)} — t={time.perf_counter()-t0:.1f}s")
|
| 413 |
|
| 414 |
print(f"[infer] {len(pil_images)} image(s) pre-decoded, output={width}x{height}, seed={seed}")
|
| 415 |
|
|
|
|
| 452 |
timer.print_timings()
|
| 453 |
raise
|
| 454 |
finally:
|
| 455 |
+
# No manual pipe.to("cpu") — that fights the offload hooks' own device
|
| 456 |
+
# bookkeeping. Hooks already return each component to CPU after its
|
| 457 |
+
# forward; empty_cache() just reclaims the freed GPU blocks.
|
| 458 |
gc.collect()
|
| 459 |
torch.cuda.empty_cache()
|
| 460 |
print(f"[infer] ===== END t={time.perf_counter()-t0:.1f}s =====")
|