Spaces:
Running on Zero
Running on Zero
Vansh Chugh commited on
Commit ·
de6f21d
1
Parent(s): 0cbb723
initial deploy
Browse files- .gitignore +5 -0
- README.md +6 -7
- SOURCES.md +4 -0
- app.py +291 -0
- diff_params/__init__.py +0 -0
- diff_params/edm.py +194 -0
- model.json +28 -0
- networks/__init__.py +0 -0
- networks/unet_cqt_oct_with_projattention_adaLN_2.py +882 -0
- requirements.txt +9 -0
- testing/__init__.py +0 -0
- testing/edm_sampler_inpainting.py +367 -0
- utils/__init__.py +0 -0
- utils/training_utils.py +384 -0
.gitignore
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__pycache__/
|
| 2 |
+
*.pyc
|
| 3 |
+
.DS_Store
|
| 4 |
+
.venv/
|
| 5 |
+
audio-inpainting-diffusion-repo/
|
README.md
CHANGED
|
@@ -1,13 +1,12 @@
|
|
| 1 |
---
|
| 2 |
title: Audio Inpainting Diffusion
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
-
python_version: '3.
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
|
|
|
| 11 |
---
|
| 12 |
-
|
| 13 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
title: Audio Inpainting Diffusion
|
| 3 |
+
emoji: 🩹
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: purple
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 5.28.0
|
| 8 |
+
python_version: '3.11'
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
| 11 |
+
license: mit
|
| 12 |
---
|
|
|
|
|
|
SOURCES.md
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Sources — audio-inpainting-diffusion
|
| 2 |
+
|
| 3 |
+
- Source repo: https://github.com/eloimoliner/audio-inpainting-diffusion
|
| 4 |
+
- Paper: https://arxiv.org/html/2305.15266
|
app.py
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
try:
|
| 2 |
+
import spaces
|
| 3 |
+
except ImportError:
|
| 4 |
+
# keep @spaces.GPU usable as a no-op; ZeroGPU requires this exact name.
|
| 5 |
+
class spaces:
|
| 6 |
+
class GPU:
|
| 7 |
+
def __init__(self, func=None, duration=60):
|
| 8 |
+
self.func = func
|
| 9 |
+
|
| 10 |
+
def __call__(self, *args, **kwargs):
|
| 11 |
+
if self.func is not None:
|
| 12 |
+
return self.func(*args, **kwargs)
|
| 13 |
+
func = args[0]
|
| 14 |
+
return func
|
| 15 |
+
|
| 16 |
+
import sys
|
| 17 |
+
sys.stdout.reconfigure(line_buffering=True)
|
| 18 |
+
|
| 19 |
+
import tempfile
|
| 20 |
+
import threading
|
| 21 |
+
|
| 22 |
+
import gradio as gr
|
| 23 |
+
import numpy as np
|
| 24 |
+
import soundfile as sf
|
| 25 |
+
import torch
|
| 26 |
+
import torchaudio
|
| 27 |
+
from huggingface_hub import hf_hub_download
|
| 28 |
+
from omegaconf import OmegaConf
|
| 29 |
+
from pyharp import ModelCard, build_endpoint
|
| 30 |
+
|
| 31 |
+
# cqt_nsgt_pytorch clips an int-dtype array against np.inf with out=, which
|
| 32 |
+
# numpy's ufunc casting rules reject on any numpy version. Compute without
|
| 33 |
+
# `out` and write the result back instead of failing outright.
|
| 34 |
+
_np_clip = np.clip
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def _clip_int_out_safe(a, a_min, a_max, out=None, **kwargs):
|
| 38 |
+
if out is not None:
|
| 39 |
+
out[...] = _np_clip(a, a_min, a_max).astype(out.dtype)
|
| 40 |
+
return out
|
| 41 |
+
return _np_clip(a, a_min, a_max, **kwargs)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
np.clip = _clip_int_out_safe
|
| 45 |
+
|
| 46 |
+
from diff_params.edm import EDM
|
| 47 |
+
from networks.unet_cqt_oct_with_projattention_adaLN_2 import Unet_CQT_oct_with_attention
|
| 48 |
+
from testing.edm_sampler_inpainting import Sampler
|
| 49 |
+
|
| 50 |
+
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
|
| 51 |
+
CHECKPOINT_REPO = "Eloimoliner/audio-inpainting-diffusion"
|
| 52 |
+
|
| 53 |
+
# Same network configs as conf/network/paper_1912_unet_cqt_oct_attention_adaLN_2.yaml
|
| 54 |
+
# and conf/network/paper_1912_unet_cqt_oct_attention_44k_2.yaml.
|
| 55 |
+
CHECKPOINTS = {
|
| 56 |
+
"MAESTRO (solo piano)": {
|
| 57 |
+
"filename": "maestro_22k_8s-750000.pt",
|
| 58 |
+
"sample_rate": 22050,
|
| 59 |
+
"audio_len": 184184,
|
| 60 |
+
"network": {
|
| 61 |
+
"use_fencoding": False,
|
| 62 |
+
"use_norm": True,
|
| 63 |
+
"depth": 7,
|
| 64 |
+
"emb_dim": 256,
|
| 65 |
+
"Ns": [64, 96, 96, 128, 128, 256, 256],
|
| 66 |
+
"attention_layers": [0, 0, 0, 0, 1, 1, 1, 1],
|
| 67 |
+
"Ss": [2, 2, 2, 2, 2, 2, 2],
|
| 68 |
+
"num_dils": [2, 3, 4, 5, 6, 7, 7],
|
| 69 |
+
"cqt": {"window": "kaiser", "beta": 1, "num_octs": 7, "bins_per_oct": 64},
|
| 70 |
+
"bottleneck_type": "res_dil_convs",
|
| 71 |
+
"num_bottleneck_layers": 1,
|
| 72 |
+
"attention_dict": {
|
| 73 |
+
"num_heads": 8, "attn_dropout": 0.0, "bias_qkv": False, "N": 0,
|
| 74 |
+
"rel_pos_num_buckets": 32, "rel_pos_max_distance": 64,
|
| 75 |
+
"use_rel_pos": False, "Nproj": 8,
|
| 76 |
+
},
|
| 77 |
+
},
|
| 78 |
+
},
|
| 79 |
+
"MusicNet (mixed classical instrumentation)": {
|
| 80 |
+
"filename": "musicnet_44k_4s-560000.pt",
|
| 81 |
+
"sample_rate": 44100,
|
| 82 |
+
"audio_len": 184184,
|
| 83 |
+
"network": {
|
| 84 |
+
"use_fencoding": False,
|
| 85 |
+
"use_norm": True,
|
| 86 |
+
"depth": 8,
|
| 87 |
+
"emb_dim": 256,
|
| 88 |
+
"Ns": [64, 64, 96, 96, 128, 128, 256, 256],
|
| 89 |
+
"attention_layers": [0, 0, 0, 0, 0, 1, 1, 1, 1],
|
| 90 |
+
"Ss": [2, 2, 2, 2, 2, 2, 2],
|
| 91 |
+
"num_dils": [2, 3, 4, 5, 6, 7, 8, 8],
|
| 92 |
+
"cqt": {"window": "kaiser", "beta": 1, "num_octs": 8, "bins_per_oct": 64},
|
| 93 |
+
"bottleneck_type": "res_dil_convs",
|
| 94 |
+
"num_bottleneck_layers": 1,
|
| 95 |
+
"attention_dict": {
|
| 96 |
+
"num_heads": 8, "attn_dropout": 0.0, "bias_qkv": False, "N": 0,
|
| 97 |
+
"rel_pos_num_buckets": 32, "rel_pos_max_distance": 64,
|
| 98 |
+
"use_rel_pos": False, "Nproj": 8,
|
| 99 |
+
},
|
| 100 |
+
},
|
| 101 |
+
},
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
# conf/diff_params/edm.yaml -- the training-time noise schedule, read by EDM.__init__.
|
| 105 |
+
BASE_DIFF_PARAMS = {
|
| 106 |
+
"sigma_data": 0.063,
|
| 107 |
+
"sigma_min": 1e-5,
|
| 108 |
+
"sigma_max": 10,
|
| 109 |
+
"P_mean": -1.2,
|
| 110 |
+
"P_std": 1.2,
|
| 111 |
+
"ro": 13,
|
| 112 |
+
"ro_train": 10,
|
| 113 |
+
"Schurn": 5,
|
| 114 |
+
"Snoise": 1,
|
| 115 |
+
"Stmin": 0,
|
| 116 |
+
"Stmax": 50,
|
| 117 |
+
"aweighting": {"use_aweighting": False, "ntaps": 101},
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
# conf/tester/inpainting_tester.yaml -- sampling-time overrides, read by Sampler.
|
| 121 |
+
# This is the same config the repo's own notebooks/demo_inpainting_spectrogram.ipynb
|
| 122 |
+
# uses for both checkpoints (it only swaps exp= and network=).
|
| 123 |
+
TESTER_DIFF_PARAMS = {
|
| 124 |
+
"same_as_training": False,
|
| 125 |
+
"sigma_data": 0.063,
|
| 126 |
+
"sigma_min": 1e-4,
|
| 127 |
+
"sigma_max": 1,
|
| 128 |
+
"P_mean": -1.2,
|
| 129 |
+
"P_std": 1.2,
|
| 130 |
+
"ro": 13,
|
| 131 |
+
"ro_train": 13,
|
| 132 |
+
"Schurn": 10,
|
| 133 |
+
"Snoise": 1.0,
|
| 134 |
+
"Stmin": 0,
|
| 135 |
+
"Stmax": 50,
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
_model_cache = {}
|
| 139 |
+
_model_locks = {name: threading.Lock() for name in CHECKPOINTS}
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def build_args(checkpoint_name, steps, guidance_strength):
|
| 143 |
+
"""Assemble the config tree the network, EDM and Sampler classes expect, mirroring the repo's hydra config composition for one checkpoint."""
|
| 144 |
+
ckpt_cfg = CHECKPOINTS[checkpoint_name]
|
| 145 |
+
return OmegaConf.create({
|
| 146 |
+
"exp": {
|
| 147 |
+
"sample_rate": ckpt_cfg["sample_rate"],
|
| 148 |
+
"audio_len": ckpt_cfg["audio_len"],
|
| 149 |
+
},
|
| 150 |
+
"network": ckpt_cfg["network"],
|
| 151 |
+
"diff_params": BASE_DIFF_PARAMS,
|
| 152 |
+
"tester": {
|
| 153 |
+
"T": steps,
|
| 154 |
+
"order": 2,
|
| 155 |
+
"filter_out_cqt_DC_Nyq": True,
|
| 156 |
+
"posterior_sampling": {"xi": guidance_strength, "norm": 2, "smoothl1_beta": 1},
|
| 157 |
+
"data_consistency": {"use": True, "type": "always", "smooth": True, "hann_size": 50},
|
| 158 |
+
"diff_params": TESTER_DIFF_PARAMS,
|
| 159 |
+
},
|
| 160 |
+
})
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
def get_network(checkpoint_name):
|
| 164 |
+
"""Build the network directly on DEVICE and load its checkpoint, caching per checkpoint name.
|
| 165 |
+
|
| 166 |
+
Building fresh on DEVICE (rather than building on CPU and calling .to(DEVICE)
|
| 167 |
+
later) matters here: the network's CQT transform allocates its kernels for a
|
| 168 |
+
specific device at construction time, so a later .to() would leave it stale.
|
| 169 |
+
"""
|
| 170 |
+
with _model_locks[checkpoint_name]:
|
| 171 |
+
if checkpoint_name not in _model_cache:
|
| 172 |
+
ckpt_cfg = CHECKPOINTS[checkpoint_name]
|
| 173 |
+
args = build_args(checkpoint_name, steps=35, guidance_strength=0.25)
|
| 174 |
+
network = Unet_CQT_oct_with_attention(args, DEVICE).to(DEVICE)
|
| 175 |
+
ckpt_path = hf_hub_download(repo_id=CHECKPOINT_REPO, filename=ckpt_cfg["filename"])
|
| 176 |
+
state_dict = torch.load(ckpt_path, map_location=DEVICE, weights_only=False)
|
| 177 |
+
network.load_state_dict(state_dict["ema"])
|
| 178 |
+
network.eval()
|
| 179 |
+
_model_cache[checkpoint_name] = network
|
| 180 |
+
return _model_cache[checkpoint_name]
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
def prepare_segment(audio, sr_in, target_sr, target_len):
|
| 184 |
+
"""Resample to the checkpoint's rate, then center-crop or zero-pad to its fixed segment length.
|
| 185 |
+
|
| 186 |
+
Adapted from Tester.resample_audio in testing/tester_inpainting.py, extended
|
| 187 |
+
to pad shorter clips: the repo only ever sees pre-cropped test-set segments,
|
| 188 |
+
but an interactive demo can be handed audio of any length.
|
| 189 |
+
"""
|
| 190 |
+
if sr_in != target_sr:
|
| 191 |
+
audio = torchaudio.functional.resample(audio, sr_in, target_sr)
|
| 192 |
+
n = audio.shape[-1]
|
| 193 |
+
if n > target_len:
|
| 194 |
+
start = (n - target_len) // 2
|
| 195 |
+
audio = audio[..., start:start + target_len]
|
| 196 |
+
elif n < target_len:
|
| 197 |
+
audio = torch.nn.functional.pad(audio, (0, target_len - n))
|
| 198 |
+
return audio
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
def build_gap_mask(audio_len, gap_ms, position_ms, sample_rate, device):
|
| 202 |
+
"""Binary mask with a single gap, matching Tester.prepare_mask's 'long' mode. position_ms of -1 centers the gap, per the repo's own 'start_gap_idx: None' convention."""
|
| 203 |
+
gap = int(gap_ms * sample_rate / 1000)
|
| 204 |
+
gap = max(1, min(gap, audio_len - 1))
|
| 205 |
+
if position_ms < 0:
|
| 206 |
+
start = audio_len // 2 - gap // 2
|
| 207 |
+
else:
|
| 208 |
+
start = int(position_ms * sample_rate / 1000)
|
| 209 |
+
start = max(0, min(start, audio_len - gap))
|
| 210 |
+
mask = torch.ones((1, audio_len), device=device)
|
| 211 |
+
mask[..., start:start + gap] = 0
|
| 212 |
+
return mask
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
@spaces.GPU
|
| 216 |
+
@torch.inference_mode()
|
| 217 |
+
def process_fn(input_audio_path, checkpoint_choice, gap_length_ms, gap_position_ms, steps, guidance_strength):
|
| 218 |
+
"""Fill a gap in the input audio using the selected diffusion model."""
|
| 219 |
+
ckpt_cfg = CHECKPOINTS[checkpoint_choice]
|
| 220 |
+
sample_rate = ckpt_cfg["sample_rate"]
|
| 221 |
+
audio_len = ckpt_cfg["audio_len"]
|
| 222 |
+
|
| 223 |
+
audio_np, sr_in = sf.read(input_audio_path, dtype="float32", always_2d=False)
|
| 224 |
+
if audio_np.ndim > 1:
|
| 225 |
+
audio_np = audio_np.mean(axis=-1) # the model is mono-only
|
| 226 |
+
audio = torch.from_numpy(audio_np).unsqueeze(0).to(DEVICE)
|
| 227 |
+
|
| 228 |
+
segment = prepare_segment(audio, sr_in, sample_rate, audio_len)
|
| 229 |
+
mask = build_gap_mask(audio_len, gap_length_ms, gap_position_ms, sample_rate, DEVICE)
|
| 230 |
+
|
| 231 |
+
network = get_network(checkpoint_choice)
|
| 232 |
+
args = build_args(checkpoint_choice, steps, guidance_strength)
|
| 233 |
+
diff_params = EDM(args)
|
| 234 |
+
sampler = Sampler(network, diff_params, args)
|
| 235 |
+
|
| 236 |
+
y_masked = segment * mask
|
| 237 |
+
pred = sampler.predict_inpainting(y_masked, mask)
|
| 238 |
+
|
| 239 |
+
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
|
| 240 |
+
out_path = f.name
|
| 241 |
+
sf.write(out_path, pred.squeeze(0).cpu().numpy(), sample_rate)
|
| 242 |
+
return out_path
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
model_card = ModelCard(
|
| 246 |
+
name="Diffusion-Based Audio Inpainting",
|
| 247 |
+
description=(
|
| 248 |
+
"Fills a gap in an audio clip using a diffusion model trained on either solo "
|
| 249 |
+
"piano (MAESTRO) or mixed classical instrumentation (MusicNet). The input is "
|
| 250 |
+
"resampled to the chosen model's rate and center-cropped or zero-padded to its "
|
| 251 |
+
"fixed segment length (about 8.4s for MAESTRO, 4.2s for MusicNet) before the gap "
|
| 252 |
+
"is filled."
|
| 253 |
+
),
|
| 254 |
+
author="Eloi Moliner, Vesa Välimäki",
|
| 255 |
+
tags=["audio-inpainting", "diffusion", "restoration"],
|
| 256 |
+
)
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
with gr.Blocks() as demo:
|
| 260 |
+
input_components = [
|
| 261 |
+
gr.Audio(type="filepath", label="Input Audio").harp_required(True),
|
| 262 |
+
gr.Dropdown(
|
| 263 |
+
choices=list(CHECKPOINTS.keys()),
|
| 264 |
+
value="MAESTRO (solo piano)",
|
| 265 |
+
label="Model",
|
| 266 |
+
info="Which checkpoint to inpaint with.",
|
| 267 |
+
),
|
| 268 |
+
gr.Slider(minimum=50, maximum=3000, step=50, value=1500, label="Gap Length (ms)",
|
| 269 |
+
info="Length of the gap to fill (default: 1500ms, per repo config)"),
|
| 270 |
+
gr.Number(value=-1, label="Gap Position (ms)",
|
| 271 |
+
info="Where the gap starts, from the beginning of the processed segment. -1 = centered (default, per repo config)"),
|
| 272 |
+
gr.Slider(minimum=10, maximum=150, step=1, value=35, label="Processing Steps",
|
| 273 |
+
info="Diffusion sampling steps (default: T=35, per repo config)"),
|
| 274 |
+
gr.Slider(minimum=0.0, maximum=1.0, step=0.05, value=0.25, label="Reconstruction Guidance",
|
| 275 |
+
info="How strongly the output is pulled toward the surrounding audio (default: ξ=0.25, per repo config)"),
|
| 276 |
+
]
|
| 277 |
+
output_components = [
|
| 278 |
+
gr.Audio(type="filepath", label="Output Audio").set_info(
|
| 279 |
+
"The processed segment with the gap filled in."
|
| 280 |
+
),
|
| 281 |
+
]
|
| 282 |
+
|
| 283 |
+
build_endpoint(
|
| 284 |
+
model_card=model_card,
|
| 285 |
+
input_components=input_components,
|
| 286 |
+
output_components=output_components,
|
| 287 |
+
process_fn=process_fn,
|
| 288 |
+
)
|
| 289 |
+
|
| 290 |
+
if __name__ == "__main__":
|
| 291 |
+
demo.queue().launch(pwa=True)
|
diff_params/__init__.py
ADDED
|
File without changes
|
diff_params/edm.py
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import numpy as np
|
| 3 |
+
|
| 4 |
+
import utils.training_utils as utils
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class EDM():
|
| 8 |
+
"""
|
| 9 |
+
Definition of most of the diffusion parameterization, following ( Karras et al., "Elucidating...", 2022)
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
def __init__(self, args):
|
| 13 |
+
"""
|
| 14 |
+
Args:
|
| 15 |
+
args (dictionary): hydra arguments
|
| 16 |
+
sigma_data (float):
|
| 17 |
+
"""
|
| 18 |
+
self.args=args
|
| 19 |
+
self.sigma_min = args.diff_params.sigma_min
|
| 20 |
+
self.sigma_max =args.diff_params.sigma_max
|
| 21 |
+
self.P_mean=args.diff_params.P_mean
|
| 22 |
+
self.P_std=args.diff_params.P_std
|
| 23 |
+
self.ro=args.diff_params.ro
|
| 24 |
+
self.ro_train=args.diff_params.ro_train
|
| 25 |
+
self.sigma_data=args.diff_params.sigma_data #depends on the training data!! precalculated variance of the dataset
|
| 26 |
+
#parameters stochastic sampling
|
| 27 |
+
self.Schurn=args.diff_params.Schurn
|
| 28 |
+
self.Stmin=args.diff_params.Stmin
|
| 29 |
+
self.Stmax=args.diff_params.Stmax
|
| 30 |
+
self.Snoise=args.diff_params.Snoise
|
| 31 |
+
|
| 32 |
+
#perceptual filter
|
| 33 |
+
if self.args.diff_params.aweighting.use_aweighting:
|
| 34 |
+
self.AW=utils.FIRFilter(filter_type="aw", fs=args.exp.sample_rate, ntaps=self.args.diff_params.aweighting.ntaps)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def get_gamma(self, t):
|
| 39 |
+
"""
|
| 40 |
+
Get the parameter gamma that defines the stochasticity of the sampler
|
| 41 |
+
Args
|
| 42 |
+
t (Tensor): shape: (N_steps, ) Tensor of timesteps, from which we will compute gamma
|
| 43 |
+
"""
|
| 44 |
+
N=t.shape[0]
|
| 45 |
+
gamma=torch.zeros(t.shape).to(t.device)
|
| 46 |
+
|
| 47 |
+
#If desired, only apply stochasticity between a certain range of noises Stmin is 0 by default and Stmax is a huge number by default. (Unless these parameters are specified, this does nothing)
|
| 48 |
+
indexes=torch.logical_and(t>self.Stmin , t<self.Stmax)
|
| 49 |
+
|
| 50 |
+
#We use Schurn=5 as the default in our experiments
|
| 51 |
+
gamma[indexes]=gamma[indexes]+torch.min(torch.Tensor([self.Schurn/N, 2**(1/2) -1]))
|
| 52 |
+
|
| 53 |
+
return gamma
|
| 54 |
+
|
| 55 |
+
def create_schedule(self,nb_steps):
|
| 56 |
+
"""
|
| 57 |
+
Define the schedule of timesteps
|
| 58 |
+
Args:
|
| 59 |
+
nb_steps (int): Number of discretized steps
|
| 60 |
+
"""
|
| 61 |
+
i=torch.arange(0,nb_steps+1)
|
| 62 |
+
t=(self.sigma_max**(1/self.ro) +i/(nb_steps-1) *(self.sigma_min**(1/self.ro) - self.sigma_max**(1/self.ro)))**self.ro
|
| 63 |
+
t[-1]=0
|
| 64 |
+
return t
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def sample_ptrain(self,N):
|
| 68 |
+
"""
|
| 69 |
+
For training, getting t as a normal distribution, folowing Karras et al.
|
| 70 |
+
I'm not using this
|
| 71 |
+
Args:
|
| 72 |
+
N (int): batch size
|
| 73 |
+
"""
|
| 74 |
+
lnsigma=np.random.randn(N)*self.P_std +self.P_mean
|
| 75 |
+
return np.clip(np.exp(lnsigma),self.sigma_min, self.sigma_max) #not sure if clipping here is necessary, but makes sense to me
|
| 76 |
+
|
| 77 |
+
def sample_ptrain_safe(self,N):
|
| 78 |
+
"""
|
| 79 |
+
For training, getting t according to the same criteria as sampling
|
| 80 |
+
Args:
|
| 81 |
+
N (int): batch size
|
| 82 |
+
"""
|
| 83 |
+
a=torch.rand(N)
|
| 84 |
+
t=(self.sigma_max**(1/self.ro_train) +a *(self.sigma_min**(1/self.ro_train) - self.sigma_max**(1/self.ro_train)))**self.ro_train
|
| 85 |
+
return t
|
| 86 |
+
|
| 87 |
+
def sample_prior(self,shape,sigma):
|
| 88 |
+
"""
|
| 89 |
+
Just sample some gaussian noise, nothing more
|
| 90 |
+
Args:
|
| 91 |
+
shape (tuple): shape of the noise to sample, something like (B,T)
|
| 92 |
+
sigma (float): noise level of the noise
|
| 93 |
+
"""
|
| 94 |
+
n=torch.randn(shape).to(sigma.device)*sigma
|
| 95 |
+
return n
|
| 96 |
+
|
| 97 |
+
def cskip(self, sigma):
|
| 98 |
+
"""
|
| 99 |
+
Just one of the preconditioning parameters
|
| 100 |
+
Args:
|
| 101 |
+
sigma (float): noise level (equal to timestep is sigma=t, which is our default)
|
| 102 |
+
|
| 103 |
+
"""
|
| 104 |
+
return self.sigma_data**2 *(sigma**2+self.sigma_data**2)**-1
|
| 105 |
+
|
| 106 |
+
def cout(self,sigma ):
|
| 107 |
+
"""
|
| 108 |
+
Just one of the preconditioning parameters
|
| 109 |
+
Args:
|
| 110 |
+
sigma (float): noise level (equal to timestep is sigma=t, which is our default)
|
| 111 |
+
"""
|
| 112 |
+
return sigma*self.sigma_data* (self.sigma_data**2+sigma**2)**(-0.5)
|
| 113 |
+
|
| 114 |
+
def cin(self, sigma):
|
| 115 |
+
"""
|
| 116 |
+
Just one of the preconditioning parameters
|
| 117 |
+
Args:
|
| 118 |
+
sigma (float): noise level (equal to timestep is sigma=t, which is our default)
|
| 119 |
+
"""
|
| 120 |
+
return (self.sigma_data**2+sigma**2)**(-0.5)
|
| 121 |
+
|
| 122 |
+
def cnoise(self,sigma ):
|
| 123 |
+
"""
|
| 124 |
+
preconditioning of the noise embedding
|
| 125 |
+
Args:
|
| 126 |
+
sigma (float): noise level (equal to timestep is sigma=t, which is our default)
|
| 127 |
+
"""
|
| 128 |
+
return (1/4)*torch.log(sigma)
|
| 129 |
+
|
| 130 |
+
def lambda_w(self,sigma):
|
| 131 |
+
return (sigma*self.sigma_data)**(-2) * (self.sigma_data**2+sigma**2)
|
| 132 |
+
|
| 133 |
+
def denoiser(self, xn , net, sigma):
|
| 134 |
+
"""
|
| 135 |
+
This method does the whole denoising step, which implies applying the model and the preconditioning
|
| 136 |
+
Args:
|
| 137 |
+
x (Tensor): shape: (B,T) Intermediate noisy latent to denoise
|
| 138 |
+
model (nn.Module): Model of the denoiser
|
| 139 |
+
sigma (float): noise level (equal to timestep is sigma=t, which is our default)
|
| 140 |
+
"""
|
| 141 |
+
if len(sigma.shape)==1:
|
| 142 |
+
sigma=sigma.unsqueeze(-1)
|
| 143 |
+
cskip=self.cskip(sigma)
|
| 144 |
+
cout=self.cout(sigma)
|
| 145 |
+
cin=self.cin(sigma)
|
| 146 |
+
cnoise=self.cnoise(sigma)
|
| 147 |
+
|
| 148 |
+
return cskip * xn +cout*net(cin*xn, cnoise) #this will crash because of broadcasting problems, debug later!
|
| 149 |
+
|
| 150 |
+
def prepare_train_preconditioning(self, x, sigma):
|
| 151 |
+
#weight=self.lambda_w(sigma)
|
| 152 |
+
#Is calling the denoiser here a good idea? Maybe it would be better to apply directly the preconditioning as in the paper, even though Karras et al seem to do it this way in their code
|
| 153 |
+
print(x.shape)
|
| 154 |
+
noise=self.sample_prior(x.shape,sigma)
|
| 155 |
+
|
| 156 |
+
cskip=self.cskip(sigma)
|
| 157 |
+
cout=self.cout(sigma)
|
| 158 |
+
cin=self.cin(sigma)
|
| 159 |
+
cnoise=self.cnoise(sigma)
|
| 160 |
+
|
| 161 |
+
target=(1/cout)*(x-cskip*(x+noise))
|
| 162 |
+
|
| 163 |
+
return cin*(x+noise), target, cnoise
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
def loss_fn(self, net, x):
|
| 167 |
+
"""
|
| 168 |
+
Loss function, which is the mean squared error between the denoised latent and the clean latent
|
| 169 |
+
Args:
|
| 170 |
+
net (nn.Module): Model of the denoiser
|
| 171 |
+
x (Tensor): shape: (B,T) Intermediate noisy latent to denoise
|
| 172 |
+
sigma (float): noise level (equal to timestep is sigma=t, which is our default)
|
| 173 |
+
"""
|
| 174 |
+
sigma=self.sample_ptrain_safe(x.shape[0]).unsqueeze(-1).to(x.device)
|
| 175 |
+
|
| 176 |
+
input, target, cnoise= self.prepare_train_preconditioning(x, sigma)
|
| 177 |
+
estimate=net(input,cnoise)
|
| 178 |
+
|
| 179 |
+
error=(estimate-target)
|
| 180 |
+
|
| 181 |
+
try:
|
| 182 |
+
#this will only happen if the model is cqt-based, if it crashes it is normal
|
| 183 |
+
if self.args.net.use_cqt_DC_correction:
|
| 184 |
+
error=net.CQTransform.apply_hpf_DC(error) #apply the DC correction to the error as we dont want to propagate the DC component of the error as the network is discarding it. It also applies for the nyquit frequency, but this is less critical.
|
| 185 |
+
except:
|
| 186 |
+
pass
|
| 187 |
+
|
| 188 |
+
#APPLY A-WEIGHTING
|
| 189 |
+
if self.args.diff_params.aweighting.use_aweighting:
|
| 190 |
+
error=self.AW(error)
|
| 191 |
+
|
| 192 |
+
#here we have the chance to apply further emphasis to the error, as some kind of perceptual frequency weighting could be
|
| 193 |
+
return error**2, sigma
|
| 194 |
+
|
model.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "audio-inpainting-diffusion",
|
| 3 |
+
"package_dir": ".",
|
| 4 |
+
"entry_point": "testing.edm_sampler_inpainting.Sampler",
|
| 5 |
+
"checkpoints": [
|
| 6 |
+
{
|
| 7 |
+
"label": "MAESTRO (solo piano)",
|
| 8 |
+
"repo": "Eloimoliner/audio-inpainting-diffusion",
|
| 9 |
+
"filename": "maestro_22k_8s-750000.pt",
|
| 10 |
+
"size_mb": 2984,
|
| 11 |
+
"exp_config": "conf/exp/maestro22k_8s.yaml",
|
| 12 |
+
"network_config": "conf/network/paper_1912_unet_cqt_oct_attention_adaLN_2.yaml",
|
| 13 |
+
"sample_rate": 22050,
|
| 14 |
+
"audio_len_samples": 184184
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"label": "MusicNet (mixed classical instrumentation)",
|
| 18 |
+
"repo": "Eloimoliner/audio-inpainting-diffusion",
|
| 19 |
+
"filename": "musicnet_44k_4s-560000.pt",
|
| 20 |
+
"size_mb": 3884,
|
| 21 |
+
"exp_config": "conf/exp/musicnet44k_4s.yaml",
|
| 22 |
+
"network_config": "conf/network/paper_1912_unet_cqt_oct_attention_44k_2.yaml",
|
| 23 |
+
"sample_rate": 44100,
|
| 24 |
+
"audio_len_samples": 184184
|
| 25 |
+
}
|
| 26 |
+
],
|
| 27 |
+
"notes": "Both checkpoints share the same tester/diff_params hyperparameters (conf/tester/inpainting_tester.yaml, conf/diff_params/edm.yaml) -- this is exactly the hydra.compose() config composition used in the repo's own notebooks/demo_inpainting_spectrogram.ipynb, which swaps only exp= and network= per checkpoint. Skipped the third HF checkpoint (22k_8s-850000.pt, the no-attention MAESTRO ablation variant) per user choice."
|
| 28 |
+
}
|
networks/__init__.py
ADDED
|
File without changes
|
networks/unet_cqt_oct_with_projattention_adaLN_2.py
ADDED
|
@@ -0,0 +1,882 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch.nn as nn
|
| 2 |
+
import numpy as np
|
| 3 |
+
import torch.nn.functional as F
|
| 4 |
+
import math as m
|
| 5 |
+
import torch
|
| 6 |
+
#import torchaudio
|
| 7 |
+
torch.pi = torch.acos(torch.zeros(1)).item() * 2 # which is 3.1415927410125732
|
| 8 |
+
|
| 9 |
+
from cqt_nsgt_pytorch import CQT_nsgt
|
| 10 |
+
import torchaudio
|
| 11 |
+
import einops
|
| 12 |
+
import math
|
| 13 |
+
|
| 14 |
+
"""
|
| 15 |
+
As similar as possible to the original CQTdiff architecture, but using the octave-base representation of the CQT
|
| 16 |
+
This should be more memory efficient, and also more efficient in terms of computation, specially when using higher sampling rates.
|
| 17 |
+
I am expecting similar performance to the original CQTdiff architecture, but faster.
|
| 18 |
+
Perhaps the fact that I am using powers of 2 for the time sizes is critical for transient reconstruction. I should thest CQT matrix model with powers of 2, this requires modifying the CQT_nsgt_pytorch.py file.
|
| 19 |
+
"""
|
| 20 |
+
def weight_init(shape, mode, fan_in, fan_out):
|
| 21 |
+
if mode == 'xavier_uniform': return np.sqrt(6 / (fan_in + fan_out)) * (torch.rand(*shape) * 2 - 1)
|
| 22 |
+
if mode == 'xavier_normal': return np.sqrt(2 / (fan_in + fan_out)) * torch.randn(*shape)
|
| 23 |
+
if mode == 'kaiming_uniform': return np.sqrt(3 / fan_in) * (torch.rand(*shape) * 2 - 1)
|
| 24 |
+
if mode == 'kaiming_normal': return np.sqrt(1 / fan_in) * torch.randn(*shape)
|
| 25 |
+
raise ValueError(f'Invalid init mode "{mode}"')
|
| 26 |
+
|
| 27 |
+
class Linear(torch.nn.Module):
|
| 28 |
+
def __init__(self, in_features, out_features, bias=True, init_mode='kaiming_normal', init_weight=1, init_bias=0):
|
| 29 |
+
super().__init__()
|
| 30 |
+
self.in_features = in_features
|
| 31 |
+
self.out_features = out_features
|
| 32 |
+
init_kwargs = dict(mode=init_mode, fan_in=in_features, fan_out=out_features)
|
| 33 |
+
self.weight = torch.nn.Parameter(weight_init([out_features, in_features], **init_kwargs) * init_weight)
|
| 34 |
+
self.bias = torch.nn.Parameter(weight_init([out_features], **init_kwargs) * init_bias) if bias else None
|
| 35 |
+
|
| 36 |
+
def forward(self, x):
|
| 37 |
+
x = x @ self.weight.to(x.dtype).t()
|
| 38 |
+
if self.bias is not None:
|
| 39 |
+
x = x.add_(self.bias.to(x.dtype))
|
| 40 |
+
return x
|
| 41 |
+
|
| 42 |
+
class Conv1d(torch.nn.Module):
|
| 43 |
+
def __init__(self,
|
| 44 |
+
in_channels, out_channels, kernel=1, bias=False, dilation=1,
|
| 45 |
+
init_mode='kaiming_normal', init_weight=1, init_bias=0,
|
| 46 |
+
):
|
| 47 |
+
super().__init__()
|
| 48 |
+
self.in_channels = in_channels
|
| 49 |
+
self.out_channels = out_channels
|
| 50 |
+
self.dilation = dilation
|
| 51 |
+
init_kwargs = dict(mode=init_mode, fan_in=in_channels*kernel, fan_out=out_channels*kernel)
|
| 52 |
+
self.weight = torch.nn.Parameter(weight_init([out_channels, in_channels, kernel], **init_kwargs) * init_weight)
|
| 53 |
+
self.bias = torch.nn.Parameter(weight_init([out_channels], **init_kwargs) * init_bias) if bias else None
|
| 54 |
+
|
| 55 |
+
def forward(self, x):
|
| 56 |
+
w = self.weight.to(x.dtype) if self.weight is not None else None
|
| 57 |
+
b = self.bias.to(x.dtype) if self.bias is not None else None
|
| 58 |
+
w_pad = w.shape[-1] // 2 if w is not None else 0
|
| 59 |
+
#f_pad = (f.shape[-1] - 1) // 2 if f is not None else 0
|
| 60 |
+
#print(x.shape, w.shape)
|
| 61 |
+
if w is not None:
|
| 62 |
+
x = torch.nn.functional.conv1d(x, w, padding="same", dilation=self.dilation)
|
| 63 |
+
if b is not None:
|
| 64 |
+
x = x.add_(b.reshape(1, -1, 1))
|
| 65 |
+
return x
|
| 66 |
+
class Conv2d(torch.nn.Module):
|
| 67 |
+
def __init__(self,
|
| 68 |
+
in_channels, out_channels, kernel=(1,1), bias=False, dilation=1,
|
| 69 |
+
init_mode='kaiming_normal', init_weight=1, init_bias=0,
|
| 70 |
+
):
|
| 71 |
+
super().__init__()
|
| 72 |
+
self.in_channels = in_channels
|
| 73 |
+
self.out_channels = out_channels
|
| 74 |
+
self.dilation = dilation
|
| 75 |
+
init_kwargs = dict(mode=init_mode, fan_in=in_channels*kernel[0]*kernel[1], fan_out=out_channels*kernel[0]*kernel[1])
|
| 76 |
+
self.weight = torch.nn.Parameter(weight_init([out_channels, in_channels, kernel[0], kernel[1]], **init_kwargs) * init_weight)
|
| 77 |
+
self.bias = torch.nn.Parameter(weight_init([out_channels], **init_kwargs) * init_bias) if bias else None
|
| 78 |
+
|
| 79 |
+
def forward(self, x):
|
| 80 |
+
w = self.weight.to(x.dtype) if self.weight is not None else None
|
| 81 |
+
b = self.bias.to(x.dtype) if self.bias is not None else None
|
| 82 |
+
w_pad = w.shape[-1] // 2 if w is not None else 0
|
| 83 |
+
#f_pad = (f.shape[-1] - 1) // 2 if f is not None else 0
|
| 84 |
+
if w is not None:
|
| 85 |
+
x = torch.nn.functional.conv2d(x, w, padding="same", dilation=self.dilation)
|
| 86 |
+
if b is not None:
|
| 87 |
+
x = x.add_(b.reshape(1, -1, 1, 1))
|
| 88 |
+
return x
|
| 89 |
+
|
| 90 |
+
class LayerScale(nn.Module):
|
| 91 |
+
"""Layer scale from [Touvron et al 2021] (https://arxiv.org/pdf/2103.17239.pdf).
|
| 92 |
+
This rescales diagonaly residual outputs close to 0 initially, then learnt.
|
| 93 |
+
"""
|
| 94 |
+
|
| 95 |
+
def __init__(self, channels: int, init: float = 1e-4, channel_last=True):
|
| 96 |
+
"""
|
| 97 |
+
channel_last = False corresponds to (B, C, T) tensors
|
| 98 |
+
channel_last = True corresponds to (T, B, C) tensors
|
| 99 |
+
"""
|
| 100 |
+
super().__init__()
|
| 101 |
+
self.channel_last = channel_last
|
| 102 |
+
self.scale = nn.Parameter(torch.zeros(channels, requires_grad=True))
|
| 103 |
+
self.scale.data[:] = init
|
| 104 |
+
|
| 105 |
+
def forward(self, x):
|
| 106 |
+
if self.channel_last:
|
| 107 |
+
return self.scale * x
|
| 108 |
+
else:
|
| 109 |
+
return self.scale[:, None] * x
|
| 110 |
+
|
| 111 |
+
class BiasFreeLayerNorm(nn.Module):
|
| 112 |
+
|
| 113 |
+
def __init__(self, num_features, eps=1e-7):
|
| 114 |
+
super(BiasFreeLayerNorm, self).__init__()
|
| 115 |
+
self.gamma = nn.Parameter(torch.ones(1,1,num_features))
|
| 116 |
+
#self.beta = nn.Parameter(torch.zeros(1,num_features,1,1))
|
| 117 |
+
#self.beta = torch.zeros(1,num_features,1,1)
|
| 118 |
+
self.eps = eps
|
| 119 |
+
|
| 120 |
+
def forward(self, x):
|
| 121 |
+
N, T, C = x.size()
|
| 122 |
+
#x = x.view(N, self.num_groups ,-1,H,W)
|
| 123 |
+
#x=einops.rearrange(x, 'n t c -> n (t c)')
|
| 124 |
+
#mean = x.mean(-1, keepdim=True)
|
| 125 |
+
#var = x.var(-1, keepdim=True)
|
| 126 |
+
|
| 127 |
+
std=x.std(-1, keepdim=True) #reduce over channels and time
|
| 128 |
+
#var = x.var(-1, keepdim=True)
|
| 129 |
+
|
| 130 |
+
## normalize
|
| 131 |
+
x = (x) / (std+self.eps)
|
| 132 |
+
# normalize
|
| 133 |
+
#x=einops.rearrange(x, 'n (t c) -> n t c', t=T)
|
| 134 |
+
#x = x.view(N,C,H,W)
|
| 135 |
+
return x * self.gamma
|
| 136 |
+
|
| 137 |
+
class BiasFreeGroupNorm(nn.Module):
|
| 138 |
+
|
| 139 |
+
def __init__(self, num_features, num_groups=32, eps=1e-7):
|
| 140 |
+
super(BiasFreeGroupNorm, self).__init__()
|
| 141 |
+
self.gamma = nn.Parameter(torch.ones(1,num_features,1,1))
|
| 142 |
+
#self.beta = nn.Parameter(torch.zeros(1,num_features,1,1))
|
| 143 |
+
#self.beta = torch.zeros(1,num_features,1,1)
|
| 144 |
+
self.num_groups = num_groups
|
| 145 |
+
self.eps = eps
|
| 146 |
+
|
| 147 |
+
def forward(self, x):
|
| 148 |
+
N, C, F, T = x.size()
|
| 149 |
+
#x = x.view(N, self.num_groups ,-1,H,W)
|
| 150 |
+
gc=C//self.num_groups
|
| 151 |
+
x=einops.rearrange(x, 'n (g gc) f t -> n g (gc f t)', g=self.num_groups, gc=gc)
|
| 152 |
+
#mean = x.mean(-1, keepdim=True)
|
| 153 |
+
#var = x.var(-1, keepdim=True)
|
| 154 |
+
|
| 155 |
+
std=x.std(-1, keepdim=True) #reduce over channels and time
|
| 156 |
+
#var = x.var(-1, keepdim=True)
|
| 157 |
+
|
| 158 |
+
## normalize
|
| 159 |
+
x = (x) / (std+self.eps)
|
| 160 |
+
# normalize
|
| 161 |
+
x=einops.rearrange(x, 'n g (gc f t) -> n (g gc) f t', g=self.num_groups, gc=gc, f=F, t=T)
|
| 162 |
+
#x = x.view(N,C,H,W)
|
| 163 |
+
return x * self.gamma
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
class RFF_MLP_Block(nn.Module):
|
| 168 |
+
"""
|
| 169 |
+
Encoder of the noise level embedding
|
| 170 |
+
Consists of:
|
| 171 |
+
-Random Fourier Feature embedding
|
| 172 |
+
-MLP
|
| 173 |
+
"""
|
| 174 |
+
def __init__(self, emb_dim=512, rff_dim=32, init=None):
|
| 175 |
+
super().__init__()
|
| 176 |
+
self.RFF_freq = nn.Parameter(
|
| 177 |
+
16 * torch.randn([1, rff_dim]), requires_grad=False)
|
| 178 |
+
self.MLP = nn.ModuleList([
|
| 179 |
+
Linear(2*rff_dim, 128, **init),
|
| 180 |
+
Linear(128, 256, **init),
|
| 181 |
+
Linear(256, emb_dim, **init),
|
| 182 |
+
])
|
| 183 |
+
|
| 184 |
+
def forward(self, sigma):
|
| 185 |
+
"""
|
| 186 |
+
Arguments:
|
| 187 |
+
sigma:
|
| 188 |
+
(shape: [B, 1], dtype: float32)
|
| 189 |
+
|
| 190 |
+
Returns:
|
| 191 |
+
x: embedding of sigma
|
| 192 |
+
(shape: [B, 512], dtype: float32)
|
| 193 |
+
"""
|
| 194 |
+
x = self._build_RFF_embedding(sigma)
|
| 195 |
+
for layer in self.MLP:
|
| 196 |
+
x = F.relu(layer(x))
|
| 197 |
+
return x
|
| 198 |
+
|
| 199 |
+
def _build_RFF_embedding(self, sigma):
|
| 200 |
+
"""
|
| 201 |
+
Arguments:
|
| 202 |
+
sigma:
|
| 203 |
+
(shape: [B, 1], dtype: float32)
|
| 204 |
+
Returns:
|
| 205 |
+
table:
|
| 206 |
+
(shape: [B, 64], dtype: float32)
|
| 207 |
+
"""
|
| 208 |
+
freqs = self.RFF_freq
|
| 209 |
+
table = 2 * np.pi * sigma * freqs
|
| 210 |
+
table = torch.cat([torch.sin(table), torch.cos(table)], dim=1)
|
| 211 |
+
return table
|
| 212 |
+
|
| 213 |
+
class AddFreqEncodingRFF(nn.Module):
|
| 214 |
+
'''
|
| 215 |
+
[B, T, F, 2] => [B, T, F, 12]
|
| 216 |
+
Generates frequency positional embeddings and concatenates them as 10 extra channels
|
| 217 |
+
This function is optimized for F=1025
|
| 218 |
+
'''
|
| 219 |
+
def __init__(self, f_dim, N):
|
| 220 |
+
super(AddFreqEncodingRFF, self).__init__()
|
| 221 |
+
self.N=N
|
| 222 |
+
self.RFF_freq = nn.Parameter(
|
| 223 |
+
16 * torch.randn([1, N]), requires_grad=False)
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
self.f_dim=f_dim #f_dim is fixed
|
| 227 |
+
embeddings=self.build_RFF_embedding()
|
| 228 |
+
self.embeddings=nn.Parameter(embeddings, requires_grad=False)
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
def build_RFF_embedding(self):
|
| 232 |
+
"""
|
| 233 |
+
Returns:
|
| 234 |
+
table:
|
| 235 |
+
(shape: [C,F], dtype: float32)
|
| 236 |
+
"""
|
| 237 |
+
freqs = self.RFF_freq
|
| 238 |
+
#freqs = freqs.to(device=torch.device("cuda"))
|
| 239 |
+
freqs=freqs.unsqueeze(-1) # [1, 32, 1]
|
| 240 |
+
|
| 241 |
+
self.n=torch.arange(start=0,end=self.f_dim)
|
| 242 |
+
self.n=self.n.unsqueeze(0).unsqueeze(0) #[1,1,F]
|
| 243 |
+
|
| 244 |
+
table = 2 * np.pi * self.n * freqs
|
| 245 |
+
|
| 246 |
+
#print(freqs.shape, x.shape, table.shape)
|
| 247 |
+
table = torch.cat([torch.sin(table), torch.cos(table)], dim=1) #[1,32,F]
|
| 248 |
+
|
| 249 |
+
return table
|
| 250 |
+
|
| 251 |
+
|
| 252 |
+
def forward(self, input_tensor):
|
| 253 |
+
|
| 254 |
+
#print(input_tensor.shape)
|
| 255 |
+
batch_size_tensor = input_tensor.shape[0] # get batch size
|
| 256 |
+
time_dim = input_tensor.shape[-1] # get time dimension
|
| 257 |
+
|
| 258 |
+
fembeddings_2 = torch.broadcast_to(self.embeddings, [batch_size_tensor, time_dim,self.N*2, self.f_dim])
|
| 259 |
+
fembeddings_2=fembeddings_2.permute(0,2,3,1)
|
| 260 |
+
|
| 261 |
+
|
| 262 |
+
#print(input_tensor.shape, fembeddings_2.shape)
|
| 263 |
+
return torch.cat((input_tensor,fembeddings_2),1)
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
class RelativePositionBias(nn.Module):
|
| 267 |
+
def __init__(self, num_buckets: int, max_distance: int, num_heads: int):
|
| 268 |
+
super().__init__()
|
| 269 |
+
self.num_buckets = num_buckets
|
| 270 |
+
self.max_distance = max_distance
|
| 271 |
+
self.num_heads = num_heads
|
| 272 |
+
self.relative_attention_bias = nn.Embedding(num_buckets, num_heads)
|
| 273 |
+
|
| 274 |
+
@staticmethod
|
| 275 |
+
def _relative_position_bucket(
|
| 276 |
+
relative_position, num_buckets: int, max_distance: int
|
| 277 |
+
):
|
| 278 |
+
num_buckets //= 2
|
| 279 |
+
ret = (relative_position >= 0).to(torch.long) * num_buckets
|
| 280 |
+
n = torch.abs(relative_position)
|
| 281 |
+
|
| 282 |
+
max_exact = num_buckets // 2
|
| 283 |
+
is_small = n < max_exact
|
| 284 |
+
|
| 285 |
+
val_if_large = (
|
| 286 |
+
max_exact
|
| 287 |
+
+ (
|
| 288 |
+
torch.log(n.float() / max_exact)
|
| 289 |
+
/ math.log(max_distance / max_exact)
|
| 290 |
+
* (num_buckets - max_exact)
|
| 291 |
+
).long()
|
| 292 |
+
)
|
| 293 |
+
val_if_large = torch.min(
|
| 294 |
+
val_if_large, torch.full_like(val_if_large, num_buckets - 1)
|
| 295 |
+
)
|
| 296 |
+
|
| 297 |
+
ret += torch.where(is_small, n, val_if_large)
|
| 298 |
+
return ret
|
| 299 |
+
|
| 300 |
+
def forward(self, num_queries: int, num_keys: int):
|
| 301 |
+
i, j, device = num_queries, num_keys, self.relative_attention_bias.weight.device
|
| 302 |
+
q_pos = torch.arange(j - i, j, dtype=torch.long, device=device)
|
| 303 |
+
k_pos = torch.arange(j, dtype=torch.long, device=device)
|
| 304 |
+
rel_pos = einops.rearrange(k_pos, "j -> 1 j") - einops.rearrange(q_pos, "i -> i 1")
|
| 305 |
+
|
| 306 |
+
relative_position_bucket = self._relative_position_bucket(
|
| 307 |
+
rel_pos, num_buckets=self.num_buckets, max_distance=self.max_distance
|
| 308 |
+
)
|
| 309 |
+
|
| 310 |
+
bias = self.relative_attention_bias(relative_position_bucket)
|
| 311 |
+
bias = einops.rearrange(bias, "m n h -> 1 h m n")
|
| 312 |
+
return bias
|
| 313 |
+
|
| 314 |
+
class TimeAttentionBlock(nn.Module):
|
| 315 |
+
def __init__(self, Nin,attention_dict, init, init_zero, Fdim) -> None:
|
| 316 |
+
super().__init__()
|
| 317 |
+
#NA=attention_dict.N
|
| 318 |
+
self.attention_dict=attention_dict
|
| 319 |
+
self.Fdim=Fdim
|
| 320 |
+
N=attention_dict.num_heads*Fdim
|
| 321 |
+
self.qk = Conv1d(N, N*2, bias=self.attention_dict.bias_qkv, **init )
|
| 322 |
+
self.proj_in=Conv2d(Nin, attention_dict.num_heads, (1,1), bias=False, **init)
|
| 323 |
+
self.proj_out=Conv2d(attention_dict.num_heads, Nin, (1,1), bias=False, **init)
|
| 324 |
+
#not sure if a bias is a good idea here
|
| 325 |
+
#self.v = Conv2d(N, N*2, (1,1), bias=False,**init )
|
| 326 |
+
#I think that as long as the main signal path layers are bias free, we should be safe from artifacts
|
| 327 |
+
#self.proj = Conv1d(NA, NA, 1, bias=False, **init)
|
| 328 |
+
|
| 329 |
+
self.scale=(N/self.attention_dict.num_heads)**-0.5
|
| 330 |
+
self.use_rel_pos = self.attention_dict.use_rel_pos
|
| 331 |
+
if self.use_rel_pos:
|
| 332 |
+
self.rel_pos = RelativePositionBias(
|
| 333 |
+
num_buckets=attention_dict.rel_pos_num_buckets,
|
| 334 |
+
max_distance=attention_dict.rel_pos_max_distance,
|
| 335 |
+
num_heads=attention_dict.num_heads,
|
| 336 |
+
)
|
| 337 |
+
|
| 338 |
+
def forward(self, x):
|
| 339 |
+
#shape of x is [batch, C,F, T]
|
| 340 |
+
|
| 341 |
+
#we need shape: [batch, heads, T, D]
|
| 342 |
+
#with heands on different (original) channels
|
| 343 |
+
#print(x.shape, self.Fdim)
|
| 344 |
+
|
| 345 |
+
x=self.proj_in(x) #reduce the C dimensionality
|
| 346 |
+
|
| 347 |
+
#print(x.shape, self.Fdim)
|
| 348 |
+
#normalize everyting (easy)
|
| 349 |
+
|
| 350 |
+
#split into heads
|
| 351 |
+
x=einops.rearrange(x, "b h f t -> b (h f) t")
|
| 352 |
+
|
| 353 |
+
v=einops.rearrange(x,"b (h f) t -> b h t f", f=self.Fdim) #identity layer for the values
|
| 354 |
+
|
| 355 |
+
qk=self.qk(x) #linear layer
|
| 356 |
+
#for now, f are features (all merged) but still represents frequency
|
| 357 |
+
|
| 358 |
+
qk=einops.rearrange(qk, "b (h d) t -> b h t d", h=self.attention_dict.num_heads)
|
| 359 |
+
q,k=qk.chunk(2,dim=-1)
|
| 360 |
+
|
| 361 |
+
#print("qk",q.shape, k.shape)
|
| 362 |
+
sim = torch.einsum("... n d, ... m d -> ... n m", q, k)
|
| 363 |
+
#print("sim",sim.shape)
|
| 364 |
+
sim = (sim + self.rel_pos(*sim.shape[-2:])) if self.use_rel_pos else sim
|
| 365 |
+
#print("sim",sim.shape)
|
| 366 |
+
sim = sim * self.scale
|
| 367 |
+
# Get attention matrix with softmax
|
| 368 |
+
attn = sim.softmax(dim=-1)
|
| 369 |
+
# Compute values
|
| 370 |
+
#print("attn",attn.shape, v.shape)
|
| 371 |
+
out = torch.einsum("... n m, ... m d -> ... n d", attn, v)
|
| 372 |
+
|
| 373 |
+
#print("out",out.shape)
|
| 374 |
+
out = einops.rearrange(out, "b h t f -> b h f t", f=self.Fdim)
|
| 375 |
+
#out = einops.rearrange(out, "b (h f) t -> b h f t", f=self.Fdim)
|
| 376 |
+
|
| 377 |
+
#reverse step
|
| 378 |
+
out=self.proj_out(out)
|
| 379 |
+
|
| 380 |
+
return out
|
| 381 |
+
|
| 382 |
+
class ResnetBlock(nn.Module):
|
| 383 |
+
def __init__(
|
| 384 |
+
self,
|
| 385 |
+
dim,
|
| 386 |
+
dim_out,
|
| 387 |
+
use_norm=True,
|
| 388 |
+
num_dils = 6,
|
| 389 |
+
bias=False,
|
| 390 |
+
kernel_size=(5,3),
|
| 391 |
+
emb_dim=512,
|
| 392 |
+
proj_place='before', #using 'after' in the decoder out blocks
|
| 393 |
+
init=None,
|
| 394 |
+
init_zero=None,
|
| 395 |
+
attention_dict=None,
|
| 396 |
+
Fdim=128, #number of frequency bins
|
| 397 |
+
):
|
| 398 |
+
super().__init__()
|
| 399 |
+
|
| 400 |
+
self.bias=bias
|
| 401 |
+
self.use_norm=use_norm
|
| 402 |
+
self.num_dils=num_dils
|
| 403 |
+
self.proj_place=proj_place
|
| 404 |
+
self.Fdim=Fdim
|
| 405 |
+
|
| 406 |
+
if self.proj_place=='before':
|
| 407 |
+
#dim_out is the block dimension
|
| 408 |
+
N=dim_out
|
| 409 |
+
else:
|
| 410 |
+
#dim in is the block dimension
|
| 411 |
+
N=dim
|
| 412 |
+
self.proj_out = Conv2d(N, dim_out, bias=bias, **init) if N!=dim_out else nn.Identity() #linear projection
|
| 413 |
+
|
| 414 |
+
self.res_conv = Conv2d(dim, dim_out, bias=bias, **init) if dim!= dim_out else nn.Identity() #linear projection
|
| 415 |
+
self.proj_in = Conv2d(dim, N, bias=bias, **init) if dim!=N else nn.Identity()#linear projection
|
| 416 |
+
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
self.H=nn.ModuleList()
|
| 420 |
+
self.affine=nn.ModuleList()
|
| 421 |
+
self.gate=nn.ModuleList()
|
| 422 |
+
if self.use_norm:
|
| 423 |
+
self.norm=nn.ModuleList()
|
| 424 |
+
|
| 425 |
+
for i in range(self.num_dils):
|
| 426 |
+
|
| 427 |
+
if self.use_norm:
|
| 428 |
+
self.norm.append(BiasFreeGroupNorm(N,8))
|
| 429 |
+
|
| 430 |
+
self.affine.append(Linear(emb_dim, N, **init))
|
| 431 |
+
self.gate.append(Linear(emb_dim, N, **init_zero))
|
| 432 |
+
#self.H.append(Gated_residual_layer(dim_out, (5,3), (2**i,1), bias=bias)) #sometimes I changed this 1,5 to 3,5. be careful!!! (in exp 80 as far as I remember)
|
| 433 |
+
self.H.append(Conv2d(N,N,
|
| 434 |
+
kernel=kernel_size,
|
| 435 |
+
dilation=(2**i,1),
|
| 436 |
+
bias=bias, **init)) #freq convolution (dilated)
|
| 437 |
+
|
| 438 |
+
self.attention_dict=attention_dict
|
| 439 |
+
if self.attention_dict is not None:
|
| 440 |
+
#NA=self.attention_dict.N
|
| 441 |
+
self.norm2=BiasFreeGroupNorm(N,8)
|
| 442 |
+
self.affine2=Linear(emb_dim, N, **init)
|
| 443 |
+
self.gate2=Linear(emb_dim, N, **init_zero)
|
| 444 |
+
#self.norm2 = BiasFreeGroupNorm(N,8)
|
| 445 |
+
#self.proj_attn_in = Conv1d(N*Fdim, NA, bias=bias, **init) if (N*Fdim)!=NA else nn.Identity()#linear projection
|
| 446 |
+
#self.proj_attn_out = Conv1d(NA, N*Fdim, bias=bias, **init_zero) if NA!=(N*Fdim) else nn.Identity() #linear projection
|
| 447 |
+
##the attention is applied time-wise, since channels times frequency is too much, we need to reduce the dimensionality using a linear projection
|
| 448 |
+
self.attn_block=TimeAttentionBlock(N,self.attention_dict, init,init_zero, self.Fdim)
|
| 449 |
+
|
| 450 |
+
|
| 451 |
+
|
| 452 |
+
def forward(self, input_x, sigma):
|
| 453 |
+
|
| 454 |
+
x=input_x
|
| 455 |
+
|
| 456 |
+
x=self.proj_in(x)
|
| 457 |
+
|
| 458 |
+
if self.attention_dict is not None:
|
| 459 |
+
i_x=x
|
| 460 |
+
|
| 461 |
+
gamma=self.affine2(sigma)
|
| 462 |
+
scale=self.gate2(sigma)
|
| 463 |
+
|
| 464 |
+
x=self.norm2(x)
|
| 465 |
+
x=x*(gamma.unsqueeze(2).unsqueeze(3)+1) #no bias
|
| 466 |
+
|
| 467 |
+
x=self.attn_block(x)*scale.unsqueeze(2).unsqueeze(3)
|
| 468 |
+
|
| 469 |
+
#x=(x+i_x)
|
| 470 |
+
x=(x+i_x)/(2**0.5)
|
| 471 |
+
|
| 472 |
+
for norm, affine, gate, conv in zip(self.norm, self.affine, self.gate, self.H):
|
| 473 |
+
x0=x
|
| 474 |
+
if self.use_norm:
|
| 475 |
+
x=norm(x)
|
| 476 |
+
gamma =affine(sigma)
|
| 477 |
+
scale=gate(sigma)
|
| 478 |
+
|
| 479 |
+
x=x*(gamma.unsqueeze(2).unsqueeze(3)+1) #no bias
|
| 480 |
+
|
| 481 |
+
|
| 482 |
+
x=(x0+conv(F.gelu(x))*scale.unsqueeze(2).unsqueeze(3))/(2**0.5)
|
| 483 |
+
#x=(x0+conv(F.gelu(x))*scale.unsqueeze(2).unsqueeze(3))
|
| 484 |
+
|
| 485 |
+
#one residual connection here after the dilated convolutions
|
| 486 |
+
|
| 487 |
+
|
| 488 |
+
if self.proj_place=='after':
|
| 489 |
+
x=self.proj_out(x)
|
| 490 |
+
|
| 491 |
+
x=(x + self.res_conv(input_x))/(2**0.5)
|
| 492 |
+
|
| 493 |
+
return x
|
| 494 |
+
|
| 495 |
+
|
| 496 |
+
class AttentionOp(torch.autograd.Function):
|
| 497 |
+
|
| 498 |
+
def forward(ctx, q, k):
|
| 499 |
+
w = torch.einsum('ncq,nck->nqk', q.to(torch.float32), (k / np.sqrt(k.shape[1])).to(torch.float32)).softmax(dim=2).to(q.dtype)
|
| 500 |
+
ctx.save_for_backward(q, k, w)
|
| 501 |
+
return w
|
| 502 |
+
|
| 503 |
+
def backward(ctx, dw):
|
| 504 |
+
q, k, w = ctx.saved_tensors
|
| 505 |
+
db = torch._softmax_backward_data(grad_output=dw.to(torch.float32), output=w.to(torch.float32), dim=2, input_dtype=torch.float32)
|
| 506 |
+
dq = torch.einsum('nck,nqk->ncq', k.to(torch.float32), db).to(q.dtype) / np.sqrt(k.shape[1])
|
| 507 |
+
dk = torch.einsum('ncq,nqk->nck', q.to(torch.float32), db).to(k.dtype) / np.sqrt(k.shape[1])
|
| 508 |
+
return dq, dk
|
| 509 |
+
|
| 510 |
+
_kernels = {
|
| 511 |
+
'linear':
|
| 512 |
+
[1 / 8, 3 / 8, 3 / 8, 1 / 8],
|
| 513 |
+
'cubic':
|
| 514 |
+
[-0.01171875, -0.03515625, 0.11328125, 0.43359375,
|
| 515 |
+
0.43359375, 0.11328125, -0.03515625, -0.01171875],
|
| 516 |
+
'lanczos3':
|
| 517 |
+
[0.003689131001010537, 0.015056144446134567, -0.03399861603975296,
|
| 518 |
+
-0.066637322306633, 0.13550527393817902, 0.44638532400131226,
|
| 519 |
+
0.44638532400131226, 0.13550527393817902, -0.066637322306633,
|
| 520 |
+
-0.03399861603975296, 0.015056144446134567, 0.003689131001010537]
|
| 521 |
+
}
|
| 522 |
+
class UpDownResample(nn.Module):
|
| 523 |
+
def __init__(self,
|
| 524 |
+
up=False,
|
| 525 |
+
down=False,
|
| 526 |
+
mode_resample="T", #T for time, F for freq, TF for both
|
| 527 |
+
resample_filter='cubic',
|
| 528 |
+
pad_mode='reflect'
|
| 529 |
+
):
|
| 530 |
+
super().__init__()
|
| 531 |
+
assert not (up and down) #you cannot upsample and downsample at the same time
|
| 532 |
+
assert up or down #you must upsample or downsample
|
| 533 |
+
self.down=down
|
| 534 |
+
self.up=up
|
| 535 |
+
if up or down:
|
| 536 |
+
#upsample block
|
| 537 |
+
self.pad_mode = pad_mode #I think reflect is a goof choice for padding
|
| 538 |
+
self.mode_resample=mode_resample
|
| 539 |
+
if mode_resample=="T":
|
| 540 |
+
kernel_1d = torch.tensor(_kernels[resample_filter], dtype=torch.float32)
|
| 541 |
+
elif mode_resample=="F":
|
| 542 |
+
#kerel shouuld be the same
|
| 543 |
+
kernel_1d = torch.tensor(_kernels[resample_filter], dtype=torch.float32)
|
| 544 |
+
else:
|
| 545 |
+
raise NotImplementedError("Only time upsampling is implemented")
|
| 546 |
+
#TODO implement freq upsampling and downsampling
|
| 547 |
+
self.pad = kernel_1d.shape[0] // 2 - 1
|
| 548 |
+
self.register_buffer('kernel', kernel_1d)
|
| 549 |
+
def forward(self, x):
|
| 550 |
+
shapeorig=x.shape
|
| 551 |
+
#x=x.view(x.shape[0],-1,x.shape[-1])
|
| 552 |
+
x=x.view(-1,x.shape[-2],x.shape[-1]) #I have the feeling the reshape makes everything consume too much memory. There is no need to have the channel dimension different than 1. I leave it like this because otherwise it requires a contiguous() call, but I should check if the memory gain / speed, would be significant.
|
| 553 |
+
if self.mode_resample=="F":
|
| 554 |
+
x=x.permute(0,2,1)#call contiguous() here?
|
| 555 |
+
|
| 556 |
+
#print("after view",x.shape)
|
| 557 |
+
if self.down:
|
| 558 |
+
x = F.pad(x, (self.pad,) * 2, self.pad_mode)
|
| 559 |
+
elif self.up:
|
| 560 |
+
x = F.pad(x, ((self.pad + 1) // 2,) * 2, self.pad_mode)
|
| 561 |
+
|
| 562 |
+
#print("after pad",x.shape)
|
| 563 |
+
|
| 564 |
+
weight = x.new_zeros([x.shape[1], x.shape[1], self.kernel.shape[0]])
|
| 565 |
+
#print("weight",weight.shape)
|
| 566 |
+
indices = torch.arange(x.shape[1], device=x.device)
|
| 567 |
+
#print("indices",indices.shape)
|
| 568 |
+
#weight = self.kernel.to(x.device).unsqueeze(0).unsqueeze(0).expand(x.shape[1], x.shape[1], -1)
|
| 569 |
+
#print("weight",weight.shape)
|
| 570 |
+
weight[indices, indices] = self.kernel.to(weight)
|
| 571 |
+
if self.down:
|
| 572 |
+
x_out= F.conv1d(x, weight, stride=2)
|
| 573 |
+
elif self.up:
|
| 574 |
+
x_out =F.conv_transpose1d(x, weight, stride=2, padding=self.pad * 2 + 1)
|
| 575 |
+
|
| 576 |
+
if self.mode_resample=="F":
|
| 577 |
+
x_out=x_out.permute(0,2,1).contiguous()
|
| 578 |
+
return x_out.view(shapeorig[0],-1,x_out.shape[-2], shapeorig[-1])
|
| 579 |
+
else:
|
| 580 |
+
return x_out.view(shapeorig[0],-1,shapeorig[2], x_out.shape[-1])
|
| 581 |
+
|
| 582 |
+
|
| 583 |
+
class Unet_CQT_oct_with_attention(nn.Module):
|
| 584 |
+
"""
|
| 585 |
+
Main U-Net model based on the CQT
|
| 586 |
+
"""
|
| 587 |
+
def __init__(self, args, device):
|
| 588 |
+
"""
|
| 589 |
+
Args:
|
| 590 |
+
args (dictionary): hydra dictionary
|
| 591 |
+
device: torch device ("cuda" or "cpu")
|
| 592 |
+
"""
|
| 593 |
+
super(Unet_CQT_oct_with_attention, self).__init__()
|
| 594 |
+
self.args=args
|
| 595 |
+
self.depth=args.network.cqt.num_octs
|
| 596 |
+
#self.depth=args.network.inner_depth+self.args.network.cqt.num_octs
|
| 597 |
+
#assert self.depth==args.network.depth, "The depth of the network should be the sum of the inner depth and the number of octaves" #make sure we are aware of the depth of the network
|
| 598 |
+
|
| 599 |
+
init = dict(init_mode='kaiming_uniform', init_weight=np.sqrt(1/3)) #same as ADM, according to edm implementation
|
| 600 |
+
init_zero = dict(init_mode='kaiming_uniform', init_weight=1e-7) #I think it is safer to initialize the last layer with a small weight, rather than zero. Breaking symmetry and all that.
|
| 601 |
+
|
| 602 |
+
|
| 603 |
+
|
| 604 |
+
self.emb_dim=args.network.emb_dim
|
| 605 |
+
self.embedding = RFF_MLP_Block(emb_dim=args.network.emb_dim, init=init)
|
| 606 |
+
self.use_norm=args.network.use_norm
|
| 607 |
+
|
| 608 |
+
#fmax=self.args.exp.sample_rate/2
|
| 609 |
+
#self.fmin=fmax/(2**self.args.cqt.numocts)
|
| 610 |
+
self.fbins=int(self.args.network.cqt.bins_per_oct*self.args.network.cqt.num_octs)
|
| 611 |
+
self.device=device
|
| 612 |
+
self.bins_per_oct=self.args.network.cqt.bins_per_oct
|
| 613 |
+
self.num_octs=self.args.network.cqt.num_octs
|
| 614 |
+
#self.CQTransform=CQT_nsgt(self.args.network.cqt.num_octs,self.args.network.cqt.bins_per_oct, "oct", self.args.exp.sample_rate, self.args.exp.audio_len, device=self.device)
|
| 615 |
+
if self.args.network.cqt.window=="kaiser":
|
| 616 |
+
win=("kaiser",self.args.network.cqt.beta)
|
| 617 |
+
else:
|
| 618 |
+
win=self.args.network.cqt.window
|
| 619 |
+
|
| 620 |
+
self.CQTransform=CQT_nsgt(self.args.network.cqt.num_octs, self.args.network.cqt.bins_per_oct, mode="oct",window=win,fs=self.args.exp.sample_rate, audio_len=self.args.exp.audio_len, dtype=torch.float32, device=self.device)
|
| 621 |
+
|
| 622 |
+
|
| 623 |
+
self.f_dim=self.fbins #assuming we have thrown away the DC component and the Nyquist frequency
|
| 624 |
+
|
| 625 |
+
self.use_fencoding=self.args.network.use_fencoding
|
| 626 |
+
if self.use_fencoding:
|
| 627 |
+
N_freq_encoding=32
|
| 628 |
+
|
| 629 |
+
self.freq_encodings=nn.ModuleList([])
|
| 630 |
+
for i in range(self.num_octs):
|
| 631 |
+
self.freq_encodings.append(AddFreqEncodingRFF(self.bins_per_oct,N_freq_encoding))
|
| 632 |
+
Nin=2*N_freq_encoding+2
|
| 633 |
+
else:
|
| 634 |
+
Nin=2
|
| 635 |
+
|
| 636 |
+
#Encoder
|
| 637 |
+
self.Ns= self.args.network.Ns
|
| 638 |
+
self.Ss= self.args.network.Ss
|
| 639 |
+
|
| 640 |
+
self.num_dils= self.args.network.num_dils #intuition: less dilations for the first layers and more for the deeper layers
|
| 641 |
+
#self.inner_num_dils=self.args.network.inner_num_dils
|
| 642 |
+
|
| 643 |
+
self.attention_dict=self.args.network.attention_dict
|
| 644 |
+
#self.attention_Ns=self.args.network.attention_Ns
|
| 645 |
+
|
| 646 |
+
self.downsamplerT=UpDownResample(down=True, mode_resample="T")
|
| 647 |
+
#self.downsamplerF=UpDownResample(down=True, mode_resample="F")
|
| 648 |
+
self.upsamplerT=UpDownResample(up=True, mode_resample="T")
|
| 649 |
+
#self.upsamplerF=UpDownResample(up=True, mode_resample="F")
|
| 650 |
+
|
| 651 |
+
self.downs=nn.ModuleList([])
|
| 652 |
+
self.middle=nn.ModuleList([])
|
| 653 |
+
self.ups=nn.ModuleList([])
|
| 654 |
+
|
| 655 |
+
self.attention_layers=self.args.network.attention_layers
|
| 656 |
+
#sth like [0,0,0,0,0,0,1,1]
|
| 657 |
+
|
| 658 |
+
for i in range(self.num_octs):
|
| 659 |
+
if i==0:
|
| 660 |
+
dim_in=self.Ns[i]
|
| 661 |
+
dim_out=self.Ns[i]
|
| 662 |
+
else:
|
| 663 |
+
dim_in=self.Ns[i-1]
|
| 664 |
+
dim_out=self.Ns[i]
|
| 665 |
+
if self.attention_layers[i]:
|
| 666 |
+
print("Attention layer at (down) octave {}".format(i))
|
| 667 |
+
attn_dict=self.attention_dict
|
| 668 |
+
#attn_dict.N=self.attention_Ns[i]
|
| 669 |
+
#assert attn_dict.N > 0
|
| 670 |
+
else:
|
| 671 |
+
attn_dict=None
|
| 672 |
+
|
| 673 |
+
self.downs.append(
|
| 674 |
+
nn.ModuleList([
|
| 675 |
+
ResnetBlock(Nin, dim_in, self.use_norm,num_dils=1, bias=False, kernel_size=(1,1), emb_dim=self.emb_dim, init=init, init_zero=init_zero),
|
| 676 |
+
Conv2d(2, dim_out, kernel=(5,3), bias=False, **init),
|
| 677 |
+
ResnetBlock(dim_in, dim_out, self.use_norm,num_dils=self.num_dils[i], bias=False , attention_dict=attn_dict, emb_dim=self.emb_dim, init=init, init_zero=init_zero, Fdim=(i+1)*self.bins_per_oct)
|
| 678 |
+
]))
|
| 679 |
+
|
| 680 |
+
if self.args.network.bottleneck_type=="res_dil_convs":
|
| 681 |
+
for i in range(self.args.network.num_bottleneck_layers):
|
| 682 |
+
if self.attention_layers[-1]:
|
| 683 |
+
attn_dict=self.attention_dict
|
| 684 |
+
#attn_dict.N=self.attention_Ns[-1]
|
| 685 |
+
#assert attn_dict.N > 0
|
| 686 |
+
else:
|
| 687 |
+
attn_dict=None
|
| 688 |
+
|
| 689 |
+
self.middle.append(nn.ModuleList([
|
| 690 |
+
ResnetBlock(self.Ns[-1], 2, use_norm=self.use_norm,num_dils= 1,bias=False, kernel_size=(1,1), proj_place="after", emb_dim=self.emb_dim, init=init, init_zero=init_zero),
|
| 691 |
+
ResnetBlock(self.Ns[-1], self.Ns[-1], self.use_norm, num_dils=self.num_dils[-1], bias=False, emb_dim=self.emb_dim,attention_dict=attn_dict, init=init, init_zero=init_zero,
|
| 692 |
+
Fdim=(self.num_octs)*self.bins_per_oct)]))
|
| 693 |
+
else:
|
| 694 |
+
raise NotImplementedError("bottleneck type not implemented")
|
| 695 |
+
|
| 696 |
+
|
| 697 |
+
|
| 698 |
+
#self.pyr_up_proj_first=nn.Conv2d(dim_out, 2, (5,3), padding="same", padding_mode="zeros", bias=False)
|
| 699 |
+
|
| 700 |
+
for i in range(self.num_octs-1,-1,-1):
|
| 701 |
+
|
| 702 |
+
if i==0:
|
| 703 |
+
dim_in=self.Ns[i]*2
|
| 704 |
+
dim_out=self.Ns[i]
|
| 705 |
+
else:
|
| 706 |
+
dim_in=self.Ns[i]*2
|
| 707 |
+
dim_out=self.Ns[i-1]
|
| 708 |
+
|
| 709 |
+
if self.attention_layers[i]:
|
| 710 |
+
print("Attention layer at (up) oct layer {}".format(i))
|
| 711 |
+
attn_dict=self.attention_dict
|
| 712 |
+
#attn_dict.N=self.attention_Ns[i]
|
| 713 |
+
#assert attn_dict.N > 0
|
| 714 |
+
else:
|
| 715 |
+
attn_dict=None
|
| 716 |
+
|
| 717 |
+
self.ups.append(nn.ModuleList(
|
| 718 |
+
[
|
| 719 |
+
ResnetBlock(dim_out, 2, use_norm=self.use_norm,num_dils= 1,bias=False, kernel_size=(1,1), proj_place="after", emb_dim=self.emb_dim, init=init, init_zero=init_zero),
|
| 720 |
+
ResnetBlock(dim_in, dim_out, use_norm=self.use_norm,num_dils= self.num_dils[i],attention_dict=attn_dict, bias=False, emb_dim=self.emb_dim, init=init, init_zero=init_zero, Fdim=(i+1)*self.bins_per_oct),
|
| 721 |
+
]))
|
| 722 |
+
|
| 723 |
+
|
| 724 |
+
|
| 725 |
+
#self.cropconcat = CropConcatBlock()
|
| 726 |
+
|
| 727 |
+
|
| 728 |
+
|
| 729 |
+
|
| 730 |
+
def forward(self, inputs, sigma):
|
| 731 |
+
"""
|
| 732 |
+
Args:
|
| 733 |
+
inputs (Tensor): Input signal in time-domsin, shape (B,T)
|
| 734 |
+
sigma (Tensor): noise levels, shape (B,1)
|
| 735 |
+
Returns:
|
| 736 |
+
pred (Tensor): predicted signal in time-domain, shape (B,T)
|
| 737 |
+
"""
|
| 738 |
+
#apply RFF embedding+MLP of the noise level
|
| 739 |
+
sigma = self.embedding(sigma)
|
| 740 |
+
|
| 741 |
+
|
| 742 |
+
#apply CQT to the inputs
|
| 743 |
+
X_list =self.CQTransform.fwd(inputs.unsqueeze(1))
|
| 744 |
+
X_list_out=X_list
|
| 745 |
+
|
| 746 |
+
hs=[]
|
| 747 |
+
for i,modules in enumerate(self.downs):
|
| 748 |
+
#print("downsampler", i)
|
| 749 |
+
if i <=(self.num_octs-1):
|
| 750 |
+
C=X_list[-1-i]#get the corresponding CQT octave
|
| 751 |
+
C=C.squeeze(1)
|
| 752 |
+
C=torch.view_as_real(C)
|
| 753 |
+
C=C.permute(0,3,1,2).contiguous() # call contiguous() here?
|
| 754 |
+
if self.use_fencoding:
|
| 755 |
+
#Cfreq=self.freq_encoding(C)
|
| 756 |
+
C2=self.freq_encodings[i](C) #B, C + Nfreq*2, F,T
|
| 757 |
+
else:
|
| 758 |
+
C2=C
|
| 759 |
+
|
| 760 |
+
init_block, pyr_down_proj, ResBlock=modules
|
| 761 |
+
C2=init_block(C2,sigma)
|
| 762 |
+
else:
|
| 763 |
+
pyr_down_proj, ResBlock=modules
|
| 764 |
+
|
| 765 |
+
if i==0:
|
| 766 |
+
X=C2 #starting the main signal path
|
| 767 |
+
pyr=self.downsamplerT(C) #starting the auxiliary path
|
| 768 |
+
elif i<(self.num_octs-1):
|
| 769 |
+
pyr=torch.cat((self.downsamplerT(C),self.downsamplerT(pyr)),dim=2) #updating the auxiliary path
|
| 770 |
+
X=torch.cat((C2,X),dim=2) #updating the main signal path with the new octave
|
| 771 |
+
elif i==(self.num_octs-1):# last layer
|
| 772 |
+
#pyr=torch.cat((self.downsamplerF(C),self.downsamplerF(pyr)),dim=2) #updating the auxiliary path
|
| 773 |
+
pyr=torch.cat((C,pyr), dim=2) #no downsampling in the last layer
|
| 774 |
+
X=torch.cat((C2,X),dim=2) #updating the main signal path with the new octave
|
| 775 |
+
else: #last layer
|
| 776 |
+
pass
|
| 777 |
+
#pyr=pyr
|
| 778 |
+
#X=X
|
| 779 |
+
|
| 780 |
+
X=ResBlock(X, sigma)
|
| 781 |
+
hs.append(X)
|
| 782 |
+
|
| 783 |
+
#downsample the main signal path
|
| 784 |
+
#we do not need to downsample in the inner layer
|
| 785 |
+
if i<(self.num_octs-1):
|
| 786 |
+
X=self.downsamplerT(X)
|
| 787 |
+
#apply the residual connection
|
| 788 |
+
#X=(X+pyr_down_proj(pyr))/(2**0.5) #I'll my need to put that inside a combiner block??
|
| 789 |
+
else: #last layer
|
| 790 |
+
#no downsampling in the last layer
|
| 791 |
+
pass
|
| 792 |
+
|
| 793 |
+
#apply the residual connection
|
| 794 |
+
X=(X+pyr_down_proj(pyr))/(2**0.5) #I'll my need to put that inside a combiner block??
|
| 795 |
+
#print("encoder ", i, X.shape, X.mean().item(), X.std().item())
|
| 796 |
+
|
| 797 |
+
|
| 798 |
+
#middle layers
|
| 799 |
+
#print("bttleneck")
|
| 800 |
+
if self.args.network.bottleneck_type=="res_dil_convs":
|
| 801 |
+
for i in range(self.args.network.num_bottleneck_layers):
|
| 802 |
+
OutBlock, ResBlock =self.middle[i]
|
| 803 |
+
X=ResBlock(X, sigma)
|
| 804 |
+
Xout=OutBlock(X,sigma)
|
| 805 |
+
|
| 806 |
+
|
| 807 |
+
for i,modules in enumerate(self.ups):
|
| 808 |
+
j=len(self.ups) -i-1
|
| 809 |
+
#print("upsampler", j)
|
| 810 |
+
|
| 811 |
+
OutBlock, ResBlock=modules
|
| 812 |
+
|
| 813 |
+
skip=hs.pop()
|
| 814 |
+
X=torch.cat((X,skip),dim=1)
|
| 815 |
+
X=ResBlock(X, sigma)
|
| 816 |
+
|
| 817 |
+
Xout=(Xout+OutBlock(X,sigma))/(2**0.5)
|
| 818 |
+
|
| 819 |
+
|
| 820 |
+
if j<=(self.num_octs-1):
|
| 821 |
+
X= X[:,:,self.bins_per_oct::,:]
|
| 822 |
+
Out, Xout= Xout[:,:,0:self.bins_per_oct,:], Xout[:,:,self.bins_per_oct::,:]
|
| 823 |
+
#pyr_out, pyr= pyr[:,:,0:self.bins_per_oct,:], pyr[:,:,self.bins_per_oct::,:]
|
| 824 |
+
#X_out=(pyr_up_proj(X_out)+pyr_out)/(2**0.5)
|
| 825 |
+
|
| 826 |
+
Out=Out.permute(0,2,3,1).contiguous() #call contiguous() here?
|
| 827 |
+
Out=torch.view_as_complex(Out)
|
| 828 |
+
|
| 829 |
+
#save output
|
| 830 |
+
X_list_out[i]=Out.unsqueeze(1)
|
| 831 |
+
|
| 832 |
+
elif j>(self.num_octs-1):
|
| 833 |
+
print("We should not be here")
|
| 834 |
+
pass
|
| 835 |
+
|
| 836 |
+
if j>0 and j<=(self.num_octs-1):
|
| 837 |
+
#pyr=self.upsampler(pyr) #call contiguous() here?
|
| 838 |
+
X=self.upsamplerT(X) #call contiguous() here?
|
| 839 |
+
Xout=self.upsamplerT(Xout) #call contiguous() here?
|
| 840 |
+
|
| 841 |
+
pred_time=self.CQTransform.bwd(X_list_out)
|
| 842 |
+
pred_time=pred_time.squeeze(1)
|
| 843 |
+
pred_time=pred_time[:,0:inputs.shape[-1]]
|
| 844 |
+
assert pred_time.shape==inputs.shape, "bad shapes"
|
| 845 |
+
return pred_time
|
| 846 |
+
|
| 847 |
+
|
| 848 |
+
|
| 849 |
+
|
| 850 |
+
class CropAddBlock(nn.Module):
|
| 851 |
+
|
| 852 |
+
def forward(self,down_layer, x, **kwargs):
|
| 853 |
+
x1_shape = down_layer.shape
|
| 854 |
+
x2_shape = x.shape
|
| 855 |
+
|
| 856 |
+
#print(x1_shape,x2_shape)
|
| 857 |
+
height_diff = (x1_shape[2] - x2_shape[2]) // 2
|
| 858 |
+
width_diff = (x1_shape[3] - x2_shape[3]) // 2
|
| 859 |
+
|
| 860 |
+
|
| 861 |
+
down_layer_cropped = down_layer[:,
|
| 862 |
+
:,
|
| 863 |
+
height_diff: (x2_shape[2] + height_diff),
|
| 864 |
+
width_diff: (x2_shape[3] + width_diff),:]
|
| 865 |
+
x = torch.add(down_layer_cropped, x)
|
| 866 |
+
return x
|
| 867 |
+
|
| 868 |
+
class CropConcatBlock(nn.Module):
|
| 869 |
+
|
| 870 |
+
def forward(self, down_layer, x, **kwargs):
|
| 871 |
+
x1_shape = down_layer.shape
|
| 872 |
+
x2_shape = x.shape
|
| 873 |
+
|
| 874 |
+
height_diff = (x1_shape[2] - x2_shape[2]) // 2
|
| 875 |
+
width_diff = (x1_shape[3] - x2_shape[3]) // 2
|
| 876 |
+
down_layer_cropped = down_layer[:,
|
| 877 |
+
:,
|
| 878 |
+
height_diff: (x2_shape[2] + height_diff),
|
| 879 |
+
width_diff: (x2_shape[3] + width_diff)]
|
| 880 |
+
x = torch.cat((down_layer_cropped, x),1)
|
| 881 |
+
return x
|
| 882 |
+
|
requirements.txt
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
git+https://github.com/TEAMuP-dev/pyharp.git@develop
|
| 2 |
+
cqt_nsgt_pytorch
|
| 3 |
+
einops
|
| 4 |
+
torch
|
| 5 |
+
torchaudio
|
| 6 |
+
omegaconf
|
| 7 |
+
soundfile
|
| 8 |
+
numpy
|
| 9 |
+
scipy
|
testing/__init__.py
ADDED
|
File without changes
|
testing/edm_sampler_inpainting.py
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from tqdm import tqdm
|
| 2 |
+
import torch
|
| 3 |
+
import torchaudio
|
| 4 |
+
#import scipy.signal
|
| 5 |
+
#import numpy as np
|
| 6 |
+
#from utils.decSTN_pytorch import apply_STN_mask
|
| 7 |
+
|
| 8 |
+
class Sampler():
|
| 9 |
+
|
| 10 |
+
def __init__(self, model, diff_params, args, rid=False):
|
| 11 |
+
|
| 12 |
+
self.model = model
|
| 13 |
+
self.diff_params = diff_params #same as training, useful if we need to apply a wrapper or something
|
| 14 |
+
self.args=args
|
| 15 |
+
if not(self.args.tester.diff_params.same_as_training):
|
| 16 |
+
self.update_diff_params()
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
self.order=self.args.tester.order
|
| 20 |
+
self.xi=self.args.tester.posterior_sampling.xi
|
| 21 |
+
#hyperparameter for the reconstruction guidance
|
| 22 |
+
self.data_consistency=self.args.tester.data_consistency.use and self.args.tester.data_consistency.type=="always"
|
| 23 |
+
|
| 24 |
+
self.data_consistency_end=self.args.tester.data_consistency.use and self.args.tester.data_consistency.type=="end"
|
| 25 |
+
if self.data_consistency or self.data_consistency_end:
|
| 26 |
+
if self.args.tester.data_consistency.smooth:
|
| 27 |
+
self.smooth=True
|
| 28 |
+
else:
|
| 29 |
+
self.smooth=False
|
| 30 |
+
|
| 31 |
+
#use reconstruction gudance without replacement
|
| 32 |
+
self.nb_steps=self.args.tester.T
|
| 33 |
+
|
| 34 |
+
#self.treshold_on_grads=args.tester.inference.max_thresh_grads
|
| 35 |
+
self.rid=rid #this is for logging, ignore for now
|
| 36 |
+
|
| 37 |
+
#try:
|
| 38 |
+
# self.stereo=self.args.tester.stereo
|
| 39 |
+
#except:
|
| 40 |
+
# self.stereo=False
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def update_diff_params(self):
|
| 44 |
+
#the parameters for testing might not be necesarily the same as the ones used for training
|
| 45 |
+
self.diff_params.sigma_min=self.args.tester.diff_params.sigma_min
|
| 46 |
+
self.diff_params.sigma_max =self.args.tester.diff_params.sigma_max
|
| 47 |
+
self.diff_params.ro=self.args.tester.diff_params.ro
|
| 48 |
+
self.diff_params.sigma_data=self.args.tester.diff_params.sigma_data
|
| 49 |
+
#par.diff_params.meters stochastic sampling
|
| 50 |
+
self.diff_params.Schurn=self.args.tester.diff_params.Schurn
|
| 51 |
+
self.diff_params.Stmin=self.args.tester.diff_params.Stmin
|
| 52 |
+
self.diff_params.Stmax=self.args.tester.diff_params.Stmax
|
| 53 |
+
self.diff_params.Snoise=self.args.tester.diff_params.Snoise
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def get_score_rec_guidance(self, x, y, t_i, degradation):
|
| 58 |
+
|
| 59 |
+
x.requires_grad_()
|
| 60 |
+
x_hat=self.diff_params.denoiser(x, self.model, t_i.unsqueeze(-1))
|
| 61 |
+
|
| 62 |
+
if self.args.tester.filter_out_cqt_DC_Nyq:
|
| 63 |
+
x_hat=self.model.CQTransform.apply_hpf_DC(x_hat)
|
| 64 |
+
|
| 65 |
+
den_rec= degradation(x_hat)
|
| 66 |
+
|
| 67 |
+
if len(y.shape)==3:
|
| 68 |
+
dim=(1,2)
|
| 69 |
+
elif len(y.shape)==2:
|
| 70 |
+
dim=1
|
| 71 |
+
|
| 72 |
+
if self.args.tester.posterior_sampling.norm=="smoothl1":
|
| 73 |
+
norm=torch.nn.functional.smooth_l1_loss(y, den_rec, reduction='sum', beta=self.args.tester.posterior_sampling.smoothl1_beta)
|
| 74 |
+
else:
|
| 75 |
+
norm=torch.linalg.norm(y-den_rec,dim=dim, ord=self.args.tester.posterior_sampling.norm)
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
rec_grads=torch.autograd.grad(outputs=norm,
|
| 79 |
+
inputs=x)
|
| 80 |
+
|
| 81 |
+
rec_grads=rec_grads[0]
|
| 82 |
+
|
| 83 |
+
normguide=torch.linalg.norm(rec_grads)/self.args.exp.audio_len**0.5
|
| 84 |
+
|
| 85 |
+
#normalize scaling
|
| 86 |
+
#s=self.xi/(normguide*t_i+1e-6)
|
| 87 |
+
s=t_i*self.xi/(normguide+1e-6)
|
| 88 |
+
|
| 89 |
+
#optionally apply a treshold to the gradients
|
| 90 |
+
if False:
|
| 91 |
+
#pply tresholding to the gradients. It is a dirty trick but helps avoiding bad artifacts
|
| 92 |
+
rec_grads=torch.clip(rec_grads, min=-self.treshold_on_grads, max=self.treshold_on_grads)
|
| 93 |
+
|
| 94 |
+
if self.rid:
|
| 95 |
+
x_hat_old=x_hat.detach().clone()
|
| 96 |
+
|
| 97 |
+
x_hat=x_hat-s*rec_grads #apply gradients
|
| 98 |
+
|
| 99 |
+
if self.rid:
|
| 100 |
+
x_hat_old_2=x_hat.detach().clone()
|
| 101 |
+
|
| 102 |
+
if self.data_consistency:
|
| 103 |
+
x_hat=self.proj_convex_set(x_hat.detach())
|
| 104 |
+
|
| 105 |
+
score=(x_hat.detach()-x)/t_i**2
|
| 106 |
+
|
| 107 |
+
#apply scaled guidance to the score
|
| 108 |
+
#score=score-s*rec_grads
|
| 109 |
+
if self.rid:
|
| 110 |
+
#score, denoised esimate, s*rec_grads, denoised_estimate minus gradients, x_hat after pocs
|
| 111 |
+
return score, x_hat_old, s*rec_grads, x_hat_old_2, x_hat
|
| 112 |
+
else:
|
| 113 |
+
return score
|
| 114 |
+
|
| 115 |
+
def get_score(self,x, y, t_i, degradation):
|
| 116 |
+
if y==None:
|
| 117 |
+
assert degradation==None
|
| 118 |
+
#unconditional sampling
|
| 119 |
+
with torch.no_grad():
|
| 120 |
+
#print("In sampling", x.shape, t_i.shape)
|
| 121 |
+
x_hat=self.diff_params.denoiser(x, self.model, t_i.unsqueeze(-1))
|
| 122 |
+
if self.args.tester.filter_out_cqt_DC_Nyq:
|
| 123 |
+
x_hat=self.model.CQTransform.apply_hpf_DC(x_hat)
|
| 124 |
+
score=(x_hat-x)/t_i**2
|
| 125 |
+
return score
|
| 126 |
+
else:
|
| 127 |
+
if self.xi>0:
|
| 128 |
+
#apply rec. guidance
|
| 129 |
+
score=self.get_score_rec_guidance(x, y, t_i, degradation)
|
| 130 |
+
|
| 131 |
+
#optionally apply replacement or consistency step
|
| 132 |
+
#if self.data_consistency:
|
| 133 |
+
# #convert score to denoised estimate using Tweedie's formula
|
| 134 |
+
# x_hat=score*t_i**2+x
|
| 135 |
+
|
| 136 |
+
# x_hat=self.proj_convex_set(x_hat)
|
| 137 |
+
|
| 138 |
+
# #convert back to score
|
| 139 |
+
# score=(x_hat-x)/t_i**2
|
| 140 |
+
|
| 141 |
+
else:
|
| 142 |
+
#denoised with replacement method
|
| 143 |
+
with torch.no_grad():
|
| 144 |
+
x_hat=self.diff_params.denoiser(x, self.model, t_i.unsqueeze(-1))
|
| 145 |
+
x_hat=self.proj_convex_set(x_hat.detach())
|
| 146 |
+
|
| 147 |
+
score=(x_hat.detach()-x)/t_i**2
|
| 148 |
+
|
| 149 |
+
#x_hat=self.data_consistency_step(x_hat,y, degradation)
|
| 150 |
+
|
| 151 |
+
#score=(x_hat-x)/t_i**2
|
| 152 |
+
|
| 153 |
+
return score
|
| 154 |
+
|
| 155 |
+
def predict_unconditional(
|
| 156 |
+
self,
|
| 157 |
+
shape, #observations (lowpssed signal) Tensor with shape ??
|
| 158 |
+
device
|
| 159 |
+
):
|
| 160 |
+
self.y=None
|
| 161 |
+
self.degradation=None
|
| 162 |
+
return self.predict(shape, device)
|
| 163 |
+
|
| 164 |
+
def predict_resample(
|
| 165 |
+
self,
|
| 166 |
+
y, #observations (lowpssed signal) Tensor with shape ??
|
| 167 |
+
shape,
|
| 168 |
+
degradation, #lambda function
|
| 169 |
+
):
|
| 170 |
+
self.degradation=degradation
|
| 171 |
+
self.y=y
|
| 172 |
+
#print(shape)
|
| 173 |
+
return self.predict(shape, y.device)
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
def predict(
|
| 179 |
+
self,
|
| 180 |
+
shape, #observations (lowpssed signal) Tensor with shape ??
|
| 181 |
+
device, #lambda function
|
| 182 |
+
):
|
| 183 |
+
|
| 184 |
+
if self.rid:
|
| 185 |
+
rid_xt=torch.zeros((self.nb_steps,shape[0], shape[1]))
|
| 186 |
+
rid_grads=torch.zeros((self.nb_steps,shape[0], shape[1]))
|
| 187 |
+
rid_denoised=torch.zeros((self.nb_steps,shape[0], shape[1]))
|
| 188 |
+
rid_grad_update=torch.zeros((self.nb_steps,shape[0], shape[1]))
|
| 189 |
+
rid_pocs=torch.zeros((self.nb_steps,shape[0], shape[1]))
|
| 190 |
+
rid_xt2=torch.zeros((self.nb_steps,shape[0], shape[1]))
|
| 191 |
+
|
| 192 |
+
#get the noise schedule
|
| 193 |
+
t = self.diff_params.create_schedule(self.nb_steps).to(device)
|
| 194 |
+
#sample from gaussian distribution with sigma_max variance
|
| 195 |
+
x = self.diff_params.sample_prior(shape,t[0]).to(device)
|
| 196 |
+
|
| 197 |
+
#parameter for langevin stochasticity, if Schurn is 0, gamma will be 0 to, so the sampler will be deterministic
|
| 198 |
+
gamma=self.diff_params.get_gamma(t).to(device)
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
for i in tqdm(range(0, self.nb_steps, 1)):
|
| 202 |
+
#print("sampling step ",i," from ",self.nb_steps)
|
| 203 |
+
|
| 204 |
+
if gamma[i]==0:
|
| 205 |
+
#deterministic sampling, do nothing
|
| 206 |
+
t_hat=t[i]
|
| 207 |
+
else:
|
| 208 |
+
#stochastic sampling
|
| 209 |
+
#move timestep
|
| 210 |
+
t_hat=t[i]+gamma[i]*t[i]
|
| 211 |
+
#sample noise, Snoise is 1 by default
|
| 212 |
+
epsilon=torch.randn(shape).to(device)*self.diff_params.Snoise
|
| 213 |
+
#add extra noise
|
| 214 |
+
x=x+((t_hat**2 - t[i]**2)**(1/2))*epsilon #x_hat
|
| 215 |
+
del epsilon
|
| 216 |
+
|
| 217 |
+
if self.rid:
|
| 218 |
+
rid_xt[i]=x
|
| 219 |
+
|
| 220 |
+
score=self.get_score(x, self.y, t_hat, self.degradation)
|
| 221 |
+
if self.rid:
|
| 222 |
+
score, x_hat1, grads, x_hat2, x_hat3=score
|
| 223 |
+
rid_denoised[i]=x_hat1
|
| 224 |
+
rid_grads[i]=grads
|
| 225 |
+
rid_grad_update[i]=x_hat2
|
| 226 |
+
rid_pocs[i]=x_hat3
|
| 227 |
+
|
| 228 |
+
|
| 229 |
+
#d=-t_hat*((denoised-x_hat)/t_hat**2)
|
| 230 |
+
d=-t_hat*score
|
| 231 |
+
|
| 232 |
+
#apply second order correction
|
| 233 |
+
h=t[i+1]-t_hat
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
if t[i+1]!=0 and self.order==2: #always except last step
|
| 237 |
+
#second order correction2
|
| 238 |
+
#h=t[i+1]-t_hat
|
| 239 |
+
t_prime=t[i+1]
|
| 240 |
+
x_prime=x+h*d
|
| 241 |
+
score=self.get_score(x_prime, self.y, t_prime, self.degradation)
|
| 242 |
+
if self.rid:
|
| 243 |
+
score, x_hat1, grads, x_hat2, x_hat3=score
|
| 244 |
+
|
| 245 |
+
d_prime=-t_prime*score
|
| 246 |
+
|
| 247 |
+
x=(x+h*((1/2)*d +(1/2)*d_prime))
|
| 248 |
+
|
| 249 |
+
elif t[i+1]==0 or self.order==1: #first condition is to avoid dividing by 0
|
| 250 |
+
#first order Euler step
|
| 251 |
+
x=x+h*d
|
| 252 |
+
|
| 253 |
+
if self.rid:
|
| 254 |
+
rid_xt2[i]=x
|
| 255 |
+
|
| 256 |
+
if self.data_consistency_end:
|
| 257 |
+
x=self.proj_convex_set(x)
|
| 258 |
+
|
| 259 |
+
if self.rid:
|
| 260 |
+
return x.detach(), rid_denoised.detach(), rid_grads.detach(), rid_grad_update.detach(), rid_pocs.detach(), rid_xt.detach(), rid_xt2.detach(), t.detach()
|
| 261 |
+
else:
|
| 262 |
+
return x.detach()
|
| 263 |
+
|
| 264 |
+
def apply_mask(self, x, mask=None):
|
| 265 |
+
|
| 266 |
+
if mask is None:
|
| 267 |
+
mask=self.mask
|
| 268 |
+
|
| 269 |
+
return mask*x
|
| 270 |
+
|
| 271 |
+
def apply_spectral_mask(self, x):
|
| 272 |
+
|
| 273 |
+
if self.args.tester.spectrogram_inpainting.stft.window=="hann":
|
| 274 |
+
window=torch.hann_window(self.args.tester.spectrogram_inpainting.stft.win_length).to(x.device)
|
| 275 |
+
else:
|
| 276 |
+
raise NotImplementedError("Only hann window is implemented for now")
|
| 277 |
+
|
| 278 |
+
n_fft=self.args.tester.spectrogram_inpainting.stft.n_fft
|
| 279 |
+
#add padding to the signal
|
| 280 |
+
input_shape=x.shape
|
| 281 |
+
x=torch.nn.functional.pad(x, (0, n_fft-x.shape[-1]%n_fft), mode='constant', value=0)
|
| 282 |
+
x=torch.stft(x, n_fft, self.args.tester.spectrogram_inpainting.stft.hop_length, self.args.tester.spectrogram_inpainting.stft.win_length, window, return_complex=True)
|
| 283 |
+
#X.shape=(B, F, T)
|
| 284 |
+
x=x*self.mask.unsqueeze(0)
|
| 285 |
+
#apply the inverse stft
|
| 286 |
+
x=torch.istft(x, n_fft, self.args.tester.spectrogram_inpainting.stft.hop_length, self.args.tester.spectrogram_inpainting.stft.win_length, window, return_complex=False)
|
| 287 |
+
#why is the size different? Because of the padding?
|
| 288 |
+
x=x[...,0:input_shape[-1]]
|
| 289 |
+
|
| 290 |
+
return x
|
| 291 |
+
|
| 292 |
+
|
| 293 |
+
#def proj_convex_set(self, x_hat, y, degradation):
|
| 294 |
+
# """
|
| 295 |
+
# Simple replacement method, used for inpainting and FIR bwe
|
| 296 |
+
# """
|
| 297 |
+
# #get reconstruction estimate
|
| 298 |
+
# den_rec= degradation(x_hat)
|
| 299 |
+
# #apply replacment (valid for linear degradations)
|
| 300 |
+
# return y+x_hat-den_rec
|
| 301 |
+
|
| 302 |
+
def prepare_smooth_mask(self, mask, size=10):
|
| 303 |
+
hann=torch.hann_window(size*2)
|
| 304 |
+
hann_left=hann[0:size]
|
| 305 |
+
hann_right=hann[size::]
|
| 306 |
+
B,N=mask.shape
|
| 307 |
+
mask=mask[0]
|
| 308 |
+
prev=1
|
| 309 |
+
new_mask=mask.clone()
|
| 310 |
+
#print(hann.shape)
|
| 311 |
+
for i in range(len(mask)):
|
| 312 |
+
if mask[i] != prev:
|
| 313 |
+
#print(i, mask.shape, mask[i], prev)
|
| 314 |
+
#transition
|
| 315 |
+
if mask[i]==0:
|
| 316 |
+
#gap encountered, apply hann right before
|
| 317 |
+
new_mask[i-size:i]=hann_right
|
| 318 |
+
if mask[i]==1:
|
| 319 |
+
#gap encountered, apply hann left after
|
| 320 |
+
new_mask[i:i+size]=hann_left
|
| 321 |
+
#print(mask[i-2*size:i+2*size])
|
| 322 |
+
#print(new_mask[i-2*size:i+2*size])
|
| 323 |
+
|
| 324 |
+
prev=mask[i]
|
| 325 |
+
return new_mask.unsqueeze(0).expand(B,-1)
|
| 326 |
+
|
| 327 |
+
def predict_inpainting(
|
| 328 |
+
self,
|
| 329 |
+
y_masked,
|
| 330 |
+
mask
|
| 331 |
+
):
|
| 332 |
+
self.mask=mask.to(y_masked.device)
|
| 333 |
+
|
| 334 |
+
self.y=y_masked
|
| 335 |
+
|
| 336 |
+
self.degradation=lambda x: self.apply_mask(x)
|
| 337 |
+
if self.data_consistency or self.data_consistency_end:
|
| 338 |
+
if self.smooth:
|
| 339 |
+
smooth_mask=self.prepare_smooth_mask(mask, self.args.tester.data_consistency.hann_size)
|
| 340 |
+
else:
|
| 341 |
+
smooth_mask=mask
|
| 342 |
+
|
| 343 |
+
self.proj_convex_set= lambda x: smooth_mask*y_masked+(1-smooth_mask)*x #will this work? I am too scared about lambdas
|
| 344 |
+
|
| 345 |
+
|
| 346 |
+
return self.predict(self.y.shape, self.y.device)
|
| 347 |
+
|
| 348 |
+
def predict_spectrogram_inpainting(
|
| 349 |
+
self,
|
| 350 |
+
y_masked,
|
| 351 |
+
mask
|
| 352 |
+
):
|
| 353 |
+
self.mask=mask.to(y_masked.device)
|
| 354 |
+
del mask
|
| 355 |
+
|
| 356 |
+
self.y=y_masked
|
| 357 |
+
del y_masked
|
| 358 |
+
|
| 359 |
+
self.degradation=lambda x: self.apply_spectral_mask(x)
|
| 360 |
+
if self.data_consistency or self.data_consistency_end:
|
| 361 |
+
|
| 362 |
+
self.proj_convex_set= lambda x: self.y+x-self.apply_spectral_mask(x) #If this fails, consider using a more appropiate projection
|
| 363 |
+
|
| 364 |
+
return self.predict(self.y.shape, self.y.device)
|
| 365 |
+
|
| 366 |
+
|
| 367 |
+
|
utils/__init__.py
ADDED
|
File without changes
|
utils/training_utils.py
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import torch
|
| 3 |
+
import torchaudio
|
| 4 |
+
import numpy as np
|
| 5 |
+
import scipy.signal
|
| 6 |
+
class EMAWarmup:
|
| 7 |
+
"""Implements an EMA warmup using an inverse decay schedule.
|
| 8 |
+
If inv_gamma=1 and power=1, implements a simple average. inv_gamma=1, power=2/3 are
|
| 9 |
+
good values for models you plan to train for a million or more steps (reaches decay
|
| 10 |
+
factor 0.999 at 31.6K steps, 0.9999 at 1M steps), inv_gamma=1, power=3/4 for models
|
| 11 |
+
you plan to train for less (reaches decay factor 0.999 at 10K steps, 0.9999 at
|
| 12 |
+
215.4k steps).
|
| 13 |
+
Args:
|
| 14 |
+
inv_gamma (float): Inverse multiplicative factor of EMA warmup. Default: 1.
|
| 15 |
+
power (float): Exponential factor of EMA warmup. Default: 1.
|
| 16 |
+
min_value (float): The minimum EMA decay rate. Default: 0.
|
| 17 |
+
max_value (float): The maximum EMA decay rate. Default: 1.
|
| 18 |
+
start_at (int): The epoch to start averaging at. Default: 0.
|
| 19 |
+
last_epoch (int): The index of last epoch. Default: 0.
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
def __init__(self, inv_gamma=1., power=1., min_value=0., max_value=1., start_at=0,
|
| 23 |
+
last_epoch=0):
|
| 24 |
+
self.inv_gamma = inv_gamma
|
| 25 |
+
self.power = power
|
| 26 |
+
self.min_value = min_value
|
| 27 |
+
self.max_value = max_value
|
| 28 |
+
self.start_at = start_at
|
| 29 |
+
self.last_epoch = last_epoch
|
| 30 |
+
|
| 31 |
+
def state_dict(self):
|
| 32 |
+
"""Returns the state of the class as a :class:`dict`."""
|
| 33 |
+
return dict(self.__dict__.items())
|
| 34 |
+
|
| 35 |
+
def load_state_dict(self, state_dict):
|
| 36 |
+
"""Loads the class's state.
|
| 37 |
+
Args:
|
| 38 |
+
state_dict (dict): scaler state. Should be an object returned
|
| 39 |
+
from a call to :meth:`state_dict`.
|
| 40 |
+
"""
|
| 41 |
+
self.__dict__.update(state_dict)
|
| 42 |
+
|
| 43 |
+
def get_value(self):
|
| 44 |
+
"""Gets the current EMA decay rate."""
|
| 45 |
+
epoch = max(0, self.last_epoch - self.start_at)
|
| 46 |
+
value = 1 - (1 + epoch / self.inv_gamma) ** -self.power
|
| 47 |
+
return 0. if epoch < 0 else min(self.max_value, max(self.min_value, value))
|
| 48 |
+
|
| 49 |
+
def step(self):
|
| 50 |
+
"""Updates the step count."""
|
| 51 |
+
self.last_epoch += 1
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
#from https://github.com/csteinmetz1/auraloss/blob/main/auraloss/perceptual.py
|
| 55 |
+
class FIRFilter(torch.nn.Module):
|
| 56 |
+
"""FIR pre-emphasis filtering module.
|
| 57 |
+
Args:
|
| 58 |
+
filter_type (str): Shape of the desired FIR filter ("hp", "fd", "aw"). Default: "hp"
|
| 59 |
+
coef (float): Coefficient value for the filter tap (only applicable for "hp" and "fd"). Default: 0.85
|
| 60 |
+
ntaps (int): Number of FIR filter taps for constructing A-weighting filters. Default: 101
|
| 61 |
+
plot (bool): Plot the magnitude respond of the filter. Default: False
|
| 62 |
+
Based upon the perceptual loss pre-empahsis filters proposed by
|
| 63 |
+
[Wright & Välimäki, 2019](https://arxiv.org/abs/1911.08922).
|
| 64 |
+
A-weighting filter - "aw"
|
| 65 |
+
First-order highpass - "hp"
|
| 66 |
+
Folded differentiator - "fd"
|
| 67 |
+
Note that the default coefficeint value of 0.85 is optimized for
|
| 68 |
+
a sampling rate of 44.1 kHz, considering adjusting this value at differnt sampling rates.
|
| 69 |
+
"""
|
| 70 |
+
|
| 71 |
+
def __init__(self, filter_type="hp", coef=0.85, fs=44100, ntaps=101, plot=False):
|
| 72 |
+
"""Initilize FIR pre-emphasis filtering module."""
|
| 73 |
+
super(FIRFilter, self).__init__()
|
| 74 |
+
self.filter_type = filter_type
|
| 75 |
+
self.coef = coef
|
| 76 |
+
self.fs = fs
|
| 77 |
+
self.ntaps = ntaps
|
| 78 |
+
self.plot = plot
|
| 79 |
+
|
| 80 |
+
if ntaps % 2 == 0:
|
| 81 |
+
raise ValueError(f"ntaps must be odd (ntaps={ntaps}).")
|
| 82 |
+
|
| 83 |
+
if filter_type == "hp":
|
| 84 |
+
self.fir = torch.nn.Conv1d(1, 1, kernel_size=3, bias=False, padding=1)
|
| 85 |
+
self.fir.weight.requires_grad = False
|
| 86 |
+
self.fir.weight.data = torch.tensor([1, -coef, 0]).view(1, 1, -1)
|
| 87 |
+
elif filter_type == "fd":
|
| 88 |
+
self.fir = torch.nn.Conv1d(1, 1, kernel_size=3, bias=False, padding=1)
|
| 89 |
+
self.fir.weight.requires_grad = False
|
| 90 |
+
self.fir.weight.data = torch.tensor([1, 0, -coef]).view(1, 1, -1)
|
| 91 |
+
elif filter_type == "aw":
|
| 92 |
+
# Definition of analog A-weighting filter according to IEC/CD 1672.
|
| 93 |
+
f1 = 20.598997
|
| 94 |
+
f2 = 107.65265
|
| 95 |
+
f3 = 737.86223
|
| 96 |
+
f4 = 12194.217
|
| 97 |
+
A1000 = 1.9997
|
| 98 |
+
|
| 99 |
+
NUMs = [(2 * np.pi * f4) ** 2 * (10 ** (A1000 / 20)), 0, 0, 0, 0]
|
| 100 |
+
DENs = np.polymul(
|
| 101 |
+
[1, 4 * np.pi * f4, (2 * np.pi * f4) ** 2],
|
| 102 |
+
[1, 4 * np.pi * f1, (2 * np.pi * f1) ** 2],
|
| 103 |
+
)
|
| 104 |
+
DENs = np.polymul(
|
| 105 |
+
np.polymul(DENs, [1, 2 * np.pi * f3]), [1, 2 * np.pi * f2]
|
| 106 |
+
)
|
| 107 |
+
|
| 108 |
+
# convert analog filter to digital filter
|
| 109 |
+
b, a = scipy.signal.bilinear(NUMs, DENs, fs=fs)
|
| 110 |
+
|
| 111 |
+
# compute the digital filter frequency response
|
| 112 |
+
w_iir, h_iir = scipy.signal.freqz(b, a, worN=512, fs=fs)
|
| 113 |
+
|
| 114 |
+
# then we fit to 101 tap FIR filter with least squares
|
| 115 |
+
taps = scipy.signal.firls(ntaps, w_iir, abs(h_iir), fs=fs)
|
| 116 |
+
|
| 117 |
+
# now implement this digital FIR filter as a Conv1d layer
|
| 118 |
+
self.fir = torch.nn.Conv1d(
|
| 119 |
+
1, 1, kernel_size=ntaps, bias=False, padding=ntaps // 2
|
| 120 |
+
)
|
| 121 |
+
self.fir.weight.requires_grad = False
|
| 122 |
+
self.fir.weight.data = torch.tensor(taps.astype("float32")).view(1, 1, -1)
|
| 123 |
+
|
| 124 |
+
def forward(self, error):
|
| 125 |
+
"""Calculate forward propagation.
|
| 126 |
+
Args:
|
| 127 |
+
input (Tensor): Predicted signal (B, #channels, #samples).
|
| 128 |
+
target (Tensor): Groundtruth signal (B, #channels, #samples).
|
| 129 |
+
Returns:
|
| 130 |
+
Tensor: Filtered signal.
|
| 131 |
+
"""
|
| 132 |
+
self.fir.weight.data=self.fir.weight.data.to(error.device)
|
| 133 |
+
error=error.unsqueeze(1)
|
| 134 |
+
error = torch.nn.functional.conv1d(
|
| 135 |
+
error, self.fir.weight.data, padding=self.ntaps // 2
|
| 136 |
+
)
|
| 137 |
+
error=error.squeeze(1)
|
| 138 |
+
return error
|
| 139 |
+
|
| 140 |
+
def resample_batch(audio, fs, fs_target, length_target):
|
| 141 |
+
|
| 142 |
+
device=audio.device
|
| 143 |
+
dtype=audio.dtype
|
| 144 |
+
B=audio.shape[0]
|
| 145 |
+
#if possible resampe in a batched way
|
| 146 |
+
#check if all the fs are the same and equal to 44100
|
| 147 |
+
if fs_target==22050:
|
| 148 |
+
if (fs==44100).all():
|
| 149 |
+
audio=torchaudio.functional.resample(audio, 2,1)
|
| 150 |
+
return audio[:, 0:length_target] #trow away the last samples
|
| 151 |
+
elif (fs==48000).all():
|
| 152 |
+
#approcimate resamppleint
|
| 153 |
+
audio=torchaudio.functional.resample(audio, 160*2,147)
|
| 154 |
+
return audio[:, 0:length_target]
|
| 155 |
+
else:
|
| 156 |
+
#if revious is unsuccesful bccause we have examples at 441000 and 48000 in the same batch,, just iterate over the batch
|
| 157 |
+
proc_batch=torch.zeros((B,length_target), device=device)
|
| 158 |
+
for i, (a, f_s) in enumerate(zip(audio, fs)): #I hope this shit wll not slow down everythingh
|
| 159 |
+
if f_s==44100:
|
| 160 |
+
#resample by 2
|
| 161 |
+
a=torchaudio.functional.resample(a, 2,1)
|
| 162 |
+
elif f_s==48000:
|
| 163 |
+
a=torchaudio.functional.resample(a, 160*2,147)
|
| 164 |
+
else:
|
| 165 |
+
print("WARNING, strange fs", f_s)
|
| 166 |
+
|
| 167 |
+
proc_batch[i]=a[0:length_target]
|
| 168 |
+
return proc_batch
|
| 169 |
+
elif fs_target==44100:
|
| 170 |
+
if (fs==44100).all():
|
| 171 |
+
return audio[:, 0:length_target] #trow away the last samples
|
| 172 |
+
elif (fs==48000).all():
|
| 173 |
+
#approcimate resamppleint
|
| 174 |
+
audio=torchaudio.functional.resample(audio, 160,147)
|
| 175 |
+
return audio[:, 0:length_target]
|
| 176 |
+
else:
|
| 177 |
+
#if revious is unsuccesful bccause we have examples at 441000 and 48000 in the same batch,, just iterate over the batch
|
| 178 |
+
proc_batch=torch.zeros((B,length_target), device=device)
|
| 179 |
+
for i, (a, f_s) in enumerate(zip(audio, fs)): #I hope this shit wll not slow down everythingh
|
| 180 |
+
if f_s==44100:
|
| 181 |
+
#resample by 2
|
| 182 |
+
pass
|
| 183 |
+
elif f_s==48000:
|
| 184 |
+
a=torchaudio.functional.resample(a, 160,147)
|
| 185 |
+
else:
|
| 186 |
+
print("WARNING, strange fs", f_s)
|
| 187 |
+
|
| 188 |
+
proc_batch[i]=a[0:length_target]
|
| 189 |
+
return proc_batch
|
| 190 |
+
else:
|
| 191 |
+
print(" resampling to fs_target", fs_target)
|
| 192 |
+
if (fs==44100).all():
|
| 193 |
+
audio=torchaudio.functional.resample(audio, 44100, fs_target)
|
| 194 |
+
return audio[:, 0:length_target] #trow away the last samples
|
| 195 |
+
elif (fs==48000).all():
|
| 196 |
+
#approcimate resamppleint
|
| 197 |
+
audio=torchaudio.functional.resample(audio, 48000,fs_target)
|
| 198 |
+
return audio[:, 0:length_target]
|
| 199 |
+
else:
|
| 200 |
+
#if revious is unsuccesful bccause we have examples at 441000 and 48000 in the same batch,, just iterate over the batch
|
| 201 |
+
proc_batch=torch.zeros((B,length_target), device=device)
|
| 202 |
+
for i, (a, f_s) in enumerate(zip(audio, fs)): #I hope this shit wll not slow down everythingh
|
| 203 |
+
if f_s==44100:
|
| 204 |
+
#resample by 2
|
| 205 |
+
a=torchaudio.functional.resample(a, 44100,fs_target)
|
| 206 |
+
elif f_s==48000:
|
| 207 |
+
a=torchaudio.functional.resample(a, 48000,fs_target)
|
| 208 |
+
else:
|
| 209 |
+
print("WARNING, strange fs", f_s)
|
| 210 |
+
|
| 211 |
+
proc_batch[i]=a[0:length_target]
|
| 212 |
+
return proc_batch
|
| 213 |
+
|
| 214 |
+
def load_state_dict( state_dict, network=None, ema=None, optimizer=None, log=True):
|
| 215 |
+
'''
|
| 216 |
+
utility for loading state dicts for different models. This function sequentially tries different strategies
|
| 217 |
+
args:
|
| 218 |
+
state_dict: the state dict to load
|
| 219 |
+
returns:
|
| 220 |
+
True if the state dict was loaded, False otherwise
|
| 221 |
+
Assuming the operations are don in_place, this function will not create a copy of the network and optimizer (I hope)
|
| 222 |
+
'''
|
| 223 |
+
#print(state_dict)
|
| 224 |
+
if log: print("Loading state dict")
|
| 225 |
+
if log:
|
| 226 |
+
print(state_dict.keys())
|
| 227 |
+
#if there
|
| 228 |
+
try:
|
| 229 |
+
if log: print("Attempt 1: trying with strict=True")
|
| 230 |
+
if network is not None:
|
| 231 |
+
network.load_state_dict(state_dict['network'])
|
| 232 |
+
if optimizer is not None:
|
| 233 |
+
optimizer.load_state_dict(state_dict['optimizer'])
|
| 234 |
+
if ema is not None:
|
| 235 |
+
ema.load_state_dict(state_dict['ema'])
|
| 236 |
+
return True
|
| 237 |
+
except Exception as e:
|
| 238 |
+
if log:
|
| 239 |
+
print("Could not load state dict")
|
| 240 |
+
print(e)
|
| 241 |
+
try:
|
| 242 |
+
if log: print("Attempt 2: trying with strict=False")
|
| 243 |
+
if network is not None:
|
| 244 |
+
network.load_state_dict(state_dict['network'], strict=False)
|
| 245 |
+
#we cannot load the optimizer in this setting
|
| 246 |
+
#self.optimizer.load_state_dict(state_dict['optimizer'], strict=False)
|
| 247 |
+
if ema is not None:
|
| 248 |
+
ema.load_state_dict(state_dict['ema'], strict=False)
|
| 249 |
+
return True
|
| 250 |
+
except Exception as e:
|
| 251 |
+
if log:
|
| 252 |
+
print("Could not load state dict")
|
| 253 |
+
print(e)
|
| 254 |
+
print("training from scratch")
|
| 255 |
+
try:
|
| 256 |
+
if log: print("Attempt 3: trying with strict=False,but making sure that the shapes are fine")
|
| 257 |
+
if ema is not None:
|
| 258 |
+
ema_state_dict = ema.state_dict()
|
| 259 |
+
if network is not None:
|
| 260 |
+
network_state_dict = network.state_dict()
|
| 261 |
+
i=0
|
| 262 |
+
if network is not None:
|
| 263 |
+
for name, param in state_dict['network'].items():
|
| 264 |
+
if log: print("checking",name)
|
| 265 |
+
if name in network_state_dict.keys():
|
| 266 |
+
if network_state_dict[name].shape==param.shape:
|
| 267 |
+
network_state_dict[name]=param
|
| 268 |
+
if log:
|
| 269 |
+
print("assigning",name)
|
| 270 |
+
i+=1
|
| 271 |
+
network.load_state_dict(network_state_dict)
|
| 272 |
+
if ema is not None:
|
| 273 |
+
for name, param in state_dict['ema'].items():
|
| 274 |
+
if log: print("checking",name)
|
| 275 |
+
if name in ema_state_dict.keys():
|
| 276 |
+
if ema_state_dict[name].shape==param.shape:
|
| 277 |
+
ema_state_dict[name]=param
|
| 278 |
+
if log:
|
| 279 |
+
print("assigning",name)
|
| 280 |
+
i+=1
|
| 281 |
+
|
| 282 |
+
ema.load_state_dict(ema_state_dict)
|
| 283 |
+
|
| 284 |
+
if i==0:
|
| 285 |
+
if log: print("WARNING, no parameters were loaded")
|
| 286 |
+
raise Exception("No parameters were loaded")
|
| 287 |
+
elif i>0:
|
| 288 |
+
if log: print("loaded", i, "parameters")
|
| 289 |
+
return True
|
| 290 |
+
|
| 291 |
+
except Exception as e:
|
| 292 |
+
print(e)
|
| 293 |
+
print("the second strict=False failed")
|
| 294 |
+
|
| 295 |
+
|
| 296 |
+
try:
|
| 297 |
+
if log: print("Attempt 4: Assuming the naming is different, with the network and ema called 'state_dict'")
|
| 298 |
+
if network is not None:
|
| 299 |
+
network.load_state_dict(state_dict['state_dict'])
|
| 300 |
+
if ema is not None:
|
| 301 |
+
ema.load_state_dict(state_dict['state_dict'])
|
| 302 |
+
except Exception as e:
|
| 303 |
+
if log:
|
| 304 |
+
print("Could not load state dict")
|
| 305 |
+
print(e)
|
| 306 |
+
print("training from scratch")
|
| 307 |
+
print("It failed 3 times!! but not giving up")
|
| 308 |
+
#print the names of the parameters in self.network
|
| 309 |
+
|
| 310 |
+
try:
|
| 311 |
+
if log: print("Attempt 5: trying to load with different names, now model='model' and ema='ema_weights'")
|
| 312 |
+
if ema is not None:
|
| 313 |
+
dic_ema = {}
|
| 314 |
+
for (key, tensor) in zip(state_dict['model'].keys(), state_dict['ema_weights']):
|
| 315 |
+
dic_ema[key] = tensor
|
| 316 |
+
ema.load_state_dict(dic_ema)
|
| 317 |
+
return True
|
| 318 |
+
except Exception as e:
|
| 319 |
+
if log:
|
| 320 |
+
print(e)
|
| 321 |
+
|
| 322 |
+
try:
|
| 323 |
+
if log: print("Attempt 6: If there is something wrong with the name of the ema parameters, we can try to load them using the names of the parameters in the model")
|
| 324 |
+
if ema is not None:
|
| 325 |
+
dic_ema = {}
|
| 326 |
+
i=0
|
| 327 |
+
for (key, tensor) in zip(state_dict['model'].keys(), state_dict['model'].values()):
|
| 328 |
+
if tensor.requires_grad:
|
| 329 |
+
dic_ema[key]=state_dict['ema_weights'][i]
|
| 330 |
+
i=i+1
|
| 331 |
+
else:
|
| 332 |
+
dic_ema[key]=tensor
|
| 333 |
+
ema.load_state_dict(dic_ema)
|
| 334 |
+
return True
|
| 335 |
+
except Exception as e:
|
| 336 |
+
if log:
|
| 337 |
+
print(e)
|
| 338 |
+
|
| 339 |
+
#try:
|
| 340 |
+
#assign the parameters in state_dict to self.network using a for loop
|
| 341 |
+
print("Attempt 7: Trying to load the parameters one by one. This is for the dance diffusion model, looking for parameters starting with 'diffusion.' or 'diffusion_ema.'")
|
| 342 |
+
if ema is not None:
|
| 343 |
+
ema_state_dict = ema.state_dict()
|
| 344 |
+
if network is not None:
|
| 345 |
+
network_state_dict = ema.state_dict()
|
| 346 |
+
i=0
|
| 347 |
+
if network is not None:
|
| 348 |
+
for name, param in state_dict['state_dict'].items():
|
| 349 |
+
print("checking",name)
|
| 350 |
+
if name.startswith("diffusion."):
|
| 351 |
+
i+=1
|
| 352 |
+
name=name.replace("diffusion.","")
|
| 353 |
+
if network_state_dict[name].shape==param.shape:
|
| 354 |
+
#print(param.shape, network.state_dict()[name].shape)
|
| 355 |
+
network_state_dict[name]=param
|
| 356 |
+
#print("assigning",name)
|
| 357 |
+
|
| 358 |
+
network.load_state_dict(network_state_dict, strict=False)
|
| 359 |
+
|
| 360 |
+
if ema is not None:
|
| 361 |
+
for name, param in state_dict['state_dict'].items():
|
| 362 |
+
if name.startswith("diffusion_ema."):
|
| 363 |
+
i+=1
|
| 364 |
+
name=name.replace("diffusion_ema.","")
|
| 365 |
+
if ema_state_dict[name].shape==param.shape:
|
| 366 |
+
if log:
|
| 367 |
+
print(param.shape, ema.state_dict()[name].shape)
|
| 368 |
+
ema_state_dict[name]=param
|
| 369 |
+
|
| 370 |
+
ema.load_state_dict(ema_state_dict, strict=False)
|
| 371 |
+
|
| 372 |
+
if i==0:
|
| 373 |
+
print("WARNING, no parameters were loaded")
|
| 374 |
+
raise Exception("No parameters were loaded")
|
| 375 |
+
elif i>0:
|
| 376 |
+
print("loaded", i, "parameters")
|
| 377 |
+
return True
|
| 378 |
+
#except Exception as e:
|
| 379 |
+
# if log:
|
| 380 |
+
# print(e)
|
| 381 |
+
|
| 382 |
+
return False
|
| 383 |
+
|
| 384 |
+
|