When keras models using backend are saved, the json (de)serialization cannot find "backend". This may be due to the use of the Lambda layer, as it appears that the name "backend" is saved in the json and then the loader cannot find it (because "backend" is not in its namespace). If it is imported as "K", then it works properly, because the loader imports backend as K.
Possible Quick Fix: Update the documentation both in backend and Lambda that backend must be imported as "K". The current doc only has a note under backend, and seems to be just a suggestion: "You can import the backend module via: from keras import backend as K". Given standard python convention, it is unintuitive that "from keras import backend", "import keras.backend", or "from keras import backend as somethingelse" should function differently.
Another workaround is to have the user add "from keras import backend" in their user-defined Lambda function.
Best,
David
Here's a script that demonstrates working and non-working cases.
theano.__version__ = '0.9.0dev4.dev-ad1310c88830ed96119194c4f2da22b9b37c7622'
keras.__version__ = '1.1.2'
from keras import backend as K
from keras.layers.convolutional import Convolution1D
from keras.layers import Lambda, Dense
from keras.models import Sequential, model_from_json
print 'Works'
model = Sequential()
model.add(Convolution1D(nb_filter=128, filter_length=5, input_shape=(4096, 16), border_mode='same', activation='relu'))
model.add(Lambda(lambda x: K.sum(x, axis=1), output_shape=(128,)))
model.add(Dense(10, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='Nadam')
model2 = model_from_json(model.to_json())
from keras import backend
print 'Fails'
model = Sequential()
model.add(Convolution1D(nb_filter=128, filter_length=5, input_shape=(4096, 16), border_mode='same', activation='relu'))
model.add(Lambda(lambda x: backend.sum(x, axis=1), output_shape=(128,)))
model.add(Dense(10, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='Nadam')
model2 = model_from_json(model.to_json())
The second model load fails with this stack trace:
Traceback (most recent call last):
File "keras_bug.py", line 23, in <module>
model2 = model_from_json(model.to_json())
File "/Users/davidslater/.virtualenvs/davidslater/lib/python2.7/site-packages/keras/models.py", line 209, in model_from_json
return layer_from_config(config, custom_objects=custom_objects)
File "/Users/davidslater/.virtualenvs/davidslater/lib/python2.7/site-packages/keras/utils/layer_utils.py", line 34, in layer_from_config
return layer_class.from_config(config['config'])
File "/Users/davidslater/.virtualenvs/davidslater/lib/python2.7/site-packages/keras/models.py", line 1061, in from_config
model.add(layer)
File "/Users/davidslater/.virtualenvs/davidslater/lib/python2.7/site-packages/keras/models.py", line 324, in add
output_tensor = layer(self.outputs[0])
File "/Users/davidslater/.virtualenvs/davidslater/lib/python2.7/site-packages/keras/engine/topology.py", line 517, in __call__
self.add_inbound_node(inbound_layers, node_indices, tensor_indices)
File "/Users/davidslater/.virtualenvs/davidslater/lib/python2.7/site-packages/keras/engine/topology.py", line 571, in add_inbound_node
Node.create_node(self, inbound_layers, node_indices, tensor_indices)
File "/Users/davidslater/.virtualenvs/davidslater/lib/python2.7/site-packages/keras/engine/topology.py", line 155, in create_node
output_tensors = to_list(outbound_layer.call(input_tensors[0], mask=input_masks[0]))
File "/Users/davidslater/.virtualenvs/davidslater/lib/python2.7/site-packages/keras/layers/core.py", line 592, in call
return self.function(x, **arguments)
File "keras_bug.py", line 20, in <lambda>
model.add(Lambda(lambda x: backend.sum(x, axis=1), output_shape=(128,)))
NameError: global name 'backend' is not defined
Please make sure that the boxes below are checked before you submit your issue. Thank you!
[X] Check that you are up-to-date with the master branch of Keras. You can update with:
pip install git+git://github.com/fchollet/keras.git --upgrade --no-deps
[X] If running on Theano, check that you are up-to-date with the master branch of Theano. You can update with:
pip install git+git://github.com/Theano/Theano.git --upgrade --no-deps
[X] Provide a link to a GitHub Gist of a Python script that can reproduce your issue (or just copy the script here if it is short).
For me a similar thing happened with TensorFlow backend after loading a serialized model with a Lambda layer calling a backend function one_hot
. The backend was imported as K
as still the error is appearing.
x = Lambda(K.one_hot, arguments={'nb_classes': nb_classes}, output_shape=(dataset.feature_frames, nb_classes))(x)
File "/home/bza/anaconda3/lib/python3.5/site-packages/keras/models.py", line 128, in load_model
model = model_from_config(model_config, custom_objects=custom_objects)
File "/home/bza/anaconda3/lib/python3.5/site-packages/keras/models.py", line 177, in model_from_config
return layer_from_config(config, custom_objects=custom_objects)
File "/home/bza/anaconda3/lib/python3.5/site-packages/keras/utils/layer_utils.py", line 36, in layer_from_config
return layer_class.from_config(config['config'])
File "/home/bza/anaconda3/lib/python3.5/site-packages/keras/engine/topology.py", line 2375, in from_config
process_layer(layer_data)
File "/home/bza/anaconda3/lib/python3.5/site-packages/keras/engine/topology.py", line 2370, in process_layer
layer(input_tensors[0])
File "/home/bza/anaconda3/lib/python3.5/site-packages/keras/engine/topology.py", line 514, in __call__ self.add_inbound_node(inbound_layers, node_indices, tensor_indices)
File "/home/bza/anaconda3/lib/python3.5/site-packages/keras/engine/topology.py", line 572, in add_inbound_node
Node.create_node(self, inbound_layers, node_indices, tensor_indices)
File "/home/bza/anaconda3/lib/python3.5/site-packages/keras/engine/topology.py", line 149, in create_node
output_tensors = to_list(outbound_layer.call(input_tensors[0], mask=input_masks[0]))
File "/home/bza/anaconda3/lib/python3.5/site-packages/keras/layers/core.py", line 556, in call
return self.function(x, **arguments)
File "/home/bza/anaconda3/lib/python3.5/site-packages/keras/backend/tensorflow_backend.py", line 923, in one_hot
return tf.one_hot(indices, depth=nb_classes, axis=-1) NameError: name 'tf' is not defined
WORKING WORKAROUND:
Importing the backend as K within the lambda function solved the problem as a workaround. It's not quite clean IMHO.
def one_hot(x, **arguments):
from keras import backend as K
return K.one_hot(x, **arguments)
input_encoded = Lambda(one_hot,
arguments={'nb_classes': nb_classes},
output_shape=(dataset.feature_frames, nb_classes))(input_int)
I was worried about a possible performance penalty (import in the function call). However, training time was almost the same in both cases (using K.one_hot directly and wrapped with import).
I would really like to see this issue resolved to the general case where you can load any model that utilizes a tensorflow layer.
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.
You can fix it by including backend
as a custom object
model2 = model_from_json(model.to_json(), custom_objects={"backend": backend})
From my understanding, the reason behind this is that load_model model_from_json
by default assumes everything declared within the model is contained in Keras, hence you have to hardwire everything else outside keras.
The second thing to note is that python modules are imported as singletons, so importing it twice has no effect. You can try changing K
by backend
and viceversa.
@antonimmo I tried your workaround but could not get it to work. Instead I used @bzamecnik's trick, which I guess forces Keras to import the tensorflow backend as the declaration is made in-line within the Lambda (so I presume it is interpreted by Keras when loaded?).
This thread saved my life. Thanks guys!
Yes, this is fixed/worked around by adding all unknown names to the custom_objects
dict. For me I was using tf
in a Lambda
, but also custom objective losses which also were not found during load_model
, so this fixed it for me:
model = keras.models.load_model('weights.h5', custom_objects={
'tf':tf,
'pix_error':pix_error,
'range_error':range_error,
'heat_error':heat_error,
})
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.
@sbhaaf as your describe, I succeeded in load_model
from file with model which contains Lambda layer with keras.activations.softmax, thanks. Seems we'd take care of all functions/objects passed to Lambda layer as customized, even if it is part of Keras.
model = keras.models.load_model('weights.h5', custom_objects={ 'tf':tf, 'pix_error':pix_error, 'range_error':range_error, 'heat_error':heat_error, })
this one saves the day :-*
Closing as this is resolved
Sorry for reopening this, but I am unsure if using the custom_objects parameter will suffice in my case. Currently my goal is to compile a model in Python to then push it to a device and train it using the C++ API (Federated Learning).
However, this would mean that I would have to provide the custom Python object in my C++ code, right? Or is there another way to handle this?
As the commenters above, I am also experiencing this error when using a Lambda layer.
Most helpful comment
Yes, this is fixed/worked around by adding all unknown names to the
custom_objects
dict. For me I was usingtf
in aLambda
, but also custom objective losses which also were not found duringload_model
, so this fixed it for me: