从已训练的自编码器中提取编码器和解码器

11
我希望将自编码器的学习和应用分为两部分,按照https://blog.keras.io/building-autoencoders-in-keras.html所述的步骤,并使用时尚MNIST数据进行测试:
  1. 加载图像,进行拟合(可能需要数小时或数天),并使用回调函数保存最佳自编码器模型。该过程可能需要数周才能完成第二个步骤。
  2. 使用此最佳模型(手动选择文件名),并绘制原始图像、由自编码器编码器生成的编码表示以及使用自编码器解码器进行预测的结果。我在从训练和保存的自编码器中提取编码器和解码器层方面遇到了问题(请参见第二步)。
对于第一步,我有一个非常简单的网络,如下所示:
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个回答

19

由于您正在使用函数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属性上的pop()方法的解决方案不起作用,因为您需要更新模型的一些内部属性。虽然,对于顺序模型,已经实现了一个内置的pop()方法。


非常感谢您提供这么详细的答案。 - tardis
难道使用 encoder = autoencoder.get_layer('dense_5')decoder = autoencoder.get_layer('dense_6') 就足够了吗?如果在创建时为它们自定义名称,例如 encoder = Model(input_img, encoded, name="decoder"),那就更好了。 - HUSMEN

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接