Spaces:
Running on Zero
Running on Zero
Vansh Chugh
fix device handling: build network on target device, keep recording on CPU until fed to sampler
dc8400f | import sys | |
| sys.stdout.reconfigure(line_buffering=True) | |
| try: | |
| import spaces | |
| except ImportError: | |
| # keep @spaces.GPU usable as a no-op; ZeroGPU requires this exact name. | |
| class spaces: | |
| class GPU: | |
| def __init__(self, func=None, duration=60): | |
| self.func = func | |
| def __call__(self, *args, **kwargs): | |
| if self.func is not None: | |
| return self.func(*args, **kwargs) | |
| func = args[0] | |
| return func | |
| import tempfile | |
| import gradio as gr | |
| import soundfile as sf | |
| import torch | |
| import torchaudio | |
| from huggingface_hub import hf_hub_download | |
| from omegaconf import OmegaConf | |
| from pyharp import ModelCard, build_endpoint | |
| from model.config import CHECKPOINTS, CHECKPOINTS_REPO | |
| from model.cqtdiff import Unet_CQT_oct_with_attention | |
| from model.edm import EDM | |
| from model.restoration import restore_audio | |
| # one entry per architecture ("piano"/"singing"), holding everything that's | |
| # lazily built/loaded once and reused across requests for that architecture | |
| _state = {} | |
| def get_arch_state(base_cfg, device): | |
| """Lazily builds (once per architecture) and caches the network and EDM diffusion parameters on `device`.""" | |
| key = base_cfg.architecture | |
| if key not in _state: | |
| net = Unet_CQT_oct_with_attention(base_cfg, device) | |
| net.to(device) | |
| net.eval() | |
| _state[key] = {"network": net, "diff_params": EDM(base_cfg), "loaded_checkpoint": None, "ltas_ref": None} | |
| return _state[key] | |
| def load_checkpoint(label, device): | |
| """Downloads (if not already cached locally) and loads the checkpoint for the selected voice/instrument, reusing the shared network for its architecture.""" | |
| filename, base_cfg = CHECKPOINTS[label] | |
| state = get_arch_state(base_cfg, device) | |
| if state["loaded_checkpoint"] != filename: | |
| ckpt_path = hf_hub_download(repo_id=CHECKPOINTS_REPO, filename=filename) | |
| checkpoint = torch.load(ckpt_path, map_location="cpu", weights_only=False) | |
| state["network"].load_state_dict(checkpoint["ema"]) | |
| state["ltas_ref"] = checkpoint["LTAS"] | |
| state["loaded_checkpoint"] = filename | |
| return state["network"], state["diff_params"], state["ltas_ref"], base_cfg | |
| model_card = ModelCard( | |
| name="BABE-2", | |
| description="Restores degraded historical piano or singing-voice recordings with a diffusion-based generative equalizer.", | |
| author="Eloi Moliner, Maija Turunen, Filip Elvander, Vesa Välimäki", | |
| tags=["restoration", "equalizer", "diffusion", "historical recordings"], | |
| ) | |
| def process_fn(input_audio_path: str, checkpoint_label: str, steps: int, strength: float) -> str: | |
| """Restores the input recording using the selected voice/instrument model, diffusion step count, and restoration strength.""" | |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| net, diff_params, ltas_ref, base_cfg = load_checkpoint(checkpoint_label, device) | |
| ltas_ref = ltas_ref.to(device) | |
| cfg = OmegaConf.create(OmegaConf.to_container(base_cfg, resolve=True)) | |
| cfg.tester.T = int(steps) | |
| cfg.tester.posterior_sampling.xi = float(strength) | |
| audio, sr = sf.read(input_audio_path) | |
| sig = torch.tensor(audio, dtype=torch.float32) | |
| if sig.dim() > 1: | |
| sig = sig.mean(dim=-1) | |
| if sr != cfg.exp.sample_rate: | |
| sig = torchaudio.functional.resample(sig, sr, cfg.exp.sample_rate) | |
| def on_progress(fraction, desc): | |
| print(f"[{fraction:.0%}] {desc}") | |
| restored = restore_audio(sig, cfg, net, diff_params, ltas_ref, device, on_progress=on_progress) | |
| out_path = tempfile.NamedTemporaryFile(suffix=".wav", delete=False).name | |
| sf.write(out_path, restored.cpu().numpy(), cfg.exp.sample_rate) | |
| return out_path | |
| def update_strength_default(checkpoint_label): | |
| """Updates the Restoration Strength slider to the selected model's paper-recommended default.""" | |
| _, base_cfg = CHECKPOINTS[checkpoint_label] | |
| return gr.update(value=float(base_cfg.tester.posterior_sampling.xi)) | |
| with gr.Blocks() as demo: | |
| checkpoint_dropdown = gr.Dropdown( | |
| choices=list(CHECKPOINTS.keys()), | |
| value="Piano (MAESTRO)", | |
| label="Voice / Instrument", | |
| info="Singer-specific models give the most faithful restoration when your recording actually resembles that singer.", | |
| ) | |
| input_components = [ | |
| gr.Audio(type="filepath", label="Input Audio").harp_required(True), | |
| checkpoint_dropdown, | |
| gr.Slider(minimum=10, maximum=100, step=1, value=51, label="Processing Steps", | |
| info="More steps can improve quality at the cost of processing time."), | |
| gr.Slider(minimum=0.0, maximum=2.0, step=0.05, value=1.0, label="Restoration Strength", | |
| info="How strongly the output is guided to match the input recording."), | |
| ] | |
| output_components = [ | |
| gr.Audio(type="filepath", label="Restored Audio").set_info("The restored recording."), | |
| ] | |
| checkpoint_dropdown.change(fn=update_strength_default, inputs=checkpoint_dropdown, outputs=input_components[3]) | |
| build_endpoint( | |
| model_card=model_card, | |
| input_components=input_components, | |
| output_components=output_components, | |
| process_fn=process_fn, | |
| ) | |
| demo.queue().launch(pwa=True) | |