5

I trained a simple model with Keras/TF2.5 and saved it as saved model.

tf.saved_model.save(my_model,'/path/to/model')

If I examine it via

saved_model_cli show --dir /path/to/model --tag_set serve --signature_def serving_default

I get these outputs/names:

inputs['conv2d_input'] tensor_info:
  dtype: DT_FLOAT
  shape: (-1, 32, 32, 1)
  name: serving_default_conv2d_input:0
outputs['dense'] tensor_info:
  dtype: DT_FLOAT
  shape: (-1, 2)
  name: StatefulPartitionedCall:0

The names serving_default_conv2d_input and StatefulPartitionedCall can actually be used for inference.

I want to extract them using python API. If I query it by loading the model:

>>> m=tf.saved_model.load('/path/to/model')
>>> m.signatures['serving_default'].inputs[0].name
'conv2d_input:0'
>>> m.signatures['serving_default'].outputs[0].name
'Identity:0'

I get entirely different names.

Questions:

  1. How can I extract these names serving_default_conv2d_input and StatefulPartitionedCall from python API?
  2. Alternatively how can I define/fix the names when I call tf.saved_model.save?
  3. What does :0 mean?

And side question:

How do you handle deployment TF model to production via SavedModel?

Artyom
  • 31,019
  • 21
  • 127
  • 215

1 Answers1

3

The input/output tensor names displayed by saved_model_cli can be extracted as follows:

from tensorflow.python.tools import saved_model_utils

saved_model_dir = '/path/to/model'
tag_set = 'serve'
signature_def_key = 'serving_default'

# 1. Load MetaGraphDef with saved_model_utils
meta_graph_def = saved_model_utils.get_meta_graph_def(saved_model_dir, tag_set)

# 2. Get input signature names
input_signatures = list(meta_graph_def.signature_def[signature_def_key].inputs.values())
input_names = [signature.name for signature in input_signatures]
print(input_names)  # ['serving_default_conv2d_input:0']

# 3. Get output signature names
output_signatures = list(meta_graph_def.signature_def[signature_def_key].outputs.values())
output_names = [signature.name for signature in output_signatures]
print(output_names)  # ['StatefulPartitionedCall:0']

Regarding the meaning of :0, op_name:0 means "the tensor that is the 0th output of an operation called op_name." So you might use …:1 to get the output of an operation with multiple outputs, but many operations are single-output so you'll always use …:0 for them (source: @mrry's comment).

rvinas
  • 11,824
  • 36
  • 58
  • 1
    Wow... I was looking for this saved_model_utils and other tools for several days! Thanks! It is great! I'll award the bounty once stackoverflow allows it!!! – Artyom Jul 31 '21 at 12:41