Spaces:
Running on Zero
Running on Zero
Download vendor/task/diffusion.py from teamup-tech/DExter: direct link, hf CLI and curl.
- Browser
- Download file 36.4 kB
-
https://huggingface.co/spaces/teamup-tech/DExter/resolve/main/vendor/task/diffusion.py
- Command line
-
hf download hf://spaces/teamup-tech/DExter/vendor/task/diffusion.py
-
curl -L -o diffusion.py https://huggingface.co/spaces/teamup-tech/DExter/resolve/main/vendor/task/diffusion.py
36.4 kB
| import os | |
| import pytorch_lightning as pl | |
| import torch | |
| import torch.nn.functional as F | |
| import torch.nn as nn | |
| import matplotlib.pyplot as plt | |
| from tqdm import tqdm | |
| from sklearn.metrics import precision_recall_fscore_support | |
| import numpy as np | |
| from scipy.stats import pearsonr | |
| import matplotlib.animation as animation | |
| from mpl_toolkits.axes_grid1 import make_axes_locatable | |
| MIN_MIDI = 21 | |
| MAX_MIDI = 108 | |
| HOP_LENGTH = 160 | |
| SAMPLE_RATE = 16000 | |
| import partitura as pt | |
| from utils import animate_sampling, get_batch_slice, plot_codec, p_codec_scale, tensor_pair_swap | |
| from renderer import Renderer | |
| # from model.utils import Normalization | |
| def linear_beta_schedule(beta_start, beta_end, timesteps): | |
| return torch.linspace(beta_start, beta_end, timesteps) | |
| def q_sample(x_start, t, sqrt_alphas_cumprod, sqrt_one_minus_alphas_cumprod, noise=None): | |
| """ | |
| x_start: x0 (B, 1, T, F) | |
| t: timestep information (B,) | |
| """ | |
| # sqrt_alphas is mean of the Gaussian N() - for the forward process distribution | |
| sqrt_alphas_cumprod_t = sqrt_alphas_cumprod[t] # extract the value of \bar{\alpha} at time=t | |
| # one minus alphas is variance of the Gaussian N() | |
| sqrt_one_minus_alphas_cumprod_t = sqrt_one_minus_alphas_cumprod[t] | |
| # boardcasting into correct shape | |
| sqrt_alphas_cumprod_t = sqrt_alphas_cumprod_t[:, None, None, None].to(x_start.device) | |
| sqrt_one_minus_alphas_cumprod_t = sqrt_one_minus_alphas_cumprod_t[:, None, None, None].to(x_start.device) | |
| # scale down the input, and scale up the noise as time increases? | |
| return sqrt_alphas_cumprod_t * x_start + sqrt_one_minus_alphas_cumprod_t * noise | |
| def extract_x0(x_t, epsilon, t, sqrt_alphas_cumprod, sqrt_one_minus_alphas_cumprod): | |
| """ | |
| x_t: The output from q_sample | |
| epsilon: The noise predicted from the model | |
| t: timestep information | |
| """ | |
| # sqrt_alphas is mean of the Gaussian N() | |
| sqrt_alphas_cumprod_t = sqrt_alphas_cumprod[t] # extract the value of \bar{\alpha} at time=t | |
| sqrt_one_minus_alphas_cumprod_t = sqrt_one_minus_alphas_cumprod[t] | |
| sqrt_alphas_cumprod_t = sqrt_alphas_cumprod_t[:, None, None, None].to(x_t.device) | |
| sqrt_one_minus_alphas_cumprod_t = sqrt_one_minus_alphas_cumprod_t[:, None, None, None].to(x_t.device) | |
| # obtaining x0 like the one in audioLDM? | |
| pred_x0 = 1.0 / sqrt_alphas_cumprod_t * x_t - epsilon / sqrt_one_minus_alphas_cumprod_t | |
| # pred_x0 = (x_t - sqrt_one_minus_alphas_cumprod_t * epsilon) / sqrt_alphas_cumprod_t # original - should be wrong - but it's the same as the labml?? | |
| return torch.clamp(pred_x0, -1.0, 1.0) | |
| class RollDiffusion(pl.LightningModule): | |
| def __init__(self, | |
| lr, | |
| timesteps, | |
| loss_type, | |
| beta_start, | |
| ): | |
| super().__init__() | |
| self.save_hyperparameters() | |
| # define beta schedule | |
| # beta is variance | |
| self.betas = linear_beta_schedule(timesteps=timesteps) | |
| # define alphas - reparameterization | |
| alphas = 1. - self.betas | |
| alphas_cumprod = torch.cumprod(alphas, axis=0) # alpha bar | |
| alphas_cumprod_prev = F.pad(alphas_cumprod[:-1], (1, 0), value=1.0) | |
| self.sqrt_recip_alphas = torch.sqrt(1.0 / alphas) | |
| # calculations for diffusion q(x_t | x_{t-1}) and others | |
| self.sqrt_alphas_cumprod = torch.sqrt(alphas_cumprod) | |
| self.sqrt_one_minus_alphas_cumprod = torch.sqrt(1. - alphas_cumprod) | |
| # calculations for posterior q(x_{t-1} | x_t, x_0) | |
| self.posterior_variance = self.betas * (1. - alphas_cumprod_prev) / (1. - alphas_cumprod) | |
| def training_step(self, batch, batch_idx): | |
| batch_size = batch["frame"].shape[0] | |
| batch = batch["frame"].unsqueeze(1) | |
| device = batch.device | |
| # Algorithm 1 line 3: sample t uniformally for every example in the batch | |
| t = torch.randint(0, self.hparams.timesteps, (batch_size,), device=device).long() | |
| loss = self.p_losses(batch, t, self.sqrt_alphas_cumprod, self.sqrt_one_minus_alphas_cumprod, loss_type=self.hparams.loss_type) | |
| self.log("Train/loss", loss) | |
| return loss | |
| def validation_step(self, batch, batch_idx): | |
| batch_size = batch["frame"].shape[0] | |
| batch = batch["frame"].unsqueeze(1) | |
| device = batch.device | |
| t = torch.randint(0, self.hparams.timesteps, (batch_size,), device=device).long() | |
| loss = self.p_losses(batch, t, self.sqrt_alphas_cumprod, self.sqrt_one_minus_alphas_cumprod, loss_type=self.hparams.loss_type) | |
| self.log("Val/loss", loss) | |
| def test_step(self, batch, batch_idx): | |
| batch_size = batch["frame"].shape[0] | |
| batch = batch["frame"].unsqueeze(1) | |
| device = batch.device | |
| t = torch.randint(0, self.hparams.timesteps, (batch_size,), device=device).long() | |
| loss = self.p_losses(batch, t, self.sqrt_alphas_cumprod, self.sqrt_one_minus_alphas_cumprod, loss_type=self.hparams.loss_type) | |
| self.log("Test/loss", loss) | |
| def predict_step(self, batch, batch_idx): | |
| # inference code | |
| # Unwrapping TensorDataset (list) | |
| # It is a pure noise | |
| img = batch[0] | |
| b = img.shape[0] # extracting batchsize | |
| device=img.device | |
| imgs = [] | |
| for i in tqdm(reversed(range(0, self.hparams.timesteps)), desc='sampling loop time step', total=self.hparams.timesteps): | |
| img = self.p_sample( | |
| img, | |
| i) | |
| img_npy = img.cpu().numpy() | |
| if (i+1)%10==0: | |
| for idx, j in enumerate(img_npy): | |
| # j (1, T, F) | |
| fig, ax = plt.subplots(1,1) | |
| ax.imshow(j[0].T, aspect='auto', origin='lower') | |
| self.logger.experiment.add_figure( | |
| f"sample_{idx}", | |
| fig, | |
| global_step=self.hparams.timesteps-i) | |
| # self.hparams.timesteps-i is used because slide bar won't show | |
| # if global step starts from self.hparams.timesteps | |
| imgs.append(img_npy) | |
| torch.save(imgs, 'imgs.pt') | |
| def p_losses(self, x_start, t, sqrt_alphas_cumprod, sqrt_one_minus_alphas_cumprod, noise=None, loss_type="l1"): | |
| if noise is None: | |
| noise = torch.randn_like(x_start) | |
| x_noisy = q_sample(x_start=x_start, t=t, sqrt_alphas_cumprod=sqrt_alphas_cumprod, sqrt_one_minus_alphas_cumprod=sqrt_one_minus_alphas_cumprod, noise=noise) | |
| predicted_noise = self(x_noisy, t) | |
| if loss_type == 'l1': | |
| loss = F.l1_loss(noise, predicted_noise) | |
| elif loss_type == 'l2': | |
| loss = F.mse_loss(noise, predicted_noise) | |
| elif loss_type == "huber": | |
| loss = F.smooth_l1_loss(noise, predicted_noise) | |
| else: | |
| raise NotImplementedError() | |
| return loss | |
| def p_sample(self, x, t_index): | |
| # x is Guassian noise | |
| # extracting coefficients at time t | |
| betas_t = self.betas[t_index] | |
| sqrt_one_minus_alphas_cumprod_t = self.sqrt_one_minus_alphas_cumprod[t_index] | |
| sqrt_recip_alphas_t = self.sqrt_recip_alphas[t_index] | |
| # boardcasting t_index into a tensor | |
| t_tensor = torch.tensor(t_index).repeat(x.shape[0]).to(x.device) | |
| # Equation 11 in the paper | |
| # Use our model (noise predictor) to predict the mean | |
| model_mean = sqrt_recip_alphas_t * ( | |
| x - betas_t * self(x, t_tensor) / sqrt_one_minus_alphas_cumprod_t | |
| ) | |
| if t_index == 0: | |
| return model_mean | |
| else: | |
| # posterior_variance_t = extract(self.posterior_variance, t, x.shape) | |
| posterior_variance_t = self.posterior_variance[t_index] | |
| noise = torch.randn_like(x) | |
| # Algorithm 2 line 4: | |
| return model_mean + torch.sqrt(posterior_variance_t) * noise | |
| def configure_optimizers(self): | |
| optimizer = torch.optim.Adam(self.parameters(), lr=self.hparams.lr) | |
| # scheduler = TriStageLRSchedule(optimizer, | |
| # [1e-8, self.hparams.lr, 1e-8], | |
| # [0.2,0.6,0.2], | |
| # max_update=len(self.train_dataloader.dataloader)*self.trainer.max_epochs) | |
| # scheduler = MultiStepLR(optimizer, [1,3,5,7,9], gamma=0.1, last_epoch=-1, verbose=False) | |
| # return [optimizer], [{"scheduler":scheduler, "interval": "step"}] | |
| return [optimizer] | |
| class CodecDiffusion(pl.LightningModule): | |
| def __init__(self, | |
| lr, | |
| timesteps, | |
| loss_type, | |
| loss_keys, | |
| beta_start, | |
| beta_end, | |
| training, | |
| sampling, | |
| samples_root, | |
| debug=False, | |
| generation_filter=0.0, | |
| **kwargs | |
| ): | |
| super().__init__() | |
| self.save_hyperparameters() | |
| # define beta schedule (beta is variance) | |
| self.betas = linear_beta_schedule(beta_start, beta_end, timesteps=timesteps) | |
| # define alphas | |
| alphas = 1. - self.betas | |
| alphas_cumprod = torch.cumprod(alphas, axis=0) | |
| alphas_cumprod_prev = F.pad(alphas_cumprod[:-1], (1, 0), value=1.0) | |
| self.sqrt_recip_alphas = torch.sqrt(1.0 / alphas) | |
| # calculations for diffusion q(x_t | x_{t-1}) and others | |
| self.sqrt_alphas_cumprod = torch.sqrt(alphas_cumprod) | |
| self.sqrt_one_minus_alphas_cumprod = torch.sqrt(1. - alphas_cumprod) | |
| # calculations for posterior q(x_{t-1} | x_t, x_0) | |
| self.posterior_variance = self.betas * (1. - alphas_cumprod_prev) / (1- alphas_cumprod) | |
| self.inner_loop = tqdm(range(self.hparams.timesteps), desc='sampling loop time step') | |
| self.reverse_diffusion = getattr(self, sampling['type']) | |
| # self.reverse_diffusion = getattr(self, sampling.type) | |
| self.alphas = alphas | |
| def training_step(self, batch, batch_idx): | |
| losses, tensors = self.step(batch, batch_idx) | |
| # calculating total loss based on keys give | |
| total_loss = 0 | |
| for k in self.hparams.loss_keys: | |
| total_loss += losses[k] | |
| self.log(f"Train/{k}", losses[k]) | |
| return total_loss | |
| def validation_step(self, batch, batch_idx): | |
| losses, tensors = self.step(batch, batch_idx) | |
| total_loss = 0 | |
| for k in self.hparams.loss_keys: | |
| total_loss += losses[k] | |
| self.log(f"Val/{k}", losses[k]) | |
| # sample a fraction (1 percent) of the testing set | |
| randgen = torch.rand(1)[0] | |
| if randgen <= self.hparams.valid_fraction: | |
| sampled_loss, tc_fig, tempo_vel_loss, tempo_vel_cor = self.predict(batch, batch_idx) | |
| self.logger.log_image(key=f"Val/tempo_curves", images=[tc_fig]) | |
| self.log(f"Val/sampled_loss", sampled_loss) | |
| self.log(f"Val/tempo_vel_loss", tempo_vel_loss) | |
| self.log(f"Val/tempo_vel_cor", tempo_vel_cor) | |
| def test_step(self, batch, batch_idx): | |
| # evaluation | |
| if batch_idx < self.hparams.eval_starting_epoch: | |
| return | |
| _, _, _, _ = self.predict(batch, batch_idx, evaluate=True) | |
| def predict(self, batch, batch_idx, save_animation=False, evaluate=False): | |
| batch_label = batch | |
| batch_source = dict([(k, tensor_pair_swap(v)) for k, v in batch.items()]) | |
| # rescale | |
| batch_source['p_codec'] = p_codec_scale(batch_source['p_codec'], self.hparams.dataset_means, self.hparams.dataset_stds) | |
| batch_label['p_codec'] = p_codec_scale(batch_label['p_codec'], self.hparams.dataset_means, self.hparams.dataset_stds) | |
| save_root = f'{self.hparams.samples_root}/{self.logger._name}/epoch={self.current_epoch}/batch={batch_idx}' | |
| c_configs = self.set_eval_c_config() | |
| for c_config in c_configs: | |
| save_root_ = save_root + f"/{c_config}" | |
| start_noise, sample_steps, c_codec = self.set_predict_start(batch_source, batch_label, c_config=c_config) | |
| pred_list = self.p_sample(batch_label, start_noise=start_noise, | |
| sample_steps=sample_steps, | |
| c_codec=c_codec) | |
| # noise_list: [(pred_t, t), ..., (pred_0, 0)] | |
| pcodec_pred, _ = pred_list[-1] # (B, 1, T, F) | |
| batch_label_codec = batch_label['p_codec'].unsqueeze(1).cpu() | |
| N = len(batch_label['score_path']) | |
| os.makedirs(save_root_, exist_ok=True) | |
| # save the prediction samples (of one batch) and render. | |
| np.save(f'{save_root_}/test_sample.npy', pcodec_pred) | |
| # rescale the predictions and labels back to normal | |
| pcodec_pred = p_codec_scale(pcodec_pred, self.hparams.dataset_means, self.hparams.dataset_stds) | |
| tempo_vel_loss, tempo_vel_cor = 0, 0 | |
| if len(pcodec_pred) % 2 != 1: | |
| tc_fig, tempo_vel_loss, tempo_vel_cor = self.render_batch( | |
| pcodec_pred, batch_source, batch_label, save_root_, evaluate=evaluate) | |
| if save_animation: | |
| t_list = torch.arange(1, self.hparams.timesteps, 20).flip(0) | |
| if t_list[-1] != self.hparams.timesteps: | |
| t_list = torch.cat((t_list, torch.tensor([self.hparams.timesteps])), 0) | |
| fig, axes = plt.subplots(2 * N, 1, figsize=(24, 4 * N)) | |
| ax_flat = axes.flatten() | |
| caxs = [] | |
| for ax in axes.flatten(): | |
| div = make_axes_locatable(ax) | |
| caxs.append(div.append_axes('right', '5%', '5%')) | |
| ani = animation.FuncAnimation(fig, | |
| animate_sampling, | |
| frames=tqdm(t_list, desc='Animating'), | |
| fargs=(fig, ax_flat, caxs, noise_list, self.hparams.timesteps), | |
| interval=500, | |
| blit=False, | |
| repeat_delay=1000) | |
| ani.save(f'{save_root}/animation.gif', dpi=80, writer='imagemagick') | |
| # plot the comparison between prediction and label | |
| fig, ax = plt.subplots(2 * N, 1, figsize=(24, 4 * N)) | |
| for idx, (pred, label) in enumerate(zip(pcodec_pred, batch_label_codec)): | |
| plot_codec(pred, label, ax[idx*2], ax[idx*2+1], fig) | |
| self.logger.log_image(key=f"Val/pred_label", images=[fig]) | |
| plt.savefig(f"{save_root}/pred_label.png") | |
| sampled_loss = self.p_losses(batch_label_codec, torch.tensor(pcodec_pred), loss_type='l2') | |
| return sampled_loss, tc_fig, tempo_vel_loss, tempo_vel_cor | |
| def inference_one(self, batch): | |
| sample_steps = self.hparams.timesteps - 1 | |
| pred_list = self.p_sample(batch, sample_steps=sample_steps) | |
| pcodec_pred, _ = pred_list[-1] # Extract the final prediction | |
| pcodec_pred_processed = p_codec_scale(pcodec_pred, self.hparams.dataset_means, self.hparams.dataset_stds) | |
| return pcodec_pred_processed | |
| def step(self, batch, batch_idx): | |
| p_codec, s_codec, c_codec = batch['p_codec'], batch['s_codec'], batch['c_codec'] | |
| if self.hparams.drop_c_con: | |
| c_codec = torch.zeros_like(c_codec) | |
| batch_size = p_codec.shape[0] | |
| device = p_codec.device | |
| p_codec = p_codec.unsqueeze(1) # (B, 1, T, F) | |
| t = torch.randint(0, self.hparams.timesteps, (batch_size,), device=device).long().cpu() # more diverse sampling | |
| noise = torch.randn_like(p_codec) | |
| if self.hparams.training['target'] == "transfer": # invert each pair | |
| noise = tensor_pair_swap(p_codec) | |
| # in transfer context, c_codec is the difference between the two that's being transfered. | |
| c_codec = tensor_pair_swap(c_codec) - c_codec # (tgt - src) | |
| x_t = q_sample( # sampling noise at time t | |
| x_start=p_codec, | |
| t=t, | |
| sqrt_alphas_cumprod=self.sqrt_alphas_cumprod, | |
| sqrt_one_minus_alphas_cumprod=self.sqrt_one_minus_alphas_cumprod, | |
| noise=noise) | |
| # train to predict the noise, loss is computed for the noise | |
| if self.hparams.training['mode'] == 'epsilon': | |
| epsilon_pred, _ = self(x_t, s_codec, c_codec, t) # predict the noise N(0, 1) | |
| diffusion_loss = self.p_losses(noise, epsilon_pred, loss_type=self.hparams.loss_type) | |
| pred_p_codec = extract_x0( | |
| x_t, | |
| epsilon_pred, | |
| t, | |
| sqrt_alphas_cumprod=self.sqrt_alphas_cumprod, | |
| sqrt_one_minus_alphas_cumprod=self.sqrt_one_minus_alphas_cumprod) | |
| # train to predict p_codec | |
| elif self.hparams.training['mode'] == 'x_0': | |
| pred_p_codec, _ = self(x_t, s_codec, c_codec, t) | |
| # pred_p_codec = p_codec_scale(pred_p_codec, self.hparams.dataset_means, self.hparams.dataset_stds) | |
| diffusion_loss = self.p_losses(p_codec, pred_p_codec, loss_type=self.hparams.loss_type) | |
| elif self.hparams.training['mode'] == 'ex_0': | |
| epsilon_pred, _ = self(x_t, s_codec, c_codec, t) # predict the noise N(0, 1) | |
| pred_p_codec = extract_x0( | |
| x_t, | |
| epsilon_pred, | |
| t, | |
| sqrt_alphas_cumprod=self.sqrt_alphas_cumprod, | |
| sqrt_one_minus_alphas_cumprod=self.sqrt_one_minus_alphas_cumprod) | |
| diffusion_loss = self.p_losses(p_codec, pred_p_codec, loss_type=self.hparams.loss_type) | |
| else: | |
| raise ValueError(f"training mode {self.training.mode} is not supported. Please either use 'x_0' or 'epsilon'.") | |
| losses = {} | |
| # compute tempo_vel_loss for the prediced pcodec, for bp and velocity rows. | |
| # tempo_vel_loss = self.p_losses(p_codec[:, :, :, :2], pred_p_codec[:, :, :, :2], loss_type='l2') # only tempo and velocity | |
| weight_sum = sum(self.hparams.loss_weight) | |
| for idx, name in enumerate(['tempo', 'velocity', 'timing', 'duration', 'pedal']): | |
| losses[f"recon_{name}_loss"] = (self.p_losses(p_codec[..., idx], pred_p_codec[..., idx], loss_type='l2') | |
| * self.hparams.loss_weight[idx] / weight_sum * self.hparams.recon_loss_weight) | |
| losses["diffusion_loss"] = diffusion_loss | |
| tensors = { | |
| "pred_pcodec": pred_p_codec, | |
| "label_pcodec": p_codec | |
| } | |
| return losses, tensors | |
| def p_sample(self, batch, start_noise=None, sample_steps=None, c_codec=None): | |
| p_codec = batch['p_codec'].unsqueeze(1) | |
| s_codec = batch['s_codec'] | |
| if type(c_codec) == type(None): | |
| c_codec = batch['c_codec'] | |
| # Algorithm 1 line 3: sample t uniformally for every example in the batch | |
| self.inner_loop.refresh() | |
| self.inner_loop.reset() | |
| if type(start_noise) != type(None): | |
| noise = start_noise | |
| else: | |
| noise = torch.randn_like(p_codec.float()).to(self.device) | |
| noise_list = [] | |
| noise_list.append((noise, self.hparams.timesteps)) | |
| if type(sample_steps) == type(None): | |
| sample_steps = self.hparams.timesteps | |
| for t_index in reversed(range(0, sample_steps)): | |
| noise, _ = self.reverse_diffusion(noise, s_codec, c_codec, t_index) # cfdg_ddpm_x0 or cfdg_ddpm | |
| noise_npy = noise.detach().cpu().numpy() | |
| # self.hparams.timesteps-i is used because slide bar won't show | |
| # if global step starts from self.hparams.timesteps | |
| noise_list.append((noise_npy, t_index)) | |
| self.inner_loop.update() | |
| return noise_list | |
| def p_losses(self, label, prediction, loss_type="l1"): | |
| if loss_type == 'l1': | |
| loss = F.l1_loss(label, prediction) | |
| elif loss_type == 'l2': | |
| loss = F.mse_loss(label, prediction) | |
| elif loss_type == "huber": | |
| loss = F.smooth_l1_loss(label, prediction) | |
| else: | |
| raise NotImplementedError() | |
| return loss | |
| def ddpm(self, x, waveform, t_index): | |
| # x is Guassian noise | |
| # extracting coefficients at time t | |
| betas_t = self.betas[t_index] | |
| sqrt_one_minus_alphas_cumprod_t = self.sqrt_one_minus_alphas_cumprod[t_index] | |
| sqrt_recip_alphas_t = self.sqrt_recip_alphas[t_index] | |
| # boardcasting t_index into a tensor | |
| t_tensor = torch.tensor(t_index).repeat(x.shape[0]).to(x.device) | |
| # Equation 11 in the paper | |
| # Use our model (noise predictor) to predict the mean | |
| epsilon, spec = self(x, waveform, t_tensor) | |
| model_mean = sqrt_recip_alphas_t * ( | |
| x - betas_t * epsilon / sqrt_one_minus_alphas_cumprod_t | |
| ) | |
| if t_index == 0: | |
| return model_mean, spec | |
| else: | |
| # posterior_variance_t = extract(self.posterior_variance, t, x.shape) | |
| posterior_variance_t = self.posterior_variance[t_index] | |
| noise = torch.randn_like(x) | |
| # Algorithm 2 line 4: | |
| return (model_mean + torch.sqrt(posterior_variance_t) * noise), spec | |
| def ddpm_x0(self, x, waveform, t_index): | |
| # x is x_t, when t=T it is pure Gaussian | |
| # boardcasting t_index into a tensor | |
| t_tensor = torch.tensor(t_index).repeat(x.shape[0]).to(x.device) | |
| # Equation 11 in the paper | |
| # Use our model (noise predictor) to predict the mean | |
| x0_pred, spec = self(x, waveform, t_tensor) | |
| if t_index == 0: | |
| sigma = (1/self.sqrt_one_minus_alphas_cumprod[t_index]) * ( | |
| torch.sqrt(1-self.alphas[t_index])) | |
| model_mean = x0_pred / self.sqrt_alphas_cumprod[t_index] | |
| else: | |
| sigma = (self.sqrt_one_minus_alphas_cumprod[t_index-1]/self.sqrt_one_minus_alphas_cumprod[t_index]) * ( | |
| torch.sqrt(1-self.alphas[t_index])) | |
| model_mean = (self.sqrt_alphas_cumprod[t_index-1]) * x0_pred + ( | |
| torch.sqrt(1 - self.sqrt_alphas_cumprod[t_index-1]**2 - sigma**2) * ( | |
| x-self.sqrt_alphas_cumprod[t_index]* x0_pred)/self.sqrt_one_minus_alphas_cumprod[t_index]) + ( | |
| sigma * torch.randn_like(x)) | |
| return model_mean, spec | |
| def ddim_x0(self, x, waveform, t_index): | |
| # x is x_t, when t=T it is pure Gaussian | |
| # boardcasting t_index into a tensor | |
| t_tensor = torch.tensor(t_index).repeat(x.shape[0]).to(x.device) | |
| # Equation 11 in the paper | |
| # Use our model (noise predictor) to predict the mean | |
| x0_pred, spec = self(x, waveform, t_tensor) | |
| if t_index == 0: | |
| sigma = 0 | |
| model_mean = x0_pred / self.sqrt_alphas_cumprod[t_index] | |
| else: | |
| sigma = 0 | |
| model_mean = (self.sqrt_alphas_cumprod[t_index-1]) * x0_pred + ( | |
| torch.sqrt(1 - self.sqrt_alphas_cumprod[t_index-1]**2 - sigma**2) * ( | |
| x-self.sqrt_alphas_cumprod[t_index]* x0_pred)/self.sqrt_one_minus_alphas_cumprod[t_index]) + ( | |
| sigma * torch.randn_like(x)) | |
| return model_mean, spec | |
| def ddim(self, x, waveform, t_index): | |
| # boardcasting t_index into a tensor | |
| t_tensor = torch.tensor(t_index).repeat(x.shape[0]).to(x.device) | |
| # Equation 11 in the paper | |
| # Use our model (noise predictor) to predict the mean | |
| epsilon, spec = self(x, waveform, t_tensor) | |
| if t_index == 0: | |
| model_mean = (x - self.sqrt_one_minus_alphas_cumprod[t_index] * epsilon) / self.sqrt_alphas_cumprod[t_index] | |
| else: | |
| model_mean = (self.sqrt_alphas_cumprod[t_index-1]) * ( | |
| (x - self.sqrt_one_minus_alphas_cumprod[t_index] * epsilon) / self.sqrt_alphas_cumprod[t_index]) + ( | |
| self.sqrt_one_minus_alphas_cumprod[t_index-1] * epsilon) | |
| return model_mean, spec | |
| def ddim2ddpm(self, x, waveform, t_index): | |
| # boardcasting t_index into a tensor | |
| t_tensor = torch.tensor(t_index).repeat(x.shape[0]).to(x.device) | |
| # Equation 11 in the paper | |
| # Use our model (noise predictor) to predict the mean | |
| epsilon, spec = self(x, waveform, t_tensor) | |
| if t_index == 0: | |
| model_mean = (x - self.sqrt_one_minus_alphas_cumprod[t_index] * epsilon) / self.sqrt_alphas_cumprod[t_index] | |
| else: | |
| sigma = (self.sqrt_one_minus_alphas_cumprod[t_index-1]/self.sqrt_one_minus_alphas_cumprod[t_index]) * ( | |
| torch.sqrt(1-self.alphas[t_index])) | |
| model_mean = (self.sqrt_alphas_cumprod[t_index-1]) * ( | |
| (x - self.sqrt_one_minus_alphas_cumprod[t_index] * epsilon) / self.sqrt_alphas_cumprod[t_index]) + ( | |
| torch.sqrt(1 - self.sqrt_alphas_cumprod[t_index-1]**2 - sigma**2) * epsilon) + sigma * torch.randn_like(x) | |
| return model_mean, spec | |
| def cfdg_ddpm(self, x, s_codec, c_codec, t_index): | |
| # x is Guassian noise | |
| # extracting coefficients at time t | |
| betas_t = self.betas[t_index] | |
| sqrt_one_minus_alphas_cumprod_t = self.sqrt_one_minus_alphas_cumprod[t_index] | |
| sqrt_recip_alphas_t = self.sqrt_recip_alphas[t_index] | |
| # boardcasting t_index into a tensor | |
| t_tensor = torch.tensor(t_index).repeat(x.shape[0]).to(x.device) | |
| # Use our model (noise predictor) to predict the mean | |
| epsilon_c, cond = self(x, s_codec, c_codec, t_tensor) | |
| epsilon_0, _ = self(x, torch.zeros_like(s_codec), torch.zeros_like(c_codec), t_tensor) | |
| epsilon = self.hparams.sampling['w'] * epsilon_c + (1 - self.hparams.sampling['w']) * epsilon_0 | |
| # Equation 11 in the paper | |
| model_mean = sqrt_recip_alphas_t * ( | |
| x - betas_t * epsilon / sqrt_one_minus_alphas_cumprod_t | |
| ) | |
| if t_index == 0: | |
| return model_mean, cond | |
| else: | |
| # posterior_variance_t = extract(self.posterior_variance, t, x.shape) | |
| posterior_variance_t = self.posterior_variance[t_index] | |
| noise = torch.randn_like(x) | |
| variance = torch.sqrt(posterior_variance_t) * noise | |
| # From the diffusion-inspired training strategy paper, remove the deviation parameter since noise is deterministic | |
| if self.hparams.training['target'] == "transfer": | |
| return model_mean, cond | |
| return (model_mean + variance), cond | |
| def cfdg_ddpm_x0(self, x, condition, t_index): | |
| # x is x_t, when t=T it is pure Gaussian | |
| # boardcasting t_index into a tensor | |
| t_tensor = torch.tensor(t_index).repeat(x.shape[0]).to(x.device) | |
| # Use model (noise & x0 predictor) to predict the mean and weight the conditioned & unconditioned | |
| if self.hparams.training.mode == "ex_0" or self.hparams.training.mode == "epsilon": | |
| epsilon_c, cond = self(x, condition, t_tensor) | |
| epsilon_0, _ = self(x, torch.zeros_like(condition), t_tensor) | |
| epsilon = self.hparams.sampling['w'] * epsilon_c + (1 - self.hparams.sampling['w']) * epsilon_0 | |
| x0_pred = extract_x0(x, | |
| epsilon, | |
| t_tensor, | |
| sqrt_alphas_cumprod=self.sqrt_alphas_cumprod, | |
| sqrt_one_minus_alphas_cumprod=self.sqrt_one_minus_alphas_cumprod) | |
| elif self.hparams.training.mode == "x0": | |
| x0_pred_c, cond = self(x, condition, t_tensor) | |
| x0_pred_0, _ = self(x, torch.zeros_like(condition), t_tensor, sampling=True) # if sampling = True, the input condition will be overwritten | |
| # wait... is this really weighting??? | |
| # x0_pred = (1 + self.hparams.sampling.w) * x0_pred_c - self.hparams.sampling.w * x0_pred_0 | |
| x0_pred = self.hparams.sampling['w'] * x0_pred_c + (1 - self.hparams.sampling['w']) * x0_pred_0 | |
| if t_index == 0: | |
| sigma = (1/self.sqrt_one_minus_alphas_cumprod[t_index]) * ( | |
| torch.sqrt(1-self.alphas[t_index])) | |
| model_mean = x0_pred / self.sqrt_alphas_cumprod[t_index] | |
| else: | |
| # sigma is the noise magnitude (variance to scale noise) | |
| sigma = (self.sqrt_one_minus_alphas_cumprod[t_index - 1] / self.sqrt_one_minus_alphas_cumprod[t_index]) * ( | |
| torch.sqrt(1 - self.alphas[t_index])) | |
| if self.hparams.training.mode == "x0": | |
| # I modified the division to multiplication according to the inverse of DDPM paper eq.11 | |
| epsilon = (x - self.sqrt_alphas_cumprod[t_index] * x0_pred) * self.sqrt_one_minus_alphas_cumprod[t_index] | |
| model_mean = (self.sqrt_alphas_cumprod[t_index - 1]) * x0_pred + ( | |
| torch.sqrt(1 - self.sqrt_alphas_cumprod[t_index - 1] ** 2 - sigma ** 2) * | |
| epsilon) + ( # epsilon | |
| sigma * torch.randn_like(x)) | |
| return model_mean, cond | |
| def cfdg_ddim_x0(self, x, waveform, t_index): | |
| # x is x_t, when t=T it is pure Gaussian | |
| # boardcasting t_index into a tensor | |
| t_tensor = torch.tensor(t_index).repeat(x.shape[0]).to(x.device) | |
| # Equation 11 in the paper | |
| # Use our model (noise predictor) to predict the mean | |
| x0_pred_c, spec = self(x, waveform, t_tensor) | |
| x0_pred_0, _ = self(x, torch.zeros_like(waveform), t_tensor) | |
| x0_pred = (1 + self.hparams.sampling.w) * x0_pred_c - self.hparams.sampling.w * x0_pred_0 | |
| # x0_pred = x0_pred_c | |
| # x0_pred = x0_pred_0 | |
| if t_index == 0: | |
| sigma = 0 | |
| model_mean = x0_pred / self.sqrt_alphas_cumprod[t_index] | |
| else: | |
| sigma = 0 | |
| model_mean = (self.sqrt_alphas_cumprod[t_index-1]) * x0_pred + ( | |
| torch.sqrt(1 - self.sqrt_alphas_cumprod[t_index - 1] ** 2 - sigma ** 2) * ( | |
| x - self.sqrt_alphas_cumprod[t_index] * x0_pred) / self.sqrt_one_minus_alphas_cumprod[t_index]) + ( | |
| sigma * torch.randn_like(x)) | |
| return model_mean, spec | |
| def configure_optimizers(self): | |
| optimizer = torch.optim.Adam(self.parameters(), lr=self.hparams.lr) | |
| # scheduler = TriStageLRSchedule(optimizer, | |
| # [1e-8, self.hparams.lr, 1e-8], | |
| # [0.2,0.6,0.2], | |
| # max_update=len(self.train_dataloader.dataloader)*self.trainer.max_epochs) | |
| # scheduler = MultiStepLR(optimizer, [1,3,5,7,9], gamma=0.1, last_epoch=-1, verbose=False) | |
| # return [optimizer], [{"scheduler":scheduler, "interval": "step"}] | |
| return [optimizer] | |
| def animate_sampling(self, t_idx, fig, ax_flat, caxs, noise_list): | |
| # noise_list: Tuple of (x_t, t), (x_t-1, t-1), ... (x_0, 0) | |
| # x_t (B, 1, T, F) | |
| # clearing figures to prevent slow down in each iteration.d | |
| fig.canvas.draw() | |
| for idx in range(len(noise_list[0][0])): # visualize only 4 piano rolls in a batch | |
| ax_flat[idx].cla() | |
| ax_flat[4+idx].cla() | |
| caxs[idx].cla() | |
| caxs[4+idx].cla() | |
| # roll_pred (1, T, F) | |
| im1 = ax_flat[idx].imshow(noise_list[0][0][idx][0].detach().T.cpu(), aspect='auto', origin='lower') | |
| im2 = ax_flat[4+idx].imshow(noise_list[1 + self.hparams.timesteps - t_idx][0][idx][0].T, aspect='auto', origin='lower') | |
| fig.colorbar(im1, cax=caxs[idx]) | |
| fig.colorbar(im2, cax=caxs[4+idx]) | |
| fig.suptitle(f't={t_idx}') | |
| row1_txt = ax_flat[0].text(-400,45,f'Gaussian N(0,1)') | |
| row2_txt = ax_flat[4].text(-300,45,'x_{t-1}') | |
| def render_batch(self, pcodec_pred, batch_source, batch_label, save_root, evaluate=False): | |
| B = len(pcodec_pred) | |
| fig, ax = plt.subplots(int(B/2), 4, figsize=(24, 3*B)) | |
| tempo_vel_loss, tempo_vel_cor = 0, 0 | |
| for idx in range(B): | |
| renderer = Renderer(save_root, | |
| pcodec_pred[idx], | |
| source_data=get_batch_slice(batch_source, idx), | |
| label_data=get_batch_slice(batch_label, idx), | |
| with_source=self.hparams.transfer, | |
| idx=idx, B=B) | |
| tvl, tvc = renderer.render_sample(save_sourcelabel=True) | |
| tempo_vel_loss += tvl | |
| tempo_vel_cor += tvc | |
| if renderer.success: | |
| renderer.plot_curves(ax) | |
| if evaluate: | |
| renderer.save_performance_features(save_source=False, save_label=True) | |
| renderer.save_pf_distribution() | |
| plt.savefig(f"{save_root}/tempo_curves.png") | |
| return fig, tempo_vel_loss / B, tempo_vel_cor / B | |
| def set_predict_start(self, batch_source, batch_label, c_config=""): | |
| """set up the starting point of inference given the configuration. | |
| - transfer in training: start from source codec, conditioned on label c_codec - source c_codec | |
| - transfer in inference: starting from source codec + noise (75%), conditioned on label c_codec | |
| - no transfer: starting from noise, conditioned on label c_codec [or other adjustable c_codec] | |
| c_config: e.g. "melodiousness_more", changes the parameter by half or double | |
| """ | |
| batch_source_codec = batch_source['p_codec'] | |
| batch_source_codec = batch_source_codec.unsqueeze(1) # (B, 1, T, F) | |
| sample_steps = self.hparams.timesteps - 1 | |
| c_codec = batch_label['c_codec'] | |
| if "transfer" not in self.hparams.training.target: # pure noise | |
| noise = torch.randn_like(batch_source_codec) | |
| if self.hparams.transfer: # only transfer in inference | |
| sample_steps = int((self.hparams.timesteps - 1) * self.hparams.sample_steps_frac) # steps for noisify the source | |
| start_noise = q_sample(x_start=batch_source_codec, | |
| t=torch.tensor([sample_steps] * int(batch_source['p_codec'].shape[0])), | |
| sqrt_alphas_cumprod=self.sqrt_alphas_cumprod, | |
| sqrt_one_minus_alphas_cumprod=self.sqrt_one_minus_alphas_cumprod, | |
| noise=noise) | |
| else: | |
| start_noise = None | |
| else: # transfer in training | |
| start_noise = batch_source_codec | |
| c_codec = batch_label['c_codec'] - batch_source['c_codec'] | |
| if c_config != "": | |
| c, control = c_config.split("/") | |
| c_idx = self.c_type.index(c) | |
| if control == "more": | |
| c_codec[c_idx] *= 2 | |
| if control == "less": | |
| c_codec[c_idx] *= 0.5 # normal is just itself | |
| return start_noise, sample_steps, c_codec | |
| def set_eval_c_config(self): | |
| # set the c_config for oracle evaluation | |
| if self.hparams.condition_eval: | |
| self.c_type = ["melodiousness", "articulation", "rhythm complexity", "rhythm stability", "dissonance", "tonal stability", "minorness"] | |
| c_configs = [f"{c}_{control}" for c in self.c_type for control in ["less", "normal", "more"]] | |
| else: | |
| c_configs = [""] | |
| return c_configs | |