Reputation: 4316
I have converted a Keras model to a Tensorflow estimator, added Tensorflow Transform to the graph and then exported the model for serving.
When I check the model signature, I can see the following info:
signature_def['serving_default']:
The given SavedModel SignatureDef contains the following input(s):
inputs['examples'] tensor_info:
dtype: DT_STRING
shape: (-1)
name: input_example_tensor:0
The given SavedModel SignatureDef contains the following output(s):
outputs['specialities'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 154)
name: specialities/Softmax:0
Method name is: tensorflow/serving/predict
I converted the feature specifications with tf.estimator.export.build_parsing_serving_input_receiver_fn
therefore the name of the input node in the signature is example
. The name of the input node in my model is procedures
.
I then use saved_model_cli
to manually test the exported model and everything looks good (I got a list of probabilities)
!saved_model_cli run --dir=/model_dir/1533849825
--tag_set serve
--signature_def serving_default
--input_examples 'examples=[{"procedures": ["99214,17000,17000,13121,99203"]}]'
Now, I load this model into TF Serving, the model server starts up ok.
When I request a model prediction with the json payload below (application/json), I am getting the following error:
{
"signature_name":"serving_default",
"instances":[
{
"examples":["99214,17000,17000,13121,99203"]
}
]
}
Error:
"error": "Expected serialized to be a vector, got shape: [1,1]
A different payload structure, leads to this error
{
"signature_name":"serving_default",
"examples":[
{
"procedure":["99214,17000,17000,13121,99203"]
}
]
}
Error:
"error": "JSON Value: {\n \"signature_name\": \"serving_default\",\n
\"examples\": [\n {\n \"procedures\":
["99214,17000,17000,13121,99203"]]\n }\n ]\n} not formatted
correctly. Expecting object with \'instances\' key and a list/array as the value."
What is the correct payload format for the TensorFlow Serving request in this prediction case?
Does the payload need to be formatted in the tf.Example structure?
Upvotes: 6
Views: 4991
Reputation: 492
As netfs above said, it is cumbersome to use build_parsing_serving_input_receiver_fn()
for REST APIs. To elaborate how cumbersome it is, here is the answer to your original question, the POST body should be something like:
{
"signature_name":"serving_default",
"instances":[
{
"examples":{"b64": base64.b64encode(example.SerializeToString()).decode('utf-8')}
}
]
}
The example
is a tf.Example proto object. For instance:
example = tf.train.Example(
features=tf.train.Features(
feature={"procedures":
tf.train.Feature(int64_list=tf.train.Int64List(value=[99214,17000,17000,13121,99203]))
)
)
Upvotes: 0
Reputation: 1940
I give an example here with Estimator
api, hope it can help someone who come up with the similar problems.
To export a SavedModel
with Estimator
you need a input_receiver_fn
to accpect inputs when serving. The input_receiver_fn
in my application is as following:
def _serving_input_receiver_fn():
serialized_tf_sample = tf.placeholder(dtype=tf.string,
shape=None, name='input_example_tensor')
receiver_tensors = {'example': serialized_tf_sample}
# example_proto: {'feature_name': tf.VarLenFeature(tf.int64),}
features = tf.parse_example(serialized_tf_sample, example_proto)
return tf.estimator.export.ServingInputReceiver(features, receiver_tensors)
You can put the following code under train_and_evaluate
to export a SavedModel
estimator.export_savedmodel(model_export_path, _serving_input_receiver_fn)
To serve the model you can pull the tensorflow/serving
docker image, you can refer https://www.tensorflow.org/serving/docker for help. (I suggest you pull the image with devel tag, since it's better to debug)
Simply run the below command to start serving
/usr/local/bin/tensorflow_model_server --port=8500 --rest_api_port=8501 --model_name=my_model --model_base_path my_model_path
The client code is simple, but should take care of. Because the serialized example should be encoded with base64 and added a b64
key.
import requests
resp = requests.post('http://host:8501/v1/models/my_model:predict', json={
'instances': [
{'example': {'b64':base64.b64encode(single_example.SerializeToString())}}
]})
resp.json()
If you have any question, just comment below.
Upvotes: 2
Reputation: 21
Can you try exporting your model using build_raw_serving_input_receiver_fn() instead? And pass the raw tensor (procedure
) in JSON predict request as:
{
"signature_name": "serving_default",
"instances": [
{
"procedure": ["99214,17000,17000,13121,99203"]
}
]
}
given that you are using default serving signature name and single named input you can shorten the request to:
{
"instances": ["99214,17000,17000,13121,99203"]
}
Regarding your existing code, exporting model using build_parsing_serving_input_receiver_fn()
requires serialized tf.Example
string blob as input. saved_model_cli
tool (being python and having access to protos) does this serialization for you and hence works well. Doing proto serialization while using Web/REST APIs can get cumbersome (requires protobuf libs), and is an overkill for your usage.
Upvotes: 1