【问题标题】:Autoencoder with 3D convolutions and convolutional LSTMs具有 3D 卷积和卷积 LSTM 的自动编码器
【发布时间】:2019-12-01 18:43:33
【问题描述】:

我已经在编码器和解码器中实现了一个带有 CNN 层的变分自动编码器。代码如下所示。我的训练数据 (train_X) 包含 40,000 张大小为 64 x 80 x 1 的图像,而我的验证数据 (valid_X) 包含 4500 张大小为 64 x 80 x 1 的图像。

我想通过以下两种方式调整我的网络:

  1. 我不想使用 2D 卷积(Conv2D 和 Conv2DTranspose),而是使用 3D 卷积来考虑时间(作为第三维)。为此,我想使用 10 个图像的切片,即我将拥有大小为 64 x 80 x 1 x 10 的图像。我可以只使用 Conv3D 和 Conv3DTranspose 还是需要进行其他更改?

  2. 我想在编码器和解码器中尝试卷积 LSTM (ConvLSTM2D),而不是普通的 2D 卷积。同样,图像的输入大小将是 64 x 80 x 1 x 10(即 10 个图像的时间序列)。如何调整我的网络以使用 ConvLSTM2D?

import keras
from keras import backend as K
from keras.layers import (Dense, Input, Flatten)
from keras.layers import Lambda, Conv2D
from keras.models import Model
from keras.layers import Reshape, Conv2DTranspose
from keras.losses import mse

def sampling(args):
    z_mean, z_log_var = args
    batch = K.shape(z_mean)[0]
    dim = K.int_shape(z_mean)[1]
    epsilon = K.random_normal(shape=(batch, dim))
    return z_mean + K.exp(0.5 * z_log_var) * epsilon

inner_dim = 16
latent_dim = 6

image_size = (64,78,1)
inputs = Input(shape=image_size, name='encoder_input')
x = inputs

x = Conv2D(32, 3, strides=2, activation='relu', padding='same')(x)
x = Conv2D(64, 3, strides=2, activation='relu', padding='same')(x)

# shape info needed to build decoder model
shape = K.int_shape(x)

# generate latent vector Q(z|X)
x = Flatten()(x)
x = Dense(inner_dim, activation='relu')(x)
z_mean = Dense(latent_dim, name='z_mean')(x)
z_log_var = Dense(latent_dim, name='z_log_var')(x)

z = Lambda(sampling, output_shape=(latent_dim,), name='z')([z_mean, z_log_var])

# instantiate encoder model
encoder = Model(inputs, [z_mean, z_log_var, z], name='encoder')

# build decoder model
latent_inputs = Input(shape=(latent_dim,), name='z_sampling')
x = Dense(inner_dim, activation='relu')(latent_inputs)
x = Dense(shape[1] * shape[2] * shape[3], activation='relu')(x)
x = Reshape((shape[1], shape[2], shape[3]))(x)

x = Conv2DTranspose(64, 3, strides=2, activation='relu', padding='same')(x)
x = Conv2DTranspose(32, 3, strides=2, activation='relu', padding='same')(x)

outputs = Conv2DTranspose(filters=1, kernel_size=3, activation='sigmoid', padding='same', name='decoder_output')(x)

# instantiate decoder model
decoder = Model(latent_inputs, outputs, name='decoder')

# instantiate VAE model
outputs = decoder(encoder(inputs)[2])
vae = Model(inputs, outputs, name='vae')

def vae_loss(x, x_decoded_mean):
    reconstruction_loss = mse(K.flatten(x), K.flatten(x_decoded_mean))
    reconstruction_loss *= image_size[0] * image_size[1]
    kl_loss = 1 + z_log_var - K.square(z_mean) - K.exp(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

optimizer = keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.000)
vae.compile(loss=vae_loss, optimizer=optimizer)
vae.fit(train_X, train_X,
        epochs=500,
        batch_size=128,
        verbose=1,
        shuffle=True,
        validation_data=(valid_X, valid_X))

非常感谢您的帮助。我真的很感激。

【问题讨论】:

    标签: keras conv-neural-network lstm keras-layer autoencoder


    【解决方案1】:

    将您的输入形状设为(10, 64 , 80, 1),然后替换图层。

    如果你打算使用滑动窗口或者只是从(images, 64,80,1) 重塑为(images//10, 10, 64,80,1),那么无聊的部分是组织输入数据。

    滑动窗口(重叠)与否?

    1 - 好的....如果您希望您的模型理解 10 个图像的各个部分,您可能会重叠或不重叠。你的选择。重叠时性能可能会更好,但不一定。

    图像中没有真正的顺序,只要 10 帧是按顺序排列的。

    Conv3DLSTMstateful=False 支持此功能。

    2 - 但是如果你想让你的模型理解整个序列,仅仅因为内存而划分序列,只有LSTMstateful=True 可以支持这一点。

    (内核大小 = (frames, w, h)Conv3D 可以工作,但仅限于 frames,永远不会理解比 frames 更长的序列。虽然它可能仍然能够检测到准时事件的存在,但是不是长序列关系)

    在这种情况下,对于LSTM,您需要:

    • 在训练中设置shuffle = False
    • 使用固定的批量大小sequences
    • 不重叠图片
    • 创建一个手动训练循环,每次为训练和预测提供“新序列”时,您都需要在其中执行 model.reset_states()

    循环结构是:

    for epoch in range(epochs):
        for group_of_sequences in range(groups):
            model.reset_states()
    
            sequences = getAGroupOfCompleteSequences() #shape (sequences, total_length, ....)            
    
            for batch in range(slide_divisions):
                batch = sequences[:,10*batch : 10*(batch+1)]
    
                model.train_on_batch(batch, ....)
    

    【讨论】:

    • 太好了,谢谢。我将创建一个矩阵 (images//10, 10, 64,80,1),例如 (4000, 10, 64,80,1)。我认为对于 LSTM 来说,顺序也很重要。输入是否由 (1, 10, 64,80,1), (2, 10, 64,80,1), (3, 10, 64,80,1) 等处理?此外,序列中的图像应该是唯一的还是序列中的图像应该重叠?重叠的意思是例如 seq1=(im1,im2,im3,...,im10) 和 seq2=(im5,im6,im7,...,im14)。
    • 顺序是(:,0,:,:,:), (:,1,:,:,:), (:,2,:,:,:) .... ---- 数据组织由您决定。如果您认为每组 10 张图像形成可理解的序列,您可以按照您的建议进行滑动窗口。
    • 你的意思是重叠或不重叠的滑动窗口?关于顺序,(:,0,:,:,:), (:,1,:,:,:),..., (:,10,:,:,:) 是 Conv3D 或ConvLSTM 单元,但是当我使用例如 128 的批次大小时,这样的批次中的顺序是什么?我问是因为我有 700 个图像的序列(形成一个视频),但由于内存限制、训练时间等,我必须将这些序列拆分为更小的块(例如 10 个图像)。但是当然当我拆分 700 个序列时图片分成 10 张图片的块,它们被消费的顺序很重要......
    • 详情请看答案。
    • 非常感谢。我目前正在实施它。假设我的批次大小为 100,我的序列大小为 980。在最后一批中,我只有 80 张图像。在这种情况下我该怎么办?只是跳过 80 张图片?
    猜你喜欢
    • 2020-08-20
    • 2018-11-12
    • 1970-01-01
    • 2018-05-02
    • 2017-11-11
    • 1970-01-01
    • 2022-01-27
    • 1970-01-01
    • 2019-11-09
    相关资源
    最近更新 更多