|
|
|
@@ -37,6 +37,9 @@ def default(val, d):
|
|
|
|
|
return val
|
|
|
|
|
return d() if callable(d) else d
|
|
|
|
|
|
|
|
|
|
def identity(t, *args, **kwargs):
|
|
|
|
|
return t
|
|
|
|
|
|
|
|
|
|
def cycle(dl):
|
|
|
|
|
while True:
|
|
|
|
|
for data in dl:
|
|
|
|
@@ -53,14 +56,11 @@ def num_to_groups(num, divisor):
|
|
|
|
|
arr.append(remainder)
|
|
|
|
|
return arr
|
|
|
|
|
|
|
|
|
|
def convert_image_to(img_type, image):
|
|
|
|
|
def convert_image_to_fn(img_type, image):
|
|
|
|
|
if image.mode != img_type:
|
|
|
|
|
return image.convert(img_type)
|
|
|
|
|
return image
|
|
|
|
|
|
|
|
|
|
def l2norm(t):
|
|
|
|
|
return F.normalize(t, dim = -1)
|
|
|
|
|
|
|
|
|
|
# normalization functions
|
|
|
|
|
|
|
|
|
|
def normalize_to_neg_one_to_one(img):
|
|
|
|
@@ -236,9 +236,10 @@ class LinearAttention(nn.Module):
|
|
|
|
|
class Attention(nn.Module):
|
|
|
|
|
def __init__(self, dim, heads = 4, dim_head = 32, scale = 10):
|
|
|
|
|
super().__init__()
|
|
|
|
|
self.scale = scale
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
@@ -247,11 +248,12 @@ class Attention(nn.Module):
|
|
|
|
|
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, k = map(l2norm, (q, k))
|
|
|
|
|
q = q * self.scale
|
|
|
|
|
|
|
|
|
|
sim = einsum('b h d i, b h d j -> b h i j', q, k) * self.scale
|
|
|
|
|
sim = einsum('b h d i, b h d j -> b h i j', q, k)
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
@@ -447,7 +449,7 @@ class GaussianDiffusion(nn.Module):
|
|
|
|
|
raise ValueError(f'unknown beta schedule {beta_schedule}')
|
|
|
|
|
|
|
|
|
|
alphas = 1. - betas
|
|
|
|
|
alphas_cumprod = torch.cumprod(alphas, axis=0)
|
|
|
|
|
alphas_cumprod = torch.cumprod(alphas, dim=0)
|
|
|
|
|
alphas_cumprod_prev = F.pad(alphas_cumprod[:-1], (1, 0), value = 1.)
|
|
|
|
|
|
|
|
|
|
timesteps, = betas.shape
|
|
|
|
@@ -517,16 +519,19 @@ class GaussianDiffusion(nn.Module):
|
|
|
|
|
posterior_log_variance_clipped = extract(self.posterior_log_variance_clipped, t, x_t.shape)
|
|
|
|
|
return posterior_mean, posterior_variance, posterior_log_variance_clipped
|
|
|
|
|
|
|
|
|
|
def model_predictions(self, x, t, x_self_cond = None):
|
|
|
|
|
def model_predictions(self, x, t, x_self_cond = None, clip_x_start = False):
|
|
|
|
|
model_output = self.model(x, t, x_self_cond)
|
|
|
|
|
maybe_clip = partial(torch.clamp, min = -1., max = 1.) if clip_x_start else identity
|
|
|
|
|
|
|
|
|
|
if self.objective == 'pred_noise':
|
|
|
|
|
pred_noise = model_output
|
|
|
|
|
x_start = self.predict_start_from_noise(x, t, model_output)
|
|
|
|
|
x_start = self.predict_start_from_noise(x, t, pred_noise)
|
|
|
|
|
x_start = maybe_clip(x_start)
|
|
|
|
|
|
|
|
|
|
elif self.objective == 'pred_x0':
|
|
|
|
|
pred_noise = self.predict_noise_from_start(x, t, model_output)
|
|
|
|
|
x_start = model_output
|
|
|
|
|
x_start = maybe_clip(x_start)
|
|
|
|
|
pred_noise = self.predict_noise_from_start(x, t, x_start)
|
|
|
|
|
|
|
|
|
|
return ModelPrediction(pred_noise, x_start)
|
|
|
|
|
|
|
|
|
@@ -568,31 +573,30 @@ class GaussianDiffusion(nn.Module):
|
|
|
|
|
def ddim_sample(self, shape, clip_denoised = True):
|
|
|
|
|
batch, device, total_timesteps, sampling_timesteps, eta, objective = shape[0], self.betas.device, self.num_timesteps, self.sampling_timesteps, self.ddim_sampling_eta, self.objective
|
|
|
|
|
|
|
|
|
|
times = torch.linspace(0., total_timesteps, steps = sampling_timesteps + 2)[:-1]
|
|
|
|
|
times = torch.linspace(-1, total_timesteps - 1, steps=sampling_timesteps + 1) # [-1, 0, 1, 2, ..., T-1] when sampling_timesteps == total_timesteps
|
|
|
|
|
times = list(reversed(times.int().tolist()))
|
|
|
|
|
time_pairs = list(filter(lambda a: a[0] > a[1], zip(times[:-1], times[1:])))
|
|
|
|
|
time_pairs = list(zip(times[:-1], times[1:])) # [(T-1, T-2), (T-2, T-3), ..., (1, 0), (0, -1)]
|
|
|
|
|
|
|
|
|
|
img = torch.randn(shape, device = device)
|
|
|
|
|
|
|
|
|
|
x_start = None
|
|
|
|
|
|
|
|
|
|
for time, time_next in tqdm(time_pairs, desc = 'sampling loop time step'):
|
|
|
|
|
time_cond = torch.full((batch,), time, device=device, dtype=torch.long)
|
|
|
|
|
self_cond = x_start if self.self_condition else None
|
|
|
|
|
pred_noise, x_start, *_ = self.model_predictions(img, time_cond, self_cond, clip_x_start = clip_denoised)
|
|
|
|
|
|
|
|
|
|
if time_next < 0:
|
|
|
|
|
img = x_start
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
alpha = self.alphas_cumprod[time]
|
|
|
|
|
alpha_next = self.alphas_cumprod[time_next]
|
|
|
|
|
|
|
|
|
|
time_cond = torch.full((batch,), time, device = device, dtype = torch.long)
|
|
|
|
|
|
|
|
|
|
self_cond = x_start if self.self_condition else None
|
|
|
|
|
|
|
|
|
|
pred_noise, x_start, *_ = self.model_predictions(img, time_cond, self_cond)
|
|
|
|
|
|
|
|
|
|
if clip_denoised:
|
|
|
|
|
x_start.clamp_(-1., 1.)
|
|
|
|
|
|
|
|
|
|
sigma = eta * ((1 - alpha / alpha_next) * (1 - alpha_next) / (1 - alpha)).sqrt()
|
|
|
|
|
c = ((1 - alpha_next) - sigma ** 2).sqrt()
|
|
|
|
|
c = (1 - alpha_next - sigma ** 2).sqrt()
|
|
|
|
|
|
|
|
|
|
noise = torch.randn_like(img) if time_next > 0 else 0.
|
|
|
|
|
noise = torch.randn_like(img)
|
|
|
|
|
|
|
|
|
|
img = x_start * alpha_next.sqrt() + \
|
|
|
|
|
c * pred_noise + \
|
|
|
|
@@ -699,7 +703,7 @@ class Dataset(Dataset):
|
|
|
|
|
self.image_size = image_size
|
|
|
|
|
self.paths = [p for ext in exts for p in Path(f'{folder}').glob(f'**/*.{ext}')]
|
|
|
|
|
|
|
|
|
|
maybe_convert_fn = partial(convert_image_to, convert_image_to) if exists(convert_image_to) else nn.Identity()
|
|
|
|
|
maybe_convert_fn = partial(convert_image_to_fn, convert_image_to) if exists(convert_image_to) else nn.Identity()
|
|
|
|
|
|
|
|
|
|
self.transform = T.Compose([
|
|
|
|
|
T.Lambda(maybe_convert_fn),
|
|
|
|
@@ -805,7 +809,10 @@ class Trainer(object):
|
|
|
|
|
torch.save(data, str(self.results_folder / f'model-{milestone}.pt'))
|
|
|
|
|
|
|
|
|
|
def load(self, milestone):
|
|
|
|
|
data = torch.load(str(self.results_folder / f'model-{milestone}.pt'))
|
|
|
|
|
accelerator = self.accelerator
|
|
|
|
|
device = accelerator.device
|
|
|
|
|
|
|
|
|
|
data = torch.load(str(self.results_folder / f'model-{milestone}.pt'), map_location=device)
|
|
|
|
|
|
|
|
|
|
model = self.accelerator.unwrap_model(self.model)
|
|
|
|
|
model.load_state_dict(data['model'])
|
|
|
|
@@ -837,6 +844,7 @@ class Trainer(object):
|
|
|
|
|
|
|
|
|
|
self.accelerator.backward(loss)
|
|
|
|
|
|
|
|
|
|
accelerator.clip_grad_norm_(self.model.parameters(), 1.0)
|
|
|
|
|
pbar.set_description(f'loss: {total_loss:.4f}')
|
|
|
|
|
|
|
|
|
|
accelerator.wait_for_everyone()
|
|
|
|
@@ -846,6 +854,7 @@ class Trainer(object):
|
|
|
|
|
|
|
|
|
|
accelerator.wait_for_everyone()
|
|
|
|
|
|
|
|
|
|
self.step += 1
|
|
|
|
|
if accelerator.is_main_process:
|
|
|
|
|
self.ema.to(device)
|
|
|
|
|
self.ema.update()
|
|
|
|
@@ -862,7 +871,6 @@ class Trainer(object):
|
|
|
|
|
utils.save_image(all_images, str(self.results_folder / f'sample-{milestone}.png'), nrow = int(math.sqrt(self.num_samples)))
|
|
|
|
|
self.save(milestone)
|
|
|
|
|
|
|
|
|
|
self.step += 1
|
|
|
|
|
pbar.update(1)
|
|
|
|
|
|
|
|
|
|
accelerator.print('training complete')
|
|
|
|
|