Keras:自定义损失导致“您必须输入占位符张量的值”

时间:2019-04-27 14:54:00

标签: python tensorflow keras

我正在尝试在Keras储存库中的example之后在Keras中构建变体自动编码器。这是我的设置:

a=Circle(2)
a.show()
#Circle

这有效,但是如果您查看from keras.layers import Dense, Input, merge, concatenate, Dense, LSTM, Lambda, Flatten, Reshape from keras import backend as K from keras.models import Model from keras.losses import mse import numpy as np class VAE: def __init__(self, n_verts=15, n_dims=3, n_layers=3, n_units=128, latent_dim=2): self.n_verts = n_verts self.n_dims = n_dims self.n_layers = n_layers self.n_units = n_units self.latent_dim = latent_dim self.encoder = self.build_encoder() self.decoder = self.build_decoder() inputs = Input((self.n_verts, self.n_dims)) outputs = self.decoder(self.encoder(inputs)[2]) self.model = Model(inputs, outputs, name='vae') self.model.compile(optimizer='adam', loss=self.get_loss) def build_encoder(self): i = Input(shape=(self.n_verts, self.n_dims), name='encoder_input') h = i h = Flatten()(h) h = Dense(self.n_units, activation='relu')(h) for idx in range(1, self.n_layers, 1): h = Dense(self.n_units // (2*idx), activation='relu')(h) self.z_mean = Dense(self.latent_dim, name='z_mean')(h) self.z_log_var = Dense(self.latent_dim, name='z_log_var')(h) # use reparameterization trick to factor stochastic node out of gradient flow self.z = Lambda(self.sample, output_shape=(self.latent_dim,), name='z')([self.z_mean, self.z_log_var]) return Model(i, [self.z_mean, self.z_log_var, self.z], name='encoder') def sample(self, args): ''' Reparameterization trick by sampling from an isotropic unit Gaussian. @arg (tensor): mean and log of variance of Q(z|X) @returns z (tensor): sampled latent vector ''' z_mean, z_log_var = args batch = K.shape(z_mean)[0] dim = K.int_shape(z_mean)[1] # by default, random_normal has mean = 0 and std = 1.0 epsilon = K.random_normal(shape=(batch, dim)) return z_mean + K.exp(0.5 * z_log_var) * epsilon def build_decoder(self): i = Input(shape=(self.latent_dim,), name='z_sampling') h = i for idx in range(1, self.n_layers, 1): h = Dense(self.n_units//(2*(self.n_layers-idx)), activation='relu')(h) h = Dense(self.n_units, activation='relu')(h) h = Dense(self.n_verts * self.n_dims, activation='sigmoid')(h) o = Reshape((self.n_verts, self.n_dims))(h) return Model(i, o, name='decoder') def get_loss(self, inputs, outputs): reconstruction_loss = mse(inputs, outputs) reconstruction_loss *= self.n_verts * self.n_dims return reconstruction_loss # this works fine kl_loss = 1 + self.z_log_var - K.square(self.z_mean) - K.exp(self.z_log_var) kl_loss = K.sum(kl_loss, axis=-1) kl_loss *= -0.5 vae_loss = K.mean(reconstruction_loss + kl_loss) # todo: make this balance parameterizable return vae_loss # this doesn't def train(self, X, predict='frame', n_epochs=10000): for idx in range(n_epochs): i = np.random.randint(0, X.shape[1]-1) # sample idx frame = np.expand_dims( X[:,i:i+1,:].squeeze(), axis=0) # shape = 1 sample, v verts, d dims next_frame = np.expand_dims( X[:,i+1:i+2,:].squeeze(), axis=0) if predict == 'frame': loss = self.model.train_on_batch(frame, frame) elif predict == 'next_frame': loss = self.model.train_on_batch(frame, next_frame) if idx % 1000 == 0: print(' * training idx', idx, 'loss', loss) X_train = np.random.rand(15, 100, 3) vae = VAE(n_verts=15, latent_dim=2, n_layers=3, n_units=128) vae.encoder.summary() vae.train(X_train, n_epochs=10000, predict='frame') 函数,您会发现它过早返回。如果我注释掉get_loss,以使损失函数返回return reconstruction_loss,则会出现错误:

vae_loss

有人知道如何解决此错误吗?任何建议将不胜感激!

1 个答案:

答案 0 :(得分:0)

啊,一旦我的变量的范围正确,我就解决了这个问题:

from keras.layers import Dense, Input, merge, concatenate, Dense, LSTM, Lambda, Flatten, Reshape
from keras import backend as K
from keras.models import Model
from keras.losses import mse
import numpy as np


class VAE:
  def __init__(self, n_verts=15, n_dims=3, n_layers=3, n_units=128, latent_dim=2):
    self.input_shape = (n_verts*n_dims,)
    self.n_layers = n_layers
    self.n_units = n_units
    self.latent_dim = latent_dim
    # build the encoder and decoder
    inputs = Input(shape=self.input_shape, name='encoder_input')
    self.encoder = self.get_encoder(inputs)
    self.decoder = self.get_decoder()
    # build the VAE
    outputs = self.decoder(self.encoder(inputs)[2])
    self.model = Model(inputs, outputs, name='vae_mlp')
    # add loss and compile
    self.model.add_loss(self.get_loss(inputs, outputs))
    self.model.compile(optimizer='adam')


  def get_encoder(self, inputs):
    h = inputs
    h = Dense(self.n_units, activation='relu')(h)
    for idx in range(1, self.n_layers, 1):
      h = Dense(self.n_units // (2*idx), activation='relu')(h)
    self.z_mean = Dense(self.latent_dim, name='z_mean')(h)
    self.z_log_var = Dense(self.latent_dim, name='z_log_var')(h)
    z = Lambda(self.sampling, output_shape=(self.latent_dim,), name='z')([self.z_mean, self.z_log_var])
    encoder = Model(inputs, [self.z_mean, self.z_log_var, z], name='encoder')
    return encoder


  def sampling(self, args):
    self.z_mean, self.z_log_var = args
    batch = K.shape(self.z_mean)[0]
    dim = K.int_shape(self.z_mean)[1]
    # by default, random_normal has mean = 0 and std = 1.0
    epsilon = K.random_normal(shape=(batch, dim))
    return self.z_mean + K.exp(0.5 * self.z_log_var) * epsilon


  def get_decoder(self):
    latent_inputs = Input(shape=(self.latent_dim,), name='z_sampling')
    h = latent_inputs
    for idx in range(1, self.n_layers, 1):
      h = Dense(self.n_units//(2*(self.n_layers-idx)), activation='relu')(h)
    h = Dense(self.n_units, activation='relu')(h)
    outputs = Dense(self.input_shape[0], activation='sigmoid')(h)
    decoder = Model(latent_inputs, outputs, name='decoder')
    return decoder


  def get_loss(self, inputs, outputs):
    reconstruction_loss = mse(inputs, outputs)
    reconstruction_loss *= self.input_shape[0]
    kl_loss = 1 + self.z_log_var - K.square(self.z_mean) - K.exp(self.z_log_var)
    kl_loss = K.sum(kl_loss, axis=-1)
    kl_loss *= -0.5
    vae_loss = K.mean(reconstruction_loss + kl_loss)
    return vae_loss


# train
x_train = np.random.rand(10000, 45)
vae = VAE(n_verts=15, latent_dim=2, n_layers=3, n_units=128)
vae.model.fit(x_train[:-1000,:],
        epochs=100,
        batch_size=128,
        validation_data=(x_train[-1000:,:], None))