Tensorflow
model freezing
frozen models
.pb files
deep learning

Cannot freeze Tensorflow models into frozen.pb file

Master System Design with Codemia

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

Introduction

Freezing a TensorFlow model into a single frozen.pb file used to be a common TensorFlow 1.x deployment step. In TensorFlow 2.x, that workflow is no longer the default, so attempts to "freeze the model" often fail because the code still assumes sessions, checkpoints, and graph utilities from the older API.

What A Frozen Graph Actually Is

A frozen graph is a graph definition where variable values have been converted into constants embedded in the graph itself. In TensorFlow 1.x, that made it easier to ship a single .pb file for inference.

Today, TensorFlow prefers SavedModel, which keeps more structure and works better with serving, signatures, and modern tooling. That means the first question is not "how do I freeze," but "do I actually need a frozen graph, or would SavedModel solve the problem better?"

Prefer SavedModel When Possible

If your deployment target accepts modern TensorFlow artifacts, export the model directly.

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

That is the clean path for TensorFlow Serving and many TensorFlow 2.x workflows.

Freezing In TensorFlow 2.x

If you truly need a frozen .pb, the usual TensorFlow 2.x route is:

  • build a concrete function from the model
  • convert variables to constants
  • serialize the frozen graph definition
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=(4,)),
6    tf.keras.layers.Dense(8, activation="relu"),
7    tf.keras.layers.Dense(1),
8])
9
10# Run the model once so variables exist.
11_ = model(tf.zeros([1, 4]))
12
13full_model = tf.function(lambda x: model(x))
14concrete = full_model.get_concrete_function(
15    tf.TensorSpec(shape=[None, 4], dtype=tf.float32)
16)
17
18frozen_func = convert_variables_to_constants_v2(concrete)
19frozen_graph = frozen_func.graph.as_graph_def()
20
21with tf.io.gfile.GFile("frozen.pb", "wb") as handle:
22    handle.write(frozen_graph.SerializeToString())
23
24print("Inputs:", frozen_func.inputs)
25print("Outputs:", frozen_func.outputs)

That produces a serialized graph definition suitable for graph-based inference scenarios.

Why Old Freezing Code Often Breaks

Older tutorials rely on APIs such as:

  • 'tf.Session()'
  • 'tf.graph_util.convert_variables_to_constants'
  • checkpoint restoration into the default graph

Those patterns belong to TensorFlow 1.x graph execution. In TensorFlow 2.x, eager execution is enabled by default, so there is no persistent session-driven default path to freeze in the same way.

If the code mixes Keras model objects with old session utilities, the result is often confusion about missing graph nodes, uninitialized variables, or incompatible APIs.

Input Signatures Matter

When freezing fails, the real issue is often the exported function signature rather than the conversion step itself. The freezing utility needs a concrete function with known input structure.

python
concrete = full_model.get_concrete_function(
    tf.TensorSpec(shape=[1, 4], dtype=tf.float32, name="inputs")
)

A vague or mismatched signature can produce a graph that does not match your intended inference input.

Freezing Custom Layers Or Training Logic

Custom layers usually freeze correctly if they are built from TensorFlow ops and variables. Problems start when the model relies on Python-side control flow, external state, or training-only logic that never became part of the traced inference function.

That is another reason SavedModel is usually safer: it preserves more of the intended runtime behavior and signatures.

When A Frozen .pb Is Still Useful

A frozen graph can still be useful for legacy C++ inference pipelines, older deployment tools, or ecosystems that expect a graph-only artifact. But it is now a compatibility format, not the primary TensorFlow export format.

That distinction matters because many errors come from treating frozen graphs as the normal endpoint of every TensorFlow model.

Common Pitfalls

The most common mistake is using TensorFlow 1.x freezing code against a TensorFlow 2.x eager model. Another is trying to freeze before the model variables exist, which is why running the model once or building it explicitly matters. Developers also often forget to create a concrete function with the correct input signature. Finally, many deployment problems disappear if the target can consume SavedModel, so do not choose frozen .pb out of habit alone.

Summary

  • 'SavedModel is the preferred export format in modern TensorFlow.'
  • If you truly need frozen.pb, freeze a concrete function with convert_variables_to_constants_v2.
  • Old session-based freezing code usually belongs to TensorFlow 1.x.
  • Build the model and define a concrete input signature before freezing.
  • Treat frozen graphs as a legacy compatibility format, not the default deployment target.

Course illustration
Course illustration

All Rights Reserved.