keras icon indicating copy to clipboard operation
keras copied to clipboard

TypeError: Cannot serialize object Ellipsis of type <class 'ellipsis'>

Open emosqueira opened this issue 1 year ago • 6 comments

In chapter 8 the book "Deep Learning with Python" it explains how to use a pretrained model. However, the provided code doesn't run, and an error message is obtained when executing model.fit:

TypeError: Cannot serialize object Ellipsis of type <class 'ellipsis'>. 
To be serializable, a class must implement the 'get_config()' method.

I am using Tensorflow version 2.15.0 and keras version 3.0.4

The program uses the dogs-vs-cats dataset from kaggle. It creates a smaller subset and creates a training, validation and test dataset. This all works as it is used for some other examples in the book. It then uses the pretrained VGG16 model and trains a dense layer connected to it.

Here it is the code:

data_augmentation = keras.Sequential(
    [
      keras.layers.RandomFlip("horizontal"),
      keras.layers.RandomRotation(0.1),
      keras.layers.RandomZoom(0.2)
    ]
)

inputs = keras.Input(shape=(180, 180, 3))
x = data_augmentation(inputs)
x = keras.applications.vgg16.preprocess_input(x)
x = conv_base(x)
x = keras.layers.Flatten()(x)
x = keras.layers.Dense(256)(x)
x = keras.layers.Dropout(0.5)(x)
outputs = keras.layers.Dense(1, activation="sigmoid")(x)

model = keras.Model(inputs, outputs)

model.compile(
    loss="binary_crossentropy",
    optimizer="rmsprop",
    metrics=["accuracy"]
)

callbacks = [
    keras.callbacks.ModelCheckpoint(
        filepath="features_extraction_with_data_augmentation.keras",
        save_best_only=True,
        monitor="val_loss"
    )
]
history = model.fit(  # error thrown here
    train_dataset,
    epochs=50,
    validation_data=validation_dataset,
    callbacks=callbacks
)

emosqueira avatar Feb 04 '24 22:02 emosqueira

Hi, Since the new .keras saving format, for custom objects, you must define a get_config() method. You can find complete details here https://keras.io/guides/serialization_and_saving/#custom-objects

sachinprasadhs avatar Feb 07 '24 22:02 sachinprasadhs

I also encountered this error on tf 2.15.0. It reproduces with this snippet:

import tensorflow as tf

x = tf.keras.layers.Input(shape=(42,))
model = tf.keras.Model(x, x[...])
model.save("tmp.keras", save_format="keras")
# TypeError: Cannot serialize object Ellipsis of type <class 'ellipsis'>. To be serializable, a class must implement the `get_config()` method.

verinov avatar Feb 08 '24 10:02 verinov

Yes, when the save_format="keras", you need to implement get_config() for Custom Objects.

sachinprasadhs avatar Feb 08 '24 22:02 sachinprasadhs

@sachinprasadhs does my example have custom objects?

Here is what I think is happening:

  • TFSlicingOpDispatcher is used to create a SlicingOpLambda layer, which will represent the tensor slicing. In the process, if transforms arguments with _slice_to_dict().
  • _slice_to_dict() encodes slice instances to dicts, but leaves everything else (ints and Ellipsis) as-is. These encoded args end up in the layer's config (get_config() is derived from TFOpLambda).
  • When serializing a config with Ellipsis, tf.keras.saving.serialize_keras_object(...) raises the TypeError, because ... is not handled there.

A simple solution might be to handle ... (Ellipsis) in _slice_to_dict() and _dict_to_slice().

verinov avatar Feb 09 '24 11:02 verinov

In the example I missed to include what conv_base(x) was. Here it is:

conv_base = keras.applications.vgg16.VGG16(
    weights="imagenet",
    include_top=False,
    input_shape=(180, 180, 3))

So, there is no custom model per se, all that is being used is inside the Keras library:

  • A data augmentation layer composed by keras layers: RandomFlip, RandomRotation and RandomZoom.
  • A layer that uses the VGG16 architecture from keras
  • Normal keras layers such as Flatten, Dense or Dropout.

emosqueira avatar Feb 09 '24 12:02 emosqueira

@emosqueira I also got stuck on this code snippet from the book. I found a workaround by dropping the .keras extension from the filepath. This seems to save the model and all its metadata to a folder instead of packed into .keras file.

callbacks = [
    keras.callbacks.ModelCheckpoint(
        filepath="features_extraction_with_data_augmentation",  # <-- removed the `.keras` ext
        save_best_only=True,
        monitor="val_loss"
    )
]

I agree with you though, this isn't a custom model so I think the .keras file should work automatically.

wrhansen avatar Feb 15 '24 02:02 wrhansen

Hey @emosqueira I found the same issue and solved it by following the solution* from https://stackoverflow.com/questions/77716307/typeerror-cannot-serialize-object-ellipsis-of-type-class-ellipsis:

You can simply wrap the function keras.applications.vgg16.preprocess_input in keras.layers.Lambda as follows:

#x = keras.applications.vgg16.preprocess_input(x)
x = keras.layers.Lambda(lambda x: keras.applications.vgg16.preprocess_input(x))(x)
image

and you would need to set safe_mode=False when you load the model with Lambda layer:

test_model = keras.models.load_model("feature_extraction_with_data_augmentation.keras", safe_mode=False)

image

Hope this helps~~

*Only worked on google colab (tensorflow==2.15.0 and keras==2.15.0), still having an error on my local machine with tensorflow==2.16.1 and keras==3.0.5:

NotImplementedError: Exception encountered when calling Lambda.call().

We could not automatically infer the shape of the Lambda's output. Please specify the `output_shape` argument for this Lambda layer.

Arguments received by Lambda.call():
  • args=('<KerasTensor shape=(None, 180, 180, 3), dtype=float32, sparse=False, name=keras_tensor_645>',)
  • kwargs={'mask': 'None'}

justudin avatar Apr 06 '24 19:04 justudin

This issue is stale because it has been open for 14 days with no activity. It will be closed if no further activity occurs. Thank you.

github-actions[bot] avatar Apr 24 '24 01:04 github-actions[bot]

This works for me. изображение

@tf.keras.utils.register_keras_serializable()
class PreprocessInput(tf.keras.layers.Layer):
    def call(self,inputs):
        return tf.reverse(inputs, axis=[-1]) - tf.constant([103.939, 116.779, 123.68], dtype=tf.float32)

DanisDeveloper avatar Apr 30 '24 12:04 DanisDeveloper

This issue is stale because it has been open for 14 days with no activity. It will be closed if no further activity occurs. Thank you.

github-actions[bot] avatar May 15 '24 01:05 github-actions[bot]

This issue was closed because it has been inactive for 28 days. Please reopen if you'd like to work on this further.

github-actions[bot] avatar May 29 '24 01:05 github-actions[bot]

Are you satisfied with the resolution of your issue? Yes No

google-ml-butler[bot] avatar May 29 '24 01:05 google-ml-butler[bot]