tensorflow keras savedmodel lost inputs name and add unknow inputs - tensorflow

I'm currently implement the sequantial deep matching model (https://arxiv.org/abs/1909.00385) using tensorflow 2.3. And I included the preprocessing layer as part of the model via subclassing keras.layers.Layer.
The preprocessing part of code is listed below
class Preprocessing(keras.layers.Layer):
def __init__(self, str_columns, hash_bins, float_columns, float_buckets, embedding_dim, user_columns, short_seq_columns, prefer_seq_columns, item_key_feats,
item_key_hash_bucket_size, series_feats, series_feats_hash_bucket_size, deviceid_num, device_list, **kwargs):
super(Preprocessing, self).__init__(**kwargs)
self.str_columns = str_columns
self.hash_bins = hash_bins
self.float_columns = float_columns
self.float_buckets = float_buckets
self.embedding_dim = embedding_dim
self.user_columns = user_columns
self.short_seq_columns = short_seq_columns
self.prefer_seq_columns = prefer_seq_columns
self.item_key_feats = item_key_feats
self.item_key_hash_bucket_size = item_key_hash_bucket_size
self.series_feats = series_feats
self.series_feats_hash_bucket_size = series_feats_hash_bucket_size
self.deviceid_num = deviceid_num
self.device_list = device_list
self.user_outputs = {}
self.short_outputs = {}
self.prefer_outputs = {}
deviceid_lookup = keras.layers.experimental.preprocessing.StringLookup(vocabulary=device_list, mask_token=None, oov_token="-1")
deviceid_embedding = keras.layers.Embedding(input_dim=deviceid_num, output_dim=embedding_dim)
item_key_hashing = keras.layers.experimental.preprocessing.Hashing(num_bins=item_key_hash_bucket_size)
item_key_embedding = keras.layers.Embedding(input_dim=item_key_hash_bucket_size, output_dim=embedding_dim)
series_hashing = keras.layers.experimental.preprocessing.Hashing(num_bins=series_feats_hash_bucket_size)
series_embedding = keras.layers.Embedding(input_dim=series_feats_hash_bucket_size, output_dim=embedding_dim)
for i in str_columns:
if i == "device_id":
process = [deviceid_lookup, deviceid_embedding]
elif i in item_key_feats:
process = [item_key_hashing, item_key_embedding]
elif i in series_feats:
process = [series_hashing, series_embedding]
else:
hashing = keras.layers.experimental.preprocessing.Hashing(num_bins=hash_bins[i])
embedding = keras.layers.Embedding(input_dim=hash_bins[i], output_dim=embedding_dim)
process = [hashing, embedding]
if i in user_columns:
self.user_outputs[i] = process
if i in short_seq_columns:
self.short_outputs[i] = process
if i in prefer_seq_columns:
self.prefer_outputs[i] = process
for l in float_columns:
discrete = keras.layers.experimental.preprocessing.Discretization(bins=float_buckets[l])
embedding = keras.layers.Embedding(input_dim=len(float_buckets[l]) + 1, output_dim=embedding_dim)
if l in user_columns:
self.user_outputs[l] = [discrete, embedding]
if l in short_seq_columns:
self.short_outputs[l] = [discrete, embedding]
if l in prefer_seq_columns:
self.prefer_outputs[l] = [discrete, embedding]
#staticmethod
def get_embedding(input_tmp, name, embed_dict):
func = embed_dict[name]
if len(func) < 2:
print(func)
raise Exception('Not enough function to retrieve embedding')
output = func[0](input_tmp)
output = func[1](output)
return output
def call(self, inputs):
user_embedding = tf.concat([tf.reduce_mean(self.get_embedding(inputs[i], i, self.user_outputs), axis=[1, 2]) for i in self.user_columns], axis=-1)
short_embedding = tf.concat([tf.squeeze(self.get_embedding(inputs[l], l, self.short_outputs), axis=1).to_tensor() for l in self.short_seq_columns], axis=-1)
prefer_embedding = {k: tf.squeeze(self.get_embedding(inputs[k], k, self.prefer_outputs).to_tensor(), axis=1) for k in self.prefer_seq_columns}
return user_embedding, short_embedding, prefer_embedding
And also my input code:
def read_row(csv_row):
record_defaults = [[0.]] * numeric_feature_size + [['']] * category_feature_size + [['0-0']] + [['0']]
row = tf.io.decode_csv(csv_row, record_defaults=record_defaults, field_delim='', use_quote_delim=False)
features = []
for i, feature in enumerate(row):
if i < numeric_feature_size:
features.append(feature)
elif i < numeric_feature_size + category_feature_size:
tmp_tf = tf.strings.split([feature], ";")
features.append(tmp_tf)
res = OrderedDict(zip(numeric_columns + category_columns, features))
res['target'] = [tf.cast(row[-2], tf.string)]
return res
The other part of code is not giving here, cause I believe it's right, and might be too much to list here.
The model is working correctly during training using model.compile then model.fit, however, after I saved it with model.save(path), the resulting Graph gets many unknown inputs and none of the inputs name is saved.
saved_model_cli show --dir ./ --tag_set serve --signature_def serving_default
The given SavedModel SignatureDef contains the following input(s):
inputs['args_0'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0:0
inputs['args_0_1'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_1:0
inputs['args_0_10'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_10:0
inputs['args_0_11'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_11:0
inputs['args_0_12'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_12:0
inputs['args_0_13'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_13:0
inputs['args_0_14'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_14:0
inputs['args_0_15'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_15:0
inputs['args_0_16'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_16:0
inputs['args_0_17'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_17:0
inputs['args_0_18'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_18:0
inputs['args_0_19'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_19:0
inputs['args_0_2'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_2:0
inputs['args_0_20'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_20:0
inputs['args_0_21'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_21:0
inputs['args_0_22'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_22:0
inputs['args_0_23'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_23:0
inputs['args_0_24'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_24:0
inputs['args_0_25'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_25:0
inputs['args_0_26'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_26:0
inputs['args_0_27'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_27:0
inputs['args_0_28'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_28:0
inputs['args_0_29'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_29:0
inputs['args_0_3'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_3:0
inputs['args_0_30'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_30:0
inputs['args_0_31'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_31:0
inputs['args_0_32'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_32:0
inputs['args_0_33'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_33:0
inputs['args_0_34'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_34:0
inputs['args_0_35'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_35:0
inputs['args_0_36'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_36:0
inputs['args_0_37'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_37:0
inputs['args_0_38'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_38:0
inputs['args_0_39'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_39:0
inputs['args_0_4'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_4:0
inputs['args_0_40'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_40:0
inputs['args_0_41'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_41:0
inputs['args_0_42'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_42:0
inputs['args_0_43'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_43:0
inputs['args_0_44'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_44:0
inputs['args_0_45'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_45:0
inputs['args_0_46'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_46:0
inputs['args_0_47'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_47:0
inputs['args_0_48'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_48:0
inputs['args_0_49'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_49:0
inputs['args_0_5'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_5:0
inputs['args_0_50'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_50:0
inputs['args_0_6'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_6:0
inputs['args_0_7'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_7:0
inputs['args_0_8'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_8:0
inputs['args_0_9'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_args_0_9:0
The given SavedModel SignatureDef contains the following output(s):
outputs['output_1'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 64)
name: StatefulPartitionedCall:0
In this model, I only used the categorical features with dtype as tf.string, so all the inputs with dtype of DT_INT64 is not part of my model inputs.
Can anyone help me with this?

I finally got this work.
The error came from my tf.io.decode_csv method. tf.strings.split()will return a RaggedTensor by default, which will also contain two int variables. That's why the input signatures contains 17 string type and 34 int type.
The RaggedTensor will also harm the keras serialization, which is why all of the input names were missing.
I transformed all the RaggedTensor to EagerTensor, and all things worked.
However, that's not the only error I've encountered when I tried to load the model.
I also encountered
The same saveable will be restored with two names error, which cost me tons of time to resolved it. And it turns out to be as bug of keras.layers.experimental.preprocessing module, the same function in it cannot be used twice, cause variables will be recorded as the same name, and result in a non-loadable savedmodel.

It is easy, I test with multiple ways and found name is the most significant thing that happen.
The custom class and RNN with lstm cell are not working, I spend time testing also that takes a lot of time because tracing on and RNN .
[ Sample ]:
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
: Model Initialize
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
model = tf.keras.models.Sequential([
tf.keras.layers.InputLayer(input_shape=( 32, 32, 3 ), batch_size=1, name='layer_input'),
tf.keras.layers.Normalization(mean=3., variance=2., name='layer_normalize_1'),
tf.keras.layers.Normalization(mean=4., variance=6., name='layer_normalize_2'),
tf.keras.layers.Conv2DTranspose(2, 3, activation='relu', padding="same", name='layer_conv2dT_1'),
tf.keras.layers.MaxPooling2D(pool_size=(2, 2), strides=(1, 1), padding='valid', name='layer_maxpool_1'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(4 * 256, name='layer_dense_1'),
tf.keras.layers.Reshape((4 * 256, 1)),
tf.keras.layers.LSTM(128, name='layer_4', return_sequences=True, return_state=False),
tf.keras.layers.LSTM(128, name='layer_5'),
tf.keras.layers.Dropout(0.2),
])
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(64, activation='relu', name='layer_dense_2'))
model.add(tf.keras.layers.Dense(7, name='layer_dense_3'))
model.summary()
# Loads the weights
if exists(target_saved_model) :
model = load_model(target_saved_model)
print("model load: " + target_saved_model)
input("Press Any Key!")
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
: Training
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
history = model.fit(x_train, y_train, epochs=10, batch_size=1 ,validation_data=(x_test, y_test))
model.save(target_saved_model)
print('.................')
[ Output ]: 1. Error messages from layer lstm
Epoch 10/10
20/20 [==============================] - 1s 71ms/step - loss: 0.7332 - val_loss: 0.8078
2022-04-06 23:23:26.017439: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
WARNING:absl:Found untraced functions such as lstm_cell_layer_call_fn, lstm_cell_layer_call_and_return_conditional_losses, lstm_cell_1_layer_call_fn, lstm_cell_1_layer_call_and_return_conditional_losses while saving (showing 4 of 4). These functions will not be directly callable after loading.
WARNING:absl:<keras.layers.recurrent.LSTMCell object at 0x00000145F1C83130> has the same name 'LSTMCell' as a built-in Keras object. Consider renaming <class 'keras.layers.recurrent.LSTMCell'> to avoid naming conflicts when loading with `tf.keras.models.load_model`. If renaming is not possible, pass the object in the `custom_objects` parameter of the load function.
WARNING:absl:<keras.layers.recurrent.LSTMCell object at 0x00000145F1C83C10> has the same name 'LSTMCell' as a built-in Keras object. Consider renaming <class 'keras.layers.recurrent.LSTMCell'> to avoid naming conflicts when loading with `tf.keras.models.load_model`. If renaming is not possible, pass the object in the `custom_objects` parameter of the load function.
...
[ Output 2 ]: 2. Error message removed
Epoch 10/10
100/100 [==============================] - 6s 63ms/step - loss: 0.3954 - val_loss: 0.5108
.................
...

Related

(Tensorflow 1.14) Not able to convert saved_model.pb and variables in to frozen_inference_graph.pb

I am using tensorflow=1.14. During periodic evaluation, I save best model using tf.estimator.BestExporter. I have following questions.
1)
When I try to convert saved_model.pb stored by BestExporter during training to frozen graph using freeze_graph() function, usual input/output node names ("image_tensor" / ['detection_boxes', 'detection_classes', 'detection_scores', 'num_detections']) are not present in saved_model. when I inspect using saved model cli, input / output names are completely different than the saved model stored by export_inference_graph.py using checkpoint and graph with pipeline.config.
"""
export_inference_graph's saved model saverDef
signature_def['serving_default']:
The given SavedModel SignatureDef contains the following input(s):
inputs['serialized_example'] tensor_info:
dtype: DT_STRING
shape: ()
name: tf_example:0
The given SavedModel SignatureDef contains the following output(s):
outputs['detection_boxes'] tensor_info:
dtype: DT_FLOAT
shape: (1, 150, 4)
name: Postprocessor/BatchMultiClassNonMaxSuppression/stack_4:0
outputs['detection_classes'] tensor_info:
dtype: DT_FLOAT
shape: (1, 150)
name: Postprocessor/BatchMultiClassNonMaxSuppression/stack_6:0
outputs['detection_scores'] tensor_info:
dtype: DT_FLOAT
shape: (1, 150)
name: Postprocessor/BatchMultiClassNonMaxSuppression/stack_5:0
outputs['num_detections'] tensor_info:
dtype: DT_FLOAT
shape: (1)
name: Postprocessor/ToFloat_3:0
Method name is: tensorflow/serving/predict
BestExporter saverdef
signature_def['serving_default']:
The given SavedModel SignatureDef contains the following input(s):
inputs['inputs'] tensor_info:
dtype: DT_UINT8
shape: (-1, -1, -1, 3)
name: image_tensor:0
The given SavedModel SignatureDef contains the following output(s):
outputs['detection_boxes'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 150, 4)
name: detection_boxes:0
outputs['detection_classes'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 150)
name: detection_classes:0
outputs['detection_scores'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 150)
name: detection_scores:0
outputs['num_detections'] tensor_info:
dtype: DT_FLOAT
shape: (-1)
name: num_detections:0
Method name is: tensorflow/serving/predict
"""
As one can see, both have different ip/op names.
2)
Alternate approach I tried which is directly using saved_model.pb saved by BestExporter for inference. By inspecting .pb file using saved model cli, input shape it refers to is string with no dimension, which again prevent me using this approach because when passed numpy image for inference, it raised shape mismatch error. (From above)
Can someone help me out how can I use saved_model from BestExporter for inference or convert it to frozen graph with correct ip/op so It can be used for inference.
Let me know If you need more information.
Thank you

How to use trained model in Tensorflow Serving?

I have trained Mask-RCNN model, and want to try Tensorflow Serving to use it in web.
So i just run tensorflow/serving docker container. And realised what i have no clue how to send image to predict. Here is saved_model_cli.py output:
signature_def['serving_default']:
The given SavedModel SignatureDef contains the following input(s):
inputs['input_anchors'] tensor_info:
dtype: DT_FLOAT
shape: (-1, -1, 4)
name: input_anchors:0
inputs['input_image'] tensor_info:
dtype: DT_FLOAT
shape: (-1, -1, -1, 6)
name: input_image:0
inputs['input_image_meta'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 14)
name: input_image_meta:0
The given SavedModel SignatureDef contains the following output(s):
outputs['mrcnn_detection/Reshape_1'] tensor_info:
dtype: DT_FLOAT
shape: (1, 100, 6)
name: mrcnn_detection/Reshape_1:0
outputs['mrcnn_mask/Reshape_1'] tensor_info:
dtype: DT_FLOAT
shape: (1, 100, 28, 28, 2)
name: mrcnn_mask/Reshape_1:0
Method name is: tensorflow/serving/predict
So i tried to send 6 bands image with Postman:
But get error. How can i form a correct request to serving?
You need to create a Json file with signature_name(Signature) and instances(images in list) like below,
data = json.dumps({"signature_name": "your_signature", "instances": test_data[0:n].tolist()})`
Then you can make a request like below,
headers = {"content-type": "application/json"}
json_response = requests.post('http://localhost:8501/v1/models/your_model:predict', data=data, headers=headers)
predictions = json.loads(json_response.text)['predictions']
You can refer this section in tfx tutorial to know more.

tensorflow2 sparse input name missing in saved model

tensorflow 2.3
ubuntu16.04
python=3.7.7
When using tf.keras.Input with 'sparse=True', the input tensor info names are unreadable in serving signatures, such as args_0, args_0_1, args_0_2. As a result, it is very hard to distinguish when multiple sparse inputs are used in one model.
Source code / logs
def make_parse_example_test(serialized_example):
# 解析的字典格式
data_dict_test = { # 解析example
'label': tf.io.FixedLenFeature([1], tf.float32),
'features': tf.io.FixedLenFeature([38], tf.float32),
# 'emb_arr': tf.io.FixedLenFeature([100],tf.float32),
'scid_index': tf.io.VarLenFeature(tf.int64),
}
features = tf.io.parse_single_example(serialized_example, features=data_dict_test)
label = features.pop('label')
return features,label
def batch_input(file_dir,batchsize):
# 判断是否是文件目录,创建文件流
if os.path.isdir(file_dir):
files = os.listdir(file_dir)
filenamequeues = list(map(lambda x: file_dir+x, files))
else:
filenamequeues = [file_dir]
print(filenamequeues)
dataset = tf.data.TFRecordDataset(filenamequeues)
# dataset = dataset.batch(batchsize)
dataset = dataset.map(make_parse_example_test,num_parallel_calls=4)
dataset = dataset.batch(batchsize)
# 读入数据,对数据进行混洗(shuffle)、分批batch
dataset = dataset.prefetch(-1)
return dataset
class EmbeddingLayer(tf.keras.layers.Layer):
def __init__(self, input_dim, output_dim):
super(EmbeddingLayer, self).__init__(trainable=True)
self.params = tf.Variable(tf.random.truncated_normal([input_dim, output_dim]), trainable=True)
def call(self,inputs):
param = tf.nn.safe_embedding_lookup_sparse(self.params,inputs)
return param
def get_config(self):
return super(EmbeddingLayer, self).get_config()
def models():
feature1 = tf.keras.layers.Input(shape=[38], name='features', dtype=tf.float32)
scid_index = tf.keras.layers.Input(shape=[None], name='scid_index', dtype=tf.int64,sparse=True)
scid_em = EmbeddingLayer(780000,50)(scid_index)
feature_all = tf.keras.layers.concatenate([
feature1,scid_em
])
h1 = tf.keras.layers.Dense(256, activation=leaky_relu,name='h1')(feature_all)
h2 = tf.keras.layers.Dense(256, activation=leaky_relu, name="h2")(h1)
h3 = tf.keras.layers.Dense(1, activation=leaky_relu, name="h3")(h2)
output = tf.keras.layers.Activation(activation="sigmoid")(h3)
out = tf.keras.models.Model(
inputs=[feature1,scid_index],
outputs=[output]
)
return out
train = batch_input('./part-r-00001',512)
model = models()
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=[tf.keras.metrics.AUC(),
tf.keras.metrics.Precision(),
tf.keras.metrics.Recall(),
tf.keras.metrics.BinaryAccuracy()])
model.fit(train, epochs=1,verbose=1,class_weight={0:1,1:2},steps_per_epoch=5)
print(model.input_names)
model.save("./model3test")
[examine exported_model]
$ saved_model_cli show --dir ./model3test --all
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:
signature_def['__saved_model_init_op']:
The given SavedModel SignatureDef contains the following input(s):
The given SavedModel SignatureDef contains the following output(s):
outputs['__saved_model_init_op'] tensor_info:
dtype: DT_INVALID
shape: unknown_rank
name: NoOp
Method name is:
signature_def['serving_default']:
The given SavedModel SignatureDef contains the following input(s):
inputs['args_0'] tensor_info:
dtype: DT_INT64
shape: (-1, 2)
name: serving_default_args_0:0
inputs['args_0_1'] tensor_info:
dtype: DT_INT64
shape: (-1)
name: serving_default_args_0_1:0
inputs['args_0_2'] tensor_info:
dtype: DT_INT64
shape: (2)
name: serving_default_args_0_2:0
The given SavedModel SignatureDef contains the following output(s):
outputs['label'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 1)
name: StatefulPartitionedCall_18:0
Method name is: tensorflow/serving/predict

`Table not initialized` when predicting with AI-platform

I'm trying to save faster R-CNN hub model and use it with AI-platform gcloud ai-platform local predict. The error I'm getting is:
Failed to run the provided model: Exception during running the graph: [_Derived_] Table not initialized.\n\t [[{{node hub_input/index_to_string_1_Lookup}}]]\n\t [[StatefulPartitionedCall_1/StatefulPartitionedCall/model/keras_layer/StatefulPartitionedCall]] (Error code: 2)\n'
The code for saving the model:
model_url = "https://tfhub.dev/google/faster_rcnn/openimages_v4/inception_resnet_v2/1"
input = tf.keras.Input(shape=(), dtype=tf.string)
decoded = tf.keras.layers.Lambda(
lambda y: tf.map_fn(
lambda x: tf.image.resize(
tf.image.convert_image_dtype(
tf.image.decode_jpeg(x, channels=3), tf.float32), (416, 416)
),
tf.io.decode_base64(y), dtype=tf.float32)
)(input)
results = hub.KerasLayer(model_url, signature_outputs_as_dict=True)(decoded)
model = tf.keras.Model(inputs=input, outputs=results)
model.save("./saved_model", save_format="tf")
The model works when I load with tf.keras.models.load_model("./saved_model") and predict with it, but not with ai-platform local predict.
Command for ai-platform local predictions:
gcloud ai-platform local predict --model-dir ./saved_model --json-instances data.json --framework TENSORFLOW
Versions:
python 3.7.0
tensorflow==2.2.0
tensorflow-hub==0.7.0
Output of saved_model_cli:
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:
signature_def['__saved_model_init_op']:
The given SavedModel SignatureDef contains the following input(s):
The given SavedModel SignatureDef contains the following output(s):
outputs['__saved_model_init_op'] tensor_info:
dtype: DT_INVALID
shape: unknown_rank
name: NoOp
Method name is:
signature_def['serving_default']:
The given SavedModel SignatureDef contains the following input(s):
inputs['image_bytes'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: serving_default_image_bytes:0
The given SavedModel SignatureDef contains the following output(s):
outputs['keras_layer'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 4)
name: StatefulPartitionedCall_1:0
outputs['keras_layer_1'] tensor_info:
dtype: DT_STRING
shape: (-1, 1)
name: StatefulPartitionedCall_1:1
outputs['keras_layer_2'] tensor_info:
dtype: DT_INT64
shape: (-1, 1)
name: StatefulPartitionedCall_1:2
outputs['keras_layer_3'] tensor_info:
dtype: DT_STRING
shape: (-1, 1)
name: StatefulPartitionedCall_1:3
outputs['keras_layer_4'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 1)
name: StatefulPartitionedCall_1:4
Method name is: tensorflow/serving/predict
Any ideas on how to fix the error?
The problem is that your input is being interpreted as a scalar. Do:
input = tf.keras.Input(shape=(1,), dtype=tf.string)

Reshape input layer 'requested shape' size always 'input shape' size squared

I am trying to run a SavedModel using the C-API.
When it comes to running TF_SessionRun it always fails on various input nodes with the same error.
TF_SessionRun status: 3:Input to reshape is a tensor with 6 values, but the requested shape has 36
TF_SessionRun status: 3:Input to reshape is a tensor with 19 values, but the requested shape has 361
TF_SessionRun status: 3:Input to reshape is a tensor with 3111 values, but the requested shape has 9678321
...
As can be seen, the number of requested shape values is always the square of the expected input size. It's quite odd.
The model runs fine with the saved_model_cli command.
The inputs are all either scalar DT_STRING or DT_FLOATs, I'm not doing image recogition.
Here's the output of that command:
signature_def['serving_default']:
The given SavedModel SignatureDef contains the following input(s):
inputs['f1'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: f1:0
inputs['f2'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: f2:0
inputs['f3'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: f3:0
inputs['f4'] tensor_info:
dtype: DT_FLOAT
shape: (-1)
name: f4:0
inputs['f5'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: f5:0
The given SavedModel SignatureDef contains the following output(s):
outputs['o1_probs'] tensor_info:
dtype: DT_DOUBLE
shape: (-1, 2)
name: output_probs:0
outputs['o1_values'] tensor_info:
dtype: DT_STRING
shape: (-1, 2)
name: output_labels:0
outputs['predicted_o1'] tensor_info:
dtype: DT_STRING
shape: (-1, 1)
name: output_class:0
Method name is: tensorflow/serving/predict
Any clues into what's going on are much appreciated. The saved_model.pb file is coming from AutoML, my code is merely querying that model. I don't change the graph.
It turns out that the issue was caused by me not using the TF_AllocateTensor function correctly.
The original code was like:
TF_Tensor* t = TF_AllocateTensor(TF_STRING, nullptr, 0, sz);
when it appears it should have been:
int64_t dims = 0;
TF_Tensor* t = TF_AllocateTensor(TF_STRING, &dims, 1, sz);