对于像有竞争损失的VAE这样的网络,跟踪每个损失独立地非常有用。也就是说,查看总损失以及数据项和KL代码项都很有用。
在Keras中是否可以实现这一点?可以通过vae.losses恢复损失,但它们是tensorflow层,因此无法在keras中使用(例如,无法创建第二个模型来计算vae损失作为输出)。
似乎一种方法是将它们添加到编译时的度量列表中,但它们不符合指标模型。
以下是一些示例代码,抱歉长度较长,它是从Keras的示例代码中适当改编而来。主要区别是我明确地将KL分离为一个采样层的计算,这比原始样本代码更自然。
在Keras中是否可以实现这一点?可以通过vae.losses恢复损失,但它们是tensorflow层,因此无法在keras中使用(例如,无法创建第二个模型来计算vae损失作为输出)。
似乎一种方法是将它们添加到编译时的度量列表中,但它们不符合指标模型。
以下是一些示例代码,抱歉长度较长,它是从Keras的示例代码中适当改编而来。主要区别是我明确地将KL分离为一个采样层的计算,这比原始样本代码更自然。
'''This script demonstrates how to build a variational autoencoder with Keras.
Reference: "Auto-Encoding Variational Bayes" https://arxiv.org/abs/1312.6114
'''
from keras.layers import Input, Dense, Lambda, Layer
from keras.models import Model
from keras import backend as K
from keras import metrics
batch_size = 100
original_dim = 784
latent_dim = 2
intermediate_dim = 256
epochs = 50
epsilon_std = 1.0
x = Input(batch_shape=(batch_size, original_dim))
h = Dense(intermediate_dim, activation='relu')(x)
z_mean = Dense(latent_dim)(h)
z_log_var = Dense(latent_dim)(h)
class CustomSamplingLayer(Layer):
def __init__(self, **kwargs):
super(CustomSamplingLayer, self).__init__(**kwargs)
def kl_div_loss(self, z_mean, z_log_var):
kl_loss = - 0.5 * K.sum(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)
return K.mean(kl_loss)
def call(self, inputs):
z_mean = inputs[0]
z_log_var = inputs[1]
loss = self.kl_div_loss(z_mean, z_log_var)
self.add_loss(loss, inputs=inputs)
epsilon = K.random_normal(shape=(batch_size, latent_dim), mean=0.,
stddev=epsilon_std)
return z_mean + K.exp(z_log_var / 2) * epsilon
# note that "output_shape" isn't necessary with the TensorFlow backend
z = CustomSamplingLayer()([z_mean, z_log_var])
# we instantiate these layers separately so as to reuse them later
decoder_h = Dense(intermediate_dim, activation='relu')
decoder_mean = Dense(original_dim, activation='sigmoid')
h_decoded = decoder_h(z)
x_decoded_mean = decoder_mean(h_decoded)
# Custom loss layer
class CustomVariationalLayer(Layer):
def __init__(self, **kwargs):
self.is_placeholder = True
super(CustomVariationalLayer, self).__init__(**kwargs)
def vae_loss(self, x, x_decoded_mean):
xent_loss = original_dim * metrics.binary_crossentropy(x, x_decoded_mean)
return K.mean(xent_loss)
def call(self, inputs):
x = inputs[0]
x_decoded_mean = inputs[1]
loss = self.vae_loss(x, x_decoded_mean)
self.add_loss(0.0 * loss, inputs=inputs)
return x_decoded_mean
y = CustomVariationalLayer()([x, x_decoded_mean])
vae = Model(x, y)
vae.compile(optimizer='rmsprop', loss=None)