Vansh Chugh commited on
Commit
de6f21d
·
1 Parent(s): 0cbb723

initial deploy

Browse files
.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: indigo
5
- colorTo: pink
6
  sdk: gradio
7
- sdk_version: 6.20.0
8
- python_version: '3.13'
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
+