Saving TF model trained with keras and then evaluated in Go
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
The stable handoff between Python training code and Go inference code is the SavedModel format. Keras can train and export the model, and a Go application can then consume that exported model either through TensorFlow tooling or, more practically, through a serving layer. The important part is to export a clear serving signature and to keep the input tensor shape and dtype consistent across both languages.
Export the Model From Keras as a SavedModel
A model that stays inside Python-specific code is hard to reuse elsewhere. SavedModel packages the graph, weights, and callable signatures into a language-neutral artifact.
Here is a minimal Keras example that trains a small model and exports it:
That directory is the deployment artifact. Do not pass around a Python notebook or training script when what the Go side really needs is a stable saved model.
Inspect the Exported Signature Before Writing Go Code
Before integrating from Go, inspect the SavedModel so you know the exact input and output names:
You need to know:
- serving signature name, often
serving_default - input tensor name
- output tensor name
- expected dtype and shape
This step prevents most integration bugs. If you guess the tensor names from memory, you will eventually be wrong.
Practical Go Integration Through TensorFlow Serving
Direct TensorFlow Go bindings exist, but they require native library compatibility and can add operational friction. A more practical production setup is:
- export SavedModel from Python
- serve it with TensorFlow Serving
- call the prediction API from Go
Start Serving with Docker:
Then call it from Go:
This is still Go-based evaluation from the application point of view, but it avoids embedding TensorFlow runtime details into the Go binary.
If You Need Direct Model Loading in Go
Some teams still choose in-process inference with TensorFlow Go bindings. The same SavedModel artifact is used, but you must link the correct TensorFlow shared libraries and load the model with matching tags and signature names.
The workflow is still the same:
- export from Keras with
tf.saved_model.save - inspect the signature
- feed tensors with the exact expected shape
- fetch outputs by signature name
If your organization does not need in-process inference, Serving is usually simpler to operate and easier to scale.
Keep Input Contracts Explicit
Most Go inference failures are not caused by model quality. They come from contract mismatch:
- Python trained on shape
(batch, 1)but Go sends a flat scalar list - model expects
float32but client sends integers or strings - serving signature changed after retraining and no one updated the client
A small contract document is worth it. Write down the exact JSON or tensor shape expected by the exported model and keep it under version control with the model.
Versioning and Deployment Layout
SavedModel directories are commonly versioned numerically for serving:
That layout makes rollouts predictable and lets Serving expose one logical model name while switching underlying versions cleanly.
Common Pitfalls
- Exporting only weights instead of a SavedModel, which leaves Go without the computation graph and signatures.
- Guessing input tensor names instead of checking them with
saved_model_cli. - Mixing incompatible TensorFlow runtime versions between training and inference environments.
- Treating direct Go bindings as a free shortcut when native library management is actually the hard part.
- Changing input preprocessing in Python without updating the Go caller.
Summary
- Use SavedModel as the handoff format from Keras to Go-based inference.
- Inspect signatures before writing the client so tensor names and shapes are explicit.
- TensorFlow Serving plus a Go HTTP client is usually the most practical deployment path.
- Direct Go bindings are possible, but they increase runtime compatibility work.
- Most integration bugs come from mismatched input contracts, not from model export itself.

