fix(zerogpu): add explicit duration, disable geometry offload by default
Browse filesZeroGPU default lease is ~60s. Hunyuan3D .to("cuda") (~10-15 GB H2D
transfer) + 100-step diffusion easily exceeds that, causing the callback
to be killed silently at ~10/100 steps.
- Add _gpu(duration) helper; replace @GPU with @_gpu(duration=N) for each
callback: generate_mesh/generate_slat 240s, render_* 180s, videos 300s.
- Change NEAR_GEOMETRY_OFFLOAD_AFTER_MESH default to "0": H200 has 80 GB
VRAM; keeping Hunyuan on GPU after mesh generation means subsequent
calls only pay a no-op .to("cuda") instead of a full ~30s H2D transfer.
Override with NEAR_GEOMETRY_OFFLOAD_AFTER_MESH=1 if needed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
app.py
CHANGED
|
@@ -59,6 +59,13 @@ from trellis.pipelines import NeARImageToRelightable3DPipeline
|
|
| 59 |
|
| 60 |
GPU = spaces.GPU if spaces is not None else (lambda f: f)
|
| 61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
APP_DIR = Path(__file__).resolve().parent
|
| 63 |
CACHE_DIR = APP_DIR / "tmp_gradio"
|
| 64 |
CACHE_DIR.mkdir(exist_ok=True)
|
|
@@ -84,9 +91,7 @@ def _truthy_env(name: str, default: str) -> bool:
|
|
| 84 |
_CPU_PRELOAD_AT_START = _truthy_env(
|
| 85 |
"NEAR_MODEL_CPU_PRELOAD_AT_START", "1" if spaces is not None else "0"
|
| 86 |
)
|
| 87 |
-
_OFFLOAD_GEOMETRY_AFTER_MESH = _truthy_env(
|
| 88 |
-
"NEAR_GEOMETRY_OFFLOAD_AFTER_MESH", "1" if spaces is not None else "0"
|
| 89 |
-
)
|
| 90 |
|
| 91 |
|
| 92 |
def _path_is_git_lfs_pointer(p: Path) -> bool:
|
|
@@ -286,7 +291,7 @@ def _require_hdri_path(hdri_obj: Any) -> str:
|
|
| 286 |
return p
|
| 287 |
|
| 288 |
|
| 289 |
-
@
|
| 290 |
@torch.inference_mode()
|
| 291 |
def generate_mesh(
|
| 292 |
image_input: Optional[Image.Image],
|
|
@@ -326,7 +331,7 @@ def generate_mesh(
|
|
| 326 |
return state, str(mesh_path), "**① Mesh ready** — run **② SLaT** next."
|
| 327 |
|
| 328 |
|
| 329 |
-
@
|
| 330 |
@torch.inference_mode()
|
| 331 |
def generate_slat(
|
| 332 |
asset_state: Dict[str, Any],
|
|
@@ -390,7 +395,7 @@ def load_slat_npz(
|
|
| 390 |
return state, f"SLaT loaded: **{Path(resolved).name}**"
|
| 391 |
|
| 392 |
|
| 393 |
-
@
|
| 394 |
@torch.inference_mode()
|
| 395 |
def render_preview(
|
| 396 |
asset_state: Dict[str, Any],
|
|
@@ -434,7 +439,7 @@ def render_preview(
|
|
| 434 |
)
|
| 435 |
|
| 436 |
|
| 437 |
-
@
|
| 438 |
def export_pbr_glb(
|
| 439 |
asset_state: Dict[str, Any],
|
| 440 |
hdri_file_obj: Any,
|
|
@@ -471,7 +476,7 @@ def export_pbr_glb(
|
|
| 471 |
return str(out), f"**③ PBR GLB** — `{out.name}`"
|
| 472 |
|
| 473 |
|
| 474 |
-
@
|
| 475 |
@torch.inference_mode()
|
| 476 |
def render_dual_lighting_videos(
|
| 477 |
asset_state: Dict[str, Any],
|
|
|
|
| 59 |
|
| 60 |
GPU = spaces.GPU if spaces is not None else (lambda f: f)
|
| 61 |
|
| 62 |
+
|
| 63 |
+
def _gpu(duration: int = 120):
|
| 64 |
+
"""ZeroGPU decorator with explicit duration; no-op when spaces is absent."""
|
| 65 |
+
if spaces is not None:
|
| 66 |
+
return spaces.GPU(duration=duration)
|
| 67 |
+
return lambda f: f
|
| 68 |
+
|
| 69 |
APP_DIR = Path(__file__).resolve().parent
|
| 70 |
CACHE_DIR = APP_DIR / "tmp_gradio"
|
| 71 |
CACHE_DIR.mkdir(exist_ok=True)
|
|
|
|
| 91 |
_CPU_PRELOAD_AT_START = _truthy_env(
|
| 92 |
"NEAR_MODEL_CPU_PRELOAD_AT_START", "1" if spaces is not None else "0"
|
| 93 |
)
|
| 94 |
+
_OFFLOAD_GEOMETRY_AFTER_MESH = _truthy_env("NEAR_GEOMETRY_OFFLOAD_AFTER_MESH", "0")
|
|
|
|
|
|
|
| 95 |
|
| 96 |
|
| 97 |
def _path_is_git_lfs_pointer(p: Path) -> bool:
|
|
|
|
| 291 |
return p
|
| 292 |
|
| 293 |
|
| 294 |
+
@_gpu(duration=240)
|
| 295 |
@torch.inference_mode()
|
| 296 |
def generate_mesh(
|
| 297 |
image_input: Optional[Image.Image],
|
|
|
|
| 331 |
return state, str(mesh_path), "**① Mesh ready** — run **② SLaT** next."
|
| 332 |
|
| 333 |
|
| 334 |
+
@_gpu(duration=240)
|
| 335 |
@torch.inference_mode()
|
| 336 |
def generate_slat(
|
| 337 |
asset_state: Dict[str, Any],
|
|
|
|
| 395 |
return state, f"SLaT loaded: **{Path(resolved).name}**"
|
| 396 |
|
| 397 |
|
| 398 |
+
@_gpu(duration=180)
|
| 399 |
@torch.inference_mode()
|
| 400 |
def render_preview(
|
| 401 |
asset_state: Dict[str, Any],
|
|
|
|
| 439 |
)
|
| 440 |
|
| 441 |
|
| 442 |
+
@_gpu(duration=180)
|
| 443 |
def export_pbr_glb(
|
| 444 |
asset_state: Dict[str, Any],
|
| 445 |
hdri_file_obj: Any,
|
|
|
|
| 476 |
return str(out), f"**③ PBR GLB** — `{out.name}`"
|
| 477 |
|
| 478 |
|
| 479 |
+
@_gpu(duration=300)
|
| 480 |
@torch.inference_mode()
|
| 481 |
def render_dual_lighting_videos(
|
| 482 |
asset_state: Dict[str, Any],
|