What is the right way to convert saved tensorflow model to tensorflow Lite

Viewed 2194

I have a saved tensorflow model the same as all models in the model zoo.

I want to convert it to tesorflow lite, I find the following way from tensorflow github (my tensorflw version is 2):

!wget http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_resnet50_v1_fpn_640x640_coco17_tpu-8.tar.gz 
# extract the downloaded file
!tar -xzvf ssd_resnet50_v1_fpn_640x640_coco17_tpu-8.tar.gz
    
!pip install tf-nightly
import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model('ssd_mobilenet_v2_320x320_coco17_tpu-8/saved_model')
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.experimental_new_converter = True

converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS]
tflite_model = converter.convert()

open("m.tflite", "wb").write(tflite_model)

But the output and input shape of the converted model don't match the original model, check the following:

  • Original Model Input & Output shape

enter image description here

  • Converted Model Input & Output shape

enter image description here

So there is a problem here! the input / output shape should be matched the original model! Any idea?

3 Answers

From Tensorflow github issues, I used their answer to solve my problem. Link

Their approach:

!pip install tf-nightly
import tensorflow as tf

## TFLite Conversion
model = tf.saved_model.load("saved_model")
concrete_func = model.signatures[tf.saved_model.DEFAULT_SERVING_SIGNATURE_DEF_KEY]
concrete_func.inputs[0].set_shape([1, 300, 300, 3])
tf.saved_model.save(model, "saved_model_updated", signatures={"serving_default":concrete_func})
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir='saved_model_updated', signature_keys=['serving_default'])

converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS]
tflite_model = converter.convert()

## TFLite Interpreter to check input shape
interpreter = tf.lite.Interpreter(model_content=tflite_model)
interpreter.allocate_tensors()

# Get input and output tensors.
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

# Test the model on random input data.
input_shape = input_details[0]['shape']
print(input_shape)

[ 1 300 300 3]

Thank you MeghnaNatraj

The shape of both models input and output should be the same as shown below

If the model is already in saved_model format, you the code below

# if you are using same model
export_dir = 'ssd_mobilenet_v2_320x320_coco17_tpu-8/saved_model'
converter = tf.lite.TFLiteConverter.from_saved_model(export_dir)

if your model is in Keras format, use the format below

# if it's a keras model 
model = tf.keras.applications.MobileNetV2(weights="imagenet", input_shape= (224, 224, 3))
converter = tf.lite.TFLiteConverter.from_keras_model(model)

In both cases, the intention is to get the converter.

I don't have the saved_model, so I will use keras model and convert it to saved_model format just use the Keras model format as an example

import pathlib #to use path
model = tf.keras.applications.MobileNetV2(weights="imagenet", input_shape= (224, 224, 3))
export_dir = 'imagenet/saved_model'
tf.saved_model.save(model, export_dir) #convert keras to saved model

converter = tf.lite.TFLiteConverter.from_saved_model(export_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]  #you can also optimize for size or latency OPTIMIZE_FOR_SIZE, OPTIMIZE_FOR_LATENCY
tflite_model = converter.convert()

#save the model
tflite_model_file = pathlib.Path('m.tflite')
tflite_model_file.write_bytes(tflite_model)

tflite_interpreter = tf.lite.Interpreter(model_path= 'm.tflite') #you can load the content with model_content=tflite_model

# get shape of tflite input and output
input_details = tflite_interpreter.get_input_details()
output_details = tflite_interpreter.get_output_details()
print("Input: {}".format( input_details[0]['shape']))
print("Output:{}".format(output_details[0]['shape']))

# get shape of the origin model
print("Input:  {}".format( model.input.shape))
print("Output: {}".format(model.output.shape))

For the tflite: I have this

enter image description here

For the Original Model I have this

enter image description here

You will see the shape of both tflite and keras model are the same

Just reshape your input tensor.

You can use the resize_tensor_input function, like this:

interpreter.resize_tensor_input(input_index=0, tensor_size=[1, 640, 640, 3])

Now you input shape will be: [1, 640, 640, 3].

Related