Versatile workflow for autoencoders in Keras

Architecture definition

This code defines the simplest architecture: [input, encoding (2), output]

enc_dim = 2

encoder = tf.keras.Sequential([
    tf.keras.layers.Dense(enc_dim, activation="relu", input_shape=(data.shape[1], ))
decoder = tf.keras.Sequential([
    tf.keras.layers.Dense(data.shape[1], activation="sigmoid", input_shape=(enc_dim,))

Definition of a loss function

Defining the loss as a function allows us much more flexibility to compute penalties from the encodings, or even other inputs (supervised autoencoders).

def autoencoder_loss(layers):
    inp, enc, out = layers
    rec_loss = K.binary_crossentropy(inp, out)
    # compute other penalties
    loss = rec_loss # + other penalties
    return loss

Definition of the loss layer and the model

The loss function is wrapped as the last layer of the autoencoder model and connected to the necessary inputs/outputs.

loss_l = tf.keras.layers.Lambda(autoencoder_loss, output_shape=(1,), name="loss")([
    encoder.input, encoder.output, decoder(encoder(encoder.input))

autoencoder = tf.keras.Model([encoder.input, target_input], loss_l)

Compilation of model with custom loss

Since the last layer (y_pred) is actually the loss, our custom loss only needs to return that value.

autoencoder.compile(loss={'loss': lambda y_true, y_pred: y_pred}, optimizer="adam")

Fit model with dummy target

Keras will complain if no target is passed, so we just create some dummy targets which will not be used at all.

hist =, np.zeros(data.shape[0]), batch_size=8, epochs = 100)