Spaces:
Running on Zero
Running on Zero
Upload folder using huggingface_hub
Browse files- app.py +7 -0
- backend.py +33 -11
- vendor/SchenkerDiff/inference.py +2 -2
app.py
CHANGED
|
@@ -1,6 +1,13 @@
|
|
| 1 |
"""app.py β ProGress Music Generation Demo"""
|
| 2 |
from __future__ import annotations
|
| 3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
import os
|
| 5 |
import random
|
| 6 |
import sys
|
|
|
|
| 1 |
"""app.py β ProGress Music Generation Demo"""
|
| 2 |
from __future__ import annotations
|
| 3 |
|
| 4 |
+
# ZeroGPU: import `spaces` before torch so its CUDA-emulation hooks install
|
| 5 |
+
# first. No-op when not on ZeroGPU; absent (and skipped) in local dev.
|
| 6 |
+
try:
|
| 7 |
+
import spaces # noqa: F401
|
| 8 |
+
except Exception:
|
| 9 |
+
pass
|
| 10 |
+
|
| 11 |
import os
|
| 12 |
import random
|
| 13 |
import sys
|
backend.py
CHANGED
|
@@ -772,19 +772,21 @@ def device_info() -> str:
|
|
| 772 |
cuda.is_available()/get_device_name does not initialise a CUDA context,
|
| 773 |
so this is cheap to call at startup.
|
| 774 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 775 |
try:
|
| 776 |
import torch
|
| 777 |
if torch.cuda.is_available():
|
| 778 |
return f"GPU Β· {torch.cuda.get_device_name(0)}"
|
| 779 |
except Exception:
|
| 780 |
pass
|
| 781 |
-
|
| 782 |
-
# the main process reports no CUDA β surface the ZeroGPU runtime instead.
|
| 783 |
-
try:
|
| 784 |
-
import spaces # noqa: F401
|
| 785 |
-
return "ZeroGPU (attached on demand)"
|
| 786 |
-
except Exception:
|
| 787 |
-
return "CPU"
|
| 788 |
|
| 789 |
|
| 790 |
# βββ Module-level cache for SchenkerDiff inference βββββββββββββββββββββββββββ
|
|
@@ -792,6 +794,13 @@ def device_info() -> str:
|
|
| 792 |
# so successive batches in generate_until_target reuse them.
|
| 793 |
_GEN_CACHE: dict = {}
|
| 794 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 795 |
|
| 796 |
def _available_processed_idxs() -> list[int]:
|
| 797 |
"""Indices of processed .pt files actually on disk (for varied conditioning)."""
|
|
@@ -857,7 +866,10 @@ def _ensure_generation_setup(progress=None) -> dict:
|
|
| 857 |
# (b) When no GPU is present, PL passes map_location=None, so default the
|
| 858 |
# load to CPU.
|
| 859 |
_orig_torch_load = torch.load
|
| 860 |
-
|
|
|
|
|
|
|
|
|
|
| 861 |
_cpu_dev = torch.device("cpu")
|
| 862 |
def _patched_load(f, *a, **kw):
|
| 863 |
kw["weights_only"] = False
|
|
@@ -879,7 +891,7 @@ def _ensure_generation_setup(progress=None) -> dict:
|
|
| 879 |
# Pin the model + all generation tensors to one device chosen *now*.
|
| 880 |
# Under ZeroGPU, CUDA only becomes available inside the @spaces.GPU call
|
| 881 |
# (after import time), so we can't rely on the import-time config.DEVICE.
|
| 882 |
-
dev = torch.device("cuda" if
|
| 883 |
model = model.to(dev)
|
| 884 |
edim = int(model.limit_dist.E.shape[0])
|
| 885 |
|
|
@@ -1166,17 +1178,27 @@ def generate_until_target(
|
|
| 1166 |
|
| 1167 |
Returns the (mutated or new) phrases_data dict.
|
| 1168 |
"""
|
|
|
|
| 1169 |
try:
|
| 1170 |
return _run_generation_gpu(target, batch_size, max_attempts_factor, progress, pool)
|
| 1171 |
except Exception as gpu_err:
|
| 1172 |
-
# GPU unavailable / failed β
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1173 |
_GEN_CACHE.clear()
|
|
|
|
| 1174 |
if progress:
|
| 1175 |
try:
|
| 1176 |
progress(0.0, desc=f"GPU unavailable ({type(gpu_err).__name__}); running on CPUβ¦")
|
| 1177 |
except Exception:
|
| 1178 |
pass
|
| 1179 |
-
|
|
|
|
|
|
|
|
|
|
| 1180 |
|
| 1181 |
|
| 1182 |
# Keep the old function name as a thin wrapper for back-compat.
|
|
|
|
| 772 |
cuda.is_available()/get_device_name does not initialise a CUDA context,
|
| 773 |
so this is cheap to call at startup.
|
| 774 |
"""
|
| 775 |
+
# On a ZeroGPU Space the GPU only exists inside @spaces.GPU calls; touching
|
| 776 |
+
# torch.cuda in the main process triggers a forbidden low-level CUDA init.
|
| 777 |
+
# Detect ZeroGPU via the `spaces` package FIRST and avoid torch.cuda there.
|
| 778 |
+
try:
|
| 779 |
+
import spaces # noqa: F401
|
| 780 |
+
return "ZeroGPU (attached on demand)"
|
| 781 |
+
except Exception:
|
| 782 |
+
pass
|
| 783 |
try:
|
| 784 |
import torch
|
| 785 |
if torch.cuda.is_available():
|
| 786 |
return f"GPU Β· {torch.cuda.get_device_name(0)}"
|
| 787 |
except Exception:
|
| 788 |
pass
|
| 789 |
+
return "CPU"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 790 |
|
| 791 |
|
| 792 |
# βββ Module-level cache for SchenkerDiff inference βββββββββββββββββββββββββββ
|
|
|
|
| 794 |
# so successive batches in generate_until_target reuse them.
|
| 795 |
_GEN_CACHE: dict = {}
|
| 796 |
|
| 797 |
+
# When True, generation is pinned to CPU regardless of what torch.cuda reports.
|
| 798 |
+
# Needed for the ZeroGPU CPU-fallback path: ZeroGPU's emulated torch.cuda says
|
| 799 |
+
# a GPU is available even in the main process, so acting on it there would
|
| 800 |
+
# trigger a forbidden low-level CUDA init. The fallback sets this before
|
| 801 |
+
# retrying on CPU.
|
| 802 |
+
_FORCE_CPU: bool = False
|
| 803 |
+
|
| 804 |
|
| 805 |
def _available_processed_idxs() -> list[int]:
|
| 806 |
"""Indices of processed .pt files actually on disk (for varied conditioning)."""
|
|
|
|
| 866 |
# (b) When no GPU is present, PL passes map_location=None, so default the
|
| 867 |
# load to CPU.
|
| 868 |
_orig_torch_load = torch.load
|
| 869 |
+
# _FORCE_CPU wins over the (possibly emulated) cuda.is_available() so the
|
| 870 |
+
# CPU-fallback path never initialises CUDA in the ZeroGPU main process.
|
| 871 |
+
use_cuda = (not _FORCE_CPU) and torch.cuda.is_available()
|
| 872 |
+
_no_cuda = not use_cuda
|
| 873 |
_cpu_dev = torch.device("cpu")
|
| 874 |
def _patched_load(f, *a, **kw):
|
| 875 |
kw["weights_only"] = False
|
|
|
|
| 891 |
# Pin the model + all generation tensors to one device chosen *now*.
|
| 892 |
# Under ZeroGPU, CUDA only becomes available inside the @spaces.GPU call
|
| 893 |
# (after import time), so we can't rely on the import-time config.DEVICE.
|
| 894 |
+
dev = torch.device("cuda") if use_cuda else _cpu_dev
|
| 895 |
model = model.to(dev)
|
| 896 |
edim = int(model.limit_dist.E.shape[0])
|
| 897 |
|
|
|
|
| 1178 |
|
| 1179 |
Returns the (mutated or new) phrases_data dict.
|
| 1180 |
"""
|
| 1181 |
+
global _FORCE_CPU
|
| 1182 |
try:
|
| 1183 |
return _run_generation_gpu(target, batch_size, max_attempts_factor, progress, pool)
|
| 1184 |
except Exception as gpu_err:
|
| 1185 |
+
# GPU unavailable / failed β retry on CPU. Pin to CPU first: under
|
| 1186 |
+
# ZeroGPU the main process must never touch CUDA (emulated is_available()
|
| 1187 |
+
# reports True), so _FORCE_CPU stops setup from initialising the GPU here.
|
| 1188 |
+
import traceback
|
| 1189 |
+
print("GPU generation failed; falling back to CPU:\n" + traceback.format_exc(),
|
| 1190 |
+
file=sys.stderr, flush=True)
|
| 1191 |
_GEN_CACHE.clear()
|
| 1192 |
+
_FORCE_CPU = True
|
| 1193 |
if progress:
|
| 1194 |
try:
|
| 1195 |
progress(0.0, desc=f"GPU unavailable ({type(gpu_err).__name__}); running on CPUβ¦")
|
| 1196 |
except Exception:
|
| 1197 |
pass
|
| 1198 |
+
try:
|
| 1199 |
+
return _run_generation(target, batch_size, max_attempts_factor, progress, pool)
|
| 1200 |
+
finally:
|
| 1201 |
+
_FORCE_CPU = False
|
| 1202 |
|
| 1203 |
|
| 1204 |
# Keep the old function name as a thin wrapper for back-compat.
|
vendor/SchenkerDiff/inference.py
CHANGED
|
@@ -34,8 +34,8 @@ def initialize_model():
|
|
| 34 |
|
| 35 |
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
| 36 |
torch.set_float32_matmul_precision('medium')
|
| 37 |
-
|
| 38 |
-
|
| 39 |
|
| 40 |
if not dist.is_initialized():
|
| 41 |
try:
|
|
|
|
| 34 |
|
| 35 |
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
| 36 |
torch.set_float32_matmul_precision('medium')
|
| 37 |
+
# NB: no torch.cuda.empty_cache() here β under ZeroGPU's emulated main process
|
| 38 |
+
# cuda.is_available() is True but any real CUDA call triggers a forbidden init.
|
| 39 |
|
| 40 |
if not dist.is_initialized():
|
| 41 |
try:
|