diff --git a/cvae_pyramid.py b/cvae_pyramid.py index a52dbe5..28f792e 100644 --- a/cvae_pyramid.py +++ b/cvae_pyramid.py @@ -1,5 +1,5 @@ import os -os.environ["CUDA_VISIBLE_DEVICES"] = "1" +os.environ["CUDA_VISIBLE_DEVICES"] = "2" import tensorflow as tf gpus = tf.config.experimental.list_physical_devices('GPU') @@ -37,7 +37,7 @@ from custom_utils.smpl import SMPL from models.cvae_pyramid_model import Pyramid -name='cvae_pyr_1' +name='cvae_pyr_1_d128' def init_wandb(): run = wandb.init(project='vae', name=name, notes='learn offsets. smaller flattened latent vectors. with 25-85k pretraining. smaller batchsize. fixed balancing of reconst and kl loss for baseline. \ @@ -48,7 +48,7 @@ use mean l2 loss. small batch. l2 * 1000, balancing to 1 from 0.01\ fixed gender issue and retrained body encoder\ remove shape from unposed garment\ training on 100 garments with offsets over the average of these\ -l2 loss on both 32 and full res, bottom predicts base, high res predicts offsets over this') +l2 loss on both 128 and full res, bottom predicts base, high res predicts offsets over this') artifact = wandb.Artifact('code', type='code') artifact.add_file('cvae_pyramid.py') artifact.add_file('models/cvae_model.py') @@ -60,9 +60,9 @@ l2 loss on both 32 and full res, bottom predicts base, high res predicts offsets uv2mesh = UV2Mesh(res=256) -def plot_3d(mesh_gt, mesh_pred_unposed, mesh_pred_unposed_32, faces, collision, collision_faces, collision_color): +def plot_3d(mesh_gt, mesh_pred_unposed, mesh_pred_unposed_low, faces, collision, collision_faces, collision_color): mesh_pred_unposed[:,2] += 1 - mesh_pred_unposed_32[:,2] += 2 + mesh_pred_unposed_low[:,2] += 2 collision[:,2] += 3 fig = go.Figure(data=[ go.Mesh3d( @@ -82,9 +82,9 @@ def plot_3d(mesh_gt, mesh_pred_unposed, mesh_pred_unposed_32, faces, collision, k = faces[:,2], ), go.Mesh3d( - x=mesh_pred_unposed_32[:,0], - y=mesh_pred_unposed_32[:,2], - z=mesh_pred_unposed_32[:,1], + x=mesh_pred_unposed_low[:,0], + y=mesh_pred_unposed_low[:,2], + z=mesh_pred_unposed_low[:,1], i = faces[:,0], j = faces[:,1], k = faces[:,2], @@ -132,22 +132,22 @@ def train_step(batch): with tf.GradientTape() as tape: uv_curvature = tf.one_hot(batch['uv_curvature'], 7) - uv_curvature_32 = tf.one_hot(batch['uv_curvature_32'], 7) + uv_curvature_low = tf.one_hot(batch['uv_curvature' + resolution_modifier], 7) - pred_full, mean_full, logvar_full, pred_32, mean_32, logvar_32, = model([batch['uv_unposed'], batch['uv_static'], batch['uv_body_posed'], uv_curvature, - batch['uv_unposed_32'], batch['uv_static_32'], batch['uv_body_posed_32'], uv_curvature_32]) + pred_full, mean_full, logvar_full, pred_low, mean_low, logvar_low, = model([batch['uv_unposed'], batch['uv_static'], batch['uv_body_posed'], uv_curvature, + batch['uv_unposed' + resolution_modifier], batch['uv_static' + resolution_modifier], batch['uv_body_posed' + resolution_modifier], uv_curvature_low]) mesh_pred_full = uv2mesh(pred_full) mesh_pred_posed_full = smpl.run_garment(batch['pose_shape'][:, :72], batch['pose_shape'][:, 72:], mesh_pred_full) - mesh_pred_32 = uv2mesh(pred_32) - mesh_pred_posed_32 = smpl.run_garment(batch['pose_shape'][:, :72], batch['pose_shape'][:, 72:], mesh_pred_32) + mesh_pred_low = uv2mesh(pred_low) + mesh_pred_posed_low = smpl.run_garment(batch['pose_shape'][:, :72], batch['pose_shape'][:, 72:], mesh_pred_low) mesh_orig = batch['mesh_unposed'] shape = batch['pose_shape'][:, 72:] gender = tf.cast(tf.greater_equal(shape[:, 10] , 0.5), tf.int32) shape_offsets = tf.stack([tf.gather(tf.tensordot(shape[i,:10][tf.newaxis, :], smpl.shapedirs[gender[i]], axes=[[1], [2]])[0,:,:], smpl.to_keep, axis=0) for i in range(shape.shape[0])]) mesh_pred_posed_full = mesh_pred_posed_full + shape_offsets * batch['mesh_mask'][:,:,tf.newaxis] - mesh_pred_posed_32 = mesh_pred_posed_32 + shape_offsets * batch['mesh_mask'][:,:,tf.newaxis] + mesh_pred_posed_low = mesh_pred_posed_low + shape_offsets * batch['mesh_mask'][:,:,tf.newaxis] e_loss = tf.reduce_mean(edge_loss(mesh_pred_full, mesh_orig, batch['mesh_mask'])) c_loss = tf.reduce_mean(collision_penalty(mesh_pred_posed_full, batch['mesh_body_posed'], batch['mesh_mask'])) @@ -156,16 +156,16 @@ def train_step(batch): ms_ssim = tf.image.ssim_multiscale(pred_full + 1, tf.transpose(batch['uv_unposed'], [0,2,3,1]) + 1, max_val=3) kl = kl_loss(mean_full, logvar_full) - e_loss_32 = tf.reduce_mean(edge_loss(mesh_pred_32, mesh_orig, batch['mesh_mask'])) - c_loss_32 = tf.reduce_mean(collision_penalty(mesh_pred_posed_32, batch['mesh_body_posed'], batch['mesh_mask'])) - l1_loss_32 = tf.reduce_sum(tf.reduce_sum((tf.math.abs(tf.transpose(batch['uv_unposed_32'], [0,2,3,1]) - pred_32)), axis=-1), axis=[1, 2]) - l2_loss_32 = 1e3 * tf.reduce_mean(tf.reduce_sum(((tf.transpose(batch['uv_unposed_32'], [0,2,3,1]) - pred_32) ** 2), axis=-1), axis=[1, 2]) - ms_ssim_32 = tf.image.ssim(pred_32 + 1, tf.transpose(batch['uv_unposed_32'], [0,2,3,1]) + 1, max_val=3) - kl_32 = kl_loss(mean_full, logvar_full) + e_loss_low = tf.reduce_mean(edge_loss(mesh_pred_low, mesh_orig, batch['mesh_mask'])) + c_loss_low = tf.reduce_mean(collision_penalty(mesh_pred_posed_low, batch['mesh_body_posed'], batch['mesh_mask'])) + l1_loss_low = tf.reduce_sum(tf.reduce_sum((tf.math.abs(tf.transpose(batch['uv_unposed' + resolution_modifier], [0,2,3,1]) - pred_low)), axis=-1), axis=[1, 2]) + l2_loss_low = 1e3 * tf.reduce_mean(tf.reduce_sum(((tf.transpose(batch['uv_unposed' + resolution_modifier], [0,2,3,1]) - pred_low) ** 2), axis=-1), axis=[1, 2]) + ms_ssim_low = tf.image.ssim(pred_low + 1, tf.transpose(batch['uv_unposed' + resolution_modifier], [0,2,3,1]) + 1, max_val=3) + kl_low = kl_loss(mean_full, logvar_full) - reconstr_loss = l2_loss + l2_loss_32 + reconstr_loss = l2_loss + l2_loss_low reconstr_loss = tf.reduce_mean(reconstr_loss) - loss = reconstr_loss + balancing_coeff * (kl + kl_32) + loss = reconstr_loss + balancing_coeff * (kl + kl_low) ms_ssim = tf.reduce_mean(ms_ssim) l1_loss = tf.reduce_mean(l1_loss) @@ -173,25 +173,24 @@ def train_step(batch): mean = tf.reduce_mean(mean_full) logvar = tf.reduce_mean(logvar_full) - ms_ssim_32 = tf.reduce_mean(ms_ssim_32) - l1_loss_32 = tf.reduce_mean(l1_loss_32) - l2_loss_32 = tf.reduce_mean(l2_loss_32) - mean_32 = tf.reduce_mean(mean_32) - logvar_32 = tf.reduce_mean(logvar_32) + ms_ssim_low = tf.reduce_mean(ms_ssim_low) + l1_loss_low = tf.reduce_mean(l1_loss_low) + l2_loss_low = tf.reduce_mean(l2_loss_low) + mean_low = tf.reduce_mean(mean_low) + logvar_low = tf.reduce_mean(logvar_low) mesh_orig_2 = uv2mesh(batch['uv_unposed']) metric = tf.reduce_sum(tf.math.sqrt(tf.reduce_sum(batch['mesh_mask'][:,:,tf.newaxis] * (mesh_orig - mesh_pred_full) ** 2, axis=-1))) / tf.reduce_sum(batch['mesh_mask']) - metric_32 = tf.reduce_sum(tf.math.sqrt(tf.reduce_sum(batch['mesh_mask'][:,:,tf.newaxis] * (mesh_orig - mesh_pred_32) ** 2, axis=-1))) / tf.reduce_sum(batch['mesh_mask']) + metric_low = tf.reduce_sum(tf.math.sqrt(tf.reduce_sum(batch['mesh_mask'][:,:,tf.newaxis] * (mesh_orig - mesh_pred_low) ** 2, axis=-1))) / tf.reduce_sum(batch['mesh_mask']) metric_2 = tf.reduce_sum(tf.math.sqrt(tf.reduce_sum(batch['mesh_mask'][:,:,tf.newaxis] * (mesh_orig_2 - mesh_pred_full) ** 2, axis=-1))) / tf.reduce_sum(batch['mesh_mask']) gradients = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables)) return { 'train/loss': loss, 'train/edge_loss': e_loss, 'train/collision_loss': c_loss, 'train/l1_loss': l1_loss, 'train/euclid_error': metric, 'train/ms_ssim': ms_ssim, 'train/euclid_error_reconst': metric_2, 'train/reconstr_loss': reconstr_loss, 'train/mean': mean, 'train/logvar': logvar, 'train/kl_loss': kl, 'train/var': np.e ** logvar, 'train/reg_coeff': reg_coeff, 'train/l2_loss': l2_loss, - 'train/edge_loss_32': e_loss_32, 'train/collision_loss_32': c_loss_32, 'train/l1_loss_32': l1_loss_32, 'train/euclid_error_32': metric_32, 'train/ms_ssim_32': ms_ssim_32, - 'train/mean_32': mean_32, 'train/logvar_32': logvar_32, 'train/kl_loss_32': kl_32, - 'train/var_32': np.e ** logvar_32, 'train/l2_loss_32': l2_loss_32 } - + 'train/edge_loss' + resolution_modifier: e_loss_low, 'train/collision_loss' + resolution_modifier: c_loss_low, 'train/l1_loss' + resolution_modifier: l1_loss_low, 'train/euclid_error' + resolution_modifier: metric_low, 'train/ms_ssim' + resolution_modifier: ms_ssim_low, + 'train/mean' + resolution_modifier: mean_low, 'train/logvar' + resolution_modifier: logvar_low, 'train/kl_loss' + resolution_modifier: kl_low, + 'train/var' + resolution_modifier: np.e ** logvar_low, 'train/l2_loss' + resolution_modifier: l2_loss_low } @tf.function @@ -235,26 +234,26 @@ def valid_step(batch): def plot_everything(batch: dict, type: str): uv_curvature = tf.one_hot(batch['uv_curvature'], 7) - uv_curvature_32 = tf.one_hot(batch['uv_curvature_32'], 7) - pred_full, mean_full, logvar_full, pred_32, mean_32, logvar_32, = model([batch['uv_unposed'], batch['uv_static'], batch['uv_body_posed'], uv_curvature, - batch['uv_unposed_32'], batch['uv_static_32'], batch['uv_body_posed_32'], uv_curvature_32]) + uv_curvature_low = tf.one_hot(batch['uv_curvature' + resolution_modifier], 7) + pred_full, mean_full, logvar_full, pred_low, mean_low, logvar_low, = model([batch['uv_unposed'], batch['uv_static'], batch['uv_body_posed'], uv_curvature, + batch['uv_unposed' + resolution_modifier], batch['uv_static' + resolution_modifier], batch['uv_body_posed' + resolution_modifier], uv_curvature_low]) mesh_pred_full = uv2mesh(pred_full) - mesh_pred_32 = uv2mesh(pred_32) + mesh_pred_low = uv2mesh(pred_low) mesh_orig = batch['mesh_unposed'] orig_img = tf.transpose(batch['uv_unposed'], [0,2,3,1]) uv_static_img = tf.transpose(batch['uv_static'], [0,2,3,1]) uv_body_posed_img = tf.transpose(batch['uv_body_posed'], [0,2,3,1]) pred_img = pred_full - pred_32_up = tf.image.resize(pred_32, (512, 256), tf.image.ResizeMethod.LANCZOS5) - img = tf.concat((uv_static_img, uv_body_posed_img, orig_img, pred_img, pred_32_up), axis=2) + pred_low_up = tf.image.resize(pred_low, (512, 256), tf.image.ResizeMethod.LANCZOS5) + img = tf.concat((uv_static_img, uv_body_posed_img, orig_img, pred_img, pred_low_up), axis=2) imgs = [wandb.Image((img[i] + 1) / 2.0) for i in range(4)] F = np.load("custom_utils/smpl_faces.npy") mask = batch['mesh_mask'].numpy().astype(bool) garment_unposed, faces = maskFacesBatch(mesh_pred_full.numpy(), F, mask) - garment_unposed_32, faces = maskFacesBatch(mesh_pred_32.numpy(), F, mask) + garment_unposed_low, faces = maskFacesBatch(mesh_pred_low.numpy(), F, mask) gt = [mesh_orig[i].numpy()[mask[i], :] for i in range(pred_full.shape[0])] body = batch['mesh_body_posed'].numpy() @@ -269,7 +268,7 @@ def plot_everything(batch: dict, type: str): collision_faces = [np.concatenate((F, faces[i] + 14475), axis=0) for i in range(len(garment_posed))] collision_color = [np.concatenate((np.ones_like(body[i], dtype=np.int32)*100, np.ones_like(garment_posed[i], dtype=np.int32)*230), axis=0) for i in range(len(garment_posed))] - figs = { type + "/garment_" + str(i): plot_3d(gt[i], garment_unposed[i], garment_unposed_32[i], faces[i], collision[i], collision_faces[i], collision_color[i]) for i in range(4) } + figs = { type + "/garment_" + str(i): plot_3d(gt[i], garment_unposed[i], garment_unposed_low[i], faces[i], collision[i], collision_faces[i], collision_color[i]) for i in range(4) } mean_hist = wandb.Histogram(sequence=mean_full.numpy().mean(axis=0)) logvar_hist = wandb.Histogram(sequence=logvar_full.numpy().mean(axis=0)) @@ -277,8 +276,6 @@ def plot_everything(batch: dict, type: str): return { **figs, **{ type + '/images': imgs, type + '/mean_hist': mean_hist, type + '/logvar_hist': logvar_hist } } - - def sample(folder): # run = wandb.init(project='vae_plots', name=folder.split('/')[-1]) load_model(model,folder) @@ -400,6 +397,7 @@ def sample(folder): print() + if __name__ == '__main__': init_wandb() allow_memory_growth() @@ -408,6 +406,8 @@ if __name__ == '__main__': args = vars(parser.parse_args()) batch_size = 4 + low_resolution = 128 + resolution_modifier = '_' + str(low_resolution) smpl = SMPL() @@ -416,31 +416,30 @@ if __name__ == '__main__': 'pose_shape': (72 + 11,), # 'uv_posed': (3, 512, 256,), 'uv_body_posed': (3, 512, 256,), - 'uv_body_posed_32': (3, 32, 16,), + 'uv_body_posed' + resolution_modifier: (3, low_resolution, low_resolution//2,), 'mesh_body_posed': (14475, 3,), 'mesh_posed': (14475, 3,), 'mesh_unposed': (14475, 3,), 'uv_unposed': (3, 512, 256,), - 'uv_unposed_32': (3, 32, 16,), + 'uv_unposed' + resolution_modifier: (3, low_resolution, low_resolution//2,), 'uv_curvature': (512, 256), - 'uv_curvature_32': (32, 16), + 'uv_curvature' + resolution_modifier: (low_resolution, low_resolution//2), } signature_static = { 'uv_static': (3, 512, 256,), - 'uv_static_32': (3, 32, 16,), + 'uv_static' + resolution_modifier: (3, low_resolution, low_resolution//2,), # 'mesh_static': (14475, 3,), 'mesh_mask': (14475,), 'uv_mask': (512, 256,), - 'uv_shaped_body': (3, 512, 256,), + # 'uv_shaped_body': (3, 512, 256,), } - dataset_train = factory.get_dataset(folder='/home/workspace/local-data/train_100', batch_size=batch_size, signature=signature_dynamic, use_filled=True, resolutions=[512, 32]) - static_dataset_train = StaticDataset(folder='/home/workspace/local-data/train_100', signature=signature_static, use_filled=True, resolutions=[512, 32]) + dataset_train = factory.get_dataset(folder='/home/workspace/local-data/train_100', batch_size=batch_size, signature=signature_dynamic, use_filled=True, resolutions=[512, low_resolution]) + static_dataset_train = StaticDataset(folder='/home/workspace/local-data/train_100', signature=signature_static, use_filled=True, resolutions=[512, low_resolution]) dataset_valid = factory.get_dataset(folder='/home/workspace/local-data/jumpsuit_20/valid', batch_size=batch_size, signature=signature_dynamic) static_dataset_valid = StaticDataset(folder='/home/workspace/local-data/jumpsuit_20/valid', signature=signature_static) - model = Pyramid(latent_dim=128) - + model = Pyramid(latent_dim=128, low_res=low_resolution) # lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(0.0001, decay_steps=30000, decay_rate=0.1, staircase=False) optimizer = tf.optimizers.Adam(learning_rate=0.0001) diff --git a/dataset.py b/dataset.py index e8559b9..38f665a 100644 --- a/dataset.py +++ b/dataset.py @@ -61,6 +61,8 @@ class StaticDataset(): assert set(resolutions).issubset(set([32, 128, 512])) self.possible_keys = ['uv_static', 'uv_static_32', 'uv_static_128' 'mesh_static', 'mesh_mask', 'uv_mask', 'uv_shaped_body'] self.keys = [value for value in signature.keys() if value in self.possible_keys] + if 'uv_static_128' in signature.keys(): + self.keys.append('uv_static_128') self.resolutions = resolutions self.filled = '' if use_filled: diff --git a/models/ae_curv_model.py b/models/ae_curv_model.py index 242b4de..ebb7f5f 100644 --- a/models/ae_curv_model.py +++ b/models/ae_curv_model.py @@ -128,3 +128,54 @@ class AutoEncoder32(tf.keras.Model): # x = x * uv_mask[:,:,:,tf.newaxis] return x + + + +class Decoder128(tf.keras.Model): + + def __init__(self, bottleneck_size, latent_dim): + super(Decoder128, self).__init__() + + self.dense = tf.keras.layers.Dense(4 * 2 * bottleneck_size) + self.reshape = tf.keras.layers.Reshape((4, 2, bottleneck_size)) + self.decoder = ConvNeXtReverseLabels(depths=list(reversed([16, 16, 9, 9])), dims=list(reversed([bottleneck_size, 256, 128, 64])), nr_of_classes=7) + + def call(self, inputs, training=None): + x = inputs + + x = self.dense(x) + x = self.reshape(x) + x = self.decoder(x) + + return x + + +class AutoEncoder128(tf.keras.Model): + + def __init__(self): + super(AutoEncoder128, self).__init__() + + bottleneck_size = 512 + latent_dim = 128 + + self.encoder = ConvNeXt(depths=[16, 16, 9, 9], dims=[64, 128, 256, bottleneck_size], include_top=False) + self.bottleneck = Bottleneck(bottleneck_size, latent_dim) + self.decoder = Decoder128(bottleneck_size, latent_dim) + + + def call(self, inputs, training=None): + x, uv_mask = inputs + + # x = tf.transpose(x, [0,2,3,1]) + x = self.encoder(x, training=training) + + x = self.bottleneck(x, training=training) + + x = self.decoder(x, training=training) + # x = tf.transpose(x, [0,3,1,2]) + + # x = x * uv_mask[:,:, tf.newaxis] + # x = x * uv_mask[:,tf.newaxis,:,:] + # x = x * uv_mask[:,:,:,tf.newaxis] + + return x diff --git a/models/ae_static_model.py b/models/ae_static_model.py index a0a269e..bcdf98c 100644 --- a/models/ae_static_model.py +++ b/models/ae_static_model.py @@ -121,3 +121,52 @@ class AutoEncoder32(tf.keras.Model): # x = x * uv_mask[:,tf.newaxis,:,:] return x + + +class Decoder128(tf.keras.Model): + + def __init__(self, bottleneck_size, latent_dim): + super(Decoder128, self).__init__() + + self.dense = tf.keras.layers.Dense(4 * 2 * bottleneck_size) + self.reshape = tf.keras.layers.Reshape((4, 2, bottleneck_size)) + self.decoder = ConvNeXtReverse(depths=list(reversed([16, 16, 9, 9])), dims=list(reversed([bottleneck_size, 256, 128, 64]))) + + def call(self, inputs, training=None): + x = inputs + + x = self.dense(x) + x = self.reshape(x) + x = self.decoder(x) + + return x + + +class AutoEncoder128(tf.keras.Model): + + def __init__(self): + super(AutoEncoder128, self).__init__() + + + bottleneck_size = 512 + latent_dim = 128 + + self.encoder = ConvNeXt(depths=[16, 16, 9, 9], dims=[64, 128, 256, bottleneck_size], include_top=False) + self.bottleneck = Bottleneck(bottleneck_size, latent_dim) + self.decoder = Decoder128(bottleneck_size, latent_dim) + + def call(self, inputs, training=None): + x = inputs + + x = tf.transpose(x, [0,2,3,1]) + x = self.encoder(x, training=training) + + x = self.bottleneck(x, training=training) + + x = self.decoder(x, training=training) + x = tf.transpose(x, [0,3,1,2]) + + # x = x * uv_mask[:,:, tf.newaxis] + # x = x * uv_mask[:,tf.newaxis,:,:] + + return x \ No newline at end of file diff --git a/models/cvae_model.py b/models/cvae_model.py index 1246e51..d9241bb 100644 --- a/models/cvae_model.py +++ b/models/cvae_model.py @@ -15,6 +15,10 @@ from models.ae_static_model import AutoEncoder as StaticAE from models.ae_body_model import AutoEncoder32 as BodyAE32 from models.ae_curv_model import AutoEncoder32 as CurvatureAE32 from models.ae_static_model import AutoEncoder32 as StaticAE32 +from models.ae_body_model import AutoEncoder128 as BodyAE128 +from models.ae_curv_model import AutoEncoder128 as CurvatureAE128 +from models.ae_static_model import AutoEncoder128 as StaticAE128 + class Bottleneck(tf.keras.Model): @@ -339,6 +343,177 @@ class CVAE32(tf.keras.Model): return logits + def call(self, inputs, training=None, zero_latent=False): + uv_unposed, uv_template, uv_body_posed, uv_curv = inputs + uv_unposed, uv_template, uv_body_posed = tf.transpose(uv_unposed, [0,2,3,1]), tf.transpose(uv_template, [0,2,3,1]), tf.transpose(uv_body_posed, [0,2,3,1]) + z_static = self.static_enc(uv_template) + z_body = self.body_enc(uv_body_posed) + z_curv = self.curv_enc(uv_curv) + + x = tf.concat([uv_unposed, uv_template, uv_body_posed, uv_curv], axis=-1) + + mean, logvar = self.encoder(x) + z = self.reparameterize(mean, logvar) + z_cond = tf.concat([z_static, z_body, z_curv], axis=-1) + z_cond = self.cond_encoder(z_cond) + + if zero_latent: + z = tf.zeros_like(z) + + z = tf.concat([z, z_cond], axis=-1) + + # z = self.shuffle(z) + + # z = tf.concat([z, z_curv], axis=-1) + x = self.decoder(z) + + + # x = tf.transpose(x, [0,3,1,2]) + # x = x * uv_mask[:,tf.newaxis,:,:] + # x = tf.image.resize(x, (512, 256), tf.image.ResizeMethod.LANCZOS5) + # x = x + tf.transpose(uv_shaped_body, [0,2,3,1]) + if self.avg_garment is not None: + x = x + self.avg_garment[tf.newaxis,:,:,:] + # x = x * uv_mask[:,:,:,tf.newaxis] + + return x, mean, logvar, z + + + + +class Encoder128(tf.keras.Model): + + def __init__(self, latent_dim): + super(Encoder128, self).__init__() + + self.encoder = ConvNeXt(depths=[16, 16, 9, 9], dims=[256, 256, 128, 64], include_top=False) + self.flatten = tf.keras.layers.Flatten() + self.mean = tf.keras.layers.Dense(latent_dim) + self.log_var = tf.keras.layers.Dense(latent_dim) + + def call(self, inputs, training=None): + x = inputs + + x = self.encoder(x) + x = self.flatten(x) + mean = self.mean(x) + log_var = self.log_var(x) + + return mean, log_var + + +class Decoder128(tf.keras.Model): + + def __init__(self): + super(Decoder128, self).__init__() + + self.dense = tf.keras.layers.Dense(4 * 2 * 128) + self.reshape = tf.keras.layers.Reshape((4, 2, 128)) + self.decoder = ConvNeXtReverse(depths=list(reversed([16, 16, 9, 9])), dims=list(reversed([256, 256, 128, 64]))) + + + def call(self, inputs, training=None): + x = inputs + + x = self.dense(x) + x = self.reshape(x) + x = self.decoder(x) + + return x + + +class CVAE128(tf.keras.Model): + + def __init__(self, latent_dim=128, + avg_garment_path='', + static_model='', + body_model='', + curvature_model='', + freeze_encoders=False): + super(CVAE128, self).__init__() + self.latent_dim = latent_dim + + model : StaticAE128 = StaticAE128() + if static_model != '': + load_model(model, static_model) + self.static_enc = tf.keras.Sequential([model.encoder, model.bottleneck]) + + model : BodyAE128 = BodyAE128() + if body_model != '': + load_model(model, body_model) + self.body_enc = tf.keras.Sequential([model.encoder, model.bottleneck]) + + model : CurvatureAE128 = CurvatureAE128() + if curvature_model != '': + load_model(model, curvature_model) + self.curv_enc = tf.keras.Sequential([model.encoder, model.bottleneck]) + + if freeze_encoders: + self.static_enc.trainable = False + self.body_enc.trainable = False + self.curv_enc.trainable = False + + self.encoder = Encoder128(latent_dim) + self.decoder = Decoder128() + + if avg_garment_path != '': + self.avg_garment = np.load(avg_garment_path) + else: + self.avg_garment = None + + self.cond_encoder = tf.keras.Sequential([tf.keras.layers.Dense(512, activation='relu'), + tf.keras.layers.Dense(256, activation='relu'), + tf.keras.layers.Dense(128, activation='relu'), + tf.keras.layers.Dense(latent_dim),]) + + + # @tf.function + def sample(self, uv_template, uv_body_posed, uv_curv, uv_mask, nr_of_samples=4, fix_noise=False, zero_latent=False): + if not fix_noise: + eps = tf.random.normal(shape=(nr_of_samples, self.latent_dim)) + else: + eps = tf.random.normal(shape=(1, self.latent_dim)) + eps = tf.tile(eps, [nr_of_samples,1]) + + uv_template = tf.tile(tf.transpose(uv_template, [1,2,0])[tf.newaxis,:,:,:], [nr_of_samples,1,1,1]) + uv_body_posed = tf.tile(tf.transpose(uv_body_posed, [1,2,0])[tf.newaxis,:,:,:], [nr_of_samples,1,1,1]) + if len(uv_curv.shape) == 3: + uv_curv = tf.tile(uv_curv[tf.newaxis,:,:,:], [nr_of_samples,1,1,1]) + uv_mask = tf.tile(uv_mask[tf.newaxis,:,:], [nr_of_samples,1,1]) + + # uv_template, uv_body_posed = tf.transpose(uv_template, [0,2,3,1]), tf.transpose(uv_body_posed, [0,2,3,1]) + z_static = self.static_enc(uv_template) + z_body = self.body_enc(uv_body_posed) + z_curv = self.curv_enc(uv_curv) + + z_cond = tf.concat([z_static, z_body, z_curv], axis=-1) + z_cond = self.cond_encoder(z_cond) + + if zero_latent: + eps = tf.zeros_like(eps) + + z = tf.concat([eps, z_cond], axis=-1) + + x = self.decoder(z) + x = x + self.avg_garment[tf.newaxis,:,:,:] + x = x * uv_mask[:,:,:,tf.newaxis] + + return x + + + def reparameterize(self, mean, logvar): + eps = tf.random.normal(shape=mean.shape) + return eps * tf.exp(logvar * .5) + mean + + + def decode(self, z, apply_sigmoid=False): + logits = self.decoder(z) + if apply_sigmoid: + probs = tf.sigmoid(logits) + return probs + return logits + + def call(self, inputs, training=None, zero_latent=False): uv_unposed, uv_template, uv_body_posed, uv_curv = inputs uv_unposed, uv_template, uv_body_posed = tf.transpose(uv_unposed, [0,2,3,1]), tf.transpose(uv_template, [0,2,3,1]), tf.transpose(uv_body_posed, [0,2,3,1]) diff --git a/models/cvae_pyramid_model.py b/models/cvae_pyramid_model.py index 50f4beb..dfc1fd7 100644 --- a/models/cvae_pyramid_model.py +++ b/models/cvae_pyramid_model.py @@ -7,15 +7,18 @@ import numpy as np # import plotly.express as ex from custom_utils.custom_utils import load_model -from models.cvae_model import CVAE, CVAE32 +from models.cvae_model import CVAE, CVAE128, CVAE32 class Pyramid(tf.keras.Model): - def __init__(self, latent_dim=128, avg_garment_path=''): + def __init__(self, low_res=32, latent_dim=128, avg_garment_path=''): super(Pyramid, self).__init__() - self.model_32 = CVAE32(latent_dim=latent_dim) + if low_res == 32: + self.model_low = CVAE32(latent_dim=latent_dim) + if low_res == 128: + self.model_low = CVAE128(latent_dim=latent_dim) self.model_full = CVAE(latent_dim=latent_dim) if avg_garment_path != '': @@ -24,16 +27,16 @@ class Pyramid(tf.keras.Model): self.avg_garment = None def call(self, inputs, training=None): - uv_unposed, uv_static, uv_body_posed, uv_curv, uv_unposed_32, uv_static_32, uv_body_posed_32, uv_curv_32 = inputs + uv_unposed, uv_static, uv_body_posed, uv_curv, uv_unposed_low, uv_static_low, uv_body_posed_low, uv_curv_low = inputs - pred_32, mean_32, logvar_32, _ = self.model_32([uv_unposed_32, uv_static_32, uv_body_posed_32, uv_curv_32], training=training) + pred_low, mean_low, logvar_low, _ = self.model_low([uv_unposed_low, uv_static_low, uv_body_posed_low, uv_curv_low], training=training) - x = tf.image.resize(pred_32, (512, 256), tf.image.ResizeMethod.LANCZOS5) + x = tf.image.resize(pred_low, (512, 256), tf.image.ResizeMethod.LANCZOS5) pred_full, mean_full, logvar_full, _ = self.model_full([uv_unposed, uv_static, uv_body_posed, uv_curv], training=training) x = x + pred_full - return x, mean_full, logvar_full, pred_32, mean_32, logvar_32, + return x, mean_full, logvar_full, pred_low, mean_low, logvar_low,