Search code examples
keraspython-3.6autoencodertensorflow2.0

Obtaining hidden layer outputs in a denoising autoencoder using Keras


I have built a Sequential Keras model with three layers: A Gaussian Noise layer, a hidden layer, and the output layer with the same dimension as the input layer. For this, I'm using the Keras package that comes with Tensorflow 2.0.0-beta1. Thus, I'd like to get the output of the hidden layer, such that I circumvent the Gaussian Noise layer since it's only necessary in the training phase.

To achieve my goal, I followed the instructions in https://keras.io/getting-started/faq/#how-can-i-obtain-the-output-of-an-intermediate-layer, which are pretty much described in Keras, How to get the output of each layer? too.

I have tried the following example from the official Keras documentation:

from tensorflow import keras
from tensorflow.keras import backend as K

dae = keras.Sequential([
    keras.layers.GaussianNoise( 0.001, input_shape=(10,) ),
    keras.layers.Dense( 80, name="hidden", activation="relu" ),
    keras.layers.Dense( 10 )
])

optimizer = keras.optimizers.Adam()
dae.compile( loss="mse", optimizer=optimizer, metrics=["mae"] )

# Here the fitting process...
# dae.fit( · )

# Attempting to retrieve a decoder functor.
encoder = K.function([dae.input, K.learning_phase()], 
                               [dae.get_layer("hidden").output])

However, when K.learning_phase() is used to create the Keras backend functor, I get the error:

Traceback (most recent call last):
  File "/anaconda3/lib/python3.6/contextlib.py", line 99, in __exit__
    self.gen.throw(type, value, traceback)
  File "/anaconda3/lib/python3.6/site-packages/tensorflow_core/python/keras/backend.py", line 534, in _scratch_graph
    yield graph
  File "/anaconda3/lib/python3.6/site-packages/tensorflow_core/python/keras/backend.py", line 3670, in __init__
    base_graph=source_graph)
  File "/anaconda3/lib/python3.6/site-packages/tensorflow_core/python/eager/lift_to_graph.py", line 249, in lift_to_graph
    visited_ops = set([x.op for x in sources])
  File "/anaconda3/lib/python3.6/site-packages/tensorflow_core/python/eager/lift_to_graph.py", line 249, in <listcomp>
    visited_ops = set([x.op for x in sources])
AttributeError: 'int' object has no attribute 'op'

The code works great if I don't include K.learning_phase(), but I need to make sure that the output from my hidden layer is evaluated over an input that is not polluted with noise (i.e. in "test" mode -- not "training" mode).

I know my other option is to create a model from the original denoising autoencoder, but can anyone point me into why my approach from the officially documented functor creation fails?


Solution

  • Firstly, ensure your packages are up-to-date, as your script works fine for me. Second, encoder won't get the outputs - continuing from your snippet after # Here is the fitting process...,

    x = np.random.randn(32, 10) # toy data
    y = np.random.randn(32, 10) # toy labels
    dae.fit(x, y) # run one iteration
    
    encoder = K.function([dae.input, K.learning_phase()], [dae.get_layer("hidden").output])
    outputs = [encoder([x, int(False)])][0][0] # [0][0] to index into nested list of len 1
    print(outputs.shape)
    # (32, 80)
    

    However, as of Tensorflow 2.0.0-rc2, this will not work with eager execution enabled - disable via:

    tf.compat.v1.disable_eager_execution()