Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

custom_objects argument dropped on layer loading when calling model_from_config #5815

Closed
alreadytaikeune opened this issue Mar 16, 2017 · 5 comments

Comments

@alreadytaikeune
Copy link
Contributor

After switching to keras 2.0.0 and progressively migrating our code base (containing various custom layers and losses) it seemed that there were a bug in the way models are now created from a config. More specifically, the custom_objects arguments passed to model_from_config is lost in the back and forth between the deserialize_keras_object defined in generics_utils and the from_config method in models resulting in an error ValueError: Unknown layer: ....

The only solution that I've found is to introduce two simple modifications in the Model.from_config method:

  • Add a custom_objects={} argument
  • Pass this argument to each layer_module.deserialize call in the layer loop.

Did I miss something or is it indeed a problem with this new version? If it is should I submit a pull request?

Anis

@alreadytaikeune alreadytaikeune changed the title custom_objects argument on layer loading when calling model_from_config custom_objects argument dropped on layer loading when calling model_from_config Mar 16, 2017
@t-ae
Copy link
Contributor

t-ae commented Mar 23, 2017

I ran into similar problem in 2.0.2.
I'm using model.save() and load_model, and it only occurs when I use Sequential.
Here's sample code.

#!/usr/bin/env python

import os
from keras.models import Model, Sequential, load_model
from keras.layers import Input, InputLayer
from keras.engine.topology import Layer

class MyLayer(Layer):
    def __init__(self, **kwargs):
        super(MyLayer, self).__init__(**kwargs)

    def call(self, inputs):
        return inputs + 1

    def compute_output_shape(self, input_shape):
        return input_shape

    def get_config(self):
        return super(MyLayer, self).get_config()

i = Input([3])
x = MyLayer()(i)
modelA = Model(inputs=i, outputs=x)
modelA.save("model.h5")
try:
    load_model("model.h5", custom_objects={"MyLayer": MyLayer})
    print("Succeeded to load modelA.")
except:
    print("Failed to load modelA.")
os.remove("model.h5")

modelB = Sequential([
    InputLayer([10]),
    MyLayer()
])
modelB.save("model.h5")
try:
    load_model("model.h5", custom_objects={"MyLayer": MyLayer})  # this fails
    print("Succeeded to load modelB.")
except:
    print("Failed to load modelB.")
os.remove("model.h5")

I also noticed Sequential.from_config doesn't have custom_objects argument.

@t-ae
Copy link
Contributor

t-ae commented Mar 24, 2017

I found my last post may be separate issue... I'll create it.

In 2.0.2, Model.from_config can load custom layer, but model_from_config can't yet.

#!/usr/bin/env python

import os
from keras.models import Model, Sequential, load_model, model_from_config
from keras.layers import Input, InputLayer
from keras.engine.topology import Layer

class MyLayer(Layer):
    def __init__(self, **kwargs):
        super(MyLayer, self).__init__(**kwargs)

    def call(self, inputs):
        return inputs + 1

    def compute_output_shape(self, input_shape):
        return input_shape

    def get_config(self):
        return super(MyLayer, self).get_config()

i = Input([3])
x = MyLayer()(i)
modelA = Model(inputs=i, outputs=x)
conf = modelA.get_config()
try:
    Model.from_config(conf, custom_objects={"MyLayer": MyLayer})
    print("Succeeded.")
except:
    print("Failed with Model.from_config.")
try:
    model_from_config(conf, custom_objects={"MyLayer": MyLayer})  # this fails
    print("Succeeded.")
except:
    print("Failed with model_from_config.")

@buptss
Copy link

buptss commented Mar 25, 2017

@alreadytaikeune Thank you for your explanation.
I made some modification as you wrote. And here attached my modification as follows:
Suppose "SpatialPyramidPooling" is the custom layer I hope to add.
Modify "keras/models.py" as follows:
1191 #test shz
1192 #layer = layer_module.deserialize(conf) (Original, doesn't works)
1193 from SpatialPyramidPooling import SpatialPyramidPooling
1194 layer = layer_module.deserialize(conf,custom_objects = {"SpatialPyramidPooling":SpatialPyramidPooling})

I still wonder why it cannot find SpatialPyramidPooling in models.py. So I copy my layer.py into keras folder directly. It is quite ugly but useful.

@alreadytaikeune
Copy link
Contributor Author

@buptss I think there is also a modification to be made in utils/generic_utils.py and that I forgot to mention. I don't have access right now to the modified version, but here is my guess
141 return cls.from_config(config['config'])
should probably be passed custom objects as argument.

@stale stale bot added the stale label Jun 25, 2017
@stale
Copy link

stale bot commented Jun 25, 2017

This issue has been automatically marked as stale because it has not had recent activity. It will be closed after 30 days if no further activity occurs, but feel free to re-open a closed issue if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants