keras: load_model - the two structures don't have the same nested structure

I trained a model and saved it using: model.save("model_name") I then call model = tf.keras.models.load_model("model_name") and get a “The two structures don’t have the same nested structure.” error. The structure that the model is expecting upon loading is not what I defined in the model.

My model:

roberta_layer = TFRobertaModel.from_pretrained('roberta-base')

ids = tf.keras.layers.Input((64,), dtype=tf.int32)
att = tf.keras.layers.Input((64,), dtype=tf.int32)

roberta_inputs = [ids, att]

sequence_output,pooled_output = roberta_layer(roberta_inputs)

# unigram
x1 = tf.keras.layers.Conv1D(32,1,activation='relu')(sequence_output)
x1 = tf.keras.layers.GlobalMaxPool1D()(x1)

# bigram
x2 = tf.keras.layers.Conv1D(32,2,activation='relu')(sequence_output)
x2 = tf.keras.layers.GlobalMaxPool1D()(x2)

# trigram
x3 = tf.keras.layers.Conv1D(32,3,activation='relu')(sequence_output)
x3 = tf.keras.layers.GlobalMaxPool1D()(x3)

concat = tf.keras.layers.Concatenate()([x1,x2,x3])
concat = tf.keras.layers.Dropout(0.5)(concat)

outputs = tf.keras.layers.Dense(11, activation='sigmoid')(concat)

model = tf.keras.Model(inputs=roberta_inputs, outputs=outputs)

I’m using tf 2.4.0 and transformers 3.5.1

The full error is: The two structures don’t have the same nested structure.

First structure: type=dict str={‘input_ids’: TensorSpec(shape=(None, 5), dtype=tf.int32, name=‘inputs/input_ids’)}

Second structure: type=list str=[TensorSpec(shape=(None, 64), dtype=tf.int32, name=‘inputs/0’), TensorSpec(shape=(None, 64), dtype=tf.int32, name=‘inputs/1’)]

More specifically: The two namedtuples don’t have the same sequence type. First structure type=dict str={‘input_ids’: TensorSpec(shape=(None, 5), dtype=tf.int32, name=‘inputs/input_ids’)} has type dict, while second structure type=list str=[TensorSpec(shape=(None, 64), dtype=tf.int32, name=‘inputs/0’), TensorSpec(shape=(None, 64), dtype=tf.int32, name=‘inputs/1’)] has type list

During handling of the above exception, another exception occurred:

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 7
  • Comments: 33 (4 by maintainers)

Most upvoted comments

I finally solved this issue by using tf.saved_model.save(model, path_to_dir) instead of model.save(path_to_dir) or tf.keras.models.save_model(model, path_to_dir).

followed by this guide: https://www.tensorflow.org/guide/saved_model

A solution is to call the roberta model slightly different: sequence_output,pooled_output = roberta_layer.roberta(roberta_inputs)

This fixes the problem

tf.saved_model.load() instead of tf.keras.models.load_model() on Kaggle TPUs did the job for me.

Even I am facing the same issue.

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-10-3a1d333d606b> in <module>()
----> 1 ner_model_2 = pickle.load(open('ner_model_2.pkl', 'rb'))

2 frames
/usr/local/lib/python3.7/dist-packages/tensorflow/python/util/nest.py in assert_same_structure(nest1, nest2, check_types, expand_composites)
    533                   "Entire first structure:\n%s\n"
    534                   "Entire second structure:\n%s"
--> 535                   % (str(e), str1, str2))
    536 
    537 

ValueError: The two structures don't have the same nested structure.

First structure: type=tuple str=(({'input_ids': TensorSpec(shape=(None, 5), dtype=tf.int32, name='input_ids/input_ids')}, None, None, None, None, None, None, None, None, None, None, None, None, False), {})

Second structure: type=tuple str=((TensorSpec(shape=(None, 384), dtype=tf.int32, name='input_ids'), TensorSpec(shape=(None, 384), dtype=tf.int32, name='attention_mask'), TensorSpec(shape=(None, 384), dtype=tf.int32, name='token_type_ids'), None, None, None, None, None, None, None, None, None, None, False), {})

More specifically: Substructure "type=dict str={'input_ids': TensorSpec(shape=(None, 5), dtype=tf.int32, name='input_ids/input_ids')}" is a sequence, while substructure "type=TensorSpec str=TensorSpec(shape=(None, 384), dtype=tf.int32, name='input_ids')" is not
Entire first structure:
(({'input_ids': .}, ., ., ., ., ., ., ., ., ., ., ., ., .), {})
Entire second structure:
((., ., ., ., ., ., ., ., ., ., ., ., ., .), {})

I have figured out a way to overcome this problem. Instead of saving the model using model.save or tf.keras.models.save_model(), try saving the model weights using model.save_weights('model_weight.h5') during the training process.

At the prediction or testing phase, you need to create the model (architecture) manually, the same way you did in the training phase, and then load the weights to it.

Just use the post’s codes and I can reproduce it (tf.__version__: 2.2.0):

import tensorflow as tf
from transformers import TFRobertaModel


roberta_layer = TFRobertaModel.from_pretrained('roberta-base')

ids = tf.keras.layers.Input((64,), dtype=tf.int32)
att = tf.keras.layers.Input((64,), dtype=tf.int32)

roberta_inputs = [ids, att]

sequence_output,pooled_output = roberta_layer(roberta_inputs)

# unigram
x1 = tf.keras.layers.Conv1D(32,1,activation='relu')(sequence_output)
x1 = tf.keras.layers.GlobalMaxPool1D()(x1)

# bigram
x2 = tf.keras.layers.Conv1D(32,2,activation='relu')(sequence_output)
x2 = tf.keras.layers.GlobalMaxPool1D()(x2)

# trigram
x3 = tf.keras.layers.Conv1D(32,3,activation='relu')(sequence_output)
x3 = tf.keras.layers.GlobalMaxPool1D()(x3)

concat = tf.keras.layers.Concatenate()([x1,x2,x3])
concat = tf.keras.layers.Dropout(0.5)(concat)

outputs = tf.keras.layers.Dense(11, activation='sigmoid')(concat)

model = tf.keras.Model(inputs=roberta_inputs, outputs=outputs)

Then save the model

model.save('_tmp_model')

Then the following load will produce the error

restored_model = tf.keras.models.load_model("_tmp_model")

But if I load by tf.saved_model.load instead of tf.keras.models.load_model, it will succeed

restored_model = tf.saved_model.load("_tmp_model")

Also tried saving with tf.keras.models.save_model instead of model.save, the same error still exists

tf.keras.models.save_model(model, '_tmp_model_keras')
restored_model = tf.keras.models.load_model('_tmp_model_keras')

I also tried tf 2.6.0, still the same. Here’s the error it will produce:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/anaconda/lib/python3.7/site-packages/tensorflow/python/util/nest.py in assert_same_structure(nest1, nest2, check_types, expand_composites)
    527     _pywrap_utils.AssertSameStructure(nest1, nest2, check_types,
--> 528                                       expand_composites)
    529   except (ValueError, TypeError) as e:

TypeError: The two structures don't have the same nested structure.

First structure: type=tuple str=(({'input_ids': TensorSpec(shape=(None, 5), dtype=tf.int32, name='inputs/input_ids')},), {'training': False})

Second structure: type=tuple str=(([TensorSpec(shape=(None, 64), dtype=tf.int32, name='inputs/0'), TensorSpec(shape=(None, 64), dtype=tf.int32, name='inputs/1')],), {'training': False})

More specifically: The two namedtuples don't have the same sequence type. First structure type=dict str={'input_ids': TensorSpec(shape=(None, 5), dtype=tf.int32, name='inputs/input_ids')} has type dict, while second structure type=list str=[TensorSpec(shape=(None, 64), dtype=tf.int32, name='inputs/0'), TensorSpec(shape=(None, 64), dtype=tf.int32, name='inputs/1')] has type list

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
/tmp/ipykernel_25463/2006687310.py in <module>
----> 1 restored_model = tf.keras.models.load_model("_tmp_model")

/anaconda/lib/python3.7/site-packages/keras/saving/save.py in load_model(filepath, custom_objects, compile, options)
    203         filepath = path_to_string(filepath)
    204         if isinstance(filepath, str):
--> 205           return saved_model_load.load(filepath, compile, options)
    206 
    207   raise IOError(

/anaconda/lib/python3.7/site-packages/keras/saving/saved_model/load.py in load(path, compile, options)
    141 
    142   # Finalize the loaded layers and remove the extra tracked dependencies.
--> 143   keras_loader.finalize_objects()
    144   keras_loader.del_tracking()
    145 

/anaconda/lib/python3.7/site-packages/keras/saving/saved_model/load.py in finalize_objects(self)
    638         layers_revived_from_config.append(node)
    639 
--> 640     _finalize_saved_model_layers(layers_revived_from_saved_model)
    641     _finalize_config_layers(layers_revived_from_config)
    642 

/anaconda/lib/python3.7/site-packages/keras/saving/saved_model/load.py in _finalize_saved_model_layers(layers)
    835           continue
    836         if call_fn.input_signature is None:
--> 837           args, kwargs = infer_inputs_from_restored_call_function(call_fn)
    838           args = list(args)
    839           inputs = args.pop(0)

/anaconda/lib/python3.7/site-packages/keras/saving/saved_model/load.py in infer_inputs_from_restored_call_function(fn)
   1172   for concrete in fn.concrete_functions[1:]:
   1173     spec2 = concrete.structured_input_signature
-> 1174     spec = tf.nest.map_structure(common_spec, spec, spec2)
   1175   return spec
   1176 

/anaconda/lib/python3.7/site-packages/tensorflow/python/util/nest.py in map_structure(func, *structure, **kwargs)
    861   for other in structure[1:]:
    862     assert_same_structure(structure[0], other, check_types=check_types,
--> 863                           expand_composites=expand_composites)
    864 
    865   flat_structure = (flatten(s, expand_composites) for s in structure)

/anaconda/lib/python3.7/site-packages/tensorflow/python/util/nest.py in assert_same_structure(nest1, nest2, check_types, expand_composites)
    533                   "Entire first structure:\n%s\n"
    534                   "Entire second structure:\n%s"
--> 535                   % (str(e), str1, str2))
    536 
    537 

TypeError: The two structures don't have the same nested structure.

First structure: type=tuple str=(({'input_ids': TensorSpec(shape=(None, 5), dtype=tf.int32, name='inputs/input_ids')},), {'training': False})

Second structure: type=tuple str=(([TensorSpec(shape=(None, 64), dtype=tf.int32, name='inputs/0'), TensorSpec(shape=(None, 64), dtype=tf.int32, name='inputs/1')],), {'training': False})

More specifically: The two namedtuples don't have the same sequence type. First structure type=dict str={'input_ids': TensorSpec(shape=(None, 5), dtype=tf.int32, name='inputs/input_ids')} has type dict, while second structure type=list str=[TensorSpec(shape=(None, 64), dtype=tf.int32, name='inputs/0'), TensorSpec(shape=(None, 64), dtype=tf.int32, name='inputs/1')] has type list
Entire first structure:
(({'input_ids': .},), {'training': .})
Entire second structure:
(([., .],), {'training': .})

Update: if I change

sequence_output,pooled_output = roberta_layer(roberta_inputs)

to

sequence_output,pooled_output = roberta_layer.roberta(roberta_inputs)

as @eyalshafran suggested, the problem is magically solved. I wonder what’s the cause

In case this is still relevant for people, here is what I think is going on:

Keras saves the input specs on the first call of the model here. When loading a pretrained model with transformers using the from_pretrained class classmethod of TFPretrainedModel, the networks is first fed dummy inputs here. So the saved models expect their input tensors to be of sequence length 5, because that is the length of the dummy inputs.

In order to change that behaviour, you can reset the input specs before saving to a saved model like this:

# This is just a toy example of an input with sequence length 8 (as opposed to 5), just use a dictionary of your actual features instead. 
features = {"input_ids": tf.constant([[1,2,3,4,5,6,7,8]]), "attention_mask": tf.constant([[1,1,1,1,1,1,1,1]]), "token_type_ids": tf.constant([[0,0,0,0,0,0,0,0]])}

model._saved_model_inputs_spec = None
model._set_save_spec(features)

tf.saved_model.save(model, "./out_dir")

tensorflow 2.7.0 keras 2.7.0 transformers 4.15.0 pretrained model: “bert-base-multilingual-cased”

I also had the same issue when using model.save() & keras.model.load_model(). but, I change my python code to model.save_weights() & model.load_weights(), this issue resolved. thanks to @Allen-Qiu & @shreyas-jk

Yes, as introduced by shreyas-jk, model.save_weights(‘model_weight.h5’) can deal with this problem. My model contains a huggingface bert. It cannot be saved. However, I can save the weights. Subsequently, I build the model again in other files and load the weights.