Keras
TensorFlow
model conversion
protobuf
machine learning

Convert Keras model to TensorFlow protobuf

Master System Design with Codemia

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

Introduction

Converting a Keras model to TensorFlow “protobuf” can mean two different things, and confusion usually starts there. In modern TensorFlow, the standard deployable format is SavedModel, which internally uses protocol buffers as part of its representation. When people specifically ask for a .pb file, they often mean a frozen graph or GraphDef-style export for a legacy consumer. The correct conversion path depends on which of those targets you actually need.

Prefer SavedModel in Modern TensorFlow

If the goal is deployment in modern TensorFlow tooling, save the model as a SavedModel.

python
1import tensorflow as tf
2
3model = tf.keras.Sequential([
4    tf.keras.layers.Input(shape=(10,)),
5    tf.keras.layers.Dense(16, activation="relu"),
6    tf.keras.layers.Dense(1, activation="sigmoid")
7])
8
9model.save("exported_model")

This writes a directory-based TensorFlow model format, not a single frozen .pb file. But it is the normal answer for TensorFlow 2 deployment because it preserves signatures, variables, and execution metadata in a supported format.

When You Specifically Need a .pb Graph

Some older inference pipelines expect a frozen graph in GraphDef protobuf form. In that case, you need to trace the model, convert variables to constants, and serialize the resulting graph definition.

A common TensorFlow 2 pattern is:

python
1import tensorflow as tf
2from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2
3
4model = tf.keras.Sequential([
5    tf.keras.layers.Input(shape=(10,)),
6    tf.keras.layers.Dense(16, activation="relu"),
7    tf.keras.layers.Dense(1, activation="sigmoid")
8])
9
10full_model = tf.function(lambda x: model(x))
11concrete = full_model.get_concrete_function(tf.TensorSpec([None, 10], tf.float32))
12frozen = convert_variables_to_constants_v2(concrete)
13graph_def = frozen.graph.as_graph_def()
14
15with tf.io.gfile.GFile("model.pb", "wb") as f:
16    f.write(graph_def.SerializeToString())

This produces a protobuf graph file for consumers that truly require that representation.

Understand What You Lose in a Frozen Graph

A frozen graph is useful for some inference-only environments, but it is not the full general replacement for a trainable Keras model. By freezing variables into constants, you are moving from a flexible training artifact toward a static inference artifact.

That means you should decide first whether your target system wants:

  • a trainable or reloadable Keras model
  • a modern TensorFlow deployable model
  • a static graph for legacy inference

Without that clarity, “convert to protobuf” is too vague to implement safely.

Loading the Keras Model First

If the model already exists on disk, load it before conversion.

python
import tensorflow as tf

model = tf.keras.models.load_model("my_model.keras")

Then apply the export path that matches your target. If the model includes custom layers or custom objects, make sure those are available at load time.

That step often matters more than the protobuf export itself, because failed model loading blocks the whole conversion pipeline.

Verify the Export Instead of Assuming It Worked

After exporting, validate the result with the tool that will actually consume it. For SavedModel, reloading is straightforward:

python
reloaded = tf.keras.models.load_model("exported_model")
print(reloaded(tf.random.normal((2, 10))))

For a frozen graph, validation is more environment-specific, but you should still check that the consumer can load the graph and that the input and output tensor names are what you expect.

A file existing on disk is not proof that the conversion met the deployment contract.

Be Careful with Custom Layers and Dynamic Behavior

Custom Keras layers, Lambda layers, and dynamic Python logic can make graph export harder. Some models save and reload cleanly as SavedModel but require more effort to freeze into a simple .pb graph.

If the deployment target is strict, simplify the model interface and make input signatures explicit before exporting.

That usually produces a more stable conversion than trying to freeze a loosely defined model function after the fact.

Common Pitfalls

The most common mistake is saying “protobuf” when the real target should be SavedModel. In modern TensorFlow, that is usually the better deployment format.

Another mistake is exporting a frozen graph without validating tensor signatures, then discovering the inference system cannot find the expected inputs or outputs.

Developers also underestimate how much custom layers and Python-side logic can complicate graph freezing.

Summary

  • In TensorFlow 2, SavedModel is usually the preferred deployment format for Keras models.
  • A .pb file usually means a frozen graph for a legacy or graph-based consumer.
  • The correct export path depends on what the downstream system actually expects.
  • Use convert_variables_to_constants_v2 when you really need a static protobuf graph.
  • Always validate the exported artifact with the runtime that will consume it.

Course illustration
Course illustration

All Rights Reserved.