Spaces:
Running on Zero
Running on Zero
Build the default model in the worker, clean up, and declare the weights' license
Browse filesMoves the model card to module scope, builds and places the default model in the worker and fetches the others there, removes debug prints, dead code, and the nested and unused GPU functions, and declares CC-BY-NC-SA-4.0, the license the authors state for the weights.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README.md
CHANGED
|
@@ -8,7 +8,7 @@ sdk_version: 6.24.0
|
|
| 8 |
python_version: 3.11
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
| 11 |
-
license:
|
| 12 |
short_description: Remixes and extends audio by masked generation
|
| 13 |
tags:
|
| 14 |
- category:generation
|
|
@@ -22,237 +22,13 @@ tags:
|
|
| 22 |
|
| 23 |
# VampNet
|
| 24 |
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
- [programmatic usage](#programmatic-usage)
|
| 29 |
-
- [launching the web app](#launching-the-web-app)
|
| 30 |
-
- [training / fine-tuning](#training--fine-tuning)
|
| 31 |
-
- [training a model](#training-a-model)
|
| 32 |
-
- [debugging training](#debugging-training)
|
| 33 |
-
- [fine-tuning](#fine-tuning)
|
| 34 |
-
- [exporting your model](#exporting-your-model)
|
| 35 |
-
- [unloop](#unloop)
|
| 36 |
-
- [token telephone](#token-telephone)
|
| 37 |
-
- [a note on argbind](#a-note-on-argbind)
|
| 38 |
-
- [take a look at the pretrained models](#take-a-look-at-the-pretrained-models)
|
| 39 |
-
- [licensing for pretrained models](#licensing-for-pretrained-models)
|
| 40 |
-
|
| 41 |
-
## setting up
|
| 42 |
-
|
| 43 |
-
python 3.9-3.11 works well. (for example, using conda)
|
| 44 |
-
```bash
|
| 45 |
-
conda create -n vampnet python=3.9
|
| 46 |
-
conda activate vampnet
|
| 47 |
-
```
|
| 48 |
-
|
| 49 |
-
install VampNet
|
| 50 |
-
|
| 51 |
-
```bash
|
| 52 |
-
git clone https://github.com/hugofloresgarcia/vampnet.git
|
| 53 |
-
pip install -e ./vampnet
|
| 54 |
-
```
|
| 55 |
-
|
| 56 |
-
## programmatic usage
|
| 57 |
-
|
| 58 |
-
quick start!
|
| 59 |
-
```python
|
| 60 |
-
import random
|
| 61 |
-
import vampnet
|
| 62 |
-
import audiotools as at
|
| 63 |
-
|
| 64 |
-
# load the default vampnet model
|
| 65 |
-
interface = vampnet.interface.Interface.default()
|
| 66 |
-
|
| 67 |
-
# list available finetuned models
|
| 68 |
-
finetuned_model_choices = interface.available_models()
|
| 69 |
-
print(f"available finetuned models: {finetuned_model_choices}")
|
| 70 |
-
|
| 71 |
-
# pick a random finetuned model
|
| 72 |
-
model_choice = random.choice(finetuned_model_choices)
|
| 73 |
-
print(f"choosing model: {model_choice}")
|
| 74 |
-
|
| 75 |
-
# load a finetuned model
|
| 76 |
-
interface.load_finetuned(model_choice)
|
| 77 |
-
|
| 78 |
-
# load an example audio file
|
| 79 |
-
signal = at.AudioSignal("assets/example.wav")
|
| 80 |
-
|
| 81 |
-
# get the tokens for the audio
|
| 82 |
-
codes = interface.encode(signal)
|
| 83 |
-
|
| 84 |
-
# build a mask for the audio
|
| 85 |
-
mask = interface.build_mask(
|
| 86 |
-
codes, signal,
|
| 87 |
-
periodic_prompt=7,
|
| 88 |
-
upper_codebook_mask=3,
|
| 89 |
-
)
|
| 90 |
-
|
| 91 |
-
# generate the output tokens
|
| 92 |
-
output_tokens = interface.vamp(
|
| 93 |
-
codes, mask, return_mask=False,
|
| 94 |
-
temperature=1.0,
|
| 95 |
-
typical_filtering=True,
|
| 96 |
-
)
|
| 97 |
-
|
| 98 |
-
# convert them to a signal
|
| 99 |
-
output_signal = interface.decode(output_tokens)
|
| 100 |
-
|
| 101 |
-
# save the output signal
|
| 102 |
-
output_signal.write("scratch/output.wav")
|
| 103 |
-
```
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
# Launching the Web app
|
| 107 |
-
You can launch a gradio UI to play with vampnet.
|
| 108 |
-
|
| 109 |
-
```bash
|
| 110 |
-
python app.py
|
| 111 |
-
```
|
| 112 |
-
|
| 113 |
-
# Training / Fine-tuning
|
| 114 |
-
|
| 115 |
-
## Training a model
|
| 116 |
-
|
| 117 |
-
To train a model, run the following script:
|
| 118 |
-
|
| 119 |
-
```bash
|
| 120 |
-
python scripts/exp/train.py --args.load conf/vampnet.yml --save_path /path/to/checkpoints
|
| 121 |
-
```
|
| 122 |
-
|
| 123 |
-
for multi-gpu training, use torchrun:
|
| 124 |
-
|
| 125 |
-
```bash
|
| 126 |
-
torchrun --nproc_per_node gpu scripts/exp/train.py --args.load conf/vampnet.yml --save_path path/to/ckpt
|
| 127 |
-
```
|
| 128 |
-
|
| 129 |
-
You can edit `conf/vampnet.yml` to change the dataset paths or any training hyperparameters.
|
| 130 |
-
|
| 131 |
-
For coarse2fine models, you can use `conf/c2f.yml` as a starting configuration.
|
| 132 |
-
|
| 133 |
-
See `python scripts/exp/train.py -h` for a list of options.
|
| 134 |
-
|
| 135 |
-
## Debugging training
|
| 136 |
-
|
| 137 |
-
To debug training, it's easier to debug with 1 gpu and 0 workers
|
| 138 |
-
|
| 139 |
-
```bash
|
| 140 |
-
CUDA_VISIBLE_DEVICES=0 python -m pdb scripts/exp/train.py --args.load conf/vampnet.yml --save_path /path/to/checkpoints --num_workers 0
|
| 141 |
-
```
|
| 142 |
-
|
| 143 |
-
# Fine-tuning
|
| 144 |
-
|
| 145 |
-
To fine-tune a model, use the script in `scripts/exp/fine_tune.py`
|
| 146 |
-
|
| 147 |
-
for an audio folder
|
| 148 |
-
```bash
|
| 149 |
-
python scripts/exp/fine_tune.py /path/to/audio/folder <fine_tune_name>
|
| 150 |
-
```
|
| 151 |
-
|
| 152 |
-
for multiple files
|
| 153 |
-
```bash
|
| 154 |
-
python scripts/exp/fine_tune.py "/path/to/audio1.mp3 /path/to/audio2/ /path/to/audio3.wav" <fine_tune_name>
|
| 155 |
-
```
|
| 156 |
-
|
| 157 |
-
This creates configuration files for a fine tuning train job. The save_paths will be set to `runs/<fine_tune_name>/coarse` and `runs/<fine_tune_name>/c2f`.
|
| 158 |
-
|
| 159 |
-
launch the coarse job:
|
| 160 |
-
```bash
|
| 161 |
-
python scripts/exp/train.py --args.load conf/generated/<fine_tune_name>/coarse.yml
|
| 162 |
-
```
|
| 163 |
-
|
| 164 |
-
this will save the coarse model to `runs/<fine_tune_name>/coarse/ckpt/best/`.
|
| 165 |
-
|
| 166 |
-
launch the c2f job:
|
| 167 |
-
```bash
|
| 168 |
-
python scripts/exp/train.py --args.load conf/generated/<fine_tune_name>/c2f.yml
|
| 169 |
-
```
|
| 170 |
-
|
| 171 |
-
# Resuming a Training/Finetuning Job from checkpoint.
|
| 172 |
-
|
| 173 |
-
To resume from checkpoint, use the `--resume` flag and the `--save_path` to point to the checkpoint you want to resume from.
|
| 174 |
-
```bash
|
| 175 |
-
python scripts/exp/train.py --args.load conf/generated/steve/coarse.yml --save_path runs/steve/coarse --resume
|
| 176 |
-
```
|
| 177 |
-
|
| 178 |
-
# Exporting your model
|
| 179 |
-
|
| 180 |
-
Once your model has been fine-tuned, you can export it to a HuggingFace model.
|
| 181 |
-
|
| 182 |
-
In order to use your model in `app.py`, you will need to export it to HuggingFace.
|
| 183 |
-
|
| 184 |
-
**NOTE**: In order to export, you will need a [huggingface account](https://huggingface.co/).
|
| 185 |
-
|
| 186 |
-
Now, log in to huggingface using the command line:
|
| 187 |
-
```bash
|
| 188 |
-
huggingface-cli login
|
| 189 |
-
```
|
| 190 |
-
|
| 191 |
-
replace the contents of the file named `./DEFAULT_HF_MODEL_REPO` with your `<HUGGINGFACE_USERNAME>/vampnet`. A model repo will be automatically created for you with `export.py`. The default is `hugggof/vampnet`.
|
| 192 |
-
|
| 193 |
-
for example, if my username is `hugggof`, I would run the following command:`
|
| 194 |
-
```bash
|
| 195 |
-
echo 'hugggof/vampnet' > ./DEFAULT_HF_MODEL_REPO
|
| 196 |
-
```
|
| 197 |
-
|
| 198 |
-
Now, run the following command to export your model (replace `<your_finetuned_model_name>` with the name of your model):
|
| 199 |
-
|
| 200 |
-
```bash
|
| 201 |
-
python scripts/exp/export.py --name <your_finetuned_model_name> --model latest
|
| 202 |
-
```
|
| 203 |
-
|
| 204 |
-
Once that's done, your model should appear on the list of available models in the gradio interface.
|
| 205 |
-
Simply run `python app.py` and select your model from the dropdown list.
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
# Unloop
|
| 209 |
-
|
| 210 |
-
Make sure you have Max installed on your laptop!
|
| 211 |
-
|
| 212 |
-
**NOTE**: To run unloop (with a GPU-powered server), you will need to install the vampnet repo in both your local machine and your GPU server.
|
| 213 |
-
|
| 214 |
-
## start a vampnet gradio server
|
| 215 |
-
|
| 216 |
-
First, **on your GPU server**, run the gradio server:
|
| 217 |
-
```bash
|
| 218 |
-
python app.py --args.load conf/interface.yml --Interface.device cuda
|
| 219 |
-
```
|
| 220 |
-
This will run a vampnet gradio API on your GPU server. Copy the address. It will be something like `https://127.0.0.1:7860/`.
|
| 221 |
-
|
| 222 |
-
**IMPORTANT** Make sure that this gradio port (by default `7860`) is forwarded to your local machine, where you have Max installed.
|
| 223 |
-
|
| 224 |
-
## start the unloop gradio client
|
| 225 |
-
Now, **on your local machine**, run the unloop gradio client.
|
| 226 |
-
```
|
| 227 |
-
cd unloop
|
| 228 |
-
pip install -r requirements.txt
|
| 229 |
-
python client.py --vampnet_url https://127.0.0.1:7860/ # replace with your gradio server address
|
| 230 |
-
```
|
| 231 |
-
This will start a gradio client that connects to the gradio server running on your GPU server.
|
| 232 |
-
|
| 233 |
-
## start the unloop Max patch
|
| 234 |
-
Now, open the unloop Max patch. It's located at `unloop/max/unloop.maxpat`.
|
| 235 |
-
|
| 236 |
-
In the tape controls, check the heartbeat (`<3`) to make sure the connection to the local gradio client is working.
|
| 237 |
-
|
| 238 |
-
have fun!
|
| 239 |
-
|
| 240 |
-
# Token Telephone
|
| 241 |
-
|
| 242 |
-
Instructions forthcoming, but the sauce is in `token_telephone/tt.py`
|
| 243 |
-
|
| 244 |
-
## A note on argbind
|
| 245 |
-
This repository relies on [argbind](https://github.com/pseeth/argbind) to manage CLIs and config files.
|
| 246 |
-
Config files are stored in the `conf/` folder.
|
| 247 |
-
|
| 248 |
-
### Take a look at the pretrained models
|
| 249 |
-
All the pretrained models (trained by hugo) are stored here: https://huggingface.co/hugggof/vampnet
|
| 250 |
-
|
| 251 |
-
### Licensing for Pretrained Models:
|
| 252 |
-
The weights for the models are licensed [`CC BY-NC-SA 4.0`](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.ml). Likewise, any VampNet models fine-tuned on the pretrained models are also licensed [`CC BY-NC-SA 4.0`](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.ml).
|
| 253 |
-
|
| 254 |
-
Download the pretrained models from [this link](https://zenodo.org/record/8136629). Then, extract the models to the `models/` folder.
|
| 255 |
-
|
| 256 |
-
|
| 257 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 258 |
|
|
|
|
|
|
| 8 |
python_version: 3.11
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
| 11 |
+
license: cc-by-nc-sa-4.0
|
| 12 |
short_description: Remixes and extends audio by masked generation
|
| 13 |
tags:
|
| 14 |
- category:generation
|
|
|
|
| 22 |
|
| 23 |
# VampNet
|
| 24 |
|
| 25 |
+
Remixes and extends audio by masked acoustic token modeling, with
|
| 26 |
+
[VampNet](https://github.com/hugofloresgarcia/vampnet) and its fine-tuned
|
| 27 |
+
models.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
+
The code is MIT. The pretrained weights are
|
| 30 |
+
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/), as are
|
| 31 |
+
models fine-tuned from them, so results cannot be used commercially and must be
|
| 32 |
+
shared alike.
|
| 33 |
|
| 34 |
+
A HARP deployment. See https://github.com/TEAMuP-dev/HARP
|
app.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
import spaces
|
| 2 |
|
| 3 |
try: # torch>=2.6 flipped torch.load(weights_only) to True; legacy ckpts need False
|
| 4 |
import torch as _torch
|
|
@@ -17,165 +17,80 @@ try: # torch>=2.6 flipped torch.load(weights_only) to True; legacy ckpts need F
|
|
| 17 |
except Exception: # torch not installed / unexpected API -- nothing to patch
|
| 18 |
pass
|
| 19 |
|
| 20 |
-
from pathlib import Path
|
| 21 |
-
import yaml
|
| 22 |
import time
|
| 23 |
-
import uuid
|
| 24 |
|
| 25 |
import numpy as np
|
| 26 |
import soundfile as sf
|
| 27 |
import audiotools as at
|
| 28 |
-
import argbind
|
| 29 |
-
import shutil
|
| 30 |
import torch
|
| 31 |
-
from
|
| 32 |
-
from pyharp.
|
| 33 |
-
from pyharp.media.audio import save_audio
|
| 34 |
from pyharp.tags import Subcategory, SampleRate, Channels
|
| 35 |
|
| 36 |
import gradio as gr
|
| 37 |
-
from vampnet.interface import Interface
|
| 38 |
from vampnet import mask as pmask
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
init_model_choice = open("DEFAULT_MODEL").read().strip()
|
|
|
|
| 45 |
|
| 46 |
-
#
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
#
|
| 50 |
-
# process_fn, rather than inside the GPU call the first time a request picks one
|
| 51 |
if __name__ != "__main__":
|
| 52 |
from vampnet import download_finetuned
|
| 53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
if _name != "default":
|
| 55 |
download_finetuned(_name)
|
| 56 |
-
print(f"Loaded initial model: {init_model_choice}")
|
| 57 |
-
print(f"Coarse model path: {interface.coarse_path}")
|
| 58 |
-
print(f"C2F model path: {interface.c2f_path}\n")
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
def to_output(sig):
|
| 62 |
-
return sig.sample_rate, sig.cpu().detach().numpy()[0][0]
|
| 63 |
-
|
| 64 |
-
MAX_DURATION_S = 10
|
| 65 |
-
def load_audio(file):
|
| 66 |
-
print(file)
|
| 67 |
-
if isinstance(file, str):
|
| 68 |
-
filepath = file
|
| 69 |
-
elif isinstance(file, tuple):
|
| 70 |
-
# not a file
|
| 71 |
-
sr, samples = file
|
| 72 |
-
samples = samples / np.iinfo(samples.dtype).max
|
| 73 |
-
return sr, samples
|
| 74 |
-
else:
|
| 75 |
-
filepath = file.name
|
| 76 |
-
sig = at.AudioSignal.salient_excerpt(
|
| 77 |
-
filepath, duration=MAX_DURATION_S
|
| 78 |
-
)
|
| 79 |
-
sig = at.AudioSignal(filepath)
|
| 80 |
-
return to_output(sig)
|
| 81 |
-
|
| 82 |
|
| 83 |
|
| 84 |
from torch_pitch_shift import pitch_shift, get_fast_shifts
|
| 85 |
def shift_pitch(signal, interval: int):
|
| 86 |
signal.samples = pitch_shift(
|
| 87 |
-
signal.samples,
|
| 88 |
-
shift=interval,
|
| 89 |
sample_rate=signal.sample_rate
|
| 90 |
)
|
| 91 |
return signal
|
| 92 |
|
| 93 |
|
| 94 |
-
def onsets(sig: at.AudioSignal, hop_length: int):
|
| 95 |
-
assert sig.batch_size == 1, "batch size must be 1"
|
| 96 |
-
assert sig.num_channels == 1, "mono signals only"
|
| 97 |
-
import librosa
|
| 98 |
-
onset_frame_idxs = librosa.onset.onset_detect(
|
| 99 |
-
y=sig.samples[0][0].detach().cpu().numpy(), sr=sig.sample_rate,
|
| 100 |
-
hop_length=hop_length,
|
| 101 |
-
backtrack=True,
|
| 102 |
-
)
|
| 103 |
-
return onset_frame_idxs
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
@spaces.GPU
|
| 107 |
-
def new_vampnet_mask(self,
|
| 108 |
-
codes,
|
| 109 |
-
onset_idxs,
|
| 110 |
-
width: int = 5,
|
| 111 |
-
periodic_prompt=2,
|
| 112 |
-
upper_codebook_mask=1,
|
| 113 |
-
drop_amt: float = 0.1
|
| 114 |
-
):
|
| 115 |
-
from vampnet.newmask import mask_and, mask_or, onset_mask, periodic_mask, drop_ones, codebook_mask
|
| 116 |
-
mask = mask_and(
|
| 117 |
-
periodic_mask(codes, periodic_prompt, 1, random_roll=False),
|
| 118 |
-
mask_or( # this re-masks the onsets, according to a periodic schedule
|
| 119 |
-
onset_mask(onset_idxs, codes, width=width),
|
| 120 |
-
periodic_mask(codes, periodic_prompt, 1, random_roll=False),
|
| 121 |
-
)
|
| 122 |
-
).int()
|
| 123 |
-
# make sure the onset idxs themselves are unmasked
|
| 124 |
-
# mask = 1 - mask
|
| 125 |
-
mask[:, :, onset_idxs] = 0
|
| 126 |
-
mask = mask.cpu() # debug
|
| 127 |
-
mask = 1-drop_ones(1-mask, drop_amt)
|
| 128 |
-
mask = codebook_mask(mask, upper_codebook_mask)
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
mask = mask.to(self.device)
|
| 132 |
-
return mask[:, :, :]
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
@spaces.GPU
|
| 137 |
def _vamp_internal(
|
| 138 |
-
seed, input_audio, model_choice,
|
| 139 |
-
pitch_shift_amt, periodic_p,
|
| 140 |
-
n_mask_codebooks, onset_mask_width,
|
| 141 |
-
dropout, sampletemp, typical_filtering,
|
| 142 |
-
typical_mass, typical_min_tokens, top_p,
|
| 143 |
-
sample_cutoff, stretch_factor, sampling_steps, beat_mask_ms, num_feedback_steps
|
| 144 |
):
|
| 145 |
-
if torch.cuda.is_available():
|
| 146 |
-
device = "cuda"
|
| 147 |
-
elif torch.backends.mps.is_available():
|
| 148 |
-
device = "mps"
|
| 149 |
-
else:
|
| 150 |
-
device = "cpu"
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
print("args!")
|
| 154 |
-
print(f"seed: {seed}")
|
| 155 |
-
print(f"input_audio: {input_audio}")
|
| 156 |
-
print(f"model_choice: {model_choice}")
|
| 157 |
-
print(f"pitch_shift_amt: {pitch_shift_amt}")
|
| 158 |
-
print(f"periodic_p: {periodic_p}")
|
| 159 |
-
print(f"n_mask_codebooks: {n_mask_codebooks}")
|
| 160 |
-
print(f"onset_mask_width: {onset_mask_width}")
|
| 161 |
-
print(f"dropout: {dropout}")
|
| 162 |
-
print(f"sampletemp: {sampletemp}")
|
| 163 |
-
print(f"typical_filtering: {typical_filtering}")
|
| 164 |
-
print(f"typical_mass: {typical_mass}")
|
| 165 |
-
print(f"typical_min_tokens: {typical_min_tokens}")
|
| 166 |
-
print(f"top_p: {top_p}")
|
| 167 |
-
print(f"sample_cutoff: {sample_cutoff}")
|
| 168 |
-
print(f"stretch_factor: {stretch_factor}")
|
| 169 |
-
print(f"sampling_steps: {sampling_steps}")
|
| 170 |
-
print(f"api: {api}")
|
| 171 |
-
print(f"beat_mask_ms: {beat_mask_ms}")
|
| 172 |
-
print(f"using device {interface.device}")
|
| 173 |
-
print(f"num feedback steps: {num_feedback_steps}")
|
| 174 |
-
|
| 175 |
-
|
| 176 |
t0 = time.time()
|
| 177 |
-
interface.to(device)
|
| 178 |
-
print(f"using device {interface.device}")
|
| 179 |
_seed = seed if seed > 0 else None
|
| 180 |
if _seed is None:
|
| 181 |
_seed = int(torch.randint(0, 2**32, (1,)).item())
|
|
@@ -185,7 +100,7 @@ def _vamp_internal(
|
|
| 185 |
raise gr.Error("no input audio received!")
|
| 186 |
sr, input_audio = input_audio
|
| 187 |
input_audio = input_audio / np.iinfo(input_audio.dtype).max
|
| 188 |
-
|
| 189 |
sig = at.AudioSignal(input_audio, sr).to_mono()
|
| 190 |
|
| 191 |
loudness = sig.loudness()
|
|
@@ -199,31 +114,15 @@ def _vamp_internal(
|
|
| 199 |
|
| 200 |
codes = interface.encode(sig)
|
| 201 |
|
| 202 |
-
# mask = new_vampnet_mask(
|
| 203 |
-
# interface,
|
| 204 |
-
# codes,
|
| 205 |
-
# onset_idxs=onsets(sig, hop_length=interface.codec.hop_length),
|
| 206 |
-
# width=onset_mask_width,
|
| 207 |
-
# periodic_prompt=periodic_p,
|
| 208 |
-
# upper_codebook_mask=n_mask_codebooks,
|
| 209 |
-
# drop_amt=dropout
|
| 210 |
-
# ).long()
|
| 211 |
-
|
| 212 |
-
|
| 213 |
mask = interface.build_mask(
|
| 214 |
codes,
|
| 215 |
-
sig=sig,
|
| 216 |
periodic_prompt=periodic_p,
|
| 217 |
onset_mask_width=onset_mask_width,
|
| 218 |
_dropout=dropout,
|
| 219 |
upper_codebook_mask=n_mask_codebooks,
|
| 220 |
)
|
| 221 |
if beat_mask_ms > 0:
|
| 222 |
-
# bm = pmask.mask_or(
|
| 223 |
-
# pmask.periodic_mask(
|
| 224 |
-
# codes, periodic_p, random_roll=False
|
| 225 |
-
# ),
|
| 226 |
-
# )
|
| 227 |
mask = pmask.mask_and(
|
| 228 |
mask, interface.make_beat_mask(
|
| 229 |
sig, after_beat_s=beat_mask_ms/1000.,
|
|
@@ -248,9 +147,9 @@ def _vamp_internal(
|
|
| 248 |
time_stretch_factor=stretch_factor,
|
| 249 |
return_mask=True,
|
| 250 |
temperature=sampletemp,
|
| 251 |
-
typical_filtering=typical_filtering,
|
| 252 |
-
typical_mass=typical_mass,
|
| 253 |
-
typical_min_tokens=typical_min_tokens,
|
| 254 |
top_p=top_p,
|
| 255 |
seed=_seed,
|
| 256 |
sample_cutoff=sample_cutoff,
|
|
@@ -260,55 +159,7 @@ def _vamp_internal(
|
|
| 260 |
sig = interface.decode(codes)
|
| 261 |
sig = sig.normalize(loudness)
|
| 262 |
|
| 263 |
-
|
| 264 |
-
plt.clf()
|
| 265 |
-
# plt.imshow(mask_z[0].cpu().numpy(), aspect='auto
|
| 266 |
-
|
| 267 |
-
if harp:
|
| 268 |
-
return sig
|
| 269 |
-
|
| 270 |
-
return to_output(sig[0]), to_output(sig[1])
|
| 271 |
-
|
| 272 |
-
@spaces.GPU
|
| 273 |
-
def vamp(input_audio,
|
| 274 |
-
sampletemp,
|
| 275 |
-
top_p,
|
| 276 |
-
periodic_p,
|
| 277 |
-
dropout,
|
| 278 |
-
stretch_factor,
|
| 279 |
-
onset_mask_width,
|
| 280 |
-
typical_filtering,
|
| 281 |
-
typical_mass,
|
| 282 |
-
typical_min_tokens,
|
| 283 |
-
seed,
|
| 284 |
-
model_choice,
|
| 285 |
-
n_mask_codebooks,
|
| 286 |
-
pitch_shift_amt,
|
| 287 |
-
sample_cutoff,
|
| 288 |
-
sampling_steps,
|
| 289 |
-
beat_mask_ms,
|
| 290 |
-
num_feedback_steps):
|
| 291 |
-
return _vamp_internal(
|
| 292 |
-
seed=seed,
|
| 293 |
-
input_audio=input_audio,
|
| 294 |
-
model_choice=model_choice,
|
| 295 |
-
pitch_shift_amt=pitch_shift_amt,
|
| 296 |
-
periodic_p=periodic_p,
|
| 297 |
-
n_mask_codebooks=n_mask_codebooks,
|
| 298 |
-
onset_mask_width=onset_mask_width,
|
| 299 |
-
dropout=dropout,
|
| 300 |
-
sampletemp=sampletemp,
|
| 301 |
-
typical_filtering=typical_filtering,
|
| 302 |
-
typical_mass=typical_mass,
|
| 303 |
-
typical_min_tokens=typical_min_tokens,
|
| 304 |
-
top_p=top_p,
|
| 305 |
-
sample_cutoff=sample_cutoff,
|
| 306 |
-
stretch_factor=stretch_factor,
|
| 307 |
-
sampling_steps=sampling_steps,
|
| 308 |
-
beat_mask_ms=beat_mask_ms,
|
| 309 |
-
num_feedback_steps=num_feedback_steps,
|
| 310 |
-
api=False,
|
| 311 |
-
)
|
| 312 |
|
| 313 |
|
| 314 |
# Generation covers the whole input, stretched, in 10 s chunks, so the cost grows with the
|
|
@@ -330,6 +181,8 @@ def process_fn(input_audio, sampletemp, periodic_p, dropout, n_mask_codebooks, m
|
|
| 330 |
stretch_factor):
|
| 331 |
# Checked before the GPU is reserved, so a request the model cannot take spends none of the
|
| 332 |
# caller's ZeroGPU allowance
|
|
|
|
|
|
|
| 333 |
if not input_audio:
|
| 334 |
raise gr.Error("Provide the audio to rework.")
|
| 335 |
try:
|
|
@@ -367,7 +220,7 @@ def harp_vamp(input_audio, sampletemp, periodic_p, dropout, n_mask_codebooks, mo
|
|
| 367 |
input_audio = (sig.sample_rate, input_audio)
|
| 368 |
|
| 369 |
sig = _vamp_internal(
|
| 370 |
-
seed=0,
|
| 371 |
input_audio=input_audio,
|
| 372 |
model_choice=model_choice,
|
| 373 |
pitch_shift_amt=0,
|
|
@@ -385,8 +238,6 @@ def harp_vamp(input_audio, sampletemp, periodic_p, dropout, n_mask_codebooks, mo
|
|
| 385 |
sampling_steps=36,
|
| 386 |
beat_mask_ms=int(0),
|
| 387 |
num_feedback_steps=1,
|
| 388 |
-
api=False,
|
| 389 |
-
harp=True,
|
| 390 |
)
|
| 391 |
|
| 392 |
sig = sig.detach().cpu()
|
|
@@ -403,26 +254,6 @@ def harp_vamp(input_audio, sampletemp, periodic_p, dropout, n_mask_codebooks, mo
|
|
| 403 |
|
| 404 |
if __name__ == "__main__":
|
| 405 |
with gr.Blocks() as demo:
|
| 406 |
-
#NEW: HARP endpoint (new PyHARP API)
|
| 407 |
-
harp_model_card = ModelCard(
|
| 408 |
-
name="VampNet",
|
| 409 |
-
description=(
|
| 410 |
-
"Generates new audio by remixing and extending your input, filling in "
|
| 411 |
-
"the blanks to create a coherent continuation in the same style. "
|
| 412 |
-
"Available models include: cat10: fine-tuned on expressive cat sounds; "
|
| 413 |
-
"lazaro-ros-sep: percussion extracted from the Lázaro Ros discography, "
|
| 414 |
-
"rich in Afro-Cuban rhythm supermetroid: trained on Super Metroid "
|
| 415 |
-
"(SNES) gameplay audio for retro, game-style soundscapes. Generation "
|
| 416 |
-
"runs in mono at the model's own rate; the result is resampled back to "
|
| 417 |
-
"the input's rate and copied across its channels, so the output has the "
|
| 418 |
-
"format it came in with but no stereo image. Repository: "
|
| 419 |
-
"https://github.com/hugofloresgarcia/vampnet Paper: "
|
| 420 |
-
"https://arxiv.org/abs/2307.04686"
|
| 421 |
-
),
|
| 422 |
-
author="Hugo Flores Garcia, Prem Seetharaman, Rithesh Kumar, Bryan Pardo",
|
| 423 |
-
tags=[Subcategory.INFILLING, SampleRate(44100), Channels(1), 'sound-effects']
|
| 424 |
-
)
|
| 425 |
-
|
| 426 |
harp_input_components = [
|
| 427 |
gr.Audio(type="filepath", label="Input Audio").harp_required(True).set_info((
|
| 428 |
"The audio to rework. The model masks out parts of this recording "
|
|
@@ -436,7 +267,7 @@ if __name__ == "__main__":
|
|
| 436 |
info="How much of the input the model changes. 0 = close copy, higher = greater remix."),
|
| 437 |
gr.Slider(label="Timbral Reference", value=3, minimum=1, maximum=14, step=1,
|
| 438 |
info="Controls the richness of timbre retained from the source audio. Lower = simpler, higher = richer timbre."),
|
| 439 |
-
gr.Dropdown(label="Model Choice", choices=list(
|
| 440 |
info="Select which fine-tuned VampNet model to use."),
|
| 441 |
gr.Slider(label="Time Stretch Factor", minimum=1, maximum=8, step=1, value=1,
|
| 442 |
info="Scales the output's length relative to the input. 1 = the same length, 2 = twice as long."),
|
|
@@ -449,15 +280,11 @@ if __name__ == "__main__":
|
|
| 449 |
]
|
| 450 |
|
| 451 |
build_endpoint(
|
| 452 |
-
model_card=
|
| 453 |
input_components=harp_input_components,
|
| 454 |
output_components=harp_output_components,
|
| 455 |
process_fn=process_fn,
|
| 456 |
)
|
| 457 |
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
demo.launch(pwa=True, show_error=True)
|
| 461 |
-
except KeyboardInterrupt:
|
| 462 |
-
shutil.rmtree("gradio-outputs", ignore_errors=True)
|
| 463 |
-
raise
|
|
|
|
| 1 |
+
import spaces # imported first, as ZeroGPU requires
|
| 2 |
|
| 3 |
try: # torch>=2.6 flipped torch.load(weights_only) to True; legacy ckpts need False
|
| 4 |
import torch as _torch
|
|
|
|
| 17 |
except Exception: # torch not installed / unexpected API -- nothing to patch
|
| 18 |
pass
|
| 19 |
|
|
|
|
|
|
|
| 20 |
import time
|
|
|
|
| 21 |
|
| 22 |
import numpy as np
|
| 23 |
import soundfile as sf
|
| 24 |
import audiotools as at
|
|
|
|
|
|
|
| 25 |
import torch
|
| 26 |
+
from pyharp.core import build_endpoint, ModelCard
|
| 27 |
+
from pyharp.media.audio import save_audio
|
|
|
|
| 28 |
from pyharp.tags import Subcategory, SampleRate, Channels
|
| 29 |
|
| 30 |
import gradio as gr
|
| 31 |
+
from vampnet.interface import Interface
|
| 32 |
from vampnet import mask as pmask
|
| 33 |
|
| 34 |
+
model_card = ModelCard(
|
| 35 |
+
name="VampNet",
|
| 36 |
+
description=(
|
| 37 |
+
"Generates new audio by remixing and extending your input, filling in "
|
| 38 |
+
"the blanks to create a coherent continuation in the same style. "
|
| 39 |
+
"Available models include cat10, fine-tuned on expressive cat sounds; "
|
| 40 |
+
"lazaro-ros-sep, percussion extracted from the Lázaro Ros discography, "
|
| 41 |
+
"rich in Afro-Cuban rhythm; and supermetroid, trained on Super Metroid "
|
| 42 |
+
"(SNES) gameplay audio for retro, game-style soundscapes. Generation "
|
| 43 |
+
"runs in mono at the model's own rate; the result is resampled back to "
|
| 44 |
+
"the input's rate and copied across its channels, so the output has the "
|
| 45 |
+
"format it came in with but no stereo image. The code is MIT, but the "
|
| 46 |
+
"pretrained weights are CC-BY-NC-SA-4.0, so results cannot be used "
|
| 47 |
+
"commercially and must be shared alike. Repository: "
|
| 48 |
+
"https://github.com/hugofloresgarcia/vampnet Paper: "
|
| 49 |
+
"https://arxiv.org/abs/2307.04686"
|
| 50 |
+
),
|
| 51 |
+
author="Hugo Flores Garcia, Prem Seetharaman, Rithesh Kumar, Bryan Pardo",
|
| 52 |
+
tags=[Subcategory.INFILLING, SampleRate(44100), Channels(1), 'sound-effects']
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
|
| 56 |
init_model_choice = open("DEFAULT_MODEL").read().strip()
|
| 57 |
+
MODEL_CHOICES = Interface.available_models()
|
| 58 |
|
| 59 |
+
# pyharp runs process_fn in a worker, which imports this file as __mp_main__ and starts with the
|
| 60 |
+
# server, so the default model is built and placed there alone. Each fine-tuned model is 2.4 GB,
|
| 61 |
+
# too much to hold all of them, so the others are only fetched here, and built when a request
|
| 62 |
+
# picks one.
|
|
|
|
| 63 |
if __name__ != "__main__":
|
| 64 |
from vampnet import download_finetuned
|
| 65 |
+
|
| 66 |
+
interface = Interface.default()
|
| 67 |
+
interface.load_finetuned(init_model_choice)
|
| 68 |
+
interface.to(DEVICE)
|
| 69 |
+
for _name in MODEL_CHOICES:
|
| 70 |
if _name != "default":
|
| 71 |
download_finetuned(_name)
|
| 72 |
+
print(f"Loaded initial model: {init_model_choice}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
|
| 74 |
|
| 75 |
from torch_pitch_shift import pitch_shift, get_fast_shifts
|
| 76 |
def shift_pitch(signal, interval: int):
|
| 77 |
signal.samples = pitch_shift(
|
| 78 |
+
signal.samples,
|
| 79 |
+
shift=interval,
|
| 80 |
sample_rate=signal.sample_rate
|
| 81 |
)
|
| 82 |
return signal
|
| 83 |
|
| 84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
def _vamp_internal(
|
| 86 |
+
seed, input_audio, model_choice,
|
| 87 |
+
pitch_shift_amt, periodic_p,
|
| 88 |
+
n_mask_codebooks, onset_mask_width,
|
| 89 |
+
dropout, sampletemp, typical_filtering,
|
| 90 |
+
typical_mass, typical_min_tokens, top_p,
|
| 91 |
+
sample_cutoff, stretch_factor, sampling_steps, beat_mask_ms, num_feedback_steps
|
| 92 |
):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
t0 = time.time()
|
|
|
|
|
|
|
| 94 |
_seed = seed if seed > 0 else None
|
| 95 |
if _seed is None:
|
| 96 |
_seed = int(torch.randint(0, 2**32, (1,)).item())
|
|
|
|
| 100 |
raise gr.Error("no input audio received!")
|
| 101 |
sr, input_audio = input_audio
|
| 102 |
input_audio = input_audio / np.iinfo(input_audio.dtype).max
|
| 103 |
+
|
| 104 |
sig = at.AudioSignal(input_audio, sr).to_mono()
|
| 105 |
|
| 106 |
loudness = sig.loudness()
|
|
|
|
| 114 |
|
| 115 |
codes = interface.encode(sig)
|
| 116 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
mask = interface.build_mask(
|
| 118 |
codes,
|
| 119 |
+
sig=sig,
|
| 120 |
periodic_prompt=periodic_p,
|
| 121 |
onset_mask_width=onset_mask_width,
|
| 122 |
_dropout=dropout,
|
| 123 |
upper_codebook_mask=n_mask_codebooks,
|
| 124 |
)
|
| 125 |
if beat_mask_ms > 0:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
mask = pmask.mask_and(
|
| 127 |
mask, interface.make_beat_mask(
|
| 128 |
sig, after_beat_s=beat_mask_ms/1000.,
|
|
|
|
| 147 |
time_stretch_factor=stretch_factor,
|
| 148 |
return_mask=True,
|
| 149 |
temperature=sampletemp,
|
| 150 |
+
typical_filtering=typical_filtering,
|
| 151 |
+
typical_mass=typical_mass,
|
| 152 |
+
typical_min_tokens=typical_min_tokens,
|
| 153 |
top_p=top_p,
|
| 154 |
seed=_seed,
|
| 155 |
sample_cutoff=sample_cutoff,
|
|
|
|
| 159 |
sig = interface.decode(codes)
|
| 160 |
sig = sig.normalize(loudness)
|
| 161 |
|
| 162 |
+
return sig
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 163 |
|
| 164 |
|
| 165 |
# Generation covers the whole input, stretched, in 10 s chunks, so the cost grows with the
|
|
|
|
| 181 |
stretch_factor):
|
| 182 |
# Checked before the GPU is reserved, so a request the model cannot take spends none of the
|
| 183 |
# caller's ZeroGPU allowance
|
| 184 |
+
if model_choice not in MODEL_CHOICES:
|
| 185 |
+
raise gr.Error(f"Unknown model: {model_choice}")
|
| 186 |
if not input_audio:
|
| 187 |
raise gr.Error("Provide the audio to rework.")
|
| 188 |
try:
|
|
|
|
| 220 |
input_audio = (sig.sample_rate, input_audio)
|
| 221 |
|
| 222 |
sig = _vamp_internal(
|
| 223 |
+
seed=0,
|
| 224 |
input_audio=input_audio,
|
| 225 |
model_choice=model_choice,
|
| 226 |
pitch_shift_amt=0,
|
|
|
|
| 238 |
sampling_steps=36,
|
| 239 |
beat_mask_ms=int(0),
|
| 240 |
num_feedback_steps=1,
|
|
|
|
|
|
|
| 241 |
)
|
| 242 |
|
| 243 |
sig = sig.detach().cpu()
|
|
|
|
| 254 |
|
| 255 |
if __name__ == "__main__":
|
| 256 |
with gr.Blocks() as demo:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 257 |
harp_input_components = [
|
| 258 |
gr.Audio(type="filepath", label="Input Audio").harp_required(True).set_info((
|
| 259 |
"The audio to rework. The model masks out parts of this recording "
|
|
|
|
| 267 |
info="How much of the input the model changes. 0 = close copy, higher = greater remix."),
|
| 268 |
gr.Slider(label="Timbral Reference", value=3, minimum=1, maximum=14, step=1,
|
| 269 |
info="Controls the richness of timbre retained from the source audio. Lower = simpler, higher = richer timbre."),
|
| 270 |
+
gr.Dropdown(label="Model Choice", choices=list(MODEL_CHOICES), value=init_model_choice,
|
| 271 |
info="Select which fine-tuned VampNet model to use."),
|
| 272 |
gr.Slider(label="Time Stretch Factor", minimum=1, maximum=8, step=1, value=1,
|
| 273 |
info="Scales the output's length relative to the input. 1 = the same length, 2 = twice as long."),
|
|
|
|
| 280 |
]
|
| 281 |
|
| 282 |
build_endpoint(
|
| 283 |
+
model_card=model_card,
|
| 284 |
input_components=harp_input_components,
|
| 285 |
output_components=harp_output_components,
|
| 286 |
process_fn=process_fn,
|
| 287 |
)
|
| 288 |
|
| 289 |
+
demo.queue()
|
| 290 |
+
demo.launch(pwa=True, show_error=True)
|
|
|
|
|
|
|
|
|
|
|
|