TensorFlow Serving for Production
TensorFlow Serving for Production
TFLite serves models on the edge; TensorFlow Serving serves them from the server side. It is a flexible, high-performance system purpose-built for putting trained models into production, handling model loading, versioning, and request serving without you writing a custom inference server from scratch.
Setting Up TensorFlow Serving
TensorFlow Serving is most commonly run as a Docker container. You point it at a directory containing one or more SavedModel versions, and it automatically loads the latest one and exposes both REST and gRPC endpoints.
docker pull tensorflow/serving
docker run -p 8501:8501 -p 8500:8500 \
--mount type=bind,source=/path/to/saved_models/my_model,target=/models/my_model \
-e MODEL_NAME=my_model \
-t tensorflow/serving
The directory structure matters: Serving expects each version of the model in its own numerically named subfolder, such as my_model/1/, my_model/2/, and so on, and it will serve the highest-numbered version by default.
Deploying Models via REST API
Once running, Serving exposes a REST endpoint on port 8501 (by default) that accepts JSON-formatted prediction requests.
import requests
import json
data = json.dumps({
'signature_name': 'serving_default',
'instances': x_test[:3].tolist()
})
headers = {'content-type': 'application/json'}
response = requests.post(
'http://localhost:8501/v1/models/my_model:predict',
data=data, headers=headers)
predictions = json.loads(response.text)['predictions']
print(predictions)
This format is simple enough to call from almost any language or platform, which is why REST is the default choice for most teams getting started with Serving.
Deploying Models via gRPC
For latency-sensitive applications, gRPC (port 8500 by default) is significantly faster than REST because it uses a compact binary protocol (Protocol Buffers) instead of JSON, and keeps a persistent connection open rather than negotiating a new HTTP request each time.
import grpc
import tensorflow as tf
from tensorflow_serving.apis import predict_pb2, prediction_service_pb2_grpc
channel = grpc.insecure_channel('localhost:8500')
stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)
request = predict_pb2.PredictRequest()
request.model_spec.name = 'my_model'
request.model_spec.signature_name = 'serving_default'
request.inputs['input_1'].CopyFrom(
tf.make_tensor_proto(x_test[:3], dtype=tf.float32))
result = stub.Predict(request, timeout=5.0)
print(result.outputs['dense_1'])
gRPC's binary encoding and connection reuse typically cut latency noticeably compared to REST, which matters at high request volumes or in real-time applications such as fraud detection or recommendation serving.
Model Versioning
Because Serving watches a model's base directory for numbered subfolders, deploying a new model version is as simple as dropping a new SavedModel into model_name/2/. Serving detects it, loads it in the background, and switches incoming traffic to the new version, all without downtime.
Versioning Policy | Behaviour |
Latest (default) | Always serves the single highest-numbered version available |
Specific versions | Serves an explicit, fixed list of version numbers simultaneously |
All versions | Loads and serves every version found in the directory, useful for comparison testing |
# model_config_list config to pin specific versions
model_config_list {
config {
name: 'my_model'
base_path: '/models/my_model'
model_platform: 'tensorflow'
model_version_policy {
specific {
versions: 1
versions: 2
}
}
}
}
A/B Testing Models
Because Serving can load multiple versions at once, A/B testing simply means routing a percentage of incoming traffic to each version and comparing results. Serving itself does not split traffic; that logic lives in front of it, typically in a load balancer, an API gateway, or a thin routing layer in your application code.
import random
def route_request(request_data):
version = 1 if random.random() < 0.9 else 2 # 90/10 split
url = f'http://localhost:8501/v1/models/my_model/versions/{version}:predict'
return requests.post(url, json=request_data)
Did You Know?
A/B testing in production ML is not just about accuracy. Teams routinely monitor latency, error rates, and downstream business metrics (like click-through or conversion rate) alongside model accuracy, since a more accurate model that is slower or that shifts user behaviour unexpectedly may not actually be the better choice to fully roll out.










