#tensorflow #machine-learning #keras #deep-learning #autoencoder
Вопрос:
Я преобразую вариационный автоэнкодер (VRAE) из этой реализации PyTorch в Keras. Для VRAE входные данные рекуррентного декодера должны иметь форму (размер пакета, временные интервалы, функции). В PyTorch это достигается с помощью
self.decoder_inputs = torch.zeros(self.sequence_length, self.batch_size, 1, requires_grad=True).type(self.dtype)
Пожалуйста, обратите внимание, что ГРУ PyTorch по умолчанию ожидает, что размер пакета будет вторым размером его входных данных, это не относится к ГРУ TensorFlow.
Когда я реализую эту модель в TensorFlow, если я попытаюсь передать один образец (1, временные шаги, функции) модели, я получу эту ошибку
InvalidArgumentError: Недопустимая форма ввода: [1,1,300] [1,128,300] [Op:CudnnRNN]
Однако, если я передам образец, в котором первое измерение соответствует размеру пакета, на котором изначально обучалась модель, я не получу ошибки. Такой образец в этом случае будет иметь форму (размер пакета=128, временные интервалы, функции). Когда я обучал модель, я также использовал drop_remainder=True
кварг для tf.data.Dataset.batch(batch_size, drop_remainder=True)
того, чтобы избежать этой проблемы, о которой я упоминал во model.fit
время . Есть ли способ передать произвольное количество выборок в такую сеть, которая была обучена с фиксированным размером tf.Variable
? кажется действительно неэффективным всегда делать мои входные данные первым элементом тензора нулей, такого как этот
dummy_zeros = np.zeros(batch_size, timesteps, features)
a_single_sample = np.random.randn(timesteps, features)
dummy_zeros[0, :, :] = a_single_sample
а затем передайте этот тензор нулей вызову модели следующим образом
# I index the first element of the results of the forward pass through the model because
# the other elements are not samples.
a_single_sample_reconstruction = model(dummy_zeros)[0]
Ниже приведена модель, которую я сделал.
class VRAE(tf.keras.Model):
"""Variational Recurrent Autoencoder"""
def __init__(self, batch_size, rnn_units, latent_size, features, **kwargs):
"""Defines architecture layers.
:param batch_size: <class 'int'> Self-explanatory.
:param rnn_units: <class 'int'> The number of hidden units in the RNN layers.
:param latent_size: <class 'int'> Dimensions of latent space.
:param features: <class 'int'> The number of features (aka the last dimension) of the input.
"""
super().__init__(**kwargs)
# The first step of the encoding process
self.recurrent_encoder_part = tf.keras.layers.GRU(units=rnn_units, return_sequences=False, return_state=True)
# Variational part of the encoding process
self.dense_mus = tf.keras.layers.Dense(units=latent_size)
self.dense_log_vars = tf.keras.layers.Dense(units=latent_size)
self.sampling = tf.keras.layers.Lamba(function=self.reparametrize)
# Converts outputs from the sampling layer to initial hidden state for decoder rnn
self.z_to_init_hidden_state = tf.keras.layers.Dense(units=recurrent_units)
########################################################################################################
# BEGIN: THE PROBLEM IS THAT THIS VARIABLE HAS A FIXED NUMBER OF PARAMETERS DUE TO BATCH SIZE CONSTRAINT
########################################################################################################
# Define the trainable zeros tensor that is input (not hidden state) of recurrent decoder
self.decoder_input = tf.Variable(tf.zeros(shape=(batch_size, timesteps, 1)), trainable=True)
########################################################################################################
# END: THE PROBLEM IS THAT THIS VARIABLE HAS A FIXED NUMBER OF PARAMETERS DUE TO BATCH SIZE CONSTRAINT
########################################################################################################
# Decoding layer
self.recurrent_decoder = tf.keras.layers.GRU(units=recurrent_units, return_sequences=True, return_state=False)
# Reconstruct original inputs (softmax used because inputs belong to multiple classes)
self.reconstruction = tf.keras.layers.Dense(units=features, activation='softmax')
def call(self, inputs):
"""Forward computation that reconstructs original inputs.
:param inputs: Rank-3 tensor of inputs (batch_size, timesteps, features).
:return: Rank-3 tensor of probabilities (batch_size, timesteps, features).
"""
# Encode the input
h_t = self.recurrent_encoder_part(inputs)
# Get latent variables
mus = self.dense_mus(h_t)
log_vars = self.dense_log_vars(h_t)
z = self.sampling([mus, log_vars])
# Project z to correct shape for initial hidden state of decoder
decoder_h_0 = self.z_to_init_hidden(z)
# Decode -- note how the 'decoder' input is always (batch_size, timesteps, 1) shape
outputs = self.recurrent_decoder(self.decoder_input, initial_state=decoder_h_0)
# Unnormalized log probabilities -> normalized probabilities
reconstructions = self.reconstructions(outputs)
# Add KL loss term
self.add_loss(self.compute_kl_loss(mus, log_vars))
# Return the reconstructions of the original input for the main loss function (CategoricalCrossentropy) to handle
return reconstructions
def reparametrize(self, inputs):
"""Reparametrization trick that returns latent space z given means and log variances."""
mus, log_vars = inputs
# Extract the shapes from one of the input tensors.
# Note, dimensions(mus) = dimensions(log_vars)
batch_size = tf.shape(mus)[0]
dims = tf.shape(mus)[1]
# Compute epsilon
epsilon = tf.keras.random_normal(shape=(batch_size, dims))
# Sample the latent space
return mus tf.exp(log_vars/2) * epsilon
def compute_kl_loss(self, mus, log_vars):
"""Computes the Kullback-Leibler loss using means and log variances of prior distribution."""
return -0.5 * tf.reduce_mean(1. log_vars - tf.exp(log_vars) - tf.pow(mus, 2))