I'm working on two computers (one at home and one at work); they both have TensorFlow 2.8.0 installed. When I train the model at home (it is tf.keras.Sequential model), save it by calling:
model.save(<filepath>)
and load it at work by calling:
tf.keras.models.load_model(<filepath>)
it fails with error:
AttributeError: '_UserObject' object has no attribute 'predict'
I've read here error:'_UserObject' object has no attribute 'predict' that it might be because of different versions (which should not be my case) and that a possible solution is to use the Keras format (H5), but I wonder why this should be even necessary. Has anybody solved this issue using the default TF model format?
(I did not try the H5 format because it means I will have to retrain or at least re-save all my models trained at the home office; I guess it will work, but I don't understand why the TF model format should not work.)
EDIT: One of the models with which I experience this issue (though from my experience this should not play an issue):
layers = []
layers += [tf.keras.layers.Dense(len(training_data[0]), activation=None)]
layers += [tf.keras.layers.BatchNormalization()]
layers += [tf.keras.layers.Activation(activation_type)]
layers += [tf.keras.layers.Dense(len(training_data[0]) * 2, activation=None)]
layers += [tf.keras.layers.BatchNormalization()]
layers += [tf.keras.layers.Activation(activation_type)]
layers += [tf.keras.layers.Dropout(0.5)]
layers += [tf.keras.layers.Dense(len(training_data[0]), activation=None)]
layers += [tf.keras.layers.BatchNormalization()]
layers += [tf.keras.layers.Activation(activation_type)]
layers += [tf.keras.layers.Dense(len(training_data[0] / 2), activation=None)]
layers += [tf.keras.layers.BatchNormalization()]
layers += [tf.keras.layers.Activation(activation_type)]
layers += [tf.keras.layers.Dense(classes_count, activation="softmax")]
model = tf.keras.Sequential(layers)
TL;DR Invoke the model like a function on the input tensor.
model = tf.keras.models.load_model(<saved_model_folder>)
model(input_tensor) # predit is really not defined
If you want inference/predict function badly, you can do it as follows:
loaded = tf.keras.models.load_model(<saved_model_folder>)
inference_func = model_loaded.signatures['serving_default']
for batch in dataset.take(1):
print(inference_func(batch))
Explaination:
When you save a tensorflow Sequential model using the syntax model.save(<filepath>)
, you are using a keras model.
This saves the model in default SavedModel format. https://www.tensorflow.org/guide/keras/save_and_serialize#how_to_save_and_load_a_model
When saving the model and its layers, the SavedModel format stores the class name, call function, losses, and weights (and the config, if implemented). The call function defines the computation graph of the model/layer.
In the absence of the model/layer config, the call function is used to create a model that exists like the original model which can be trained, evaluated, and used for inference.
Note the explaination in second paragraph. It says that when model config is not present, model's call function
can be used for inference. Hmm !!!
How to invoke the call
function of tensorflow keras model, when you have not defined it by Model subclassing? To understand this, we need to know what is the purpose of call
method. Check the below example:
class MyModel(tf.keras.Model):
def __init__(self):
super().__init__()
self.dense1 = tf.keras.layers.Dense(4, activation=tf.nn.relu)
self.dense2 = tf.keras.layers.Dense(5, activation=tf.nn.softmax)
def call(self, inputs):
x = self.dense1(inputs)
return self.dense2(x)
From the documentation https://www.tensorflow.org/api_docs/python/tf/keras/Model#call, we know that when we define a model by subclassing, the forward pass of model is implemented in call
.
This method should not be called directly. It is only meant to be overridden when subclassing tf.keras.Model. To call a model on an input, always use the call() method, i.e. model(inputs), which relies on the underlying call() method.
This forward pass is defined by stacking the layers in a Sequential keras model. Hence we can treat the sequential model itself to be the call
function. So after loading the model, we should use it like a function which takes the input tensors.
Hence model(input_tensor)