Spaces:
Running on Zero
Running on Zero
Refuse a recording over 10 minutes before reserving the GPU, and size each reservation
Browse filesThe reservation is computed from the length (300 s of piano measured at about 15 s), and unreadable inputs are refused before the GPU is reserved.
app.py
CHANGED
|
@@ -8,6 +8,8 @@ import librosa
|
|
| 8 |
import tempfile
|
| 9 |
import os
|
| 10 |
|
|
|
|
|
|
|
| 11 |
# setuptools dropped this module in version 81, and it is only needed here
|
| 12 |
# to locate data files inside the installed transkun package, which
|
| 13 |
# importlib.resources does from the standard library.
|
|
@@ -41,7 +43,7 @@ def load_model(device: str):
|
|
| 41 |
checkpoint = torch.load(defaultWeight, map_location=device)
|
| 42 |
model = TransKun(conf=conf).to(device)
|
| 43 |
|
| 44 |
-
#
|
| 45 |
if "best_state_dict" in checkpoint:
|
| 46 |
model.load_state_dict(checkpoint["best_state_dict"], strict=False)
|
| 47 |
else:
|
|
@@ -50,7 +52,16 @@ def load_model(device: str):
|
|
| 50 |
model.eval()
|
| 51 |
return model
|
| 52 |
|
| 53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
def transcribe(input_file):
|
| 55 |
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 56 |
model = load_model(device)
|
|
@@ -84,6 +95,19 @@ def transcribe(input_file):
|
|
| 84 |
return out_path
|
| 85 |
|
| 86 |
def process_fn(input_audio_path: str) -> str:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
midi_path = transcribe(input_audio_path)
|
| 88 |
return midi_path
|
| 89 |
|
|
|
|
| 8 |
import tempfile
|
| 9 |
import os
|
| 10 |
|
| 11 |
+
import soundfile as sf
|
| 12 |
+
|
| 13 |
# setuptools dropped this module in version 81, and it is only needed here
|
| 14 |
# to locate data files inside the installed transkun package, which
|
| 15 |
# importlib.resources does from the standard library.
|
|
|
|
| 43 |
checkpoint = torch.load(defaultWeight, map_location=device)
|
| 44 |
model = TransKun(conf=conf).to(device)
|
| 45 |
|
| 46 |
+
# Checkpoints keep their weights under either key
|
| 47 |
if "best_state_dict" in checkpoint:
|
| 48 |
model.load_state_dict(checkpoint["best_state_dict"], strict=False)
|
| 49 |
else:
|
|
|
|
| 52 |
model.eval()
|
| 53 |
return model
|
| 54 |
|
| 55 |
+
# The whole recording is transcribed in one pass, so the cost grows with its length
|
| 56 |
+
MAX_INPUT_SECONDS = 600
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def gpu_seconds(input_file):
|
| 60 |
+
# Measured at about 15 s for 300 s of piano, building the model included, padded
|
| 61 |
+
return 10 + 0.1 * sf.info(input_file).duration
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
@spaces.GPU(duration=gpu_seconds)
|
| 65 |
def transcribe(input_file):
|
| 66 |
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 67 |
model = load_model(device)
|
|
|
|
| 95 |
return out_path
|
| 96 |
|
| 97 |
def process_fn(input_audio_path: str) -> str:
|
| 98 |
+
# Checked before the GPU is reserved, so a request the model cannot take spends none of the
|
| 99 |
+
# caller's ZeroGPU allowance
|
| 100 |
+
if not input_audio_path:
|
| 101 |
+
raise gr.Error("Provide the piano recording to transcribe.")
|
| 102 |
+
try:
|
| 103 |
+
duration = sf.info(input_audio_path).duration
|
| 104 |
+
except Exception as exc:
|
| 105 |
+
raise gr.Error(f"Could not read the audio file: {exc}") from exc
|
| 106 |
+
if duration > MAX_INPUT_SECONDS:
|
| 107 |
+
raise gr.Error(
|
| 108 |
+
f"The recording is {duration:.1f} s long. Trim it to {MAX_INPUT_SECONDS // 60} "
|
| 109 |
+
"minutes or less."
|
| 110 |
+
)
|
| 111 |
midi_path = transcribe(input_audio_path)
|
| 112 |
return midi_path
|
| 113 |
|