Probably typo.

@keras.saving.register_keras_serializable()
class DummyModel(keras.Model):
    def __init__(
        self,
        *,
        input_shape=(28, 28, 1),
        filters=[16, 32],
        activation='relu',
        **kwargs,
    ):
        input_spec = keras.layers.Input(shape=input_shape)
        x = input_spec
        x = layers.Conv2D(filters[0], 3, activation=activation)(x)
        x = layers.Conv2D(filters[1], 3, activation=activation)(x)
        x = layers.MaxPooling2D(3)(x)
        x = layers.Conv2D(filters[1], 3, activation=activation)(x)
        x = layers.Conv2D(filters[0], 3, activation=activation)(x)
        x = layers.GlobalMaxPooling2D()(x)
        super().__init__(inputs=input_spec, outputs=x, **kwargs)

        self.filters = filters
        self.activation = activation

    def get_config(self):
        config = super().get_config()
        config.update(
            {
                "input_shape": self.input_shape[1:],
                "filters": self.filters,
                "activation": self.activation,
            }
        )
        return config

a = np.ones((1, 28, 28, 1), dtype=np.float32); print(a.shape)
model = DummyModel()
output = model(a)
print(output.shape)
(1, 28, 28, 1)
(1, 16)

model.save('new.keras') # ok

loaded_model = keras.saving.load_model("new.keras")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/usr/local/lib/python3.10/dist-packages/keras/src/saving/serialization_lib.py in deserialize_keras_object(config, custom_objects, safe_mode, **kwargs)
    710         try:
--> 711             instance = cls.from_config(inner_config)
    712         except TypeError as e:

/usr/local/lib/python3.10/dist-packages/keras/src/models/model.py in from_config(cls, config, custom_objects)
    491 
--> 492             return functional_from_config(
    493                 cls, config, custom_objects=custom_objects

/usr/local/lib/python3.10/dist-packages/keras/src/models/functional.py in functional_from_config(cls, config, custom_objects)
    555     output_tensors = map_tensors(config["output_layers"])
--> 556     return cls(
    557         inputs=input_tensors,

<ipython-input-17-242e47f47517> in __init__(self, input_shape, filters, activation, **kwargs)
     33         x = layers.GlobalMaxPooling2D()(x)
---> 34         super().__init__(inputs=input_spec, outputs=x, **kwargs)
     35 

TypeError: keras.src.models.functional.Functional.__init__() got multiple values for keyword argument 'inputs'

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
<ipython-input-20-9e5a9738bac0> in <cell line: 1>()
----> 1 loaded_model = keras.saving.load_model("new.keras")

/usr/local/lib/python3.10/dist-packages/keras/src/saving/saving_api.py in load_model(filepath, custom_objects, compile, safe_mode)
    174 
    175     if is_keras_zip:
--> 176         return saving_lib.load_model(
    177             filepath,
    178             custom_objects=custom_objects,

/usr/local/lib/python3.10/dist-packages/keras/src/saving/saving_lib.py in load_model(filepath, custom_objects, compile, safe_mode)
    153         # Construct the model from the configuration file in the archive.
    154         with ObjectSharingScope():
--> 155             model = deserialize_keras_object(
    156                 config_dict, custom_objects, safe_mode=safe_mode
    157             )

/usr/local/lib/python3.10/dist-packages/keras/src/saving/serialization_lib.py in deserialize_keras_object(config, custom_objects, safe_mode, **kwargs)
    711             instance = cls.from_config(inner_config)
    712         except TypeError as e:
--> 713             raise TypeError(
    714                 f"{cls} could not be deserialized properly. Please"
    715                 " ensure that components that are Python object"

TypeError: <class '__main__.DummyModel'> could not be deserialized properly. Please ensure that components that are Python object instances (layers, models, etc.) returned by `get_config()` are explicitly deserialized in the model's `from_config()` method.

config={'module': None, 'class_name': 'DummyModel', 'config': {'name': 'dummy_model_3', 'trainable': True, 'layers': [{'module': 'keras.layers', 'class_name': 'InputLayer', 'config': {'batch_shape': [None, 28, 28, 1], 'dtype': 'float32', 'sparse': False, 'name': 'input_layer_2'}, 'registered_name': None, 'name': 'input_layer_2', 'inbound_nodes': []}, {'module': 'keras.layers', 'class_name': 'Conv2D', 'config': {'name': 'conv2d_24', 'trainable': True, 'dtype': 'float32', 'filters': 16, 'kernel_size': [3, 3], 'strides': [1, 1], 'padding': 'valid', 'data_format': 'channels_last', 'dilation_rate': [1, 1], 'groups': 1, 'activation': 'relu', 'use_bias': True, 'kernel_initializer': {'module': 'keras.initializers', 'class_name': 'GlorotUniform', 'config': {'seed': None}, 'registered_name': None}, 'bias_initializer': {'module': 'keras.initializers', 'class_name': 'Zeros', 'config': {}, 'registered_name': None}, 'kernel_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}, 'registered_name': None, 'build_config': {'input_shape': [None, 28, 28, 1]}, 'name': 'conv2d_24', 'inbound_nodes': [{'args': [{'class_name': '__keras_tensor__', 'config': {'shape': [None, 28, 28, 1], 'dtype': 'float32', 'keras_history': ['input_layer_2', 0, 0]}}], 'kwargs': {}}]}, {'module': 'keras.layers', 'class_name': 'Conv2D', 'config': {'name': 'conv2d_25', 'trainable': True, 'dtype': 'float32', 'filters': 32, 'kernel_size': [3, 3], 'strides': [1, 1], 'padding': 'valid', 'data_format': 'channels_last', 'dilation_rate': [1, 1], 'groups': 1, 'activation': 'relu', 'use_bias': True, 'kernel_initializer': {'module': 'keras.initializers', 'class_name': 'GlorotUniform', 'config': {'seed': None}, 'registered_name': None}, 'bias_initializer': {'module': 'keras.initializers', 'class_name': 'Zeros', 'config': {}, 'registered_name': None}, 'kernel_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}, 'registered_name': None, 'build_config': {'input_shape': [None, 26, 26, 16]}, 'name': 'conv2d_25', 'inbound_nodes': [{'args': [{'class_name': '__keras_tensor__', 'config': {'shape': [None, 26, 26, 16], 'dtype': 'float32', 'keras_history': ['conv2d_24', 0, 0]}}], 'kwargs': {}}]}, {'module': 'keras.layers', 'class_name': 'MaxPooling2D', 'config': {'name': 'max_pooling2d_6', 'trainable': True, 'dtype': 'float32', 'pool_size': [3, 3], 'padding': 'valid', 'strides': [3, 3], 'data_format': 'channels_last'}, 'registered_name': None, 'build_config': {'input_shape': [None, 24, 24, 32]}, 'name': 'max_pooling2d_6', 'inbound_nodes': [{'args': [{'class_name': '__keras_tensor__', 'config': {'shape': [None, 24, 24, 32], 'dtype': 'float32', 'keras_history': ['conv2d_25', 0, 0]}}], 'kwargs': {}}]}, {'module': 'keras.layers', 'class_name': 'Conv2D', 'config': {'name': 'conv2d_26', 'trainable': True, 'dtype': 'float32', 'filters': 32, 'kernel_size': [3, 3], 'strides': [1, 1], 'padding': 'valid', 'data_format': 'channels_last', 'dilation_rate': [1, 1], 'groups': 1, 'activation': 'relu', 'use_bias': True, 'kernel_initializer': {'module': 'keras.initializers', 'class_name': 'GlorotUniform', 'config': {'seed': None}, 'registered_name': None}, 'bias_initializer': {'module': 'keras.initializers', 'class_name': 'Zeros', 'config': {}, 'registered_name': None}, 'kernel_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}, 'registered_name': None, 'build_config': {'input_shape': [None, 8, 8, 32]}, 'name': 'conv2d_26', 'inbound_nodes': [{'args': [{'class_name': '__keras_tensor__', 'config': {'shape': [None, 8, 8, 32], 'dtype': 'float32', 'keras_history': ['max_pooling2d_6', 0, 0]}}], 'kwargs': {}}]}, {'module': 'keras.layers', 'class_name': 'Conv2D', 'config': {'name': 'conv2d_27', 'trainable': True, 'dtype': 'float32', 'filters': 16, 'kernel_size': [3, 3], 'strides': [1, 1], 'padding': 'valid', 'data_format': 'channels_last', 'dilation_rate': [1, 1], 'groups': 1, 'activation': 'relu', 'use_bias': True, 'kernel_initializer': {'module': 'keras.initializers', 'class_name': 'GlorotUniform', 'config': {'seed': None}, 'registered_name': None}, 'bias_initializer': {'module': 'keras.initializers', 'class_name': 'Zeros', 'config': {}, 'registered_name': None}, 'kernel_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}, 'registered_name': None, 'build_config': {'input_shape': [None, 6, 6, 32]}, 'name': 'conv2d_27', 'inbound_nodes': [{'args': [{'class_name': '__keras_tensor__', 'config': {'shape': [None, 6, 6, 32], 'dtype': 'float32', 'keras_history': ['conv2d_26', 0, 0]}}], 'kwargs': {}}]}, {'module': 'keras.layers', 'class_name': 'GlobalMaxPooling2D', 'config': {'name': 'global_max_pooling2d_6', 'trainable': True, 'dtype': 'float32', 'data_format': 'channels_last', 'keepdims': False}, 'registered_name': None, 'build_config': {'input_shape': [None, 4, 4, 16]}, 'name': 'global_max_pooling2d_6', 'inbound_nodes': [{'args': [{'class_name': '__keras_tensor__', 'config': {'shape': [None, 4, 4, 16], 'dtype': 'float32', 'keras_history': ['conv2d_27', 0, 0]}}], 'kwargs': {}}]}], 'input_layers': [['input_layer_2', 0, 0]], 'output_layers': [['global_max_pooling2d_6', 0, 0]], 'input_shape': [28, 28, 1], 'filters': [16, 32], 'activation': 'relu'}, 'registered_name': 'Custom>DummyModel', 'build_config': {'input_shape': None}}.

Exception encountered: keras.src.models.functional.Functional.__init__() got multiple values for keyword argument 'inputs'

Comment From: sonali-kumari1

Hi @innat -

The error you are getting is due to your custom model not being deserialized properly. To resolve this error, you must explicitly deserialize your custom components in the from_config() class method like this:

@keras.saving.register_keras_serializable()
class DummyModel(keras.Model):
    def __init__(
        self,
        *,
        input_shape=(28, 28, 1),
        filters=[16, 32],
        activation='relu',
        **kwargs,
    ):
        input_spec = keras.layers.Input(shape=input_shape)
        x = input_spec
        x = layers.Conv2D(filters[0], 3, activation=activation)(x)
        x = layers.Conv2D(filters[1], 3, activation=activation)(x)
        x = layers.MaxPooling2D(3)(x)
        x = layers.Conv2D(filters[1], 3, activation=activation)(x)
        x = layers.Conv2D(filters[0], 3, activation=activation)(x)
        x = layers.GlobalMaxPooling2D()(x)
        super().__init__(inputs=input_spec, outputs=x, **kwargs)

        self.filters = filters
        self.activation = activation

    def get_config(self):
        config = super().get_config()
        config.update(
            {
                "input_shape": self.input_shape[1:],
                "filters": self.filters,
                "activation": self.activation,
            }
        )
        return config

    @classmethod
    def from_config(cls, config):
        return cls(**config)

a = np.ones((1, 28, 28, 1), dtype=np.float32); print(a.shape)
model = DummyModel()
output = model(a)
print(output.shape)
(1, 28, 28, 1)
(1, 16)

model.save('new.keras') # ok

loaded_model = keras.saving.load_model("new.keras")

Please refer to this documentation on custom objects for more details. Thanks!

Comment From: innat

@sonali-kumari1

By adding from config should work, right?

@keras.saving.register_keras_serializable()
class DummyModel(keras.Model):
    def __init__(
        self,
        *,
        input_shape=(28, 28, 1),
        filters=[16, 32],
        activation='relu',
        **kwargs,
    ):
        ...
        super().__init__(inputs=input_spec, outputs=x, **kwargs)

        self.filters = filters
        self.activation = activation

    def get_config(self):
        config = super().get_config()
        config.update(
            {
                "input_shape": self.input_shape[1:],
                "filters": self.filters,
                "activation": self.activation,
            }
        )
        return config

    @classmethod
    def from_config(cls, config):
        return cls(**config)

a = np.ones((1, 28, 28, 1), dtype=np.float32); print(a.shape)
model = DummyModel()
output = model(a)
print(output.shape)


model.save('new.keras') # ok

loaded_model = keras.saving.load_model("new.keras")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/usr/local/lib/python3.10/dist-packages/keras/src/saving/serialization_lib.py in deserialize_keras_object(config, custom_objects, safe_mode, **kwargs)
    717         try:
--> 718             instance = cls.from_config(inner_config)
    719         except TypeError as e:

<ipython-input-5-8788dfb26b4d> in from_config(cls, config)
     36     def from_config(cls, config):
---> 37         return cls(**config)
     38 

<ipython-input-5-8788dfb26b4d> in __init__(self, input_shape, filters, activation, **kwargs)
     18         x = layers.GlobalMaxPooling2D()(x)
---> 19         super().__init__(inputs=input_spec, outputs=x, **kwargs)
     20 

/usr/local/lib/python3.10/dist-packages/keras/src/utils/tracking.py in wrapper(*args, **kwargs)
     25         with DotNotTrackScope():
---> 26             return fn(*args, **kwargs)
     27 

/usr/local/lib/python3.10/dist-packages/keras/src/models/functional.py in __init__(self, inputs, outputs, name, **kwargs)
    134 
--> 135         Function.__init__(self, inputs, outputs, name=name, **kwargs)
    136 

TypeError: Function.__init__() got an unexpected keyword argument 'layers'

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
<ipython-input-5-8788dfb26b4d> in <cell line: 47>()
     45 model.save('new.keras') # ok
     46 
---> 47 loaded_model = keras.saving.load_model("new.keras")

/usr/local/lib/python3.10/dist-packages/keras/src/saving/saving_api.py in load_model(filepath, custom_objects, compile, safe_mode)
    185 
    186     if is_keras_zip or is_keras_dir:
--> 187         return saving_lib.load_model(
    188             filepath,
    189             custom_objects=custom_objects,

/usr/local/lib/python3.10/dist-packages/keras/src/saving/saving_lib.py in load_model(filepath, custom_objects, compile, safe_mode)
    363             )
    364         with open(filepath, "rb") as f:
--> 365             return _load_model_from_fileobj(
    366                 f, custom_objects, compile, safe_mode
    367             )

/usr/local/lib/python3.10/dist-packages/keras/src/saving/saving_lib.py in _load_model_from_fileobj(fileobj, custom_objects, compile, safe_mode)
    440             config_json = f.read()
    441 
--> 442         model = _model_from_config(
    443             config_json, custom_objects, compile, safe_mode
    444         )

/usr/local/lib/python3.10/dist-packages/keras/src/saving/saving_lib.py in _model_from_config(config_json, custom_objects, compile, safe_mode)
    429     # Construct the model from the configuration file in the archive.
    430     with ObjectSharingScope():
--> 431         model = deserialize_keras_object(
    432             config_dict, custom_objects, safe_mode=safe_mode
    433         )

/usr/local/lib/python3.10/dist-packages/keras/src/saving/serialization_lib.py in deserialize_keras_object(config, custom_objects, safe_mode, **kwargs)
    718             instance = cls.from_config(inner_config)
    719         except TypeError as e:
--> 720             raise TypeError(
    721                 f"{cls} could not be deserialized properly. Please"
    722                 " ensure that components that are Python object"

TypeError: <class '__main__.DummyModel'> could not be deserialized properly. Please ensure that components that are Python object instances (layers, models, etc.) returned by `get_config()` are explicitly deserialized in the model's `from_config()` method.

config={'module': None, 'class_name': 'DummyModel', 'config': {'name': 'dummy_model_1', 'trainable': True, 'layers': [{'module': 'keras.layers', 'class_name': 'InputLayer', 'config': {'batch_shape': [None, 28, 28, 1], 'dtype': 'float32', 'sparse': False, 'name': 'input_layer_2'}, 'registered_name': None, 'name': 'input_layer_2', 'inbound_nodes': []}, {'module': 'keras.layers', 'class_name': 'Conv2D', 'config': {'name': 'conv2d_8', 'trainable': True, 'dtype': {'module': 'keras', 'class_name': 'DTypePolicy', 'config': {'name': 'float32'}, 'registered_name': None}, 'filters': 16, 'kernel_size': [3, 3], 'strides': [1, 1], 'padding': 'valid', 'data_format': 'channels_last', 'dilation_rate': [1, 1], 'groups': 1, 'activation': 'relu', 'use_bias': True, 'kernel_initializer': {'module': 'keras.initializers', 'class_name': 'GlorotUniform', 'config': {'seed': None}, 'registered_name': None}, 'bias_initializer': {'module': 'keras.initializers', 'class_name': 'Zeros', 'config': {}, 'registered_name': None}, 'kernel_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}, 'registered_name': None, 'build_config': {'input_shape': [None, 28, 28, 1]}, 'name': 'conv2d_8', 'inbound_nodes': [{'args': [{'class_name': '__keras_tensor__', 'config': {'shape': [None, 28, 28, 1], 'dtype': 'float32', 'keras_history': ['input_layer_2', 0, 0]}}], 'kwargs': {}}]}, {'module': 'keras.layers', 'class_name': 'Conv2D', 'config': {'name': 'conv2d_9', 'trainable': True, 'dtype': {'module': 'keras', 'class_name': 'DTypePolicy', 'config': {'name': 'float32'}, 'registered_name': None, 'shared_object_id': 137654361192000}, 'filters': 32, 'kernel_size': [3, 3], 'strides': [1, 1], 'padding': 'valid', 'data_format': 'channels_last', 'dilation_rate': [1, 1], 'groups': 1, 'activation': 'relu', 'use_bias': True, 'kernel_initializer': {'module': 'keras.initializers', 'class_name': 'GlorotUniform', 'config': {'seed': None}, 'registered_name': None}, 'bias_initializer': {'module': 'keras.initializers', 'class_name': 'Zeros', 'config': {}, 'registered_name': None}, 'kernel_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}, 'registered_name': None, 'build_config': {'input_shape': [None, 26, 26, 16]}, 'name': 'conv2d_9', 'inbound_nodes': [{'args': [{'class_name': '__keras_tensor__', 'config': {'shape': [None, 26, 26, 16], 'dtype': 'float32', 'keras_history': ['conv2d_8', 0, 0]}}], 'kwargs': {}}]}, {'module': 'keras.layers', 'class_name': 'MaxPooling2D', 'config': {'name': 'max_pooling2d_2', 'trainable': True, 'dtype': {'module': 'keras', 'class_name': 'DTypePolicy', 'config': {'name': 'float32'}, 'registered_name': None, 'shared_object_id': 137654361192000}, 'pool_size': [3, 3], 'padding': 'valid', 'strides': [3, 3], 'data_format': 'channels_last'}, 'registered_name': None, 'build_config': {'input_shape': [None, 24, 24, 32]}, 'name': 'max_pooling2d_2', 'inbound_nodes': [{'args': [{'class_name': '__keras_tensor__', 'config': {'shape': [None, 24, 24, 32], 'dtype': 'float32', 'keras_history': ['conv2d_9', 0, 0]}}], 'kwargs': {}}]}, {'module': 'keras.layers', 'class_name': 'Conv2D', 'config': {'name': 'conv2d_10', 'trainable': True, 'dtype': {'module': 'keras', 'class_name': 'DTypePolicy', 'config': {'name': 'float32'}, 'registered_name': None, 'shared_object_id': 137654361192000}, 'filters': 32, 'kernel_size': [3, 3], 'strides': [1, 1], 'padding': 'valid', 'data_format': 'channels_last', 'dilation_rate': [1, 1], 'groups': 1, 'activation': 'relu', 'use_bias': True, 'kernel_initializer': {'module': 'keras.initializers', 'class_name': 'GlorotUniform', 'config': {'seed': None}, 'registered_name': None}, 'bias_initializer': {'module': 'keras.initializers', 'class_name': 'Zeros', 'config': {}, 'registered_name': None}, 'kernel_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}, 'registered_name': None, 'build_config': {'input_shape': [None, 8, 8, 32]}, 'name': 'conv2d_10', 'inbound_nodes': [{'args': [{'class_name': '__keras_tensor__', 'config': {'shape': [None, 8, 8, 32], 'dtype': 'float32', 'keras_history': ['max_pooling2d_2', 0, 0]}}], 'kwargs': {}}]}, {'module': 'keras.layers', 'class_name': 'Conv2D', 'config': {'name': 'conv2d_11', 'trainable': True, 'dtype': {'module': 'keras', 'class_name': 'DTypePolicy', 'config': {'name': 'float32'}, 'registered_name': None, 'shared_object_id': 137654361192000}, 'filters': 16, 'kernel_size': [3, 3], 'strides': [1, 1], 'padding': 'valid', 'data_format': 'channels_last', 'dilation_rate': [1, 1], 'groups': 1, 'activation': 'relu', 'use_bias': True, 'kernel_initializer': {'module': 'keras.initializers', 'class_name': 'GlorotUniform', 'config': {'seed': None}, 'registered_name': None}, 'bias_initializer': {'module': 'keras.initializers', 'class_name': 'Zeros', 'config': {}, 'registered_name': None}, 'kernel_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}, 'registered_name': None, 'build_config': {'input_shape': [None, 6, 6, 32]}, 'name': 'conv2d_11', 'inbound_nodes': [{'args': [{'class_name': '__keras_tensor__', 'config': {'shape': [None, 6, 6, 32], 'dtype': 'float32', 'keras_history': ['conv2d_10', 0, 0]}}], 'kwargs': {}}]}, {'module': 'keras.layers', 'class_name': 'GlobalMaxPooling2D', 'config': {'name': 'global_max_pooling2d_2', 'trainable': True, 'dtype': {'module': 'keras', 'class_name': 'DTypePolicy', 'config': {'name': 'float32'}, 'registered_name': None, 'shared_object_id': 137654361192000}, 'data_format': 'channels_last', 'keepdims': False}, 'registered_name': None, 'build_config': {'input_shape': [None, 4, 4, 16]}, 'name': 'global_max_pooling2d_2', 'inbound_nodes': [{'args': [{'class_name': '__keras_tensor__', 'config': {'shape': [None, 4, 4, 16], 'dtype': 'float32', 'keras_history': ['conv2d_11', 0, 0]}}], 'kwargs': {}}]}], 'input_layers': [['input_layer_2', 0, 0]], 'output_layers': [['global_max_pooling2d_2', 0, 0]], 'input_shape': [28, 28, 1], 'filters': [16, 32], 'activation': 'relu'}, 'registered_name': 'Custom>DummyModel', 'build_config': {'input_shape': None}}.

Exception encountered: Function.__init__() got an unexpected keyword argument 'layers'

Comment From: sonali-kumari1

Hi @innat -

I have tried to replicate the issue in colab notebook with the latest version of keras(3.8.0) and the code works fine. Attaching gist for your reference.Thanks!

Comment From: innat

@sonali-kumari1 Thanks. I was running the model in kaggle where keras==3.5.0. And it fails to load the model. This seems like bug in 3.5 version which fixed in 3.8. Is there any workaround to make it work in 3.5?