CoolFace
Apppublic

justyoung/DiffSinger

sourceHugging Faceupdated 3y agoView on Hugging Face
1likes
diffusion.py335 linesDownload Raw Back to diff
1import math2import random3from functools import partial4from inspect import isfunction5from pathlib import Path6import numpy as np7import torch8import torch.nn.functional as F9from torch import nn10from tqdm import tqdm11from einops import rearrange12 13from modules.fastspeech.fs2 import FastSpeech214from modules.diffsinger_midi.fs2 import FastSpeech2MIDI15from utils.hparams import hparams16 17 18 19def exists(x):20    return x is not None21 22 23def default(val, d):24    if exists(val):25        return val26    return d() if isfunction(d) else d27 28 29def cycle(dl):30    while True:31        for data in dl:32            yield data33 34 35def num_to_groups(num, divisor):36    groups = num // divisor37    remainder = num % divisor38    arr = [divisor] * groups39    if remainder > 0:40        arr.append(remainder)41    return arr42 43 44class Residual(nn.Module):45    def __init__(self, fn):46        super().__init__()47        self.fn = fn48 49    def forward(self, x, *args, **kwargs):50        return self.fn(x, *args, **kwargs) + x51 52 53class SinusoidalPosEmb(nn.Module):54    def __init__(self, dim):55        super().__init__()56        self.dim = dim57 58    def forward(self, x):59        device = x.device60        half_dim = self.dim // 261        emb = math.log(10000) / (half_dim - 1)62        emb = torch.exp(torch.arange(half_dim, device=device) * -emb)63        emb = x[:, None] * emb[None, :]64        emb = torch.cat((emb.sin(), emb.cos()), dim=-1)65        return emb66 67 68class Mish(nn.Module):69    def forward(self, x):70        return x * torch.tanh(F.softplus(x))71 72 73class Upsample(nn.Module):74    def __init__(self, dim):75        super().__init__()76        self.conv = nn.ConvTranspose2d(dim, dim, 4, 2, 1)77 78    def forward(self, x):79        return self.conv(x)80 81 82class Downsample(nn.Module):83    def __init__(self, dim):84        super().__init__()85        self.conv = nn.Conv2d(dim, dim, 3, 2, 1)86 87    def forward(self, x):88        return self.conv(x)89 90 91class Rezero(nn.Module):92    def __init__(self, fn):93        super().__init__()94        self.fn = fn95        self.g = nn.Parameter(torch.zeros(1))96 97    def forward(self, x):98        return self.fn(x) * self.g99 100 101# building block modules102 103class Block(nn.Module):104    def __init__(self, dim, dim_out, groups=8):105        super().__init__()106        self.block = nn.Sequential(107            nn.Conv2d(dim, dim_out, 3, padding=1),108            nn.GroupNorm(groups, dim_out),109            Mish()110        )111 112    def forward(self, x):113        return self.block(x)114 115 116class ResnetBlock(nn.Module):117    def __init__(self, dim, dim_out, *, time_emb_dim, groups=8):118        super().__init__()119        self.mlp = nn.Sequential(120            Mish(),121            nn.Linear(time_emb_dim, dim_out)122        )123 124        self.block1 = Block(dim, dim_out)125        self.block2 = Block(dim_out, dim_out)126        self.res_conv = nn.Conv2d(dim, dim_out, 1) if dim != dim_out else nn.Identity()127 128    def forward(self, x, time_emb):129        h = self.block1(x)130        h += self.mlp(time_emb)[:, :, None, None]131        h = self.block2(h)132        return h + self.res_conv(x)133 134 135class LinearAttention(nn.Module):136    def __init__(self, dim, heads=4, dim_head=32):137        super().__init__()138        self.heads = heads139        hidden_dim = dim_head * heads140        self.to_qkv = nn.Conv2d(dim, hidden_dim * 3, 1, bias=False)141        self.to_out = nn.Conv2d(hidden_dim, dim, 1)142 143    def forward(self, x):144        b, c, h, w = x.shape145        qkv = self.to_qkv(x)146        q, k, v = rearrange(qkv, 'b (qkv heads c) h w -> qkv b heads c (h w)', heads=self.heads, qkv=3)147        k = k.softmax(dim=-1)148        context = torch.einsum('bhdn,bhen->bhde', k, v)149        out = torch.einsum('bhde,bhdn->bhen', context, q)150        out = rearrange(out, 'b heads c (h w) -> b (heads c) h w', heads=self.heads, h=h, w=w)151        return self.to_out(out)152 153 154# gaussian diffusion trainer class155 156def extract(a, t, x_shape):157    b, *_ = t.shape158    out = a.gather(-1, t)159    return out.reshape(b, *((1,) * (len(x_shape) - 1)))160 161 162def noise_like(shape, device, repeat=False):163    repeat_noise = lambda: torch.randn((1, *shape[1:]), device=device).repeat(shape[0], *((1,) * (len(shape) - 1)))164    noise = lambda: torch.randn(shape, device=device)165    return repeat_noise() if repeat else noise()166 167 168def cosine_beta_schedule(timesteps, s=0.008):169    """170    cosine schedule171    as proposed in https://openreview.net/forum?id=-NEXDKk8gZ172    """173    steps = timesteps + 1174    x = np.linspace(0, steps, steps)175    alphas_cumprod = np.cos(((x / steps) + s) / (1 + s) * np.pi * 0.5) ** 2176    alphas_cumprod = alphas_cumprod / alphas_cumprod[0]177    betas = 1 - (alphas_cumprod[1:] / alphas_cumprod[:-1])178    return np.clip(betas, a_min=0, a_max=0.999)179 180 181class GaussianDiffusion(nn.Module):182    def __init__(self, phone_encoder, out_dims, denoise_fn,183                 timesteps=1000, loss_type='l1', betas=None, spec_min=None, spec_max=None):184        super().__init__()185        self.denoise_fn = denoise_fn186        if hparams.get('use_midi') is not None and hparams['use_midi']:187            self.fs2 = FastSpeech2MIDI(phone_encoder, out_dims)188        else:189            self.fs2 = FastSpeech2(phone_encoder, out_dims)190        self.fs2.decoder = None191        self.mel_bins = out_dims192 193        if exists(betas):194            betas = betas.detach().cpu().numpy() if isinstance(betas, torch.Tensor) else betas195        else:196            betas = cosine_beta_schedule(timesteps)197 198        alphas = 1. - betas199        alphas_cumprod = np.cumprod(alphas, axis=0)200        alphas_cumprod_prev = np.append(1., alphas_cumprod[:-1])201 202        timesteps, = betas.shape203        self.num_timesteps = int(timesteps)204        self.loss_type = loss_type205 206        to_torch = partial(torch.tensor, dtype=torch.float32)207 208        self.register_buffer('betas', to_torch(betas))209        self.register_buffer('alphas_cumprod', to_torch(alphas_cumprod))210        self.register_buffer('alphas_cumprod_prev', to_torch(alphas_cumprod_prev))211 212        # calculations for diffusion q(x_t | x_{t-1}) and others213        self.register_buffer('sqrt_alphas_cumprod', to_torch(np.sqrt(alphas_cumprod)))214        self.register_buffer('sqrt_one_minus_alphas_cumprod', to_torch(np.sqrt(1. - alphas_cumprod)))215        self.register_buffer('log_one_minus_alphas_cumprod', to_torch(np.log(1. - alphas_cumprod)))216        self.register_buffer('sqrt_recip_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod)))217        self.register_buffer('sqrt_recipm1_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod - 1)))218 219        # calculations for posterior q(x_{t-1} | x_t, x_0)220        posterior_variance = betas * (1. - alphas_cumprod_prev) / (1. - alphas_cumprod)221        # above: equal to 1. / (1. / (1. - alpha_cumprod_tm1) + alpha_t / beta_t)222        self.register_buffer('posterior_variance', to_torch(posterior_variance))223        # below: log calculation clipped because the posterior variance is 0 at the beginning of the diffusion chain224        self.register_buffer('posterior_log_variance_clipped', to_torch(np.log(np.maximum(posterior_variance, 1e-20))))225        self.register_buffer('posterior_mean_coef1', to_torch(226            betas * np.sqrt(alphas_cumprod_prev) / (1. - alphas_cumprod)))227        self.register_buffer('posterior_mean_coef2', to_torch(228            (1. - alphas_cumprod_prev) * np.sqrt(alphas) / (1. - alphas_cumprod)))229 230        self.register_buffer('spec_min', torch.FloatTensor(spec_min)[None, None, :hparams['keep_bins']])231        self.register_buffer('spec_max', torch.FloatTensor(spec_max)[None, None, :hparams['keep_bins']])232 233    def q_mean_variance(self, x_start, t):234        mean = extract(self.sqrt_alphas_cumprod, t, x_start.shape) * x_start235        variance = extract(1. - self.alphas_cumprod, t, x_start.shape)236        log_variance = extract(self.log_one_minus_alphas_cumprod, t, x_start.shape)237        return mean, variance, log_variance238 239    def predict_start_from_noise(self, x_t, t, noise):240        return (241                extract(self.sqrt_recip_alphas_cumprod, t, x_t.shape) * x_t -242                extract(self.sqrt_recipm1_alphas_cumprod, t, x_t.shape) * noise243        )244 245    def q_posterior(self, x_start, x_t, t):246        posterior_mean = (247                extract(self.posterior_mean_coef1, t, x_t.shape) * x_start +248                extract(self.posterior_mean_coef2, t, x_t.shape) * x_t249        )250        posterior_variance = extract(self.posterior_variance, t, x_t.shape)251        posterior_log_variance_clipped = extract(self.posterior_log_variance_clipped, t, x_t.shape)252        return posterior_mean, posterior_variance, posterior_log_variance_clipped253 254    def p_mean_variance(self, x, t, cond, clip_denoised: bool):255        noise_pred = self.denoise_fn(x, t, cond=cond)256        x_recon = self.predict_start_from_noise(x, t=t, noise=noise_pred)257 258        if clip_denoised:259            x_recon.clamp_(-1., 1.)260 261        model_mean, posterior_variance, posterior_log_variance = self.q_posterior(x_start=x_recon, x_t=x, t=t)262        return model_mean, posterior_variance, posterior_log_variance263 264    @torch.no_grad()265    def p_sample(self, x, t, cond, clip_denoised=True, repeat_noise=False):266        b, *_, device = *x.shape, x.device267        model_mean, _, model_log_variance = self.p_mean_variance(x=x, t=t, cond=cond, clip_denoised=clip_denoised)268        noise = noise_like(x.shape, device, repeat_noise)269        # no noise when t == 0270        nonzero_mask = (1 - (t == 0).float()).reshape(b, *((1,) * (len(x.shape) - 1)))271        return model_mean + nonzero_mask * (0.5 * model_log_variance).exp() * noise272 273    def q_sample(self, x_start, t, noise=None):274        noise = default(noise, lambda: torch.randn_like(x_start))275        return (276                extract(self.sqrt_alphas_cumprod, t, x_start.shape) * x_start +277                extract(self.sqrt_one_minus_alphas_cumprod, t, x_start.shape) * noise278        )279 280    def p_losses(self, x_start, t, cond, noise=None, nonpadding=None):281        noise = default(noise, lambda: torch.randn_like(x_start))282 283        x_noisy = self.q_sample(x_start=x_start, t=t, noise=noise)284        x_recon = self.denoise_fn(x_noisy, t, cond)285 286        if self.loss_type == 'l1':287            if nonpadding is not None:288                loss = ((noise - x_recon).abs() * nonpadding.unsqueeze(1)).mean()289            else:290                # print('are you sure w/o nonpadding?')291                loss = (noise - x_recon).abs().mean()292 293        elif self.loss_type == 'l2':294            loss = F.mse_loss(noise, x_recon)295        else:296            raise NotImplementedError()297 298        return loss299 300    def forward(self, txt_tokens, mel2ph=None, spk_embed=None,301                ref_mels=None, f0=None, uv=None, energy=None, infer=False):302        b, *_, device = *txt_tokens.shape, txt_tokens.device303        ret = self.fs2(txt_tokens, mel2ph, spk_embed, ref_mels, f0, uv, energy,304                       skip_decoder=True, infer=infer)305        cond = ret['decoder_inp'].transpose(1, 2)306        if not infer:307            t = torch.randint(0, self.num_timesteps, (b,), device=device).long()308            x = ref_mels309            x = self.norm_spec(x)310            x = x.transpose(1, 2)[:, None, :, :]  # [B, 1, M, T]311            nonpadding = (mel2ph != 0).float()312            ret['diff_loss'] = self.p_losses(x, t, cond, nonpadding=nonpadding)313        else:314            t = self.num_timesteps315            shape = (cond.shape[0], 1, self.mel_bins, cond.shape[2])316            x = torch.randn(shape, device=device)317            for i in tqdm(reversed(range(0, t)), desc='sample time step', total=t):318                x = self.p_sample(x, torch.full((b,), i, device=device, dtype=torch.long), cond)319            x = x[:, 0].transpose(1, 2)320            ret['mel_out'] = self.denorm_spec(x)321 322        return ret323 324    def norm_spec(self, x):325        return (x - self.spec_min) / (self.spec_max - self.spec_min) * 2 - 1326 327    def denorm_spec(self, x):328        return (x + 1) / 2 * (self.spec_max - self.spec_min) + self.spec_min329 330    def cwt2f0_norm(self, cwt_spec, mean, std, mel2ph):331        return self.fs2.cwt2f0_norm(cwt_spec, mean, std, mel2ph)332 333    def out2mel(self, x):334        return x335