keras: Lambda Layer doesn't serialize to JSON or YAML

It appears networks with Lambda Layers can’t be saved though the to_json or to_yaml methods

To implement graves style skip connections for a classification problem I’m using a lambda layer to get the results from the last time step

Lambda(lambda x: x[:,-1,:], output_shape=last_step_shape)

where

def last_step_shape(input_shape):
    shape = list(input_shape)
    assert len(shape) == 3
    return tuple((shape[0], shape[2]))

This model does successfully start training, but I can’t save the architecture specification. The model is defined using the Graph API. Looks something like

model = Graph()
model.add_input(name='input', batch_input_shape=(batchsize, maxlen), dtype='int')
model.add_node(Embedding(257, embed_size, input_length=maxlen, name='embedding', input='input')

prev_name = 'embedding'

#add intermediate hidden LSTM layers, they need to return their sequences. 
for l in range(num_layers-1):
    ls = str(l)
    if l > 0:
        model.add_node(LSTM(lstm_layer_size, return_sequences=True), 
                       name='_f'+ls, inputs=[prev_name, 'embedding'])
        model.add_node(Lambda(lambda x: x[:,-1,:], output_shape=last_step_shape), name='f'+ls, input='_f'+ls)
    else:
        model.add_node(LSTM(lstm_layer_size, return_sequences=True), 
                       name='_f'+ls, input=prev_name)
        model.add_node(Lambda(lambda x: x[:,-1,:], output_shape=last_step_shape), name='f'+ls, input='_f'+ls)
    prev_name = '_f'+ls

#add last LSTM layer
ls = str(num_layers-1)
if num_layers > 1:
    model.add_node(LSTM(lstm_layer_size), name='f'+ls, inputs=[prev_name, 'embedding'])
    model.add_node(Dense(1, activation='sigmoid'), name='sigmoid', inputs=['f'+str(x) for x in range(num_layers)], merge_mode='concat')
else:
    model.add_node(LSTM(lstm_layer_size, dropout_W=0.5, dropout_U=0.5, W_regularizer=l2(1e-5)), name='f'+ls, input=prev_name)
    model.add_node(Dense(1, activation='sigmoid'), name='sigmoid', input='f'+ls, merge_mode='concat')

model.add_output(name='output', input='sigmoid')

# try using different optimizers and different optimizer configs
optimizer = Adam(lr=0.001, clipnorm=grad_clip)

model.compile(optimizer, {'output': 'binary_crossentropy'})

I get the error


---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)
<ipython-input-25-e4d9f49c02c8> in <module>()
----> 5 json_string = model.to_json()
      6 # open(name+'.json', 'w').write(json_string)
      7 

/usr/local/lib/python2.7/dist-packages/keras/engine/topology.pyc in to_json(self, **kwargs)
   2375             'config': config,
   2376         }
-> 2377         return json.dumps(model_config, default=get_json_type, **kwargs)
   2378 
   2379     def to_yaml(self, **kwargs):

/usr/lib/python2.7/json/__init__.pyc in dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, cls, indent, separators, encoding, default, sort_keys, **kw)
    248         check_circular=check_circular, allow_nan=allow_nan, indent=indent,
    249         separators=separators, encoding=encoding, default=default,
--> 250         sort_keys=sort_keys, **kw).encode(obj)
    251 
    252 

/usr/lib/python2.7/json/encoder.pyc in encode(self, o)
    205         # exceptions aren't as detailed.  The list call should be roughly
    206         # equivalent to the PySequence_Fast that ''.join() would do.
--> 207         chunks = self.iterencode(o, _one_shot=True)
    208         if not isinstance(chunks, (list, tuple)):
    209             chunks = list(chunks)

/usr/lib/python2.7/json/encoder.pyc in iterencode(self, o, _one_shot)
    268                 self.key_separator, self.item_separator, self.sort_keys,
    269                 self.skipkeys, _one_shot)
--> 270         return _iterencode(o, 0)
    271 
    272 def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,

UnicodeDecodeError: 'utf8' codec can't decode byte 0x83 in position 28: invalid start byte

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 27 (5 by maintainers)

Commits related to this issue

Most upvoted comments

Are Lambda layers serialized to Python bytecode? We have a GSoC student trying to read in the Keras models that have been serialized to JSON and running into issues with Lambda layers - I would guess the function in the JSON is serialized to Python bytecode and that crossing the language barrier would not be possible (without doing some sophisticated compiler-ish type things)

Hi, i found a way how to solve my issue: I was reading the dimension of a layer to parametrize the next layer:

curr_seq_length = x._shape[1] kernel_size = curr_seq_length - self._sequence_length + 1 x = Conv1D(self._nr_features, kernel_size=[kernel_size], activation='relu', padding='valid')(x)

the problem was that curr_seq_length was from type Dimension - and it seems that there something changed in the lastest tensorflow-integrated keras version. And the json serializer doesn’t know how to deal with the Dimension object.

Changing the line to curr_seq_length = x._shape[1].value solves the problem…

I also have the same problem with Lambda layer. I am trying to add temperature to my softmax by:

model.add(Lambda(lambda x: x / temp))

but getting the error that Lambda object is not JSON serializable. Any suggestion to solve this or any suggestion to add the temperature to softmax?

Keras: 2.1.3 Tensorflow: 1.5 No GPU.