从经过训练的自动编码器中提取编码器和解码器

Posted

技术标签:

【中文标题】从经过训练的自动编码器中提取编码器和解码器【英文标题】:Extract encoder and decoder from trained autoencoder 【发布时间】:2019-02-15 16:56:32 【问题描述】:

我想将自编码器的学习和应用分为https://blog.keras.io/building-autoencoders-in-keras.html之后的两个部分,并使用时尚mnist数据进行测试:

    加载图像,进行可能需要数小时或数天的拟合,并使用回调来保存最佳自动编码器模型。该过程可能比下一部分要早几周。 使用此最佳模型(按文件名手动选择)并绘制原始图像、由自动编码器的编码器生成的编码表示以及使用自动编码器的解码器进行的预测。 我在从经过训练和保存的自动编码器中提取编码器和解码器层时遇到问题(参见第二步)。

对于第一步,我有一个非常简单的网络,如下所示:

input_img = Input(shape=(784,))
# encoded representation
encoded = Dense(encoding_dim, activation='relu')(input_img)
# lossy reconstruction
decoded = Dense(784, activation='sigmoid')(encoded)

# full AE model: map an input to its reconstruction
autoencoder = Model(input_img, decoded)

# encoder: map an input to its encoded representation
encoder = Model(input_img, encoded)
# placeholder for an encoded input
encoded_input = Input(shape=(encoding_dim,))
# last layer of the autoencoder model
decoder_layer = autoencoder.layers[-1]
# decoder
decoder = Model(encoded_input, decoder_layer(encoded_input))

网络是:

autoencoder.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_5 (InputLayer)         (None, 784)               0         
_________________________________________________________________
dense_5 (Dense)              (None, 32)                25120     
_________________________________________________________________
dense_6 (Dense)              (None, 784)               25872     
=================================================================

encoder.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_5 (InputLayer)         (None, 784)               0         
_________________________________________________________________
dense_5 (Dense)              (None, 32)                25120     
=================================================================

所以我训练模型并将其保存到autoencoder.save('fashion-autoencoder.hdf5')。在我的真实示例中,我使用回调保存它,因此通过保存编码器和解码器的解决方法似乎不是真正的解决方案。稍后,我加载图像(未显示)并进行预测,如

# encode and decode some images from test set
encoded_imgs = encoder.predict(x_test)
decoded_imgs = decoder.predict(encoded_imgs)
# test the shape
print(encoded_imgs[0].shape)

得到(32,0)的形状。

所以让我们转到我遇到问题的第 2 步。我使用

加载模型
encoder= K.models.load_model('fashion-autoencoder.hdf5')
# delete the last layers to get the encoder
encoder.layers.pop()
encoder.summary() # show model data

编码器看起来与第一步中的原始编码器相同,这让我认为提取效果很好:

Layer (type)                 Output Shape              Param #   
=================================================================
input_5 (InputLayer)         (None, 784)               0         
_________________________________________________________________
dense_5 (Dense)              (None, 32)                25120     
=================================================================
Total params: 50,992
Trainable params: 50,992
Non-trainable params: 0

但我也收到警告

training.py:478: UserWarning: Discrepancy between trainable weights and collected trainable weights, did you set `model.trainable` without calling `model.compile` after ?
'Discrepancy between trainable weights and collected trainable'

我以某种方式理解但不知道它有多重要。然后我再次加载图像(未显示)并使用编码器

encoded_imgs = encoder.predict(x_test)

# test the shape
print(encoded_imgs[0].shape)

但是(784,)的形状不对。

因此,由于尺寸不正确,我对编码器的提取不起作用。 由于我无法使用push() 并尝试了decoder = decoder.layers[-1:-2] 之类的东西,但它没有成功,因此我提取解码器(从保存的自动编码器)的成功率更低。

所以,我的一般问题是如何提取已加载模型的一部分。

【问题讨论】:

【参考方案1】:

由于您使用函数式 API 来创建自动编码器,重构编码器和解码器的最佳方法是再次使用函数式 API 和 Model 类:

autoencoder= K.models.load_model('fashion-autoencoder.hdf5')

encoder = Model(autoencoder.input, autoencoder.layers[-2].output)

decoder_input = Input(shape=(encoding_dim,))
decoder = Model(decoder_input, autoencoder.layers[-1](decoder_input))

encoder.summary()
decoder.summary()

模型总结:

Layer (type)                 Output Shape              Param #   
=================================================================
input_4 (InputLayer)         (None, 784)               0         
_________________________________________________________________
dense_3 (Dense)              (None, 32)                25120     
=================================================================
Total params: 25,120
Trainable params: 25,120
Non-trainable params: 0
_________________________________________________________________


Layer (type)                 Output Shape              Param #   
=================================================================
input_6 (InputLayer)         (None, 32)                0         
_________________________________________________________________
dense_4 (Dense)              (None, 784)               25872     
=================================================================
Total params: 25,872
Trainable params: 25,872
Non-trainable params: 0
_________________________________________________________________

layers 属性does not work since you need to update some of the internal attributes of the model 上涉及pop() 的解决方案。虽然,对于顺序模型,已经实现了内置的 pop() 方法。

【讨论】:

非常感谢您的详细回答。 使用encoder = autoencoder.get_layer('dense_5')decoder = autoencoder.get_layer('dense_6') 还不够。或者,如果您在创建过程中给它们自定义名称,则更好,例如encoder = Model(input_img, encoded, name="decoder").

以上是关于从经过训练的自动编码器中提取编码器和解码器的主要内容,如果未能解决你的问题,请参考以下文章

AutoEncoder

降噪自动编码器(Denoising AutoEncoder)+BERT

tensorflow,训练后拆分自动编码器

VAE--就是AutoEncoder的编码输出服从正态分布

对抗性自动编码器系列--对抗自动编码器AAE的原理及实现-从任意随机数重建手写数字

自编码器