Hi,
I'm experiencing an issue when saving a model containing the Lambda layer. I can run the model, compile it, train it, save it. But when I try to load it again, I get an error.
The network does the convolution on each single channel of the image and performs a regression on a final scalar output. To slice the multi-channel tensor I use the Lambda layer, and the index of this layer is causing troubles when saving/loading the model
I attached a full script to replicate the issue. It does not make any sense with the cifar10 dataset, but it's just to replicate the issue! :smile:
import keras
from keras.models import Model
from keras.layers import Dense, Dropout, Activation, Flatten, Input, Concatenate, Lambda
from keras.layers import Conv2D, MaxPooling2D
import os
from keras.callbacks import ModelCheckpoint
import numpy as np
network_name = 'test_this_bug'
np.random.seed(10)
batch_size = 100
num_classes = 10
epochs = 10
(x_train, y_train),(x_test, y_test) = keras.datasets.cifar10.load_data()
Nchannels = x_train.shape[3]
img_rows = x_train.shape[1]
img_cols = x_train.shape[2]
#x_train = np.moveaxis(x_train,1,3)
#x_test = np.moveaxis(x_test,1,3)
main_input = Input(shape=(img_rows,img_cols,Nchannels))
channels = []
for i in range(Nchannels):
# Slice the tensor getting the i-th channel
x = Lambda(lambda x: x[:,:,:,i,None])(main_input)
x = Conv2D(4, kernel_size=(3,3), strides=(2,2))(x)
x = Activation('relu')(x)
x = MaxPooling2D(pool_size=(2,2), strides=(2,2))(x)
x = Conv2D(8, kernel_size=(3,3), strides=(2,2))(x)
x = Activation('relu')(x)
x = MaxPooling2D(pool_size=(2,2), strides=(2,2))(x)
x = Dropout(0.1)(x)
x = Flatten()(x)
channels.append(x)
channels = Concatenate()(channels)
channels = Dense(128)(channels)
channels = Activation('relu')(channels)
channels = Dropout(0.2)(channels)
main_output = Dense(1)(channels)
main_output = Activation('relu')(main_output)
model = Model(inputs=main_input, outputs=main_output)
model.summary()
opt = keras.optimizers.RMSprop()
model.compile(optimizer=opt, loss='mean_squared_error', metrics=['accuracy'])
x_train = x_train.astype('float32')/255;
x_test = x_test.astype('float32')/255;
best_model_name = '%s_best.h5' % network_name
# Callbacks
filepath = os.path.join(os.getcwd(),best_model_name)
checkpoint = ModelCheckpoint(filepath, monitor='val_loss', verbose=1,
save_best_only=True,period=2)
callbacks = [checkpoint]
model.fit(x_train,y_train,
batch_size=batch_size,
epochs=epochs,
validation_data=(x_test,y_test),
callbacks=callbacks)
After the script has finished, I simply open ipython and run:
import keras
import os
model = keras.models.load_model(os.path.join(os.getcwd(),'test_this_bug_best.h5'))
The result is this long error, referring to the variable _i_ of the Lambda layer:
In [5]: model = keras.models.load_model(os.path.join(os.getcwd(),'test_this_bug_best.h5'))
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-5-37356b91a563> in <module>()
----> 1 model = keras.models.load_model(os.path.join(os.getcwd(),'test_this_bug_best.h5'))
/mnt/storage/home/username/.local/lib/python2.7/site-packages/keras/models.pyc in load_model(filepath, custom_objects, compile)
241 raise ValueError('No model found in config file.')
242 model_config = json.loads(model_config.decode('utf-8'))
--> 243 model = model_from_config(model_config, custom_objects=custom_objects)
244
245 # set weights
/mnt/storage/home/username/.local/lib/python2.7/site-packages/keras/models.pyc in model_from_config(config, custom_objects)
315 'Maybe you meant to use '
316 '`Sequential.from_config(config)`?')
--> 317 return layer_module.deserialize(config, custom_objects=custom_objects)
318
319
/mnt/storage/home/username/.local/lib/python2.7/site-packages/keras/layers/__init__.pyc in deserialize(config, custom_objects)
53 module_objects=globs,
54 custom_objects=custom_objects,
---> 55 printable_module_name='layer')
/mnt/storage/home/username/.local/lib/python2.7/site-packages/keras/utils/generic_utils.pyc in deserialize_keras_object(identifier, module_objects, custom_objects, printable_module_name)
142 return cls.from_config(config['config'],
143 custom_objects=dict(list(_GLOBAL_CUSTOM_OBJECTS.items()) +
--> 144 list(custom_objects.items())))
145 with CustomObjectScope(custom_objects):
146 return cls.from_config(config['config'])
/mnt/storage/home/username/.local/lib/python2.7/site-packages/keras/engine/topology.pyc in from_config(cls, config, custom_objects)
2518 if layer in unprocessed_nodes:
2519 for node_data in unprocessed_nodes.pop(layer):
-> 2520 process_node(layer, node_data)
2521
2522 name = config.get('name')
/mnt/storage/home/username/.local/lib/python2.7/site-packages/keras/engine/topology.pyc in process_node(layer, node_data)
2475 if input_tensors:
2476 if len(input_tensors) == 1:
-> 2477 layer(input_tensors[0], **kwargs)
2478 else:
2479 layer(input_tensors, **kwargs)
/mnt/storage/home/username/.local/lib/python2.7/site-packages/keras/engine/topology.pyc in __call__(self, inputs, **kwargs)
615
616 # Actually call the layer, collecting output(s), mask(s), and shape(s).
--> 617 output = self.call(inputs, **kwargs)
618 output_mask = self.compute_mask(inputs, previous_mask)
619
/mnt/storage/home/username/.local/lib/python2.7/site-packages/keras/layers/core.pyc in call(self, inputs, mask)
661 if has_arg(self.function, 'mask'):
662 arguments['mask'] = mask
--> 663 return self.function(inputs, **arguments)
664
665 def compute_mask(self, inputs, mask=None):
/mnt/storage/home/username/.local/lib/python2.7/site-packages/keras/layers/core.pyc in <lambda>(x)
27 for i in range(Nchannels):
28 # Slice the tensor getting the i-th channel
---> 29 x = Lambda(lambda x: x[:,:,:,i,None])(main_input)
30 x = Conv2D(4, kernel_size=(3,3), strides=(2,2))(x)
31 x = Activation('relu')(x)
NameError: global name 'i' is not defined
In [6]: model = keras.models.load_model(os.path.join(os.getcwd(),'test_this_bug_best.h5'))
Some additional info:
Please make sure that the boxes below are checked before you submit your issue. If your issue is an implementation question, please ask your question on StackOverflow or join the Keras Slack channel and ask there instead of filing a GitHub 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/keras-team/keras.git --upgrade --no-deps
[x] If running on TensorFlow, check that you are up-to-date with the latest version. The installation instructions can be found here.
[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).
Same issue with me
same here. This is a more simple example:
import numpy as np
from keras.models import load_model
from keras.models import Model
from keras.layers import Input, Lambda
from keras import backend as K
rep = 2
inp = Input([1])
out = Lambda(lambda x: K.repeat_elements(K.expand_dims(x, 1), rep, 1))(inp)
model = Model(inp, out)
X = np.array([[1], [2]])
print('results', model.predict(X))
model.save('test.h5')
del model
model = load_model('test.h5')
print('results', model.predict(X))
I see this (with some anonymization):
results [[[1.]
[1.]]]
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-19-23a1dbe4ad39> in <module>()
16 del model
17
---> 18 model = load_model('test.h5')
19 print('results', model.predict(X))
/.../python3.6/site-packages/keras/engine/saving.py in load_model(filepath, custom_objects, compile)
258 raise ValueError('No model found in config file.')
259 model_config = json.loads(model_config.decode('utf-8'))
--> 260 model = model_from_config(model_config, custom_objects=custom_objects)
261
262 # set weights
/.../lib/python3.6/site-packages/keras/engine/saving.py in model_from_config(config, custom_objects)
332 '`Sequential.from_config(config)`?')
333 from ..layers import deserialize
--> 334 return deserialize(config, custom_objects=custom_objects)
335
336
/.../lib/python3.6/site-packages/keras/layers/__init__.py in deserialize(config, custom_objects)
53 module_objects=globs,
54 custom_objects=custom_objects,
---> 55 printable_module_name='layer')
/.../lib/python3.6/site-packages/keras/utils/generic_utils.py in deserialize_keras_object(identifier, module_objects, custom_objects, printable_module_name)
143 config['config'],
144 custom_objects=dict(list(_GLOBAL_CUSTOM_OBJECTS.items()) +
--> 145 list(custom_objects.items())))
146 with CustomObjectScope(custom_objects):
147 return cls.from_config(config['config'])
/.../lib/python3.6/site-packages/keras/engine/network.py in from_config(cls, config, custom_objects)
1025 if layer in unprocessed_nodes:
1026 for node_data in unprocessed_nodes.pop(layer):
-> 1027 process_node(layer, node_data)
1028
1029 name = config.get('name')
/.../lib/python3.6/site-packages/keras/engine/network.py in process_node(layer, node_data)
984 # and building the layer if needed.
985 if input_tensors:
--> 986 layer(unpack_singleton(input_tensors), **kwargs)
987
988 def process_layer(layer_data):
/.../lib/python3.6/site-packages/keras/engine/base_layer.py in __call__(self, inputs, **kwargs)
455 # Actually call the layer,
456 # collecting output(s), mask(s), and shape(s).
--> 457 output = self.call(inputs, **kwargs)
458 output_mask = self.compute_mask(inputs, previous_mask)
459
/.../lib/python3.6/site-packages/keras/layers/core.py in call(self, inputs, mask)
680 if has_arg(self.function, 'mask'):
681 arguments['mask'] = mask
--> 682 return self.function(inputs, **arguments)
683
684 def compute_mask(self, inputs, mask=None):
/.../lib/python3.6/site-packages/keras/layers/core.py in <lambda>(x)
8 rep = 2
9 inp = Input([1])
---> 10 out = Lambda(lambda x: K.repeat_elements(K.expand_dims(x, 1), rep, 1))(inp)
11 model = Model(inp, out)
12 X = np.array([[1]])
NameError: name 'rep' is not defined
I guess my PR on Tensorflow hasn't been merged to keras.
https://github.com/tensorflow/tensorflow/pull/18926
I'll resubmit it here.
I came up with a silly fix for now. Basically, using the global variables as values for arbitrary arguments solved the scope issue:
def my_lambda(x, gvar1=gvar1, ...):
return ...
out = Lambda(my_lambda)(inp)
Most helpful comment
I guess my PR on Tensorflow hasn't been merged to keras.
https://github.com/tensorflow/tensorflow/pull/18926
I'll resubmit it here.