Hub: Use Keras and get random result when export as a h5 model and saved model

Created on 25 Apr 2019  路  10Comments  路  Source: tensorflow/hub

Hey guys, I tried this tensorflow tutorials which use Keras API and tf hub image feature vector to custom model. When I try to save the model at the end, using

model.save('my_model.h5')

instead of

tf.contrib.saved_model.save_keras_model(model, "./saved_models")

error came out as

FailedPreconditionError (see above for traceback): Error while reading resource variable module/MobilenetV2/expanded_conv_9/project/weights from Container: localhost. This could mean that the variable was uninitialized. Not found: Resource localhost/module/MobilenetV2/expanded_conv_9/project/weights/class tensorflow::Var does not exist.

Then I use session to reinitialize

sess = tf.keras.backend.get_session()
init = tf.global_variables_initializer()
sess.run(init)

The model successfully saved, but when I reload this .h5 file. I found that I need to import tf hub and specify the url. Then I tried saved model to serve. Both .h5 model and saved model get random result. How can I fix this?

hub awaiting tensorflower support

Most helpful comment

Thanks for the explanation.

The solution is to use
tf.keras.experimental.export_saved_model(model, export_path) for saving and
tf.keras.experimental.load_from_saved_model(export_path, custom_objects={'KerasLayer':hub.KerasLayer}) for restoring.

Then you can just call loaded_model.predict()

hey when i use this i get AttributeError: module 'tensorflow.keras.experimental' has no attribute 'export_saved_model'

All 10 comments

Hi,

a couple of questions:

  • if you want a servable SavedModel in the end, saving using tf.contrib.saved_model.save_keras_model is the way to go. Is there any special reason why you are trying to save as .h5?

    • which saved model did you try to serve?

    • could you please describe better the random results part? How did you serve the saved model and how random was the output? Ideally some reproducible code snippet would be very useful in helping you.

@vbardiovskyg
Thank you for your reply.

  • The reason why I want to save .h5 model is to load model simply. I'm learning tensorflow, and this way is more familiar to me. At first, I just want to have a try.

  • I'm trying to build a classifier using tf hub mobilenet image feature vector.

  • There are more details about random result. Without run initialization code agian init = tf.global_variables_initializer()to save a h5 model, error will occur. And I found once I run init = tf.global_variables_initializer(), prediction will become random. It looks like [0.56666, 0.76111, ....], and before init = tf.global_variables_initializer() the prediction will be [0.99999, 0.00001, ....].

Before I save, I use this code to train a model.
````
module = hub.Module(MODEL_PATH)

def feature_vector(x)
return module(x)

IMAGE_SIZE = hub.get_expected_image_size(hub.Module(MODEL_PATH))
feature_vector_layer = tf.keras.layers.Lambda(feature_vector, input_shape=IMAGE_SIZE + [3])
feature_vector_layer.trainable = False

model = tf.keras.Sequential([
feature_vector_layer,
tf.keras.layers.Dense(1024, activation='relu'),
tf.keras.layers.Dense(20, activation='sigmoid')
])
model.compile(loss=tf.keras.losses.binary_crossentropy,
optimizer='adam')
model.summary()
sess = tf.keras.backend.get_session()
init = tf.global_variables_initializer()
sess.run(init)
history = model.fit(
train_dataset,
validation_data=val_dataset,
steps_per_epoch=int(np.ceil(len(x_train_files) / float(batch_size))),
epochs=epochs,
validation_steps=int(np.ceil(len(x_val_files) / float(batch_size))),
)

to save a .h5 model, I use
sess.run(init)
model.save('my_model.h5')
About saved model. I need a model including image prepossess to string to float. I first usetf.contrib.saved_model.save_keras_modelto export saved model. In this situation, I don't need to rerunsess.run(init) And I run code below to adjust model
graph = tf.Graph()
with tf.Session(graph=graph) as sess:

tf.saved_model.loader.load(sess, [tag_constants.SERVING], input_dir)
string_inp = tf.placeholder(tf.string, shape=(None,), name="b64")
img_float = str_proccess(string_inp)

out, = tf.import_graph_def(graph.as_graph_def(),
                           input_map={'lambda_input:0': img_float},
                           return_elements=["dense_1/Sigmoid:0"])
sess.run([tf.global_variables_initializer(), tf.tables_initializer()])

builder = tf.saved_model.builder.SavedModelBuilder(export_dir)

signature = tf.saved_model.predict_signature_def(inputs={'input': string_inp},
                                                 outputs={"prediction": out})
builder.add_meta_graph_and_variables(sess=sess,
                                     tags=[tag_constants.SERVING],
                                     signature_def_map={'serving_default': signature},
                                     legacy_init_op=tf.tables_initializer())

builder.save()

Please notice that this code also include sess.run([tf.global_variables_initializer(), tf.tables_initializer()])````, without this, error will occur. And prediction result looks like [0.4566, 0.5343, ....] which should be [0.99999, 0.00001, ....]
I'm not very familiar with saved model, and I don't know whether this code is right.

Thanks for the explanation.

The solution is to use
tf.keras.experimental.export_saved_model(model, export_path) for saving and
tf.keras.experimental.load_from_saved_model(export_path, custom_objects={'KerasLayer':hub.KerasLayer}) for restoring.

Then you can just call loaded_model.predict()

@vbardiovskyg
Thanks for reply. I'm using tensorflow 1.13, which may not have this method.

AttributeError: module 'tensorflow._api.v1.keras.experimental' has no attribute 'export_saved_model'

I found another solution :
instead of using Lambda
````
def feature_vector(x):
return module(x)

IMAGE_SIZE = hub.get_expected_image_size(hub.Module(MODEL_PATH))
feature_vector_layer = tf.keras.layers.Lambda(feature_vector, input_shape=IMAGE_SIZE + [3])
feature_vector_layer.trainable = False
model = tf.keras.Sequential([
feature_vector_layer,
tf.keras.layers.Dense(1024, activation='relu'),
tf.keras.layers.Dense(20, activation='sigmoid')
])
use inheritance layer like this
class FeatureLayer(tf.layers.Layer):
def __init__(self, kwargs):
self.trainable = False
super(FeatureLayer, self).__init__(
kwargs)

def build(self, input_shape):
    self.feature_vector = hub.Module(
        MODEL_PATH,
        trainable=self.trainable,
        name="{}_module".format(self.name)
    )
    super(FeatureLayer, self).build(input_shape)

def call(self, inputs):
    results = self.feature_vector(inputs=inputs)
    return results

fv_input = tf.keras.layers.Input(shape=(224, 224, 3))
fv_output = FeatureLayer()(fv_input)
x = tf.keras.layers.Dense(1024, activation='relu')(fv_output)
x = tf.keras.layers.Dense(20, activation='sigmoid')(x)
model = tf.keras.Model(fv_input, x)
````
The .h5 model save won't came out error and both .h5 model and saved model return correct result.
I do not know why this way works.

@HFrost0 ,
Please confirm if your issue has been resolved, or if you still need any clarifications with respect to this issue.

Any update to this? The model save and load process for tf version 1.12 and 1.13 are completely broken when using tf.keras which is meant to be the direction of the overall tensorflow project.

@HFrost0 I can certainly use your model construction instead of the lambda one but when using # new_model = tf.keras.models.load_model('my_new_model.h5',custom_objects={'FeatureLayer': FeatureLayer()}) it still produces random output. Can you give me a full example of how you predicted as well? Thanks!

Hi, @ingramator
I still get random result with .h5 model when I reload. I'm not quite sure what's wrong with it, it seems like varibles in session are not saved or reloaded. But I get correct result by saving my model by saved model using
````
version = 5

saved model

export_path = os.path.join('classifier', str(version))
tf.saved_model.simple_save(
tf.keras.backend.get_session(),
export_path,
inputs={'input_image': string_inp},
outputs={'predictions': output})
````

@HFrost0 I seem to be able to save it that way but what is the process for running inference on a sample image. There seems to be next to no documentation on the tensorflow API docs once again

@arnoegw ,
Can you PTAL

Thanks for the explanation.

The solution is to use
tf.keras.experimental.export_saved_model(model, export_path) for saving and
tf.keras.experimental.load_from_saved_model(export_path, custom_objects={'KerasLayer':hub.KerasLayer}) for restoring.

Then you can just call loaded_model.predict()

hey when i use this i get AttributeError: module 'tensorflow.keras.experimental' has no attribute 'export_saved_model'

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dav-ell picture dav-ell  路  4Comments

artemmavrin picture artemmavrin  路  3Comments

bzburr picture bzburr  路  4Comments

truas picture truas  路  4Comments

martiansideofthemoon picture martiansideofthemoon  路  3Comments