2

I followed this tutorial about building an encoder-decoder language translation model and built one for my native language.

Now I want to save it, deploy on cloud ML engine and make predictions with HTTP request.

I couldn't find a clear example on how to save this model,

I am new to ML and found TF save guide v confusing..

Is there a way to save this model using something like tf.keras.models.save_model

UpaJah
  • 6,954
  • 4
  • 24
  • 30
  • Hi @UpaJah, I don't know the way better than provided by [your link](https://www.tensorflow.org/guide/saved_model). Some non-trivial models like a encoder-decoder are not presented in keras. So while keras does its job with session for you, in tf you should control it explicitly. [Manual](https://www.tensorflow.org/guide/low_level_intro) (where `Saver` class is explained, your link, too) is not so short but quite good if you have to work with tensorflow. It helps me when I was stucked with tf – Mikhail Stepanov Dec 19 '18 at 21:18
  • @MikhailStepanov thanks, I guess I will have build model using Tensorlflow. – UpaJah Dec 19 '18 at 21:34
  • Hi, @UpaJah. Have you figured it out? I have the same problem now and looking for a solution. Can you give me some advice? – Allen_Tsang Feb 17 '20 at 06:45

3 Answers3

0

Create the train saver after opening the session and after the training is done save the model:

with tf.Session() as sess:
     saver = tf.train.Saver()
     # Training of the model
     save_path = saver.save(sess, "logs/encoder_decoder")
     print(f"Model saved in path {save_path}")
gorjan
  • 5,405
  • 2
  • 20
  • 40
  • 1
    I am using eager mode of tensorflow, how the code will work exactly? I think I need to write the code again in Tensorflow graph – UpaJah Dec 20 '18 at 14:51
0

You can save a Keras model in Keras's HDF5 format, see:

https://keras.io/getting-started/faq/#how-can-i-save-a-keras-model

You will want to do something like:

import tf.keras
model = tf.keras.Model(blah blah)
model.save('my_model.h5')

If you migrate to TF 2.0, it's more straightforward to build a model in tf.keras and deploy using the TF SavedModel format. This 2.0 tutorial shows using a pretrained tf.keras model, saving the model in SavedModel format, deploying to the cloud and then doing an HTTP request for a prediction:

https://www.tensorflow.org/beta/guide/saved_model

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
Andrew - OpenGeoCode
  • 2,299
  • 18
  • 15
0

I know I am a little late but was having the same problem (see How do I save an encoder-decoder model with TensorFlow? for more details) and figured out a solution. It's a little hacky, but it works!

Step 1 - Saving your model

Save your tokenizer (if applicable). Then individually save the weights of the model you used to train your data (naming your layers helps here).

# Save the tokenizer
with open('tokenizer.pickle', 'wb') as handle:
    pickle.dump(tokenizer, handle, protocol=pickle.HIGHEST_PROTOCOL)

# save the weights individually
for layer in model.layers:
    weights = layer.get_weights()
    if weights != []:
        np.savez(f'{layer.name}.npz', weights)

Step 2 - reloading the weights

You will want to reload the tokenizer (as applicable) then load the weights you just saved. The loaded weights are in an npz format so can't be used directly, but the very short documentation will tell you everything you need to know about this file type https://numpy.org/doc/stable/reference/generated/numpy.savez.html

# load the tokenizer
with open('tokenizer.pickle', 'rb') as handle:
    tokenizer = pickle.load(handle)

# load the weights
w_encoder_embeddings = np.load('encoder_embeddings.npz', allow_pickle=True)
w_decoder_embeddings = np.load('decoder_embeddings.npz', allow_pickle=True)
w_encoder_lstm = np.load('encoder_lstm.npz', allow_pickle=True)
w_decoder_lstm = np.load('decoder_lstm.npz', allow_pickle=True)
w_dense = np.load('dense.npz', allow_pickle=True)

Step 3 - Recreate the your training model and apply the weights

You'll want to re-run the code you used to create your model. In my case this was:

encoder_inputs = Input(shape=(None,), name="encoder_inputs")
encoder_embeddings = Embedding(vocab_size, embedding_size, mask_zero=True, name="encoder_embeddings")(encoder_inputs)

# Encoder lstm
encoder_lstm = LSTM(512, return_state=True, name="encoder_lstm")
encoder_outputs, state_h, state_c = encoder_lstm(encoder_embeddings)

# discard `encoder_outputs` and only keep the states.
encoder_states = [state_h, state_c]

# Set up the decoder, using `encoder_states` as initial state.
decoder_inputs = Input(shape=(None,), name="decoder_inputs")

# target word embeddings
decoder_embeddings = Embedding(vocab_size, embedding_size, mask_zero=True, name="decoder_embeddings")
training_decoder_embeddings = decoder_embeddings(decoder_inputs)

# decoder lstm
decoder_lstm = LSTM(512, return_sequences=True, return_state=True, name="decoder_lstm")
decoder_outputs, _, _ = decoder_lstm(training_decoder_embeddings,
                                     initial_state=encoder_states)

decoder_dense = TimeDistributed(Dense(vocab_size, activation='softmax'), name="dense")
decoder_outputs = decoder_dense(decoder_outputs)

# While training, model takes input and traget words and outputs target strings
loaded_model = Model([encoder_inputs, decoder_inputs], decoder_outputs, name="training_model")

Now you can apply your saved weights to these layers! It takes a little bit of investigation which weight goes to which layer, but this is made a lot easier by naming your layers and inspecting your model layers with model.layers.

# set the weights of the model

loaded_model.layers[2].set_weights(w_encoder_embeddings['arr_0'])
loaded_model.layers[3].set_weights(w_decoder_embeddings['arr_0'])
loaded_model.layers[4].set_weights(w_encoder_lstm['arr_0'])
loaded_model.layers[5].set_weights(w_decoder_lstm['arr_0'])
loaded_model.layers[6].set_weights(w_dense['arr_0'])

Step 4 - Create the inference model

Finally, you can now create your inference model based on this training model! Again in my case this was:

encoder_model = Model(encoder_inputs, encoder_states)

# Redefine the decoder model with decoder will be getting below inputs from encoder while in prediction
decoder_state_input_h = Input(shape=(512,))
decoder_state_input_c = Input(shape=(512,))
decoder_states_inputs = [decoder_state_input_h, decoder_state_input_c]
inference_decoder_embeddings = decoder_embeddings(decoder_inputs)

decoder_outputs2, state_h2, state_c2 = decoder_lstm(inference_decoder_embeddings, initial_state=decoder_states_inputs)

decoder_states2 = [state_h2, state_c2]
decoder_outputs2 = decoder_dense(decoder_outputs2)

# sampling model will take encoder states and decoder_input(seed initially) and output the predictions(french word index) We dont care about decoder_states2
decoder_model = Model(
    [decoder_inputs] + decoder_states_inputs,
    [decoder_outputs2] + decoder_states2)

And voilà! You can now make inferences using the previously trained model!

jda5
  • 1,390
  • 5
  • 17