Spaces:
Running on Zero
Fix real OOM: 4-D SDPA layout; cu130 is ZeroGPU-native, drop cu128 cruft
Browse filesGPU-DIAG showed torch 2.11.0+cu130 persists and diff-gaussian compiles
against the system CUDA 13.0 toolkit -- i.e. ZeroGPU natively ships
cu130 + a matching CUDA 13.0 toolkit. So cu130 was never the problem
and the cu128/nvcc machinery was unnecessary: remove the pip-nvcc
CUDA_HOME logic and the nvidia-cuda-nvcc/cccl requirements; compile
against the matching system toolkit.
The actual failure (42 GiB free yet OOM at first attention) was the
SDPA call receiving 3-D tensors, which forces SDPA's math backend to
materialize the full multi-view attention matrix (tens of GB). Reshape
q/k/v to 4-D (batch, heads, seq, head_dim) so SDPA uses its flash /
memory-efficient backend -- the efficient path xformers used to provide.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- app.py +4 -35
- mvdiffusion/models/transformer_mv2d_image.py +15 -10
- requirements.txt +2 -6
|
@@ -99,41 +99,10 @@ except ImportError:
|
|
| 99 |
print("Installing diff-gaussian-rasterization (compiling for detected CUDA arch)...")
|
| 100 |
env = os.environ.copy()
|
| 101 |
|
| 102 |
-
#
|
| 103 |
-
#
|
| 104 |
-
#
|
| 105 |
-
#
|
| 106 |
-
# and cudart lib via CPATH/LIBRARY_PATH so nvcc 12.8 matches torch 12.8.
|
| 107 |
-
import site, glob
|
| 108 |
-
_search_dirs = list(site.getsitepackages())
|
| 109 |
-
try:
|
| 110 |
-
_search_dirs.append(site.getusersitepackages())
|
| 111 |
-
except Exception:
|
| 112 |
-
pass
|
| 113 |
-
_nvcc_bins = []
|
| 114 |
-
for _d in _search_dirs:
|
| 115 |
-
_nvcc_bins += glob.glob(os.path.join(_d, "nvidia", "cuda_nvcc*", "bin", "nvcc"))
|
| 116 |
-
if _nvcc_bins:
|
| 117 |
-
_nvcc_home = os.path.dirname(os.path.dirname(_nvcc_bins[0])) # .../nvidia/cuda_nvcc
|
| 118 |
-
_nv = os.path.dirname(_nvcc_home) # .../nvidia
|
| 119 |
-
env["CUDA_HOME"] = _nvcc_home
|
| 120 |
-
env["PATH"] = os.path.join(_nvcc_home, "bin") + os.pathsep + env.get("PATH", "")
|
| 121 |
-
_incs = [p for p in (os.path.join(_nv, "cuda_runtime", "include"),
|
| 122 |
-
os.path.join(_nv, "cuda_cccl", "include")) if os.path.isdir(p)]
|
| 123 |
-
if _incs:
|
| 124 |
-
env["CPATH"] = os.pathsep.join(_incs + ([env["CPATH"]] if env.get("CPATH") else []))
|
| 125 |
-
_rt_lib = os.path.join(_nv, "cuda_runtime", "lib")
|
| 126 |
-
if os.path.isdir(_rt_lib):
|
| 127 |
-
env["LIBRARY_PATH"] = _rt_lib + os.pathsep + env.get("LIBRARY_PATH", "")
|
| 128 |
-
env["LD_LIBRARY_PATH"] = _rt_lib + os.pathsep + env.get("LD_LIBRARY_PATH", "")
|
| 129 |
-
print(f"[BUILD] using pip CUDA toolkit: CUDA_HOME={_nvcc_home}")
|
| 130 |
-
else:
|
| 131 |
-
print("⚠️ pip CUDA nvcc (nvidia-cuda-nvcc-cu12) not found under site-packages/nvidia; "
|
| 132 |
-
"falling back to system nvcc (will mismatch cu128 torch). "
|
| 133 |
-
"If this persists, Factory Reboot the Space to clear the stale build cache.")
|
| 134 |
-
|
| 135 |
-
# Build a cross-arch set incl. Blackwell sm_120 (the ZeroGPU GPU is cap 12.0);
|
| 136 |
-
# the build stage may not see a GPU, so don't rely on get_device_capability.
|
| 137 |
env["TORCH_CUDA_ARCH_LIST"] = "8.0;8.6;8.9;9.0;12.0+PTX"
|
| 138 |
|
| 139 |
# --no-build-isolation: the package's setup.py imports torch to detect the
|
|
|
|
| 99 |
print("Installing diff-gaussian-rasterization (compiling for detected CUDA arch)...")
|
| 100 |
env = os.environ.copy()
|
| 101 |
|
| 102 |
+
# ZeroGPU ships a cu130 torch and a matching CUDA 13.0 toolkit, so compile
|
| 103 |
+
# against the system toolkit (no version mismatch). Include Blackwell sm_120
|
| 104 |
+
# (the ZeroGPU GPU is capability 12.0); the build stage may not see a GPU, so
|
| 105 |
+
# use a fixed cross-arch set rather than get_device_capability.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
env["TORCH_CUDA_ARCH_LIST"] = "8.0;8.6;8.9;9.0;12.0+PTX"
|
| 107 |
|
| 108 |
# --no-build-isolation: the package's setup.py imports torch to detect the
|
|
@@ -725,20 +725,25 @@ class MVAttnProcessor:
|
|
| 725 |
# value = rearrange(values, 'b t f d c -> (b t) (f d) c')
|
| 726 |
|
| 727 |
|
| 728 |
-
|
| 729 |
-
|
| 730 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 731 |
|
| 732 |
-
# Memory-efficient attention via PyTorch SDPA. Mathematically equivalent to
|
| 733 |
-
# the get_attention_scores (baddbmm) + softmax + bmm full-attention path, but
|
| 734 |
-
# it never materializes the full attention matrix -- that full matrix OOMs on
|
| 735 |
-
# multi-view 512-res inputs. xformers' kernels were the original efficient
|
| 736 |
-
# path but don't support the Blackwell GPU, so use SDPA (flash/mem-efficient
|
| 737 |
-
# backend), which does and runs on Blackwell.
|
| 738 |
hidden_states = F.scaled_dot_product_attention(
|
| 739 |
query, key, value, attn_mask=attention_mask, scale=attn.scale
|
| 740 |
)
|
| 741 |
-
hidden_states =
|
|
|
|
|
|
|
| 742 |
|
| 743 |
# linear proj
|
| 744 |
hidden_states = attn.to_out[0](hidden_states)
|
|
|
|
| 725 |
# value = rearrange(values, 'b t f d c -> (b t) (f d) c')
|
| 726 |
|
| 727 |
|
| 728 |
+
# Memory-efficient attention via PyTorch SDPA. Reshape to 4-D
|
| 729 |
+
# (batch, heads, seq, head_dim): SDPA only dispatches to its flash /
|
| 730 |
+
# memory-efficient backends for 4-D inputs -- with the 3-D head_to_batch_dim
|
| 731 |
+
# layout it falls back to the math backend, which materializes the full
|
| 732 |
+
# multi-view attention matrix (tens of GB at 512-res) and OOMs. xformers was
|
| 733 |
+
# the original efficient path but doesn't support the Blackwell GPU.
|
| 734 |
+
# reshape (not view): the multi-view key/value are non-contiguous.
|
| 735 |
+
bsz = query.shape[0]
|
| 736 |
+
head_dim = query.shape[-1] // attn.heads
|
| 737 |
+
query = query.reshape(bsz, -1, attn.heads, head_dim).transpose(1, 2)
|
| 738 |
+
key = key.reshape(bsz, -1, attn.heads, head_dim).transpose(1, 2)
|
| 739 |
+
value = value.reshape(bsz, -1, attn.heads, head_dim).transpose(1, 2)
|
| 740 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 741 |
hidden_states = F.scaled_dot_product_attention(
|
| 742 |
query, key, value, attn_mask=attention_mask, scale=attn.scale
|
| 743 |
)
|
| 744 |
+
hidden_states = hidden_states.transpose(1, 2).reshape(
|
| 745 |
+
bsz, -1, attn.heads * head_dim
|
| 746 |
+
).to(query.dtype)
|
| 747 |
|
| 748 |
# linear proj
|
| 749 |
hidden_states = attn.to_out[0](hidden_states)
|
|
@@ -1,13 +1,9 @@
|
|
| 1 |
# torch 2.11.0 is ZeroGPU-supported and the version line where torchvision 0.26.0
|
| 2 |
# and xformers 0.0.35 agree (xformers 0.0.33 hard-pinned torch==2.9.0, which ZeroGPU
|
| 3 |
-
# rejects; 0.0.35 relaxed to >=2.10).
|
| 4 |
-
#
|
| 5 |
torch==2.11.0
|
| 6 |
torchvision==0.26.0
|
| 7 |
-
# CUDA 12.8 compiler + headers so diff-gaussian-rasterization compiles against a
|
| 8 |
-
# toolkit matching cu128 torch (the container only ships CUDA 13.0). See app.py.
|
| 9 |
-
nvidia-cuda-nvcc-cu12~=12.8.0
|
| 10 |
-
nvidia-cuda-cccl-cu12~=12.8.0
|
| 11 |
numpy==1.26.4
|
| 12 |
pillow==10.4.0
|
| 13 |
diffusers[torch]==0.30.3
|
|
|
|
| 1 |
# torch 2.11.0 is ZeroGPU-supported and the version line where torchvision 0.26.0
|
| 2 |
# and xformers 0.0.35 agree (xformers 0.0.33 hard-pinned torch==2.9.0, which ZeroGPU
|
| 3 |
+
# rejects; 0.0.35 relaxed to >=2.10). ZeroGPU provides the cu130 build + a matching
|
| 4 |
+
# CUDA 13.0 toolkit, so diff-gaussian-rasterization compiles against the system toolkit.
|
| 5 |
torch==2.11.0
|
| 6 |
torchvision==0.26.0
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
numpy==1.26.4
|
| 8 |
pillow==10.4.0
|
| 9 |
diffusers[torch]==0.30.3
|