onnx
tensorflow
model conversion
machine learning
deep learning

How could I convert onnx model to tensorflow saved model?

Master System Design with Codemia

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

Introduction

Converting an ONNX model to a TensorFlow SavedModel is usually a tooling workflow, not a manual rewrite of network layers. The reliable approach is to load the ONNX file with a converter, export a SavedModel directory, and then validate that TensorFlow can run it with the same inputs and numerically similar outputs.

Convert with a dedicated backend tool

One common route uses onnx plus onnx-tf. The converter reads the ONNX graph and builds an equivalent TensorFlow representation where operator support allows it.

python
1import onnx
2from onnx_tf.backend import prepare
3
4onnx_model = onnx.load("model.onnx")
5tf_rep = prepare(onnx_model)
6tf_rep.export_graph("saved_model")

The result is a SavedModel directory named saved_model, not a single file. That directory typically contains saved_model.pb, a variables folder, and metadata needed by TensorFlow tooling.

Load the SavedModel in TensorFlow

After export, verify that TensorFlow can load the result and inspect the available signatures:

python
1import tensorflow as tf
2
3loaded = tf.saved_model.load("saved_model")
4print(list(loaded.signatures.keys()))

If you see a serving signature, you are in a much better position than if you stop after file generation. Successful export alone does not prove the model is correct or production-ready.

Compare outputs against ONNX Runtime

The most important validation step is numerical comparison. Run the same sample input through the original ONNX model and the converted TensorFlow SavedModel, then compare outputs within a tolerance.

python
1import numpy as np
2import onnxruntime as ort
3import tensorflow as tf
4
5sample = np.random.rand(1, 3, 224, 224).astype("float32")
6
7ort_session = ort.InferenceSession("model.onnx")
8ort_input_name = ort_session.get_inputs()[0].name
9onnx_output = ort_session.run(None, {ort_input_name: sample})[0]
10
11loaded = tf.saved_model.load("saved_model")
12infer = loaded.signatures["serving_default"]
13tf_output = list(infer(tf.constant(sample)).values())[0].numpy()
14
15print(np.allclose(onnx_output, tf_output, atol=1e-4))

The exact tensor layout depends on the model. Some conversions require channel-order fixes or wrapper logic around the exported signature.

Operator coverage is the real constraint

Most failed conversions are not caused by the export command itself. They fail because some ONNX operators, dynamic shapes, or graph patterns do not map cleanly to the TensorFlow backend used by the converter.

That means you should check:

  • converter version compatibility
  • ONNX opset version
  • whether custom operators are present
  • whether the model uses dynamic behavior the target backend struggles with

If an operator is unsupported, the answer is often to simplify the model, export differently from the source framework, or choose a different deployment path.

Treat signatures and input names as part of the migration

A technically successful conversion can still be awkward to serve if the input names, output names, or signature layout are unclear. TensorFlow Serving, local inference wrappers, and downstream apps are easier to maintain when the SavedModel has stable, predictable entry points.

If needed, you can wrap the converted model in a small TensorFlow module that normalizes the public signature before deployment.

Common Pitfalls

  • Assuming every ONNX operator converts cleanly into TensorFlow.
  • Treating successful file export as proof that the model is numerically correct.
  • Forgetting that SavedModel is a directory-based format, not just one standalone .pb file.
  • Ignoring input shape or dtype differences introduced by the conversion.
  • Using old converter versions and then debugging behavior that is really a tooling compatibility issue.

Summary

  • Use a converter library such as onnx-tf instead of manually rebuilding the model.
  • Export to a SavedModel directory, then immediately load it in TensorFlow to verify the artifact.
  • Compare ONNX Runtime output with TensorFlow output on the same sample input.
  • Expect conversion problems around unsupported operators, opset mismatches, and dynamic shapes.
  • Treat conversion as an integration workflow that requires testing, not a one-command guarantee.

Course illustration
Course illustration

All Rights Reserved.