TensorFlow
Estimator
ServingInputReceiver
Machine Learning
receiver_tensors

TensorFlow Estimator ServingInputReceiver features vs receiver_tensors when and why?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When you export a TensorFlow Estimator model, ServingInputReceiver describes how prediction requests enter the SavedModel. The two arguments that confuse most people are features and receiver_tensors, because they often contain related tensors but represent different layers of the serving pipeline.

The short version is this: receiver_tensors are the external inputs exposed to clients, while features are the tensors your model_fn actually consumes after parsing or preprocessing. If you keep that distinction in mind, the API becomes much easier to reason about.

What receiver_tensors Represents

receiver_tensors defines the serving signature. These are the input tensors that TensorFlow Serving or another client feeds at inference time.

In many deployments, the client sends serialized tf.Example records rather than already-parsed model features. In that case, the receiver is usually a placeholder for raw bytes.

python
1import tensorflow as tf
2
3
4def serving_input_receiver_fn():
5    serialized_examples = tf.compat.v1.placeholder(
6        dtype=tf.string,
7        shape=[None],
8        name="examples",
9    )
10
11    feature_spec = {
12        "age": tf.io.FixedLenFeature([1], tf.float32),
13        "income": tf.io.FixedLenFeature([1], tf.float32),
14    }
15    parsed = tf.io.parse_example(serialized_examples, feature_spec)
16
17    features = {
18        "age": parsed["age"] / 100.0,
19        "income": parsed["income"] / 100000.0,
20    }
21
22    return tf.estimator.export.ServingInputReceiver(
23        features=features,
24        receiver_tensors={"examples": serialized_examples},
25    )

In this example, clients feed only one thing: the examples tensor. That tensor belongs in receiver_tensors because it is the public input contract of the exported model.

What features Represents

features is the dictionary passed into your Estimator model_fn. It should match the structure your model expects at prediction time.

In the example above, the model does not consume serialized protocol buffers directly. It consumes parsed numeric tensors named age and income. Those tensors therefore belong in features.

This is the main mental model:

  • 'receiver_tensors is the outside of the model.'
  • 'features is the inside of the model.'

The two can be identical if you serve already-prepared values. For example, if your client sends one float tensor per feature, the placeholders exposed to the client can also be the exact tensors your model uses.

python
1import tensorflow as tf
2
3
4def serving_input_receiver_fn():
5    age = tf.compat.v1.placeholder(tf.float32, shape=[None, 1], name="age")
6    income = tf.compat.v1.placeholder(tf.float32, shape=[None, 1], name="income")
7
8    features = {
9        "age": age / 100.0,
10        "income": income / 100000.0,
11    }
12
13    return tf.estimator.export.ServingInputReceiver(
14        features=features,
15        receiver_tensors={
16            "age": age,
17            "income": income,
18        },
19    )

Even here the roles are still different. The client feeds age and income through receiver_tensors, and the model receives the normalized version through features.

When to Put Logic Between the Two

The gap between receiver_tensors and features is where serving-time preprocessing belongs. Common examples include:

  • parsing serialized tf.Example input
  • casting string or integer values to the expected type
  • normalizing numeric features
  • building lookup tables or vocabulary mappings
  • reshaping tensors to the exact rank expected by the model

This separation is useful because it keeps the serving API stable even if your internal model representation changes. A client can continue sending serialized examples while you evolve feature engineering inside the SavedModel.

One practical note: Estimator is now a legacy API and current TensorFlow guidance favors tf.keras. Still, many production systems maintain Estimator exports, so understanding this distinction matters when you debug an existing serving graph.

Common Pitfalls

  • Swapping the two concepts. If a tensor is fed by the client, it belongs in receiver_tensors, even if it later becomes a feature.
  • Forgetting preprocessing in the serving graph. A model trained on normalized data will produce bad predictions if the export receives raw values without the same transformation.
  • Mismatching names or shapes. The client must feed the keys defined in receiver_tensors, and the resulting features must match what model_fn expects.
  • Reusing a training input_fn for serving. Training input pipelines often include labels, shuffling, or dataset logic that does not belong in inference.
  • Assuming the exported signature is obvious. Inspect the SavedModel signature when debugging so you know what clients are expected to send.

Summary

  • 'receiver_tensors defines the external serving inputs.'
  • 'features defines the tensors consumed by the Estimator model.'
  • Use the space between them for parsing and preprocessing.
  • The two may look similar, but they answer different questions: what the client sends versus what the model reads.
  • If serving predictions look wrong, check shapes, names, and preprocessing before suspecting the model weights.

Course illustration
Course illustration

All Rights Reserved.