mirror of
https://github.com/lucidrains/DALLE2-pytorch.git
synced 2026-02-14 10:24:31 +01:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4016f6302 | ||
|
|
1212f7058d | ||
|
|
dab106d4e5 | ||
|
|
bb151ca6b1 | ||
|
|
4a59dea4cf | ||
|
|
ecf9e8027d |
@@ -1,6 +1,6 @@
|
|||||||
from dalle2_pytorch.dalle2_pytorch import DALLE2, DiffusionPriorNetwork, DiffusionPrior, Unet, Decoder
|
from dalle2_pytorch.dalle2_pytorch import DALLE2, DiffusionPriorNetwork, DiffusionPrior, Unet, Decoder
|
||||||
from dalle2_pytorch.dalle2_pytorch import OpenAIClipAdapter
|
from dalle2_pytorch.dalle2_pytorch import OpenAIClipAdapter
|
||||||
from dalle2_pytorch.train import DecoderTrainer, DiffusionPriorTrainer
|
from dalle2_pytorch.trainer import DecoderTrainer, DiffusionPriorTrainer
|
||||||
|
|
||||||
from dalle2_pytorch.vqgan_vae import VQGanVAE
|
from dalle2_pytorch.vqgan_vae import VQGanVAE
|
||||||
from x_clip import CLIP
|
from x_clip import CLIP
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ def default(val, d):
|
|||||||
def cast_tuple(val, length = 1):
|
def cast_tuple(val, length = 1):
|
||||||
return val if isinstance(val, tuple) else ((val,) * length)
|
return val if isinstance(val, tuple) else ((val,) * length)
|
||||||
|
|
||||||
|
def module_device(module):
|
||||||
|
return next(module.parameters()).device
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def null_context(*args, **kwargs):
|
def null_context(*args, **kwargs):
|
||||||
yield
|
yield
|
||||||
@@ -901,6 +904,7 @@ class DiffusionPrior(BaseGaussianDiffusion):
|
|||||||
self.channels = default(image_channels, lambda: clip.image_channels)
|
self.channels = default(image_channels, lambda: clip.image_channels)
|
||||||
|
|
||||||
self.cond_drop_prob = cond_drop_prob
|
self.cond_drop_prob = cond_drop_prob
|
||||||
|
self.can_classifier_guidance = cond_drop_prob > 0.
|
||||||
self.condition_on_text_encodings = condition_on_text_encodings
|
self.condition_on_text_encodings = condition_on_text_encodings
|
||||||
|
|
||||||
# in paper, they do not predict the noise, but predict x0 directly for image embedding, claiming empirically better results. I'll just offer both.
|
# in paper, they do not predict the noise, but predict x0 directly for image embedding, claiming empirically better results. I'll just offer both.
|
||||||
@@ -914,8 +918,10 @@ class DiffusionPrior(BaseGaussianDiffusion):
|
|||||||
self.training_clamp_l2norm = training_clamp_l2norm
|
self.training_clamp_l2norm = training_clamp_l2norm
|
||||||
self.init_image_embed_l2norm = init_image_embed_l2norm
|
self.init_image_embed_l2norm = init_image_embed_l2norm
|
||||||
|
|
||||||
def p_mean_variance(self, x, t, text_cond, clip_denoised: bool):
|
def p_mean_variance(self, x, t, text_cond, clip_denoised = False, cond_scale = 1.):
|
||||||
pred = self.net(x, t, **text_cond)
|
assert not (cond_scale != 1. and not self.can_classifier_guidance), 'the model was not trained with conditional dropout, and thus one cannot use classifier free guidance (cond_scale anything other than 1)'
|
||||||
|
|
||||||
|
pred = self.net.forward_with_cond_scale(x, t, cond_scale = cond_scale, **text_cond)
|
||||||
|
|
||||||
if self.predict_x_start:
|
if self.predict_x_start:
|
||||||
x_recon = pred
|
x_recon = pred
|
||||||
@@ -933,17 +939,17 @@ class DiffusionPrior(BaseGaussianDiffusion):
|
|||||||
model_mean, posterior_variance, posterior_log_variance = self.q_posterior(x_start=x_recon, x_t=x, t=t)
|
model_mean, posterior_variance, posterior_log_variance = self.q_posterior(x_start=x_recon, x_t=x, t=t)
|
||||||
return model_mean, posterior_variance, posterior_log_variance
|
return model_mean, posterior_variance, posterior_log_variance
|
||||||
|
|
||||||
@torch.inference_mode()
|
@torch.no_grad()
|
||||||
def p_sample(self, x, t, text_cond = None, clip_denoised = True, repeat_noise = False):
|
def p_sample(self, x, t, text_cond = None, clip_denoised = True, repeat_noise = False, cond_scale = 1.):
|
||||||
b, *_, device = *x.shape, x.device
|
b, *_, device = *x.shape, x.device
|
||||||
model_mean, _, model_log_variance = self.p_mean_variance(x = x, t = t, text_cond = text_cond, clip_denoised = clip_denoised)
|
model_mean, _, model_log_variance = self.p_mean_variance(x = x, t = t, text_cond = text_cond, clip_denoised = clip_denoised, cond_scale = cond_scale)
|
||||||
noise = noise_like(x.shape, device, repeat_noise)
|
noise = noise_like(x.shape, device, repeat_noise)
|
||||||
# no noise when t == 0
|
# no noise when t == 0
|
||||||
nonzero_mask = (1 - (t == 0).float()).reshape(b, *((1,) * (len(x.shape) - 1)))
|
nonzero_mask = (1 - (t == 0).float()).reshape(b, *((1,) * (len(x.shape) - 1)))
|
||||||
return model_mean + nonzero_mask * (0.5 * model_log_variance).exp() * noise
|
return model_mean + nonzero_mask * (0.5 * model_log_variance).exp() * noise
|
||||||
|
|
||||||
@torch.inference_mode()
|
@torch.no_grad()
|
||||||
def p_sample_loop(self, shape, text_cond):
|
def p_sample_loop(self, shape, text_cond, cond_scale = 1.):
|
||||||
device = self.betas.device
|
device = self.betas.device
|
||||||
|
|
||||||
b = shape[0]
|
b = shape[0]
|
||||||
@@ -954,7 +960,7 @@ class DiffusionPrior(BaseGaussianDiffusion):
|
|||||||
|
|
||||||
for i in tqdm(reversed(range(0, self.num_timesteps)), desc='sampling loop time step', total=self.num_timesteps):
|
for i in tqdm(reversed(range(0, self.num_timesteps)), desc='sampling loop time step', total=self.num_timesteps):
|
||||||
times = torch.full((b,), i, device = device, dtype = torch.long)
|
times = torch.full((b,), i, device = device, dtype = torch.long)
|
||||||
image_embed = self.p_sample(image_embed, times, text_cond = text_cond)
|
image_embed = self.p_sample(image_embed, times, text_cond = text_cond, cond_scale = cond_scale)
|
||||||
|
|
||||||
return image_embed
|
return image_embed
|
||||||
|
|
||||||
@@ -978,21 +984,21 @@ class DiffusionPrior(BaseGaussianDiffusion):
|
|||||||
loss = self.loss_fn(pred, target)
|
loss = self.loss_fn(pred, target)
|
||||||
return loss
|
return loss
|
||||||
|
|
||||||
@torch.inference_mode()
|
@torch.no_grad()
|
||||||
@eval_decorator
|
@eval_decorator
|
||||||
def sample_batch_size(self, batch_size, text_cond):
|
def sample_batch_size(self, batch_size, text_cond, cond_scale = 1.):
|
||||||
device = self.betas.device
|
device = self.betas.device
|
||||||
shape = (batch_size, self.image_embed_dim)
|
shape = (batch_size, self.image_embed_dim)
|
||||||
|
|
||||||
img = torch.randn(shape, device = device)
|
img = torch.randn(shape, device = device)
|
||||||
|
|
||||||
for i in tqdm(reversed(range(0, self.num_timesteps)), desc = 'sampling loop time step', total = self.num_timesteps):
|
for i in tqdm(reversed(range(0, self.num_timesteps)), desc = 'sampling loop time step', total = self.num_timesteps):
|
||||||
img = self.p_sample(img, torch.full((batch_size,), i, device = device, dtype = torch.long), text_cond = text_cond)
|
img = self.p_sample(img, torch.full((batch_size,), i, device = device, dtype = torch.long), text_cond = text_cond, cond_scale = cond_scale)
|
||||||
return img
|
return img
|
||||||
|
|
||||||
@torch.inference_mode()
|
@torch.no_grad()
|
||||||
@eval_decorator
|
@eval_decorator
|
||||||
def sample(self, text, num_samples_per_batch = 2):
|
def sample(self, text, num_samples_per_batch = 2, cond_scale = 1.):
|
||||||
# in the paper, what they did was
|
# in the paper, what they did was
|
||||||
# sample 2 image embeddings, choose the top 1 similarity, as judged by CLIP
|
# sample 2 image embeddings, choose the top 1 similarity, as judged by CLIP
|
||||||
text = repeat(text, 'b ... -> (b r) ...', r = num_samples_per_batch)
|
text = repeat(text, 'b ... -> (b r) ...', r = num_samples_per_batch)
|
||||||
@@ -1007,7 +1013,7 @@ class DiffusionPrior(BaseGaussianDiffusion):
|
|||||||
if self.condition_on_text_encodings:
|
if self.condition_on_text_encodings:
|
||||||
text_cond = {**text_cond, 'text_encodings': text_encodings, 'mask': text_mask}
|
text_cond = {**text_cond, 'text_encodings': text_encodings, 'mask': text_mask}
|
||||||
|
|
||||||
image_embeds = self.p_sample_loop((batch_size, image_embed_dim), text_cond = text_cond)
|
image_embeds = self.p_sample_loop((batch_size, image_embed_dim), text_cond = text_cond, cond_scale = cond_scale)
|
||||||
|
|
||||||
# retrieve original unscaled image embed
|
# retrieve original unscaled image embed
|
||||||
|
|
||||||
@@ -1793,6 +1799,7 @@ class Decoder(BaseGaussianDiffusion):
|
|||||||
|
|
||||||
self.image_cond_drop_prob = image_cond_drop_prob
|
self.image_cond_drop_prob = image_cond_drop_prob
|
||||||
self.text_cond_drop_prob = text_cond_drop_prob
|
self.text_cond_drop_prob = text_cond_drop_prob
|
||||||
|
self.can_classifier_guidance = image_cond_drop_prob > 0. or text_cond_drop_prob > 0.
|
||||||
|
|
||||||
# whether to clip when sampling
|
# whether to clip when sampling
|
||||||
|
|
||||||
@@ -1812,13 +1819,19 @@ class Decoder(BaseGaussianDiffusion):
|
|||||||
unet = self.get_unet(unet_number)
|
unet = self.get_unet(unet_number)
|
||||||
|
|
||||||
self.cuda()
|
self.cuda()
|
||||||
self.unets.cpu()
|
|
||||||
|
|
||||||
|
devices = [module_device(unet) for unet in self.unets]
|
||||||
|
self.unets.cpu()
|
||||||
unet.cuda()
|
unet.cuda()
|
||||||
|
|
||||||
yield
|
yield
|
||||||
unet.cpu()
|
|
||||||
|
for unet, device in zip(self.unets, devices):
|
||||||
|
unet.to(device)
|
||||||
|
|
||||||
def p_mean_variance(self, unet, x, t, image_embed, text_encodings = None, text_mask = None, lowres_cond_img = None, clip_denoised = True, predict_x_start = False, learned_variance = False, cond_scale = 1., model_output = None):
|
def p_mean_variance(self, unet, x, t, image_embed, text_encodings = None, text_mask = None, lowres_cond_img = None, clip_denoised = True, predict_x_start = False, learned_variance = False, cond_scale = 1., model_output = None):
|
||||||
|
assert not (cond_scale != 1. and not self.can_classifier_guidance), 'the decoder was not trained with conditional dropout, and thus one cannot use classifier free guidance (cond_scale anything other than 1)'
|
||||||
|
|
||||||
pred = default(model_output, lambda: unet.forward_with_cond_scale(x, t, image_embed = image_embed, text_encodings = text_encodings, text_mask = text_mask, cond_scale = cond_scale, lowres_cond_img = lowres_cond_img))
|
pred = default(model_output, lambda: unet.forward_with_cond_scale(x, t, image_embed = image_embed, text_encodings = text_encodings, text_mask = text_mask, cond_scale = cond_scale, lowres_cond_img = lowres_cond_img))
|
||||||
|
|
||||||
if learned_variance:
|
if learned_variance:
|
||||||
@@ -1847,7 +1860,7 @@ class Decoder(BaseGaussianDiffusion):
|
|||||||
|
|
||||||
return model_mean, posterior_variance, posterior_log_variance
|
return model_mean, posterior_variance, posterior_log_variance
|
||||||
|
|
||||||
@torch.inference_mode()
|
@torch.no_grad()
|
||||||
def p_sample(self, unet, x, t, image_embed, text_encodings = None, text_mask = None, cond_scale = 1., lowres_cond_img = None, predict_x_start = False, learned_variance = False, clip_denoised = True, repeat_noise = False):
|
def p_sample(self, unet, x, t, image_embed, text_encodings = None, text_mask = None, cond_scale = 1., lowres_cond_img = None, predict_x_start = False, learned_variance = False, clip_denoised = True, repeat_noise = False):
|
||||||
b, *_, device = *x.shape, x.device
|
b, *_, device = *x.shape, x.device
|
||||||
model_mean, _, model_log_variance = self.p_mean_variance(unet, x = x, t = t, image_embed = image_embed, text_encodings = text_encodings, text_mask = text_mask, cond_scale = cond_scale, lowres_cond_img = lowres_cond_img, clip_denoised = clip_denoised, predict_x_start = predict_x_start, learned_variance = learned_variance)
|
model_mean, _, model_log_variance = self.p_mean_variance(unet, x = x, t = t, image_embed = image_embed, text_encodings = text_encodings, text_mask = text_mask, cond_scale = cond_scale, lowres_cond_img = lowres_cond_img, clip_denoised = clip_denoised, predict_x_start = predict_x_start, learned_variance = learned_variance)
|
||||||
@@ -1856,14 +1869,15 @@ class Decoder(BaseGaussianDiffusion):
|
|||||||
nonzero_mask = (1 - (t == 0).float()).reshape(b, *((1,) * (len(x.shape) - 1)))
|
nonzero_mask = (1 - (t == 0).float()).reshape(b, *((1,) * (len(x.shape) - 1)))
|
||||||
return model_mean + nonzero_mask * (0.5 * model_log_variance).exp() * noise
|
return model_mean + nonzero_mask * (0.5 * model_log_variance).exp() * noise
|
||||||
|
|
||||||
@torch.inference_mode()
|
@torch.no_grad()
|
||||||
def p_sample_loop(self, unet, shape, image_embed, predict_x_start = False, learned_variance = False, clip_denoised = True, lowres_cond_img = None, text_encodings = None, text_mask = None, cond_scale = 1):
|
def p_sample_loop(self, unet, shape, image_embed, predict_x_start = False, learned_variance = False, clip_denoised = True, lowres_cond_img = None, text_encodings = None, text_mask = None, cond_scale = 1, is_latent_diffusion = False):
|
||||||
device = self.betas.device
|
device = self.betas.device
|
||||||
|
|
||||||
b = shape[0]
|
b = shape[0]
|
||||||
img = torch.randn(shape, device = device)
|
img = torch.randn(shape, device = device)
|
||||||
|
|
||||||
lowres_cond_img = maybe(normalize_neg_one_to_one)(lowres_cond_img)
|
if not is_latent_diffusion:
|
||||||
|
lowres_cond_img = maybe(normalize_neg_one_to_one)(lowres_cond_img)
|
||||||
|
|
||||||
for i in tqdm(reversed(range(0, self.num_timesteps)), desc = 'sampling loop time step', total = self.num_timesteps):
|
for i in tqdm(reversed(range(0, self.num_timesteps)), desc = 'sampling loop time step', total = self.num_timesteps):
|
||||||
img = self.p_sample(
|
img = self.p_sample(
|
||||||
@@ -1883,13 +1897,14 @@ class Decoder(BaseGaussianDiffusion):
|
|||||||
unnormalize_img = unnormalize_zero_to_one(img)
|
unnormalize_img = unnormalize_zero_to_one(img)
|
||||||
return unnormalize_img
|
return unnormalize_img
|
||||||
|
|
||||||
def p_losses(self, unet, x_start, times, *, image_embed, lowres_cond_img = None, text_encodings = None, text_mask = None, predict_x_start = False, noise = None, learned_variance = False, clip_denoised = False):
|
def p_losses(self, unet, x_start, times, *, image_embed, lowres_cond_img = None, text_encodings = None, text_mask = None, predict_x_start = False, noise = None, learned_variance = False, clip_denoised = False, is_latent_diffusion = False):
|
||||||
noise = default(noise, lambda: torch.randn_like(x_start))
|
noise = default(noise, lambda: torch.randn_like(x_start))
|
||||||
|
|
||||||
# normalize to [-1, 1]
|
# normalize to [-1, 1]
|
||||||
|
|
||||||
x_start = normalize_neg_one_to_one(x_start)
|
if not is_latent_diffusion:
|
||||||
lowres_cond_img = maybe(normalize_neg_one_to_one)(lowres_cond_img)
|
x_start = normalize_neg_one_to_one(x_start)
|
||||||
|
lowres_cond_img = maybe(normalize_neg_one_to_one)(lowres_cond_img)
|
||||||
|
|
||||||
# get x_t
|
# get x_t
|
||||||
|
|
||||||
@@ -1949,12 +1964,14 @@ class Decoder(BaseGaussianDiffusion):
|
|||||||
|
|
||||||
return loss + vb_loss
|
return loss + vb_loss
|
||||||
|
|
||||||
@torch.inference_mode()
|
@torch.no_grad()
|
||||||
@eval_decorator
|
@eval_decorator
|
||||||
def sample(
|
def sample(
|
||||||
self,
|
self,
|
||||||
image_embed = None,
|
image_embed = None,
|
||||||
text = None,
|
text = None,
|
||||||
|
text_mask = None,
|
||||||
|
text_encodings = None,
|
||||||
batch_size = 1,
|
batch_size = 1,
|
||||||
cond_scale = 1.,
|
cond_scale = 1.,
|
||||||
stop_at_unet_number = None
|
stop_at_unet_number = None
|
||||||
@@ -1964,8 +1981,8 @@ class Decoder(BaseGaussianDiffusion):
|
|||||||
if not self.unconditional:
|
if not self.unconditional:
|
||||||
batch_size = image_embed.shape[0]
|
batch_size = image_embed.shape[0]
|
||||||
|
|
||||||
text_encodings = text_mask = None
|
if exists(text) and not exists(text_encodings) and not self.unconditional:
|
||||||
if exists(text):
|
assert exists(self.clip)
|
||||||
_, text_encodings, text_mask = self.clip.embed_text(text)
|
_, text_encodings, text_mask = self.clip.embed_text(text)
|
||||||
|
|
||||||
assert not (self.condition_on_text_encodings and not exists(text_encodings)), 'text or text encodings must be passed into decoder if specified'
|
assert not (self.condition_on_text_encodings and not exists(text_encodings)), 'text or text encodings must be passed into decoder if specified'
|
||||||
@@ -2001,7 +2018,8 @@ class Decoder(BaseGaussianDiffusion):
|
|||||||
predict_x_start = predict_x_start,
|
predict_x_start = predict_x_start,
|
||||||
learned_variance = learned_variance,
|
learned_variance = learned_variance,
|
||||||
clip_denoised = not is_latent_diffusion,
|
clip_denoised = not is_latent_diffusion,
|
||||||
lowres_cond_img = lowres_cond_img
|
lowres_cond_img = lowres_cond_img,
|
||||||
|
is_latent_diffusion = is_latent_diffusion
|
||||||
)
|
)
|
||||||
|
|
||||||
img = vae.decode(img)
|
img = vae.decode(img)
|
||||||
@@ -2017,6 +2035,7 @@ class Decoder(BaseGaussianDiffusion):
|
|||||||
text = None,
|
text = None,
|
||||||
image_embed = None,
|
image_embed = None,
|
||||||
text_encodings = None,
|
text_encodings = None,
|
||||||
|
text_mask = None,
|
||||||
unet_number = None
|
unet_number = None
|
||||||
):
|
):
|
||||||
assert not (len(self.unets) > 1 and not exists(unet_number)), f'you must specify which unet you want trained, from a range of 1 to {len(self.unets)}, if you are training cascading DDPM (multiple unets)'
|
assert not (len(self.unets) > 1 and not exists(unet_number)), f'you must specify which unet you want trained, from a range of 1 to {len(self.unets)}, if you are training cascading DDPM (multiple unets)'
|
||||||
@@ -2041,7 +2060,6 @@ class Decoder(BaseGaussianDiffusion):
|
|||||||
assert exists(self.clip), 'if you want to derive CLIP image embeddings automatically, you must supply `clip` to the decoder on init'
|
assert exists(self.clip), 'if you want to derive CLIP image embeddings automatically, you must supply `clip` to the decoder on init'
|
||||||
image_embed, _ = self.clip.embed_image(image)
|
image_embed, _ = self.clip.embed_image(image)
|
||||||
|
|
||||||
text_encodings = text_mask = None
|
|
||||||
if exists(text) and not exists(text_encodings) and not self.unconditional:
|
if exists(text) and not exists(text_encodings) and not self.unconditional:
|
||||||
assert exists(self.clip), 'if you are passing in raw text, you need to supply `clip` to the decoder'
|
assert exists(self.clip), 'if you are passing in raw text, you need to supply `clip` to the decoder'
|
||||||
_, text_encodings, text_mask = self.clip.embed_text(text)
|
_, text_encodings, text_mask = self.clip.embed_text(text)
|
||||||
@@ -2060,12 +2078,14 @@ class Decoder(BaseGaussianDiffusion):
|
|||||||
image = aug(image)
|
image = aug(image)
|
||||||
lowres_cond_img = aug(lowres_cond_img, params = aug._params)
|
lowres_cond_img = aug(lowres_cond_img, params = aug._params)
|
||||||
|
|
||||||
|
is_latent_diffusion = not isinstance(vae, NullVQGanVAE)
|
||||||
|
|
||||||
vae.eval()
|
vae.eval()
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
image = vae.encode(image)
|
image = vae.encode(image)
|
||||||
lowres_cond_img = maybe(vae.encode)(lowres_cond_img)
|
lowres_cond_img = maybe(vae.encode)(lowres_cond_img)
|
||||||
|
|
||||||
return self.p_losses(unet, image, times, image_embed = image_embed, text_encodings = text_encodings, text_mask = text_mask, lowres_cond_img = lowres_cond_img, predict_x_start = predict_x_start, learned_variance = learned_variance)
|
return self.p_losses(unet, image, times, image_embed = image_embed, text_encodings = text_encodings, text_mask = text_mask, lowres_cond_img = lowres_cond_img, predict_x_start = predict_x_start, learned_variance = learned_variance, is_latent_diffusion = is_latent_diffusion)
|
||||||
|
|
||||||
# main class
|
# main class
|
||||||
|
|
||||||
@@ -2088,22 +2108,23 @@ class DALLE2(nn.Module):
|
|||||||
|
|
||||||
self.to_pil = T.ToPILImage()
|
self.to_pil = T.ToPILImage()
|
||||||
|
|
||||||
@torch.inference_mode()
|
@torch.no_grad()
|
||||||
@eval_decorator
|
@eval_decorator
|
||||||
def forward(
|
def forward(
|
||||||
self,
|
self,
|
||||||
text,
|
text,
|
||||||
cond_scale = 1.,
|
cond_scale = 1.,
|
||||||
|
prior_cond_scale = 1.,
|
||||||
return_pil_images = False
|
return_pil_images = False
|
||||||
):
|
):
|
||||||
device = next(self.parameters()).device
|
device = module_device(self)
|
||||||
one_text = isinstance(text, str) or (not is_list_str(text) and text.shape[0] == 1)
|
one_text = isinstance(text, str) or (not is_list_str(text) and text.shape[0] == 1)
|
||||||
|
|
||||||
if isinstance(text, str) or is_list_str(text):
|
if isinstance(text, str) or is_list_str(text):
|
||||||
text = [text] if not isinstance(text, (list, tuple)) else text
|
text = [text] if not isinstance(text, (list, tuple)) else text
|
||||||
text = tokenizer.tokenize(text).to(device)
|
text = tokenizer.tokenize(text).to(device)
|
||||||
|
|
||||||
image_embed = self.prior.sample(text, num_samples_per_batch = self.prior_num_samples)
|
image_embed = self.prior.sample(text, num_samples_per_batch = self.prior_num_samples, cond_scale = prior_cond_scale)
|
||||||
|
|
||||||
text_cond = text if self.decoder_need_text_cond else None
|
text_cond = text if self.decoder_need_text_cond else None
|
||||||
images = self.decoder.sample(image_embed, text = text_cond, cond_scale = cond_scale)
|
images = self.decoder.sample(image_embed, text = text_cond, cond_scale = cond_scale)
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
from dalle2_pytorch.dataloaders.decoder_loader import ImageEmbeddingDataset, create_image_embedding_dataloader
|
from dalle2_pytorch.dataloaders.decoder_loader import ImageEmbeddingDataset, create_image_embedding_dataloader
|
||||||
|
from dalle2_pytorch.dataloaders.embedding_wrapper import make_splits
|
||||||
|
|||||||
180
dalle2_pytorch/dataloaders/embedding_wrapper.py
Normal file
180
dalle2_pytorch/dataloaders/embedding_wrapper.py
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
from torch.utils.data import IterableDataset
|
||||||
|
from torch import from_numpy
|
||||||
|
from clip import tokenize
|
||||||
|
from embedding_reader import EmbeddingReader
|
||||||
|
|
||||||
|
|
||||||
|
class PriorEmbeddingLoader(IterableDataset):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
text_conditioned: bool,
|
||||||
|
batch_size: int,
|
||||||
|
start: int,
|
||||||
|
stop: int,
|
||||||
|
image_reader,
|
||||||
|
text_reader: EmbeddingReader = None,
|
||||||
|
device: str = "cpu",
|
||||||
|
) -> None:
|
||||||
|
super(PriorEmbeddingLoader).__init__()
|
||||||
|
|
||||||
|
self.text_conditioned = text_conditioned
|
||||||
|
|
||||||
|
if not self.text_conditioned:
|
||||||
|
self.text_reader = text_reader
|
||||||
|
|
||||||
|
self.image_reader = image_reader
|
||||||
|
self.batch_size = batch_size
|
||||||
|
self.start = start
|
||||||
|
self.stop = stop
|
||||||
|
self.device = device
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
self.n = 0
|
||||||
|
loader_args = dict(
|
||||||
|
batch_size=self.batch_size,
|
||||||
|
start=self.start,
|
||||||
|
end=self.stop,
|
||||||
|
show_progress=False,
|
||||||
|
)
|
||||||
|
if self.text_conditioned:
|
||||||
|
self.loader = self.image_reader(**loader_args)
|
||||||
|
else:
|
||||||
|
self.loader = zip(
|
||||||
|
self.image_reader(**loader_args), self.text_reader(**loader_args)
|
||||||
|
)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
try:
|
||||||
|
return self.get_sample()
|
||||||
|
except StopIteration:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
def get_sample(self):
|
||||||
|
"""
|
||||||
|
pre-proocess data from either reader into a common format
|
||||||
|
"""
|
||||||
|
self.n += 1
|
||||||
|
|
||||||
|
if self.text_conditioned:
|
||||||
|
image_embedding, caption = next(self.loader)
|
||||||
|
|
||||||
|
image_embedding = from_numpy(image_embedding).to(self.device)
|
||||||
|
tokenized_caption = tokenize(
|
||||||
|
caption["caption"].to_list(), truncate=True
|
||||||
|
).to(self.device)
|
||||||
|
|
||||||
|
return image_embedding, tokenized_caption
|
||||||
|
|
||||||
|
else:
|
||||||
|
(image_embedding, _), (text_embedding, _) = next(self.loader)
|
||||||
|
|
||||||
|
image_embedding = from_numpy(image_embedding).to(self.device)
|
||||||
|
text_embedding = from_numpy(text_embedding).to(self.device)
|
||||||
|
|
||||||
|
return image_embedding, text_embedding
|
||||||
|
|
||||||
|
|
||||||
|
def make_splits(
|
||||||
|
text_conditioned: bool,
|
||||||
|
batch_size: int,
|
||||||
|
num_data_points: int,
|
||||||
|
train_split: float,
|
||||||
|
eval_split: float,
|
||||||
|
device: str,
|
||||||
|
img_url: str,
|
||||||
|
meta_url: str = None,
|
||||||
|
txt_url: str = None,
|
||||||
|
):
|
||||||
|
|
||||||
|
assert img_url is not None, "Must supply some image embeddings"
|
||||||
|
|
||||||
|
if text_conditioned:
|
||||||
|
assert meta_url is not None, "Must supply metadata url if text-conditioning"
|
||||||
|
image_reader = EmbeddingReader(
|
||||||
|
embeddings_folder=img_url,
|
||||||
|
file_format="parquet_npy",
|
||||||
|
meta_columns=["caption"],
|
||||||
|
metadata_folder=meta_url,
|
||||||
|
)
|
||||||
|
|
||||||
|
# compute split points
|
||||||
|
if num_data_points > image_reader.count:
|
||||||
|
print("Specified point count is larger than the number of points available...defaulting to max length of reader.")
|
||||||
|
num_data_points = image_reader.count
|
||||||
|
|
||||||
|
train_set_size = int(train_split * num_data_points)
|
||||||
|
eval_set_size = int(eval_split * num_data_points)
|
||||||
|
eval_stop = int(train_set_size + eval_set_size)
|
||||||
|
|
||||||
|
train_loader = PriorEmbeddingLoader(
|
||||||
|
text_conditioned=text_conditioned,
|
||||||
|
image_reader=image_reader,
|
||||||
|
batch_size=batch_size,
|
||||||
|
start=0,
|
||||||
|
stop=train_set_size,
|
||||||
|
device=device,
|
||||||
|
)
|
||||||
|
eval_loader = PriorEmbeddingLoader(
|
||||||
|
text_conditioned=text_conditioned,
|
||||||
|
image_reader=image_reader,
|
||||||
|
batch_size=batch_size,
|
||||||
|
start=train_set_size,
|
||||||
|
stop=eval_stop,
|
||||||
|
device=device,
|
||||||
|
)
|
||||||
|
test_loader = PriorEmbeddingLoader(
|
||||||
|
text_conditioned=text_conditioned,
|
||||||
|
image_reader=image_reader,
|
||||||
|
batch_size=batch_size,
|
||||||
|
start=eval_stop,
|
||||||
|
stop=int(num_data_points),
|
||||||
|
device=device,
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
assert (
|
||||||
|
txt_url is not None
|
||||||
|
), "Must supply text embedding url if not text-conditioning"
|
||||||
|
|
||||||
|
image_reader = EmbeddingReader(img_url, file_format="npy")
|
||||||
|
text_reader = EmbeddingReader(txt_url, file_format="npy")
|
||||||
|
|
||||||
|
# compute split points
|
||||||
|
if num_data_points > image_reader.count:
|
||||||
|
print("Specified point count is larger than the number of points available...defaulting to max length of reader.")
|
||||||
|
num_data_points = image_reader.count
|
||||||
|
|
||||||
|
train_set_size = int(train_split * num_data_points)
|
||||||
|
eval_set_size = int(eval_split * num_data_points)
|
||||||
|
eval_stop = int(train_set_size + eval_set_size)
|
||||||
|
|
||||||
|
train_loader = PriorEmbeddingLoader(
|
||||||
|
text_conditioned=text_conditioned,
|
||||||
|
image_reader=image_reader,
|
||||||
|
text_reader=text_reader,
|
||||||
|
batch_size=batch_size,
|
||||||
|
start=0,
|
||||||
|
stop=train_set_size,
|
||||||
|
device=device,
|
||||||
|
)
|
||||||
|
eval_loader = PriorEmbeddingLoader(
|
||||||
|
text_conditioned=text_conditioned,
|
||||||
|
image_reader=image_reader,
|
||||||
|
text_reader=text_reader,
|
||||||
|
batch_size=batch_size,
|
||||||
|
start=train_set_size,
|
||||||
|
stop=eval_stop,
|
||||||
|
device=device,
|
||||||
|
)
|
||||||
|
test_loader = PriorEmbeddingLoader(
|
||||||
|
text_conditioned=text_conditioned,
|
||||||
|
image_reader=image_reader,
|
||||||
|
text_reader=text_reader,
|
||||||
|
batch_size=batch_size,
|
||||||
|
start=eval_stop,
|
||||||
|
stop=int(num_data_points),
|
||||||
|
device=device,
|
||||||
|
)
|
||||||
|
|
||||||
|
return train_loader, eval_loader, test_loader
|
||||||
59
dalle2_pytorch/dataloaders/simple_image_only_dataloader.py
Normal file
59
dalle2_pytorch/dataloaders/simple_image_only_dataloader.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import torch
|
||||||
|
from torch.utils import data
|
||||||
|
from torchvision import transforms, utils
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
# helpers functions
|
||||||
|
|
||||||
|
def cycle(dl):
|
||||||
|
while True:
|
||||||
|
for data in dl:
|
||||||
|
yield data
|
||||||
|
|
||||||
|
# dataset and dataloader
|
||||||
|
|
||||||
|
class Dataset(data.Dataset):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
folder,
|
||||||
|
image_size,
|
||||||
|
exts = ['jpg', 'jpeg', 'png']
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
self.folder = folder
|
||||||
|
self.image_size = image_size
|
||||||
|
self.paths = [p for ext in exts for p in Path(f'{folder}').glob(f'**/*.{ext}')]
|
||||||
|
|
||||||
|
self.transform = transforms.Compose([
|
||||||
|
transforms.Resize(image_size),
|
||||||
|
transforms.RandomHorizontalFlip(),
|
||||||
|
transforms.CenterCrop(image_size),
|
||||||
|
transforms.ToTensor()
|
||||||
|
])
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.paths)
|
||||||
|
|
||||||
|
def __getitem__(self, index):
|
||||||
|
path = self.paths[index]
|
||||||
|
img = Image.open(path)
|
||||||
|
return self.transform(img)
|
||||||
|
|
||||||
|
def get_images_dataloader(
|
||||||
|
folder,
|
||||||
|
*,
|
||||||
|
batch_size,
|
||||||
|
image_size,
|
||||||
|
shuffle = True,
|
||||||
|
cycle_dl = True,
|
||||||
|
pin_memory = True
|
||||||
|
):
|
||||||
|
ds = Dataset(folder, image_size)
|
||||||
|
dl = data.DataLoader(ds, batch_size = batch_size, shuffle = shuffle, pin_memory = pin_memory)
|
||||||
|
|
||||||
|
if cycle_dl:
|
||||||
|
dl = cycle(dl)
|
||||||
|
return dl
|
||||||
@@ -179,8 +179,8 @@ class EMA(nn.Module):
|
|||||||
self.online_model = model
|
self.online_model = model
|
||||||
self.ema_model = copy.deepcopy(model)
|
self.ema_model = copy.deepcopy(model)
|
||||||
|
|
||||||
self.update_after_step = update_after_step # only start EMA after this step number, starting at 0
|
|
||||||
self.update_every = update_every
|
self.update_every = update_every
|
||||||
|
self.update_after_step = update_after_step // update_every # only start EMA after this step number, starting at 0
|
||||||
|
|
||||||
self.register_buffer('initted', torch.Tensor([False]))
|
self.register_buffer('initted', torch.Tensor([False]))
|
||||||
self.register_buffer('step', torch.tensor([0.]))
|
self.register_buffer('step', torch.tensor([0.]))
|
||||||
@@ -189,6 +189,9 @@ class EMA(nn.Module):
|
|||||||
device = self.initted.device
|
device = self.initted.device
|
||||||
self.ema_model.to(device)
|
self.ema_model.to(device)
|
||||||
|
|
||||||
|
def copy_params_from_model_to_ema(self):
|
||||||
|
self.ema_model.state_dict(self.online_model.state_dict())
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.step += 1
|
self.step += 1
|
||||||
|
|
||||||
@@ -196,7 +199,7 @@ class EMA(nn.Module):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if not self.initted:
|
if not self.initted:
|
||||||
self.ema_model.state_dict(self.online_model.state_dict())
|
self.copy_params_from_model_to_ema()
|
||||||
self.initted.data.copy_(torch.Tensor([True]))
|
self.initted.data.copy_(torch.Tensor([True]))
|
||||||
|
|
||||||
self.update_moving_average(self.ema_model, self.online_model)
|
self.update_moving_average(self.ema_model, self.online_model)
|
||||||
@@ -278,17 +281,17 @@ class DiffusionPriorTrainer(nn.Module):
|
|||||||
|
|
||||||
self.step += 1
|
self.step += 1
|
||||||
|
|
||||||
@torch.inference_mode()
|
@torch.no_grad()
|
||||||
@cast_torch_tensor
|
@cast_torch_tensor
|
||||||
def p_sample_loop(self, *args, **kwargs):
|
def p_sample_loop(self, *args, **kwargs):
|
||||||
return self.ema_diffusion_prior.ema_model.p_sample_loop(*args, **kwargs)
|
return self.ema_diffusion_prior.ema_model.p_sample_loop(*args, **kwargs)
|
||||||
|
|
||||||
@torch.inference_mode()
|
@torch.no_grad()
|
||||||
@cast_torch_tensor
|
@cast_torch_tensor
|
||||||
def sample(self, *args, **kwargs):
|
def sample(self, *args, **kwargs):
|
||||||
return self.ema_diffusion_prior.ema_model.sample(*args, **kwargs)
|
return self.ema_diffusion_prior.ema_model.sample(*args, **kwargs)
|
||||||
|
|
||||||
@torch.inference_mode()
|
@torch.no_grad()
|
||||||
def sample_batch_size(self, *args, **kwargs):
|
def sample_batch_size(self, *args, **kwargs):
|
||||||
return self.ema_diffusion_prior.ema_model.sample_batch_size(*args, **kwargs)
|
return self.ema_diffusion_prior.ema_model.sample_batch_size(*args, **kwargs)
|
||||||
|
|
||||||
@@ -377,8 +380,11 @@ class DecoderTrainer(nn.Module):
|
|||||||
scaler = getattr(self, f'scaler{index}')
|
scaler = getattr(self, f'scaler{index}')
|
||||||
return scaler.scale(loss)
|
return scaler.scale(loss)
|
||||||
|
|
||||||
def update(self, unet_number):
|
def update(self, unet_number = None):
|
||||||
assert 1 <= unet_number <= self.num_unets
|
if self.num_unets == 1:
|
||||||
|
unet_number = default(unet_number, 1)
|
||||||
|
|
||||||
|
assert exists(unet_number) and 1 <= unet_number <= self.num_unets
|
||||||
index = unet_number - 1
|
index = unet_number - 1
|
||||||
unet = self.decoder.unets[index]
|
unet = self.decoder.unets[index]
|
||||||
|
|
||||||
@@ -402,6 +408,9 @@ class DecoderTrainer(nn.Module):
|
|||||||
@torch.no_grad()
|
@torch.no_grad()
|
||||||
@cast_torch_tensor
|
@cast_torch_tensor
|
||||||
def sample(self, *args, **kwargs):
|
def sample(self, *args, **kwargs):
|
||||||
|
if kwargs.pop('use_non_ema', False):
|
||||||
|
return self.decoder.sample(*args, **kwargs)
|
||||||
|
|
||||||
if self.use_ema:
|
if self.use_ema:
|
||||||
trainable_unets = self.decoder.unets
|
trainable_unets = self.decoder.unets
|
||||||
self.decoder.unets = self.unets # swap in exponential moving averaged unets for sampling
|
self.decoder.unets = self.unets # swap in exponential moving averaged unets for sampling
|
||||||
@@ -421,10 +430,13 @@ class DecoderTrainer(nn.Module):
|
|||||||
def forward(
|
def forward(
|
||||||
self,
|
self,
|
||||||
*args,
|
*args,
|
||||||
unet_number,
|
unet_number = None,
|
||||||
max_batch_size = None,
|
max_batch_size = None,
|
||||||
**kwargs
|
**kwargs
|
||||||
):
|
):
|
||||||
|
if self.num_unets == 1:
|
||||||
|
unet_number = default(unet_number, 1)
|
||||||
|
|
||||||
total_loss = 0.
|
total_loss = 0.
|
||||||
|
|
||||||
for chunk_size_frac, (chunked_args, chunked_kwargs) in split_args_and_kwargs(*args, split_size = max_batch_size, **kwargs):
|
for chunk_size_frac, (chunked_args, chunked_kwargs) in split_args_and_kwargs(*args, split_size = max_batch_size, **kwargs):
|
||||||
2
setup.py
2
setup.py
@@ -10,7 +10,7 @@ setup(
|
|||||||
'dream = dalle2_pytorch.cli:dream'
|
'dream = dalle2_pytorch.cli:dream'
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
version = '0.2.37',
|
version = '0.2.43',
|
||||||
license='MIT',
|
license='MIT',
|
||||||
description = 'DALL-E 2',
|
description = 'DALL-E 2',
|
||||||
author = 'Phil Wang',
|
author = 'Phil Wang',
|
||||||
|
|||||||
@@ -5,10 +5,13 @@ import time
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
|
import clip
|
||||||
from torch import nn
|
from torch import nn
|
||||||
|
|
||||||
from dalle2_pytorch import DiffusionPrior, DiffusionPriorNetwork
|
from dalle2_pytorch.dataloaders import make_splits
|
||||||
from dalle2_pytorch.train import DiffusionPriorTrainer, load_diffusion_model, save_diffusion_model, print_ribbon
|
from dalle2_pytorch import DiffusionPrior, DiffusionPriorNetwork, OpenAIClipAdapter
|
||||||
|
from dalle2_pytorch.trainer import DiffusionPriorTrainer, load_diffusion_model, save_diffusion_model, print_ribbon
|
||||||
|
|
||||||
from dalle2_pytorch.trackers import ConsoleTracker, WandbTracker
|
from dalle2_pytorch.trackers import ConsoleTracker, WandbTracker
|
||||||
|
|
||||||
from embedding_reader import EmbeddingReader
|
from embedding_reader import EmbeddingReader
|
||||||
@@ -17,8 +20,7 @@ from tqdm import tqdm
|
|||||||
|
|
||||||
# constants
|
# constants
|
||||||
|
|
||||||
NUM_TEST_EMBEDDINGS = 100 # for cosine similarity reporting during training
|
REPORT_METRICS_EVERY = 250 # for cosine similarity and other metric reporting during training
|
||||||
REPORT_METRICS_EVERY = 100 # for cosine similarity and other metric reporting during training
|
|
||||||
|
|
||||||
tracker = WandbTracker()
|
tracker = WandbTracker()
|
||||||
|
|
||||||
@@ -36,81 +38,106 @@ class Timer:
|
|||||||
|
|
||||||
def elapsed(self):
|
def elapsed(self):
|
||||||
return time.time() - self.last_time
|
return time.time() - self.last_time
|
||||||
|
|
||||||
# functions
|
# functions
|
||||||
|
|
||||||
def eval_model(model,device,image_reader,text_reader,start,end,batch_size,loss_type,phase="Validation"):
|
def eval_model(model, dataloader, text_conditioned, loss_type, phase="Validation"):
|
||||||
model.eval()
|
model.eval()
|
||||||
|
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
total_loss = 0.
|
total_loss = 0.
|
||||||
total_samples = 0.
|
total_samples = 0.
|
||||||
|
|
||||||
for emb_images, emb_text in zip(image_reader(batch_size=batch_size, start=start, end=end),
|
for image_embeddings, text_data in tqdm(dataloader):
|
||||||
text_reader(batch_size=batch_size, start=start, end=end)):
|
|
||||||
|
|
||||||
emb_images_tensor = torch.tensor(emb_images[0]).to(device)
|
batches = image_embeddings.shape[0]
|
||||||
emb_text_tensor = torch.tensor(emb_text[0]).to(device)
|
|
||||||
|
|
||||||
batches = emb_images_tensor.shape[0]
|
input_args = dict(image_embed=image_embeddings)
|
||||||
|
if text_conditioned:
|
||||||
|
input_args = dict(**input_args, text = text_data)
|
||||||
|
else:
|
||||||
|
input_args = dict(**input_args, text_embed=text_data)
|
||||||
|
|
||||||
loss = model(text_embed = emb_text_tensor, image_embed = emb_images_tensor)
|
loss = model(**input_args)
|
||||||
|
|
||||||
total_loss += loss.item() * batches
|
total_loss += loss * batches
|
||||||
total_samples += batches
|
total_samples += batches
|
||||||
|
|
||||||
avg_loss = (total_loss / total_samples)
|
avg_loss = (total_loss / total_samples)
|
||||||
|
|
||||||
tracker.log({f'{phase} {loss_type}': avg_loss})
|
tracker.log({f'{phase} {loss_type}': avg_loss})
|
||||||
|
|
||||||
def report_cosine_sims(diffusion_prior,image_reader,text_reader,train_set_size,NUM_TEST_EMBEDDINGS,device):
|
def report_cosine_sims(diffusion_prior, dataloader, text_conditioned):
|
||||||
diffusion_prior.eval()
|
diffusion_prior.eval()
|
||||||
|
|
||||||
cos = nn.CosineSimilarity(dim=1, eps=1e-6)
|
cos = nn.CosineSimilarity(dim=1, eps=1e-6)
|
||||||
|
|
||||||
tstart = train_set_size
|
for test_image_embeddings, text_data in tqdm(dataloader):
|
||||||
tend = train_set_size+NUM_TEST_EMBEDDINGS
|
|
||||||
|
# we are text conditioned, we produce an embedding from the tokenized text
|
||||||
|
if text_conditioned:
|
||||||
|
text_embedding, text_encodings, text_mask = diffusion_prior.clip.embed_text(
|
||||||
|
text_data)
|
||||||
|
text_cond = dict(text_embed=text_embedding,
|
||||||
|
text_encodings=text_encodings, mask=text_mask)
|
||||||
|
else:
|
||||||
|
text_embedding = text_data
|
||||||
|
text_cond = dict(text_embed=text_embedding)
|
||||||
|
|
||||||
|
# make a copy of the text embeddings for shuffling
|
||||||
|
text_embed_shuffled = text_embedding.clone()
|
||||||
|
|
||||||
|
# roll the text to simulate "unrelated" captions
|
||||||
|
rolled_idx = torch.roll(torch.arange(text_embedding.shape[0]), 1)
|
||||||
|
text_embed_shuffled = text_embed_shuffled[rolled_idx]
|
||||||
|
text_embed_shuffled = text_embed_shuffled / \
|
||||||
|
text_embed_shuffled.norm(dim=1, keepdim=True)
|
||||||
|
|
||||||
|
if text_conditioned:
|
||||||
|
text_encodings_shuffled = text_encodings[rolled_idx]
|
||||||
|
text_mask_shuffled = text_mask[rolled_idx]
|
||||||
|
else:
|
||||||
|
text_encodings_shuffled = None
|
||||||
|
text_mask_shuffled = None
|
||||||
|
|
||||||
|
text_cond_shuffled = dict(text_embed=text_embed_shuffled,
|
||||||
|
text_encodings=text_encodings_shuffled, mask=text_mask_shuffled)
|
||||||
|
|
||||||
for embt, embi in zip(text_reader(batch_size=NUM_TEST_EMBEDDINGS, start=tstart, end=tend),
|
|
||||||
image_reader(batch_size=NUM_TEST_EMBEDDINGS, start=tstart, end=tend)):
|
|
||||||
# make a copy of the text embeddings for shuffling
|
|
||||||
text_embed = torch.tensor(embt[0]).to(device)
|
|
||||||
text_embed_shuffled = text_embed.clone()
|
|
||||||
# roll the text embeddings to simulate "unrelated" captions
|
|
||||||
rolled_idx = torch.roll(torch.arange(NUM_TEST_EMBEDDINGS), 1)
|
|
||||||
text_embed_shuffled = text_embed_shuffled[rolled_idx]
|
|
||||||
text_embed_shuffled = text_embed_shuffled / \
|
|
||||||
text_embed_shuffled.norm(dim=1, keepdim=True)
|
|
||||||
test_text_shuffled_cond = dict(text_embed=text_embed_shuffled)
|
|
||||||
# prepare the text embedding
|
# prepare the text embedding
|
||||||
text_embed = text_embed / text_embed.norm(dim=1, keepdim=True)
|
text_embed = text_embedding / text_embedding.norm(dim=1, keepdim=True)
|
||||||
test_text_cond = dict(text_embed=text_embed)
|
|
||||||
# prepare image embeddings
|
# prepare image embeddings
|
||||||
test_image_embeddings = torch.tensor(embi[0]).to(device)
|
test_image_embeddings = test_image_embeddings / \
|
||||||
test_image_embeddings = test_image_embeddings / \
|
test_image_embeddings.norm(dim=1, keepdim=True)
|
||||||
test_image_embeddings.norm(dim=1, keepdim=True)
|
|
||||||
# predict on the unshuffled text embeddings
|
# predict on the unshuffled text embeddings
|
||||||
predicted_image_embeddings = diffusion_prior.p_sample_loop(
|
predicted_image_embeddings = diffusion_prior.p_sample_loop(
|
||||||
(NUM_TEST_EMBEDDINGS, 768), text_cond=test_text_cond)
|
test_image_embeddings.shape, text_cond)
|
||||||
predicted_image_embeddings = predicted_image_embeddings / \
|
predicted_image_embeddings = predicted_image_embeddings / \
|
||||||
predicted_image_embeddings.norm(dim=1, keepdim=True)
|
predicted_image_embeddings.norm(dim=1, keepdim=True)
|
||||||
|
|
||||||
# predict on the shuffled embeddings
|
# predict on the shuffled embeddings
|
||||||
predicted_unrelated_embeddings = diffusion_prior.p_sample_loop(
|
predicted_unrelated_embeddings = diffusion_prior.p_sample_loop(
|
||||||
(NUM_TEST_EMBEDDINGS, 768), text_cond=test_text_shuffled_cond)
|
test_image_embeddings.shape, text_cond_shuffled)
|
||||||
predicted_unrelated_embeddings = predicted_unrelated_embeddings / \
|
predicted_unrelated_embeddings = predicted_unrelated_embeddings / \
|
||||||
predicted_unrelated_embeddings.norm(dim=1, keepdim=True)
|
predicted_unrelated_embeddings.norm(dim=1, keepdim=True)
|
||||||
|
|
||||||
# calculate similarities
|
# calculate similarities
|
||||||
original_similarity = cos(
|
original_similarity = cos(
|
||||||
text_embed, test_image_embeddings).cpu().numpy()
|
text_embed, test_image_embeddings).cpu().numpy()
|
||||||
predicted_similarity = cos(
|
predicted_similarity = cos(
|
||||||
text_embed, predicted_image_embeddings).cpu().numpy()
|
text_embed, predicted_image_embeddings).cpu().numpy()
|
||||||
unrelated_similarity = cos(
|
unrelated_similarity = cos(
|
||||||
text_embed, predicted_unrelated_embeddings).cpu().numpy()
|
text_embed, predicted_unrelated_embeddings).cpu().numpy()
|
||||||
predicted_img_similarity = cos(
|
predicted_img_similarity = cos(
|
||||||
test_image_embeddings, predicted_image_embeddings).cpu().numpy()
|
test_image_embeddings, predicted_image_embeddings).cpu().numpy()
|
||||||
tracker.log({"CosineSimilarity(text_embed,image_embed)": np.mean(original_similarity),
|
tracker.log({"CosineSimilarity(text_embed,image_embed)": np.mean(original_similarity),
|
||||||
"CosineSimilarity(text_embed,predicted_image_embed)":np.mean(predicted_similarity),
|
"CosineSimilarity(text_embed,predicted_image_embed)":np.mean(predicted_similarity),
|
||||||
"CosineSimilarity(orig_image_embed,predicted_image_embed)":np.mean(predicted_img_similarity),
|
"CosineSimilarity(orig_image_embed,predicted_image_embed)":np.mean(predicted_img_similarity),
|
||||||
"CosineSimilarity(text_embed,predicted_unrelated_embed)": np.mean(unrelated_similarity),
|
"CosineSimilarity(text_embed,predicted_unrelated_embed)": np.mean(unrelated_similarity),
|
||||||
"Cosine similarity difference":np.mean(predicted_similarity - original_similarity)})
|
"Cosine similarity difference":np.mean(predicted_similarity - original_similarity)})
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--wandb-entity", default="laion")
|
@click.option("--wandb-entity", default="laion")
|
||||||
@click.option("--wandb-project", default="diffusion-prior")
|
@click.option("--wandb-project", default="diffusion-prior")
|
||||||
@@ -118,29 +145,32 @@ def report_cosine_sims(diffusion_prior,image_reader,text_reader,train_set_size,N
|
|||||||
@click.option("--wandb-arch", default="DiffusionPrior")
|
@click.option("--wandb-arch", default="DiffusionPrior")
|
||||||
@click.option("--image-embed-url", default="https://mystic.the-eye.eu/public/AI/cah/laion5b/embeddings/laion2B-en/img_emb/")
|
@click.option("--image-embed-url", default="https://mystic.the-eye.eu/public/AI/cah/laion5b/embeddings/laion2B-en/img_emb/")
|
||||||
@click.option("--text-embed-url", default="https://mystic.the-eye.eu/public/AI/cah/laion5b/embeddings/laion2B-en/text_emb/")
|
@click.option("--text-embed-url", default="https://mystic.the-eye.eu/public/AI/cah/laion5b/embeddings/laion2B-en/text_emb/")
|
||||||
|
@click.option("--meta-url", default="https://mystic.the-eye.eu/public/AI/cah/laion5b/embeddings/laion2B-en/laion2B-en-metadata/")
|
||||||
@click.option("--learning-rate", default=1.1e-4)
|
@click.option("--learning-rate", default=1.1e-4)
|
||||||
@click.option("--weight-decay", default=6.02e-2)
|
@click.option("--weight-decay", default=6.02e-2)
|
||||||
@click.option("--dropout", default=5e-2)
|
@click.option("--dropout", default=5e-2)
|
||||||
@click.option("--max-grad-norm", default=0.5)
|
@click.option("--max-grad-norm", default=0.5)
|
||||||
@click.option("--batch-size", default=10**4)
|
@click.option("--num-data-points", default=250e6)
|
||||||
|
@click.option("--batch-size", default=320)
|
||||||
@click.option("--num-epochs", default=5)
|
@click.option("--num-epochs", default=5)
|
||||||
@click.option("--image-embed-dim", default=768)
|
@click.option("--image-embed-dim", default=768)
|
||||||
@click.option("--train-percent", default=0.7)
|
@click.option("--train-percent", default=0.9)
|
||||||
@click.option("--val-percent", default=0.2)
|
@click.option("--val-percent", default=1e-7)
|
||||||
@click.option("--test-percent", default=0.1)
|
@click.option("--test-percent", default=0.0999999)
|
||||||
@click.option("--dpn-depth", default=6)
|
@click.option("--dpn-depth", default=12)
|
||||||
@click.option("--dpn-dim-head", default=64)
|
@click.option("--dpn-dim-head", default=64)
|
||||||
@click.option("--dpn-heads", default=8)
|
@click.option("--dpn-heads", default=12)
|
||||||
@click.option("--dp-condition-on-text-encodings", default=False)
|
@click.option("--dp-condition-on-text-encodings", default=True)
|
||||||
@click.option("--dp-timesteps", default=100)
|
@click.option("--dp-timesteps", default=1000)
|
||||||
@click.option("--dp-normformer", default=False)
|
@click.option("--dp-normformer", default=True)
|
||||||
@click.option("--dp-cond-drop-prob", default=0.1)
|
@click.option("--dp-cond-drop-prob", default=0.1)
|
||||||
@click.option("--dp-loss-type", default="l2")
|
@click.option("--dp-loss-type", default="l2")
|
||||||
@click.option("--clip", default=None)
|
@click.option("--clip", default="ViT-L/14")
|
||||||
@click.option("--amp", default=False)
|
@click.option("--amp", default=False)
|
||||||
@click.option("--save-interval", default=30)
|
@click.option("--save-interval", default=120)
|
||||||
@click.option("--save-path", default="./diffusion_prior_checkpoints")
|
@click.option("--save-path", default="./diffusion_prior_checkpoints")
|
||||||
@click.option("--pretrained-model-path", default=None)
|
@click.option("--pretrained-model-path", default=None)
|
||||||
|
@click.option("--gpu-device", default=0)
|
||||||
def train(
|
def train(
|
||||||
wandb_entity,
|
wandb_entity,
|
||||||
wandb_project,
|
wandb_project,
|
||||||
@@ -148,10 +178,12 @@ def train(
|
|||||||
wandb_arch,
|
wandb_arch,
|
||||||
image_embed_url,
|
image_embed_url,
|
||||||
text_embed_url,
|
text_embed_url,
|
||||||
|
meta_url,
|
||||||
learning_rate,
|
learning_rate,
|
||||||
weight_decay,
|
weight_decay,
|
||||||
dropout,
|
dropout,
|
||||||
max_grad_norm,
|
max_grad_norm,
|
||||||
|
num_data_points,
|
||||||
batch_size,
|
batch_size,
|
||||||
num_epochs,
|
num_epochs,
|
||||||
image_embed_dim,
|
image_embed_dim,
|
||||||
@@ -170,7 +202,8 @@ def train(
|
|||||||
amp,
|
amp,
|
||||||
save_interval,
|
save_interval,
|
||||||
save_path,
|
save_path,
|
||||||
pretrained_model_path
|
pretrained_model_path,
|
||||||
|
gpu_device
|
||||||
):
|
):
|
||||||
config = {
|
config = {
|
||||||
"learning_rate": learning_rate,
|
"learning_rate": learning_rate,
|
||||||
@@ -197,7 +230,7 @@ def train(
|
|||||||
|
|
||||||
# Check if DPRIOR_PATH exists(saved model path)
|
# Check if DPRIOR_PATH exists(saved model path)
|
||||||
|
|
||||||
DPRIOR_PATH = args.pretrained_model_path
|
DPRIOR_PATH = pretrained_model_path
|
||||||
RESUME = exists(DPRIOR_PATH)
|
RESUME = exists(DPRIOR_PATH)
|
||||||
|
|
||||||
if not RESUME:
|
if not RESUME:
|
||||||
@@ -211,7 +244,7 @@ def train(
|
|||||||
|
|
||||||
has_cuda = torch.cuda.is_available()
|
has_cuda = torch.cuda.is_available()
|
||||||
if has_cuda:
|
if has_cuda:
|
||||||
device = torch.device("cuda:0")
|
device = torch.device(f"cuda:{gpu_device}")
|
||||||
torch.cuda.set_device(device)
|
torch.cuda.set_device(device)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
@@ -227,11 +260,17 @@ def train(
|
|||||||
normformer = dp_normformer
|
normformer = dp_normformer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Load clip model if text-conditioning
|
||||||
|
if dp_condition_on_text_encodings:
|
||||||
|
clip_adapter = OpenAIClipAdapter(clip)
|
||||||
|
else:
|
||||||
|
clip_adapter = None
|
||||||
|
|
||||||
# diffusion prior with text embeddings and image embeddings pre-computed
|
# diffusion prior with text embeddings and image embeddings pre-computed
|
||||||
|
|
||||||
diffusion_prior = DiffusionPrior(
|
diffusion_prior = DiffusionPrior(
|
||||||
net = prior_network,
|
net = prior_network,
|
||||||
clip = clip,
|
clip = clip_adapter,
|
||||||
image_embed_dim = image_embed_dim,
|
image_embed_dim = image_embed_dim,
|
||||||
timesteps = dp_timesteps,
|
timesteps = dp_timesteps,
|
||||||
cond_drop_prob = dp_cond_drop_prob,
|
cond_drop_prob = dp_cond_drop_prob,
|
||||||
@@ -265,33 +304,37 @@ def train(
|
|||||||
|
|
||||||
Path(save_path).mkdir(exist_ok = True, parents = True)
|
Path(save_path).mkdir(exist_ok = True, parents = True)
|
||||||
|
|
||||||
# Get image and text embeddings from the servers
|
# Utilize wrapper to abstract away loader logic
|
||||||
|
print_ribbon("Downloading Embeddings")
|
||||||
|
loader_args = dict(text_conditioned=dp_condition_on_text_encodings, batch_size=batch_size, num_data_points=num_data_points,
|
||||||
|
train_split=train_percent, eval_split=val_percent, device=device, img_url=image_embed_url)
|
||||||
|
|
||||||
print_ribbon("Downloading embeddings - image and text")
|
if dp_condition_on_text_encodings:
|
||||||
image_reader = EmbeddingReader(embeddings_folder=image_embed_url, file_format="npy")
|
loader_args = dict(**loader_args, meta_url=meta_url)
|
||||||
text_reader = EmbeddingReader(embeddings_folder=text_embed_url, file_format="npy")
|
else:
|
||||||
num_data_points = text_reader.count
|
loader_args = dict(**loader_args, txt_url=text_embed_url)
|
||||||
|
|
||||||
|
train_loader, eval_loader, test_loader = make_splits(**loader_args)
|
||||||
|
|
||||||
### Training code ###
|
### Training code ###
|
||||||
|
|
||||||
|
step = 1
|
||||||
timer = Timer()
|
timer = Timer()
|
||||||
epochs = num_epochs
|
epochs = num_epochs
|
||||||
|
|
||||||
train_set_size = int(train_percent*num_data_points)
|
|
||||||
val_set_size = int(val_percent*num_data_points)
|
|
||||||
eval_start = train_set_size
|
|
||||||
|
|
||||||
for _ in range(epochs):
|
for _ in range(epochs):
|
||||||
|
|
||||||
for emb_images,emb_text in zip(image_reader(batch_size=batch_size, start=0, end=train_set_size),
|
for image, text in tqdm(train_loader):
|
||||||
text_reader(batch_size=batch_size, start=0, end=train_set_size)):
|
|
||||||
|
|
||||||
trainer.train()
|
|
||||||
|
|
||||||
emb_images_tensor = torch.tensor(emb_images[0]).to(device)
|
diffusion_prior.train()
|
||||||
emb_text_tensor = torch.tensor(emb_text[0]).to(device)
|
|
||||||
|
input_args = dict(image_embed=image)
|
||||||
|
if dp_condition_on_text_encodings:
|
||||||
|
input_args = dict(**input_args, text = text)
|
||||||
|
else:
|
||||||
|
input_args = dict(**input_args, text_embed=text)
|
||||||
|
|
||||||
loss = trainer(text_embed = emb_text_tensor, image_embed = emb_images_tensor)
|
loss = trainer(**input_args)
|
||||||
|
|
||||||
# Samples per second
|
# Samples per second
|
||||||
|
|
||||||
@@ -310,37 +353,23 @@ def train(
|
|||||||
image_embed_dim)
|
image_embed_dim)
|
||||||
|
|
||||||
# Log to wandb
|
# Log to wandb
|
||||||
tracker.log({"Training loss": loss.item(),
|
tracker.log({"Training loss": loss,
|
||||||
"Steps": step,
|
"Steps": step,
|
||||||
"Samples per second": samples_per_sec})
|
"Samples per second": samples_per_sec})
|
||||||
# Log cosineSim(text_embed,predicted_image_embed) - cosineSim(text_embed,image_embed)
|
# Log cosineSim(text_embed,predicted_image_embed) - cosineSim(text_embed,image_embed)
|
||||||
# Use NUM_TEST_EMBEDDINGS samples from the test set each time
|
# Use NUM_TEST_EMBEDDINGS samples from the test set each time
|
||||||
# Get embeddings from the most recently saved model
|
# Get embeddings from the most recently saved model
|
||||||
if(step % REPORT_METRICS_EVERY) == 0:
|
if(step % REPORT_METRICS_EVERY) == 0:
|
||||||
report_cosine_sims(diffusion_prior,
|
report_cosine_sims(diffusion_prior, eval_loader, dp_condition_on_text_encodings)
|
||||||
image_reader,
|
|
||||||
text_reader,
|
|
||||||
train_set_size,
|
|
||||||
NUM_TEST_EMBEDDINGS,
|
|
||||||
device)
|
|
||||||
### Evaluate model(validation run) ###
|
### Evaluate model(validation run) ###
|
||||||
eval_model(diffusion_prior,
|
eval_model(diffusion_prior, eval_loader, dp_condition_on_text_encodings, dp_loss_type, phase="Validation")
|
||||||
device,
|
|
||||||
image_reader,
|
|
||||||
text_reader,
|
|
||||||
eval_start,
|
|
||||||
eval_start+NUM_TEST_EMBEDDINGS,
|
|
||||||
NUM_TEST_EMBEDDINGS,
|
|
||||||
dp_loss_type,
|
|
||||||
phase="Validation")
|
|
||||||
|
|
||||||
|
step += 1
|
||||||
trainer.update()
|
trainer.update()
|
||||||
|
|
||||||
### Test run ###
|
### Test run ###
|
||||||
test_set_size = int(test_percent*train_set_size)
|
eval_model(diffusion_prior, test_loader, dp_condition_on_text_encodings, dp_loss_type, phase="Test")
|
||||||
start = train_set_size+val_set_size
|
|
||||||
end = num_data_points
|
|
||||||
eval_model(diffusion_prior,device,image_reader,text_reader,start,end,batch_size,dp_loss_type,phase="Test")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
train()
|
train()
|
||||||
|
|||||||
Reference in New Issue
Block a user