I am trying to develop an autoencoder that also uses the labels of the greyscale images I am trying to reconstruct. For that, I define a custom loss function.
However, when I try to run my code, I get this error:
TypeError: Keras symbolic inputs/outputs do not implement
__len__
. You may be trying to pass Keras symbolic inputs/outputs to a TF API that does not register dispatching, preventing Keras from automatically converting the API call to a lambda layer in the Functional Model. This error will also get raised if you try asserting a symbolic input/output directly.
I confirmed, that it's being produced at return total_loss
(see below)
I already tried the solutions provided here (trying to disable eager execution) and here (changing math operations to tf.math versions + disabling eager execution). Similar questions provide more or less the same answers or use additional libraries which I don't. However, none of the solutions work for me.
Here is the code I'm working with:
import tensorflow as tf
from tensorflow.keras.callbacks import EarlyStopping
from tensorflow import keras
def joint_loss(imgs_true, imgs_pred, y_true, y_pred, reconstruction_weight,
classification_weight):
# imgs_true = original images (= keras.input)
# imgs_pred = reconstructed images of my autoencoder
# y_true = true labels of my data (= keras.input)
# y_pred = predicted labels from my bottleneck layer
# reconstruction_weight/classification_weight = explanation below in "hyperparameters"
reconstruction_loss = tf.reduce_mean(tf.square(imgs_true - imgs_pred))
classification_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(y_true, y_pred))
total_loss = (tf.math.scalar_mul(reconstruction_weight, reconstruction_loss) +
tf.math.scalar_mul(classification_weight, classification_loss))
return total_loss
# define function of the autoencoder that's to be optimized; give back validation loss
def create_and_train_autoencoder(encoding_dim, f1, f2, f3, f4, f5, k1, k2,
num_epochs, bat_size, learning_rate,
recon_weight, class_weight):
# explanation for parameters in "hyperparameter" below
# input for images and labels
input_img = keras.Input(shape=(64, 128, 1))
input_label = keras.Input(shape=(1,))
# Encoding layers
x = keras.layers.Conv2D(f1, (k1, k2), activation='relu', padding='same')(input_img)
x = keras.layers.MaxPooling2D((2, 2), padding='same')(x)
x = keras.layers.Conv2D(f2, (k1, k2), activation='relu', padding='same')(x)
x = keras.layers.MaxPooling2D((2, 2), padding='same')(x)
x = keras.layers.Conv2D(f3, (k1, k2), activation='relu', padding='same')(x)
x = keras.layers.MaxPooling2D((2, 2), padding='same')(x)
# Bottleneck
encoded = keras.layers.Conv2D(encoding_dim, (k1, k2), activation='relu',
padding='same')(x)
# Define the classification branch
encoded_flattened = keras.layers.Flatten()(encoded)
encoded_flattened_dense1 = keras.layers.Dense(f4, activation='relu')(encoded_flattened)
encoded_flattened_dense2 = keras.layers.Dense(f5, activation='relu')(encoded_flattened_dense1)
label_output = keras.layers.Dense(1, activation='sigmoid')(encoded_flattened_dense2)
# Decoding layers
x = keras.layers.UpSampling2D((2, 2))(encoded)
x = keras.layers.Conv2D(f3, (k1, k2), activation='relu', padding='same')(x)
x = keras.layers.UpSampling2D((2, 2))(x)
x = keras.layers.Conv2D(f2, (k1, k2), activation='relu', padding='same')(x)
x = keras.layers.UpSampling2D((2, 2))(x)
x = keras.layers.Conv2D(f1, (k1, k2), activation='relu', padding='same')(x)
decoded = keras.layers.Conv2D(1, (k1, k2), activation='sigmoid', padding='same')(x)
# create model and compile
autoencoder = keras.Model([input_img, input_label], [decoded, label_output])
autoencoder.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate),
loss=joint_loss(input_img, decoded, input_label, label_output,
recon_weight, class_weight))
# Create early stopping callback
early_stopping = EarlyStopping(monitor='val_loss', patience=15,
restore_best_weights=True)
# fit
history = autoencoder.fit([x_train, y_train], [x_train, y_train],
epochs=num_epochs,
batch_size= bat_size,
shuffle=True,
validation_data=([x_test, y_test], [x_test, y_test]),
callbacks=[early_stopping])
return history.history['val_loss'][-1]
# execute the function
best_autoencoder = create_and_train_autoencoder(
encoding_dim, f1, f2, f3, f4, f5, k1, k2, num_epochs, bat_size,
learning_rate, reconstr_weight, class_weight)
A little bit of background if needed:
I have 51 (64,128) greyscale images in a (51,64,128) array as my x_train. I have 13 (64,128) greyscale images in a (13,64,128) array as my x_test. I have 51 (1,) labels in a (51,) array as my y_train. I have 13 (1,) labels in a (13,) array as my y_test. My labels are [0,1].
For the sake of this example I'm using the following hyperparameters:
- encoding_dim=14 # number filters for reduced dimension
- f1 = 16 # number filters
- f2=f3 = 8 # number filters
- f4=f5 = 64 # number filters
- k1=k2 = 3 # kernel size
- num_epochs = 25 # number of epochs
- bat_size = 32 # batch_size
- learning_rate = 0.0001 # learning rate
- reconstr_weight = 0.5 # parameter for manipulating joint loss
- class_weight = 0.5 # parameter for manipulating joint loss
I'm using tensorflow 2.7. I'm not using Cuda.
Any help is much appreciated!