Compare commits

..
3 Commits
Author SHA1 Message Date
Phil Wang bd1e3b676e get rid of numpy 2022-04-12 11:58:46 -07:00
Phil Wang f4615599bc use full attention at the center of the unet 2022-04-04 09:03:41 -07:00
Phil Wang eb6e1b508e greater kernel size in convnext blocks 2022-01-31 17:13:27 -08:00
2 changed files with 53 additions and 33 deletions
@@ -12,7 +12,6 @@ from torch.optim import Adam
from torchvision import transforms, utils from torchvision import transforms, utils
from PIL import Image from PIL import Image
import numpy as np
from tqdm import tqdm from tqdm import tqdm
from einops import rearrange from einops import rearrange
@@ -95,7 +94,7 @@ def Upsample(dim):
return nn.ConvTranspose2d(dim, dim, 4, 2, 1) return nn.ConvTranspose2d(dim, dim, 4, 2, 1)
def Downsample(dim): def Downsample(dim):
return nn.Conv2d(dim, dim, 3, 2, 1) return nn.Conv2d(dim, dim, 4, 2, 1)
class LayerNorm(nn.Module): class LayerNorm(nn.Module):
def __init__(self, dim, eps = 1e-5): def __init__(self, dim, eps = 1e-5):
@@ -135,10 +134,9 @@ class ConvNextBlock(nn.Module):
self.net = nn.Sequential( self.net = nn.Sequential(
LayerNorm(dim) if norm else nn.Identity(), LayerNorm(dim) if norm else nn.Identity(),
nn.Conv2d(dim, dim_out * mult, 1), nn.Conv2d(dim, dim_out * mult, 3, padding = 1),
nn.GELU(), nn.GELU(),
LayerNorm(dim_out * mult), nn.Conv2d(dim_out * mult, dim_out, 3, padding = 1)
nn.Conv2d(dim_out * mult, dim_out, 1)
) )
self.res_conv = nn.Conv2d(dim, dim_out, 1) if dim != dim_out else nn.Identity() self.res_conv = nn.Conv2d(dim, dim_out, 1) if dim != dim_out else nn.Identity()
@@ -176,6 +174,29 @@ class LinearAttention(nn.Module):
out = rearrange(out, 'b h c (x y) -> b (h c) x y', h = self.heads, x = h, y = w) out = rearrange(out, 'b h c (x y) -> b (h c) x y', h = self.heads, x = h, y = w)
return self.to_out(out) return self.to_out(out)
class Attention(nn.Module):
def __init__(self, dim, heads = 4, dim_head = 32):
super().__init__()
self.scale = dim_head ** -0.5
self.heads = heads
hidden_dim = dim_head * heads
self.to_qkv = nn.Conv2d(dim, hidden_dim * 3, 1, bias = False)
self.to_out = nn.Conv2d(hidden_dim, dim, 1)
def forward(self, x):
b, c, h, w = x.shape
qkv = self.to_qkv(x).chunk(3, dim = 1)
q, k, v = map(lambda t: rearrange(t, 'b (h c) x y -> b h c (x y)', h = self.heads), qkv)
q = q * self.scale
sim = einsum('b h d i, b h d j -> b h i j', q, k)
sim = sim - sim.amax(dim = -1, keepdim = True).detach()
attn = sim.softmax(dim = -1)
out = einsum('b h i j, b h d j -> b h i d', attn, v)
out = rearrange(out, 'b h (x y) d -> b (h d) x y', x = h, y = w)
return self.to_out(out)
# model # model
class Unet(nn.Module): class Unet(nn.Module):
@@ -221,7 +242,7 @@ class Unet(nn.Module):
mid_dim = dims[-1] mid_dim = dims[-1]
self.mid_block1 = ConvNextBlock(mid_dim, mid_dim, time_emb_dim = time_dim) self.mid_block1 = ConvNextBlock(mid_dim, mid_dim, time_emb_dim = time_dim)
self.mid_attn = Residual(PreNorm(mid_dim, LinearAttention(mid_dim))) self.mid_attn = Residual(PreNorm(mid_dim, Attention(mid_dim)))
self.mid_block2 = ConvNextBlock(mid_dim, mid_dim, time_emb_dim = time_dim) self.mid_block2 = ConvNextBlock(mid_dim, mid_dim, time_emb_dim = time_dim)
for ind, (dim_in, dim_out) in enumerate(reversed(in_out[1:])): for ind, (dim_in, dim_out) in enumerate(reversed(in_out[1:])):
@@ -283,11 +304,11 @@ def cosine_beta_schedule(timesteps, s = 0.008):
as proposed in https://openreview.net/forum?id=-NEXDKk8gZ as proposed in https://openreview.net/forum?id=-NEXDKk8gZ
""" """
steps = timesteps + 1 steps = timesteps + 1
x = np.linspace(0, steps, steps) x = torch.linspace(0, steps, steps)
alphas_cumprod = np.cos(((x / steps) + s) / (1 + s) * np.pi * 0.5) ** 2 alphas_cumprod = torch.cos(((x / steps) + s) / (1 + s) * torch.pi * 0.5) ** 2
alphas_cumprod = alphas_cumprod / alphas_cumprod[0] alphas_cumprod = alphas_cumprod / alphas_cumprod[0]
betas = 1 - (alphas_cumprod[1:] / alphas_cumprod[:-1]) betas = 1 - (alphas_cumprod[1:] / alphas_cumprod[:-1])
return np.clip(betas, a_min = 0, a_max = 0.999) return torch.clip(betas, 0, 0.999)
class GaussianDiffusion(nn.Module): class GaussianDiffusion(nn.Module):
def __init__( def __init__(
@@ -297,22 +318,18 @@ class GaussianDiffusion(nn.Module):
image_size, image_size,
channels = 3, channels = 3,
timesteps = 1000, timesteps = 1000,
loss_type = 'l1', loss_type = 'l1'
betas = None
): ):
super().__init__() super().__init__()
self.channels = channels self.channels = channels
self.image_size = image_size self.image_size = image_size
self.denoise_fn = denoise_fn self.denoise_fn = denoise_fn
if exists(betas): betas = cosine_beta_schedule(timesteps)
betas = betas.detach().cpu().numpy() if isinstance(betas, torch.Tensor) else betas
else:
betas = cosine_beta_schedule(timesteps)
alphas = 1. - betas alphas = 1. - betas
alphas_cumprod = np.cumprod(alphas, axis=0) alphas_cumprod = torch.cumprod(alphas, axis=0)
alphas_cumprod_prev = np.append(1., alphas_cumprod[:-1]) alphas_cumprod_prev = F.pad(alphas_cumprod[:-1], (0, 1), value = 1.)
timesteps, = betas.shape timesteps, = betas.shape
self.num_timesteps = int(timesteps) self.num_timesteps = int(timesteps)
@@ -320,27 +337,31 @@ class GaussianDiffusion(nn.Module):
to_torch = partial(torch.tensor, dtype=torch.float32) to_torch = partial(torch.tensor, dtype=torch.float32)
self.register_buffer('betas', to_torch(betas)) self.register_buffer('betas', betas)
self.register_buffer('alphas_cumprod', to_torch(alphas_cumprod)) self.register_buffer('alphas_cumprod', alphas_cumprod)
self.register_buffer('alphas_cumprod_prev', to_torch(alphas_cumprod_prev)) self.register_buffer('alphas_cumprod_prev', alphas_cumprod_prev)
# calculations for diffusion q(x_t | x_{t-1}) and others # calculations for diffusion q(x_t | x_{t-1}) and others
self.register_buffer('sqrt_alphas_cumprod', to_torch(np.sqrt(alphas_cumprod)))
self.register_buffer('sqrt_one_minus_alphas_cumprod', to_torch(np.sqrt(1. - alphas_cumprod))) self.register_buffer('sqrt_alphas_cumprod', torch.sqrt(alphas_cumprod))
self.register_buffer('log_one_minus_alphas_cumprod', to_torch(np.log(1. - alphas_cumprod))) self.register_buffer('sqrt_one_minus_alphas_cumprod', torch.sqrt(1. - alphas_cumprod))
self.register_buffer('sqrt_recip_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod))) self.register_buffer('log_one_minus_alphas_cumprod', torch.log(1. - alphas_cumprod))
self.register_buffer('sqrt_recipm1_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod - 1))) self.register_buffer('sqrt_recip_alphas_cumprod', torch.sqrt(1. / alphas_cumprod))
self.register_buffer('sqrt_recipm1_alphas_cumprod', torch.sqrt(1. / alphas_cumprod - 1))
# calculations for posterior q(x_{t-1} | x_t, x_0) # calculations for posterior q(x_{t-1} | x_t, x_0)
posterior_variance = betas * (1. - alphas_cumprod_prev) / (1. - alphas_cumprod) posterior_variance = betas * (1. - alphas_cumprod_prev) / (1. - alphas_cumprod)
# above: equal to 1. / (1. / (1. - alpha_cumprod_tm1) + alpha_t / beta_t) # above: equal to 1. / (1. / (1. - alpha_cumprod_tm1) + alpha_t / beta_t)
self.register_buffer('posterior_variance', to_torch(posterior_variance))
self.register_buffer('posterior_variance', posterior_variance)
# below: log calculation clipped because the posterior variance is 0 at the beginning of the diffusion chain # below: log calculation clipped because the posterior variance is 0 at the beginning of the diffusion chain
self.register_buffer('posterior_log_variance_clipped', to_torch(np.log(np.maximum(posterior_variance, 1e-20))))
self.register_buffer('posterior_mean_coef1', to_torch( self.register_buffer('posterior_log_variance_clipped', torch.log(posterior_variance.clamp(min =1e-20)))
betas * np.sqrt(alphas_cumprod_prev) / (1. - alphas_cumprod))) self.register_buffer('posterior_mean_coef1', betas * torch.sqrt(alphas_cumprod_prev) / (1. - alphas_cumprod))
self.register_buffer('posterior_mean_coef2', to_torch( self.register_buffer('posterior_mean_coef2', (1. - alphas_cumprod_prev) * torch.sqrt(alphas) / (1. - alphas_cumprod))
(1. - alphas_cumprod_prev) * np.sqrt(alphas) / (1. - alphas_cumprod)))
def q_mean_variance(self, x_start, t): def q_mean_variance(self, x_start, t):
mean = extract(self.sqrt_alphas_cumprod, t, x_start.shape) * x_start mean = extract(self.sqrt_alphas_cumprod, t, x_start.shape) * x_start
+1 -2
View File
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
setup( setup(
name = 'denoising-diffusion-pytorch', name = 'denoising-diffusion-pytorch',
packages = find_packages(), packages = find_packages(),
version = '0.7.0', version = '0.8.1',
license='MIT', license='MIT',
description = 'Denoising Diffusion Probabilistic Models - Pytorch', description = 'Denoising Diffusion Probabilistic Models - Pytorch',
author = 'Phil Wang', author = 'Phil Wang',
@@ -15,7 +15,6 @@ setup(
], ],
install_requires=[ install_requires=[
'einops', 'einops',
'numpy',
'pillow', 'pillow',
'torch', 'torch',
'torchvision', 'torchvision',