简体   繁体   English

Keras,使用数据生成器 (VAE)

[英]Keras, using a generator for the data (VAE)

I'm currently trying to implement a variational autoencoder but I'm quite stuck, I cannot understand how to use a datagenerator in Keras.我目前正在尝试实现一个变分自动编码器,但我很困惑,我无法理解如何在 Keras 中使用数据生成器。 What I have so far is:到目前为止我所拥有的是:


import keras
import tensorflow as tf
from tensorflow.keras import layers


class Sampling(layers.Layer):
    
    def call(self, inputs):
        z_mean, z_log_var = inputs
        batch = tf.shape(z_mean)[0]
        dim = tf.shape(z_mean)[1]
        epsilon = tf.keras.backend.random_normal(shape=(batch, dim))
        return z_mean + tf.exp(z_log_var / 2) * epsilon

class factor_vae(keras.Model):
    def __init__(self):
        super(factor_vae, self).__init__()
        self.encoder = self.encoder_factor_vae()
        self.decoder = self.decoder_factor_vae()
        self.classifier = self.MLP_classifier()

    def train_step(self, data):
        data = data[0]
        with tf.GradientTape() as tape:
            z, z_mean, z_log_var = self.encoder(data)
            reconstruction = self.decoder(z)
            reconstruction_loss = tf.reduce_mean(
                keras.losses.mse(data, reconstruction))
            reconstruction_loss *= 4096 #denna kan ändras
            kl_loss = 1 + z_log_var - tf.square(z_mean) - tf.exp(z_log_var)
            kl_loss = tf.reduce_mean(kl_loss)
            kl_loss *= -0.5
            total_loss = reconstruction_loss + (kl_loss)
        grads = tape.gradient(total_loss, self.trainable_weights)
        self.optimizer.apply_gradients(zip(grads, self.trainable_weights))
        return {
            "loss": total_loss,
            "reconstruction_loss": reconstruction_loss,
            "kl_loss": kl_loss,
        }

    def encoder_factor_vae(self):
        x_inp = Input(shape=(64, 64, 1))
        z = layers.Conv2D(filters=32, kernel_size=(4, 4), activation="relu", strides=2, padding="same")(x_inp)
        z = BatchNormalization()(z)
        z = layers.Conv2D(filters=32, kernel_size=(4, 4), activation="relu", strides=2, padding="same")(z)
        z = BatchNormalization()(z)
        z = layers.Conv2D(filters=64, kernel_size=(4, 4), activation="relu", strides=2, padding="same")(z)
        z = BatchNormalization()(z)
        z = layers.Conv2D(filters=64, kernel_size=(4, 4), activation="relu", strides=2, padding="same")(z)
        z = BatchNormalization()(z)
        z = layers.Flatten()(z)
        z = Dense(units=128, activation='relu')(z)
        z = BatchNormalization()(z)
        z_mean = Dense(units=10, activation='relu')(z)  # här tror jag samplingen ska ske
        z_log_var = Dense(units=10, activation='sigmoid')(z)  # bör vara sampling från reparameterizationen
        z = Sampling()([z_mean, z_log_var])
        encoder = keras.Model(x_inp, [z, z_mean, z_log_var], name="encoder")
        encoder.summary()
        return encoder

    def decoder_factor_vae(self):
        z_inp = Input(shape=(10,))
        x_rec = Dense(units=128, activation='relu')(z_inp)
        x_rec = BatchNormalization()(x_rec)
        x_rec = Dense(units=1024, activation='relu')(x_rec) #hit fungerar
        x_rec = BatchNormalization()(x_rec)
        x_rec = layers.Reshape((4, 4, 64))(x_rec)
        x_rec = layers.Conv2DTranspose(filters=64, kernel_size=(4, 4), activation='relu', strides=2, padding='same')(
            x_rec)
        x_rec = BatchNormalization()(x_rec)
        x_rec = layers.Conv2DTranspose(filters=32, kernel_size=(4, 4), activation='relu', strides=2, padding='same')(
            x_rec)
        x_rec = BatchNormalization()(x_rec)
        x_rec = layers.Conv2DTranspose(filters=32, kernel_size=(4, 4), activation='relu', strides=2, padding='same')(
            x_rec)
        x_rec = BatchNormalization()(x_rec)
        x_rec = layers.Conv2DTranspose(filters=1, kernel_size=(4, 4), strides=2, padding='same')(
            x_rec)
        decoder = keras.Model(z_inp, x_rec, name="decoder")  # går att skicka in vilken batchsize som helst
        decoder.summary()
        return decoder

    def MLP_classifier(self):
        z_inp = Input(shape=(10,))
        x_rec = Dense(units=1000)(z_inp) #1
        x_rec = LeakyReLU(alpha=0.3)(x_rec)
        x_rec = BatchNormalization()(x_rec)
        x_rec = Dense(units=1000)(x_rec)  #2
        x_rec = LeakyReLU(alpha=0.3)(x_rec)
        x_rec = BatchNormalization()(x_rec)
        x_rec = Dense(units=1000)(x_rec)  # 3
        x_rec = LeakyReLU(alpha=0.3)(x_rec)
        x_rec = BatchNormalization()(x_rec)
        x_rec = Dense(units=1000)(x_rec)  # 4
        x_rec = LeakyReLU(alpha=0.3)(x_rec)
        x_rec = BatchNormalization()(x_rec)
        x_rec = Dense(units=1000)(x_rec)  # 5
        x_rec = LeakyReLU(alpha=0.3)(x_rec)
        x_rec = BatchNormalization()(x_rec)
        x_rec = Dense(units=2)(x_rec)  # 6
        classifier = keras.Model(z_inp, x_rec, name="clasifier")
        return classifier
     
    def generate_batches(data):
        L = 50
        start = 0
        end = start + L
        y_L_real = np.zeros((L, 2))
        y_L_fake = np.zeros((L, 2))
        y_L_real[:, 0] = 1
        y_L_fake[:, 1] = 1
        #total_y = np.vstack((y_L_real, y_L_fake))
        while True:
            x_L_real = data[start:end] #antalet värden är 2xL
            x_L_fake = np.roll(x_L_real, shift=2, axis=0)
            total_x = np.vstack((x_L_real, x_L_fake))
            start += L
            end += L
            if start >= data.shape[0]:
                start = 0
                end = L
            yield total_x, total_x
            
            
    data = dsprite()
    factor = factor_vae()
    xyz = np.load("C:\\Users\\joaki\\OneDrive\\Skrivbord\\images\\dsprites_ndarray_"
                           "co1sh3sc6or40x32y32_64x64.npz")
    test_data = xyz['imgs']
    train_steps = 3000
    steps_epoch = 300
    factor.compile(optimizer=keras.optimizers.Adam(0.001))
    train_generator = generate_batches(test_data)
    factor.fit_generator(train_generator, steps_per_epoch=steps_epoch, epochs=50)

There is a lot of code, but it does work fine as long as I used my entire dataset, but as soon as I try to use my implemented "train_generator" it breaks down and I get the error message: NotImplementedError: When subclassing the Model class, you should implement a call method.有很多代码,但只要我使用我的整个数据集,它就可以正常工作,但是一旦我尝试使用我实现的“train_generator”,它就会崩溃并收到错误消息:NotImplementedError: When subclassing the Model类,你应该实现一个call方法。 So I know there is something wrong with my implementation of the train_generator, but I dont understand what I've missed, can someone provide me more information?所以我知道我的 train_generator 实现有问题,但我不明白我错过了什么,有人可以提供更多信息吗?

Try reading this forum page, seems that you should call method in your class when subclassing:尝试阅读此论坛页面,似乎您应该在子类化时在类中调用方法:

https://github.com/tensorflow/tensorflow/issues/43173 https://github.com/tensorflow/tensorflow/issues/43173

Although all subclasses of keras.Model must implement call , it is missing in several examples of Keras (see here or here ).尽管keras.Model所有子类keras.Model必须实现call ,但在keras.Model几个示例中都缺少它(请参阅此处此处)。 Under certain conditions, the error 'When subclassing the Model class, you should implement a call method.'在某些情况下,会出现错误“当对Model类进行子类化时,您应该实现一个call方法。” is thrown.被抛出。

I encounter this problem when including a DataGenerator (subclassed from keras.utils.Sequence ) and solved it by implementing call() like this:我在包含 DataGenerator (从keras.utils.Sequence子类keras.utils.Sequence )并通过实现call()解决它时遇到了这个问题,如下所示:

Autoencoder自编码器

...
def call(self, inputs, training=None, mask=None):
    z = self.encoder(inputs=inputs, training=training, mask=mask)
    return self.decoder(z)
...

GAN生成网络

...
def call(self, inputs, training=None, mask=None):
    batch_size = tf.shape(inputs)[0]
    random_latent_vector = tf.random.normal(shape=(batch_size, self.latent_dim))
    x = self.generator(inputs=random_latent_vector, training=training, mask=mask)

    if len(x.shape) != len(inputs.shape):
        raise Exception(f'Fake signal ({x.shape}) and real signal ({inputs.shape}) do not have same shape dimension')

    return self.critic(inputs=x, training=training, mask=mask)
...

It seems to be a known problem (see here )这似乎是一个已知问题(请参阅此处

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM