| |
| |
| |
|
|
| import torch |
| import torch.nn.functional as F |
| import sys |
| import math |
| import time |
| import os |
| import einops |
| import numpy as np |
|
|
| from utils.multitrack_utils import multitrack_batched_processing |
| from utils.data_utils import apply_RMS_normalization |
|
|
| class EDM_Multitrack_Embeddings: |
| """ |
| This implements the time-frequency domain diffusion |
| Definition of the diffusion parameterization, following ( Karras et al., "Elucidating...", 2022). |
| This includes only the utilities needed for training, not for sampling. |
| """ |
|
|
| def __init__(self, |
| type, |
| sde_hp, |
| default_shape, |
| cfg_dropout_prob=0.2, |
| sample_rate=44100, |
| context_signal="dry", |
| content_encoder_type="CLAP", |
| style_encoder_type="fx_encoder2048+AFv6", |
| *args, |
| **kwargs |
| ): |
|
|
| self.type = type |
| self.sde_hp = sde_hp |
|
|
| self.sigma_data = self.sde_hp.sigma_data |
| self.sigma_min = self.sde_hp.sigma_min |
| self.sigma_max = self.sde_hp.sigma_max |
| self.rho = self.sde_hp.rho |
|
|
| self.default_shape = torch.Size(default_shape) |
|
|
| try: |
| self.max_t = self.sde_hp.max_sigma |
| except Exception as e: |
| print(e) |
| print("max_sigma not defined, please add it. It should be the highest sigma value seen during training") |
|
|
| device=torch.device("cuda" if torch.cuda.is_available() else "cpu") |
| self.device=device |
|
|
| self.cfg_dropout_prob = cfg_dropout_prob |
|
|
| self.context_signal=context_signal |
|
|
| self.sample_rate=sample_rate |
|
|
| self.prepare_content_encoder(content_encoder_type, sample_rate, *args, **kwargs) |
| self.prepare_style_encoder(style_encoder_type, *args, **kwargs) |
|
|
| def prepare_content_encoder(self, type, sample_rate, *args, **kwargs): |
|
|
| if type=="CLAP": |
| CLAP_args= kwargs.get("CLAP_args", None) |
| assert CLAP_args is not None, "CLAP_args must be provided for CLAP AE" |
|
|
| |
| from utils.feature_extractors.load_features import load_CLAP |
| CLAP_encoder= load_CLAP(CLAP_args, device=self.device) |
|
|
| def encode_fn(x, *args, **kwargs): |
| x=x.to(self.device) |
|
|
| type= kwargs.get("type", None) |
| z=CLAP_encoder(x, type) |
|
|
| z=z.view(z.shape[0], 64, -1) |
|
|
| z=z.permute(0, 2, 1) |
|
|
| return z |
| |
| self.content_encode_fn=encode_fn |
|
|
| else: |
| raise NotImplementedError(f"AE type {AE_type} not implemented") |
|
|
|
|
| def prepare_style_encoder(self, type, *args, **kwargs): |
|
|
| if type=="FxEncoder++_DynamicFeatures": |
|
|
| Fxencoder_plusplus_args=kwargs.get("fx_encoder_plusplus_args", None) |
|
|
| from utils.feature_extractors.load_features import load_fx_encoder_plusplus_2048 |
| feat_extractor = load_fx_encoder_plusplus_2048(Fxencoder_plusplus_args, self.device) |
|
|
| from utils.feature_extractors.AF_features_embedding import AF_fourier_embedding |
| AFembedding= AF_fourier_embedding(device=self.device) |
|
|
| def fxencode_fn(x): |
| """ |
| x: tensor of shape [B, C, L] where B is the batch size, C is the number of channels and L is the length of the audio |
| """ |
| z=feat_extractor(x) |
| z=torch.nn.functional.normalize(z, dim=-1, p=2) |
| z=z*math.sqrt(z.shape[-1]) |
|
|
| z_af,_=AFembedding.encode(x) |
| z_af=z_af* math.sqrt(z_af.shape[-1]) |
|
|
|
|
| z_all= torch.cat([z, z_af], dim=-1) |
|
|
| |
|
|
| norm_z= z_all/ math.sqrt(z_all.shape[-1]) |
|
|
| norm_z=norm_z.view(norm_z.shape[0], 64, -1) |
|
|
| return norm_z |
|
|
| def reshape_fn(embed): |
| """ |
| embed: tensor of shape [B, 64, L//64] where B is the batch size |
| """ |
| embed=embed.view(embed.shape[0], -1) |
|
|
| return embed |
|
|
|
|
| self.style_encode_fn=fxencode_fn |
| self.style_reshape=reshape_fn |
|
|
| else: |
| raise NotImplementedError(f"FX encoder type {type} not implemented") |
|
|
| def sample_time_training(self, N): |
| """ |
| For training, getting t according to a similar criteria as sampling. Simpler and safer to what Karras et al. did |
| Args: |
| N (int): batch size |
| """ |
| a = torch.rand(N) |
| t = (self.sigma_max**(1/self.rho) +a *(self.sigma_min**(1/self.rho) - self.sigma_max**(1/self.rho)))**self.rho |
|
|
| return t |
|
|
| def sample_prior(self, shape=None, t=None, dtype=None): |
| """ |
| Just sample some gaussian noise, nothing more |
| Args: |
| shape (tuple): shape of the noise to sample, something like (B,T) |
| """ |
| assert shape is not None |
| if t is not None: |
| n = torch.randn(shape).to(t.device) * t |
| else: |
| n = torch.randn(shape) |
| return n |
|
|
| def cskip(self, sigma): |
| """ |
| Just one of the preconditioning parameters |
| Args: |
| sigma (float): noise level (equal to timestep is sigma=t, which is our default) |
| |
| """ |
| return self.sigma_data**2 *(sigma**2+self.sigma_data**2)**-1 |
|
|
| def cout(self, sigma): |
| """ |
| Just one of the preconditioning parameters |
| Args: |
| sigma (float): noise level (equal to timestep is sigma=t, which is our default) |
| """ |
| return sigma*self.sigma_data* (self.sigma_data**2+sigma**2)**(-0.5) |
|
|
| def cin(self, sigma): |
| """ |
| Just one of the preconditioning parameters |
| Args: |
| sigma (float): noise level (equal to timestep is sigma=t, which is our default) |
| """ |
| return (self.sigma_data**2+sigma**2)**(-0.5) |
|
|
| def cnoise(self, sigma): |
| """ |
| preconditioning of the noise embedding |
| Args: |
| sigma (float): noise level (equal to timestep is sigma=t, which is our default) |
| """ |
| return (1/4)*torch.log(sigma) |
|
|
| def lambda_w(self, sigma): |
| """ |
| Score matching loss weighting |
| """ |
| return (sigma*self.sigma_data)**(-2) * (self.sigma_data**2+sigma**2) |
|
|
| def prepare_train_preconditioning(self, x, t, n=None, *args, **kwargs): |
|
|
| mu, sigma = self._mean(x, t), self._std(t).unsqueeze(-1) |
| sigma = sigma.view(*sigma.size(), *(1,)*(x.ndim - sigma.ndim)) |
| if n is None: |
| n=self.sample_prior(shape=x.shape).to(x.device) |
| x_perturbed = mu + sigma *n |
| |
|
|
| cskip = self.cskip(sigma) |
| cout = self.cout(sigma) |
| cin = self.cin(sigma) |
| cnoise = self.cnoise(sigma.squeeze()) |
|
|
| |
| if len(cnoise.shape) == 0: |
| cnoise = cnoise.repeat(x.shape[0],) |
| else: |
| cnoise = cnoise.view(x.shape[0],) |
|
|
| target = 1/cout * (x - cskip * x_perturbed) |
|
|
| return cin * x_perturbed, target, cnoise |
|
|
| def loss_fn(self, net, sample=None, sample_aug=None, context=None, clusters=None, taxonomy=None, masks=None, *args, **kwargs): |
| """ |
| Loss function, which is the mean squared error between the denoised latent and the clean latent |
| Args: |
| net (nn.Module): Model of the denoiser |
| x (Tensor): shape: (B,T) Intermediate noisy latent to denoise |
| sigma (float): noise level (equal to timestep is sigma=t, which is our default) |
| """ |
|
|
| start=time.time() |
| y=sample |
|
|
| t = self.sample_time_training(y.shape[0]).to(y.device) |
|
|
| if self.context_signal == "wet": |
| if sample_aug is not None: |
| context = sample_aug |
| else: |
| context = y.clone() |
|
|
| else: |
| assert context is not None, "Context must be provided if context_signal is not 'wet'" |
| |
| a=time.time |
|
|
| with torch.no_grad(): |
| |
| y_style=self.style_encode(y, masks=masks, taxonomy=taxonomy) |
|
|
| if context is not None: |
| z, x=self.transform_forward(context, is_condition=True, clusters=clusters, masks=masks, taxonomy=taxonomy, is_wet=(self.context_signal == "wet")) |
| if self.cfg_dropout_prob > 0.0: |
| null_embed = torch.zeros_like(z, device=z.device) |
| |
| mask = torch.rand(z.shape[0], device=z.device) < self.cfg_dropout_prob |
| z = torch.where(mask.view(-1,1,1,1), null_embed, z) |
|
|
|
|
| input, target, cnoise = self.prepare_train_preconditioning(y_style, t ) |
|
|
|
|
| if len(cnoise.shape)==1: |
| cnoise=cnoise.unsqueeze(-1) |
| if input.ndim==2: |
| input=input.unsqueeze(1) |
|
|
| estimate = net(input, cnoise, cross_attn_cond=z, taxonomy=taxonomy, mask=masks, cross_attn_cond_mask=masks) |
| |
| if target.ndim==2 and estimate.ndim==3: |
| estimate=estimate.squeeze(1) |
|
|
| error=torch.square(torch.abs(estimate-target)) |
|
|
| |
| error= error*masks.view(masks.shape[0], masks.shape[1], 1, 1) |
|
|
| compensating_scalar= torch.numel(masks)/ torch.sum(masks, dim=(0,1), keepdim=False).clamp(min=1.0) |
| error= error * compensating_scalar.view(-1, 1, 1, 1) |
|
|
| return error, self._std(t), x, y |
|
|
|
|
| def get_null_embed(self, context): |
| null_embed = torch.zeros_like(context, device=context.device) |
| return null_embed |
|
|
|
|
| def denoiser(self, xn , net, t, cond=None,cfg_scale=1.0, masks=None, taxonomy=None, **kwargs): |
| """ |
| This method does the whole denoising step, which implies applying the model and the preconditioning |
| Args: |
| x (Tensor): shape: (CQT shape?) Intermediate noisy latent to denoise |
| model (nn.Module): Model of the denoiser |
| sigma (float): noise level (equal to timestep is sigma=t, which is our default) |
| """ |
| sigma = self._std(t).unsqueeze(-1) |
| sigma = sigma.view(*sigma.size(), *(1,)*(xn.ndim - sigma.ndim)) |
|
|
| cskip = self.cskip(sigma) |
| cout = self.cout(sigma) |
| cin = self.cin(sigma) |
| cnoise = self.cnoise(sigma.squeeze()) |
|
|
| |
| if len(cnoise.shape) == 0: |
| cnoise = cnoise.repeat(xn.shape[0],).unsqueeze(-1) |
| else: |
| cnoise = cnoise.view(xn.shape[0],).unsqueeze(-1) |
|
|
|
|
| x_in=cin*xn |
|
|
| if cfg_scale == 1.0: |
| net_out=net(x_in, cnoise.to(torch.float32), cross_attn_cond=cond, mask=masks, taxonomy=taxonomy, cross_attn_cond_mask=masks) |
| else: |
| null_embed = self.get_null_embed(cond) |
|
|
| inputs_cond= torch.cat([cond, null_embed], dim=0) |
|
|
| x_in_cat= torch.cat([x_in, x_in], dim=0) |
|
|
| cnoise= torch.cat([cnoise, cnoise], dim=0) |
|
|
| masks_in= torch.cat([masks, masks], dim=0) if masks is not None else None |
|
|
|
|
| net_out_batch=net(x_in_cat, cnoise.to(torch.float32), cross_attn_cond=inputs_cond , mask=masks_in, cross_attn_cond_mask=masks_in) |
|
|
| cond_output, uncond_output = torch.chunk(net_out_batch, 2, dim=0) |
|
|
| net_out = uncond_output + (cond_output - uncond_output) * cfg_scale |
|
|
|
|
| x_hat=cskip*xn + cout*net_out |
| x_hat=x_hat* masks.view(masks.shape[0], masks.shape[1], 1, 1) |
|
|
| return x_hat |
|
|
| def style_encode(self, x, masks=None, taxonomy=None, use_adaptor=False): |
| """ |
| Encode the input audio using the style encoder |
| Args: |
| x (Tensor): shape: (B,N, C, T) Audio to encode |
| masks (Tensor): shape: (B, N) Mask indicating which tracks are present in the batch |
| """ |
| def apply_fxenc(x_masked, taxonommy=None): |
| x_emb=self.style_encode_fn(x_masked) |
|
|
| return x_emb |
|
|
| assert masks is not None, "masks must be provided for style encoding" |
|
|
| output_emb=multitrack_batched_processing( x, taxonomy=taxonomy ,function=apply_fxenc, class_dependent=False, masks=masks) |
|
|
| return output_emb |
|
|
| def _mean(self, x, t): |
| return x |
| |
| def _std(self, t): |
| return t |
| |
| def _ode_integrand(self, x, t, score): |
| return -t * score |
| |
| def transform_inverse(self, z): |
| |
| B, N, C, T = z.shape |
| |
| z_reshaped = einops.rearrange(z, "b n c t -> (b n) c t") |
| z_reshaped= self.style_reshape(z_reshaped) |
|
|
| |
|
|
| z_out = einops.rearrange(z_reshaped, "(b n) c -> b n c", b=B, n=N) |
|
|
| return z_out |
| |
| def preprocessor(self, x, is_test=False, taxonomy=None): |
| """ |
| x: tensor of shape (BxN, C, T) where B is the batch size, N is the number of tracks, C is the number of channels and T is the number of time steps |
| taxonomy: list of lists of strings, where each string is the taxonomy of the track with length BxN. It may be useful if we want to apply different augmentations depending on the taxonomy of the track. |
| """ |
| if x.shape[1] == 2: |
| x = torch.mean(x, dim=1, keepdim=True).expand(-1, 2, -1) |
| elif x.shape[1] == 1: |
| x = x.expand(-1, 2, -1) |
| |
| if not is_test: |
| |
| if np.random.rand() > 0.5: |
| x = -x |
|
|
| |
| x= apply_RMS_normalization(x, -25, device=self.device) |
|
|
| return x |
|
|
| def Tweedie2score(self, tweedie, xt, t, *args, **kwargs): |
| return (tweedie - self._mean(xt, t)) / self._std(t)**2 |
|
|
| def score2Tweedie(self, score, xt, t, *args, **kwargs): |
| return self._std(t)**2 * score + self._mean(xt, t) |
|
|
| def transform_forward(self, x, y=None, is_condition=False, is_test=False, clusters=None, masks=None, taxonomy=None, is_wet=False): |
|
|
| assert masks is not None |
|
|
| |
|
|
| def prerprocess_and_encode(x_masked, taxonomy=None): |
| if is_condition: |
|
|
| x_masked=self.preprocessor(x_masked, is_test=is_test, taxonomy=taxonomy) |
| |
| with torch.no_grad(): |
| x_emb=self.content_encode_fn(x_masked, type="wet" if is_wet else "dry") |
|
|
| return x_emb, x_masked |
|
|
| z, x_out=multitrack_batched_processing( |
| x, taxonomy=taxonomy, function=prerprocess_and_encode, class_dependent=False, masks=masks, number_outputs=2 |
| ) |
| return z, x_out |
|
|