def conv_decoder(output_side=32, n_channels=3, representation_dim=256, activation='relu'): nf = 64 Slicer = Lambda(lambda x, slice_size: x[:, :slice_size, :slice_size, :], output_shape=(output_side, output_side, n_channels), name="slice_layer") # Define your lambda layer Slicer.arguments = {'slice_size': output_side} # Update extra arguments to F rep_in = Input(shape=(representation_dim,)) if output_side == 21: height, width, feat_mult = (3, 3, 4) else: height, width, feat_mult = (4, 4, 4) g = Dense(nf * feat_mult * height * width)(rep_in) g = BatchNormalization(axis=-1)(g) g = Activation(activation)(g) conv_shape = (nf * feat_mult, height, width) if get_channels_axis() == 1 else (height, width, nf * feat_mult) g = Reshape(conv_shape)(g) # upsample x2 g = Conv2DTranspose(nf * 2, kernel_size=(3, 3), strides=(2, 2), padding='same')(g) g = BatchNormalization(axis=get_channels_axis())(g) g = Activation(activation)(g) # upsample x2 g = Conv2DTranspose(nf, kernel_size=(3, 3), strides=(2, 2), padding='same')(g) g = BatchNormalization(axis=get_channels_axis())(g) g = Activation(activation)(g) if output_side == 64: # upsample x2 g = Conv2DTranspose(nf, kernel_size=(3, 3), strides=(2, 2), padding='same')(g) g = BatchNormalization(axis=get_channels_axis())(g) g = Activation(activation)(g) # upsample x2 g = Conv2DTranspose(n_channels, kernel_size=(3, 3), strides=(2, 2), padding='same')(g) g = Activation('tanh')(g) g = Slicer(g) return Model(rep_in, g)
def __init__(self, vector_len, dimension): def connection(x, i): return x[:, i, :] v = Input(shape=(vector_len, dimension)) m = Input(shape=(memory_len, )) alphas = [] weight_input = Dense(1, activation='tanh') weight_memory = Dense(1, activation='tanh') weight_hidden = Dense(1, activation='softmax') multiplication = multiply extraction = Lambda(connection, arguments={'i': 0}) for i in range(vector_len): if i % 1000 == 0: print(i) extraction.arguments = {'i': i} vi = extraction(v) hidden = multiplication([weight_input(vi), weight_memory(m)]) alpha = weight_hidden(hidden) alphas.append(alpha) alphas = concatenate(alphas) attented_v = Lambda(apply_weights, arguments={'length': dimension})([v, alphas]) self.model = Model([v, m], outputs=attented_v)
def __init__(self, data_dims, latent_dims, network_architecture='synthetic'): """ Args: data_dims: tuple, flattened data dimension for each dataset latent_dims: tuple, flattened latent dimensions for each private latent space and the dimension of the shared space. network_architecture: str, the codename of the encoder network architecture (will be the same for all) """ assert len(latent_dims) == len(data_dims) + 1, \ "Expected too receive {} private latent spaces and one shared for {} data inputs " \ "but got {} instead.".format(len(data_dims) + 1, len(data_dims), len(latent_dims)) # NOTE: this encoder is better off not having BaseEncoder as super class. # This might be refactored in the future if multiple variations of the conjoint model are to be implemented, # and this class can be used as a base class for them. name = 'Reparametrised Gaussian Conjoint Encoder' logger.info( "Initialising {} model with {}-dimensional data inputs " "and {}-dimensional latent outputs (last one is shared)".format( name, data_dims, latent_dims)) def lin_transform_standard_gaussian(params): from keras.backend import exp mu, log_sigma, z = params transformed_z = mu + exp(log_sigma / 2.0) * z return transformed_z inputs, latent_space, latent_means, latent_log_vars, features = [], [], [], [], [] for i in range(len(data_dims)): data_input = Input(shape=(data_dims[i], ), name="enc_data_input_{}".format(i)) features_i = get_network_by_name['conjoint_encoder'][ network_architecture](data_input, 'conj_{}'.format(i)) private_latent_mean = Dense( latent_dims[i], activation=None, name='enc_mean_{}'.format(i))(features_i) # since the variance must be positive and this is not easy to restrict, take it in the log domain # and exponentiate it during the reparametrisation private_latent_log_var = Dense( latent_dims[i], activation=None, name='enc_log_var_{}'.format(i))(features_i) inputs.append(data_input) latent_means.append(private_latent_mean) latent_log_vars.append(private_latent_log_var) features.append(features_i) features = Concatenate(axis=-1, name='enc_concat_all_features')(features) shared_latent_mean = Dense(latent_dims[-1], activation=None, name='enc_shared_mean')(features) shared_latent_log_var = Dense(latent_dims[-1], activation=None, name='enc_shared_log_var')(features) total_latent_mean = Concatenate( axis=-1, name='enc_total_mean')(latent_means + [shared_latent_mean]) total_latent_log_var = Concatenate( axis=-1, name='enc_total_log_var')(latent_log_vars + [shared_latent_log_var]) # introduce the noise and reparametrise it standard_normal_sampler = Lambda(sample_standard_normal_noise, name='enc_normal_sampler') standard_normal_sampler.arguments = { 'data_dim': sum(data_dims), 'noise_dim': sum(latent_dims), 'seed': config['seed'] } noise = standard_normal_sampler(total_latent_mean) total_latent_space = Lambda(lin_transform_standard_gaussian, name='enc_latent')([ total_latent_mean, total_latent_log_var, noise ]) self.encoder_inference_model = Model(inputs=inputs, outputs=total_latent_space, name='encoder_inference') self.encoder_learning_model = Model(inputs=inputs, outputs=[ total_latent_space, total_latent_mean, total_latent_log_var ], name='encoder_learning')
def __init__(self, data_dims, noise_dim, latent_dims, network_architecture='synthetic', noise_mode='add'): """ Args: data_dims: tuple, flattened data dimension for each dataset noise_dim: int, flattened noise dimensionality latent_dims: tuple, flattened latent dimensions for each private latent space and the dimension of the shared space. network_architecture: str, the codename of the encoder network architecture (will be the same for all) noise_mode: str, the way the noise will be merged with the input('add', 'concat', 'product') """ assert len(latent_dims) == len(data_dims) + 1, \ "Expected too receive {} private latent spaces and one shared for {} data inputs " \ "but got {} instead.".format(len(data_dims) + 1, len(data_dims), len(latent_dims)) name = 'Standard Conjoint Encoder' logger.info( "Initialising {} model with {}-dimensional data inputs " "and {}-dimensional latent outputs (last one is shared)".format( name, data_dims, latent_dims)) latent_space, features = [], [] inputs = [ Input(shape=(dim, ), name="enc_data_input_{}".format(i)) for i, dim in enumerate(data_dims) ] standard_normal_sampler = Lambda(sample_standard_normal_noise, name='enc_normal_sampler') if noise_mode == 'concatenate': if network_architecture == 'mnist': assert ((noise_dim % sqrt(data_dims[0]) == 0) and (noise_dim % sqrt(data_dims[1]) == 0)), \ "Expected to receive a noise_dim that, when concatenated, can form a rectangle with " \ "the given inputs_dims. Received {} noise and {} data dimensions.".format(noise_dim, data_dims) elif noise_mode == 'product': assert data_dims[0] == noise_dim and data_dims[1] == noise_dim, \ "Expected to receive a noise_dim that is equal to the given inputs dimensions. " \ "Received {} noise and {} data dimensions.".format(noise_dim, data_dims) elif noise_mode != 'add': raise ValueError( "Only the noise modes 'add', 'concatenate' and 'product' are available." ) standard_normal_sampler.arguments = { 'seed': config['seed'], 'noise_dim': noise_dim, 'mode': noise_mode } for i, inp in enumerate(inputs): noise_input = standard_normal_sampler(inp) feature = get_network_by_name['conjoint_encoder'][ network_architecture](noise_input, 'enc_feat_{}'.format(i)) latent_factors = Dense( latent_dims[i], activation=None, name='enc_latent_private_{}'.format(i))(feature) latent_space.append(latent_factors) features.append(feature) merged_features = Concatenate(axis=-1, name='enc_concat_features')(features) shared_latent = Dense(latent_dims[-1], activation=None, name='enc_shared_latent')(merged_features) latent_space = Concatenate( axis=-1, name='enc_concat_all_features')(latent_space + [shared_latent]) self.encoder_model = Model(inputs=inputs, outputs=latent_space, name='encoder')