Spaces:
Running on Zero
Running on Zero
Build the model once in the worker, size the GPU reservation by the length, and check requests before the GPU is reserved.
Browse files
app.py
CHANGED
|
@@ -44,9 +44,15 @@ def _unique_path(ext: str) -> str:
|
|
| 44 |
return os.path.join("/tmp", f"t2m_{time_ns()}_{uuid4().hex[:8]}{ext}")
|
| 45 |
|
| 46 |
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
# Load REMI vocab/tokenizer (pickle dict used by the provided model)
|
| 52 |
with open(TOKENIZER_PATH, "rb") as f:
|
|
@@ -62,16 +68,28 @@ def generate_midi(prompt: str, temperature: float = 0.9, max_len: int = 500) ->
|
|
| 62 |
1024, # max_seq_len
|
| 63 |
False, # use_rotary
|
| 64 |
8, # rotary_dim
|
| 65 |
-
device=
|
| 66 |
)
|
| 67 |
-
model.load_state_dict(torch.load(MODEL_PATH, map_location=
|
| 68 |
model.eval()
|
|
|
|
| 69 |
|
| 70 |
tokenizer = T5Tokenizer.from_pretrained("google/flan-t5-base")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
inputs = tokenizer(prompt, return_tensors="pt", padding=True, truncation=True)
|
| 72 |
|
| 73 |
-
input_ids = nn.utils.rnn.pad_sequence(inputs.input_ids, batch_first=True, padding_value=0).to(
|
| 74 |
-
attention_mask = nn.utils.rnn.pad_sequence(inputs.attention_mask, batch_first=True, padding_value=0).to(
|
| 75 |
|
| 76 |
with torch.no_grad():
|
| 77 |
output = model.generate(input_ids, attention_mask, max_len=max_len, temperature=temperature)
|
|
@@ -83,7 +101,10 @@ def generate_midi(prompt: str, temperature: float = 0.9, max_len: int = 500) ->
|
|
| 83 |
generated_midi.dump_midi(midi_path)
|
| 84 |
return midi_path
|
| 85 |
|
| 86 |
-
|
|
|
|
|
|
|
|
|
|
| 87 |
def process_fn(prompt: str, temperature: float, max_length: int):
|
| 88 |
"""
|
| 89 |
Generate a MIDI from a text description.
|
|
@@ -98,6 +119,15 @@ def process_fn(prompt: str, temperature: float, max_length: int):
|
|
| 98 |
midi_path (str): The generated MIDI.
|
| 99 |
"""
|
| 100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
try:
|
| 102 |
return generate_midi(prompt, float(temperature), int(max_length))
|
| 103 |
except Exception as error:
|
|
|
|
| 44 |
return os.path.join("/tmp", f"t2m_{time_ns()}_{uuid4().hex[:8]}{ext}")
|
| 45 |
|
| 46 |
|
| 47 |
+
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
|
| 48 |
+
model = None
|
| 49 |
+
r_tokenizer = None
|
| 50 |
+
tokenizer = None
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def load_model():
|
| 54 |
+
"""Builds the model on the CPU, then places it on DEVICE."""
|
| 55 |
+
global model, r_tokenizer, tokenizer
|
| 56 |
|
| 57 |
# Load REMI vocab/tokenizer (pickle dict used by the provided model)
|
| 58 |
with open(TOKENIZER_PATH, "rb") as f:
|
|
|
|
| 68 |
1024, # max_seq_len
|
| 69 |
False, # use_rotary
|
| 70 |
8, # rotary_dim
|
| 71 |
+
device="cpu" # device
|
| 72 |
)
|
| 73 |
+
model.load_state_dict(torch.load(MODEL_PATH, map_location="cpu"))
|
| 74 |
model.eval()
|
| 75 |
+
model.to(DEVICE)
|
| 76 |
|
| 77 |
tokenizer = T5Tokenizer.from_pretrained("google/flan-t5-base")
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
# Built in the worker, which runs process_fn, on its main thread, where ZeroGPU's emulation records
|
| 81 |
+
# the CUDA placement, so that no request spends the caller's allowance on building it. The server
|
| 82 |
+
# never runs process_fn.
|
| 83 |
+
if __name__ != "__main__":
|
| 84 |
+
load_model()
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
# Core Text -> MIDI
|
| 88 |
+
def generate_midi(prompt: str, temperature: float = 0.9, max_len: int = 500) -> str:
|
| 89 |
inputs = tokenizer(prompt, return_tensors="pt", padding=True, truncation=True)
|
| 90 |
|
| 91 |
+
input_ids = nn.utils.rnn.pad_sequence(inputs.input_ids, batch_first=True, padding_value=0).to(DEVICE)
|
| 92 |
+
attention_mask = nn.utils.rnn.pad_sequence(inputs.attention_mask, batch_first=True, padding_value=0).to(DEVICE)
|
| 93 |
|
| 94 |
with torch.no_grad():
|
| 95 |
output = model.generate(input_ids, attention_mask, max_len=max_len, temperature=temperature)
|
|
|
|
| 101 |
generated_midi.dump_midi(midi_path)
|
| 102 |
return midi_path
|
| 103 |
|
| 104 |
+
def gpu_seconds(prompt: str, temperature: float, max_length: int) -> float:
|
| 105 |
+
return 15 + 0.1 * int(max_length)
|
| 106 |
+
|
| 107 |
+
|
| 108 |
def process_fn(prompt: str, temperature: float, max_length: int):
|
| 109 |
"""
|
| 110 |
Generate a MIDI from a text description.
|
|
|
|
| 119 |
midi_path (str): The generated MIDI.
|
| 120 |
"""
|
| 121 |
|
| 122 |
+
# Checked before the GPU is reserved, so a request the model cannot take spends none of the
|
| 123 |
+
# caller's ZeroGPU allowance
|
| 124 |
+
if not (prompt or "").strip():
|
| 125 |
+
raise gr.Error("Describe the music to generate.")
|
| 126 |
+
return compose(prompt, temperature, max_length)
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
@spaces.GPU(duration=gpu_seconds)
|
| 130 |
+
def compose(prompt: str, temperature: float, max_length: int) -> str:
|
| 131 |
try:
|
| 132 |
return generate_midi(prompt, float(temperature), int(max_length))
|
| 133 |
except Exception as error:
|