tensorflow
tf.Print()
debugging
machine learning
troubleshooting

Why does tf.Print does not print in tensorflow

Master System Design with Codemia

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

Introduction

In TensorFlow 1.x, tf.Print (capital P) was an operation that printed tensor values during graph execution. However, many developers found that tf.Print produced no output at all. This happened because tf.Print was a graph node that only executed when its output was consumed by another operation that actually ran. In TensorFlow 2.x, tf.Print was removed entirely in favor of tf.print (lowercase p) and eager execution, which behave more like standard Python print().

Why tf.Print Did Not Print (TF 1.x)

In TensorFlow 1.x, computation was defined as a graph and executed lazily via Session.run(). tf.Print returned a tensor identical to its input, but with a side effect of printing. If that returned tensor was never used in the computation graph, the print node was never executed:

python
1# TensorFlow 1.x — THIS DOES NOT PRINT
2import tensorflow as tf
3
4x = tf.constant([1.0, 2.0, 3.0])
5printed_x = tf.Print(x, [x], message="x = ")  # Creates a print node
6
7# BUG: Using 'x' instead of 'printed_x' — the print node is never reached
8y = x * 2  # This does NOT trigger tf.Print
9
10with tf.Session() as sess:
11    result = sess.run(y)  # Prints nothing

The fix was to use the output of tf.Print in subsequent operations:

python
1# TensorFlow 1.x — THIS PRINTS
2x = tf.constant([1.0, 2.0, 3.0])
3printed_x = tf.Print(x, [x], message="x = ")
4
5# Use printed_x instead of x
6y = printed_x * 2  # Now the print node is in the execution path
7
8with tf.Session() as sess:
9    result = sess.run(y)  # Prints: x = [1 2 3]

The TF 2.x Solution: tf.print (lowercase)

TensorFlow 2.x removed tf.Print and introduced tf.print (lowercase). With eager execution enabled by default, tf.print works immediately:

python
1import tensorflow as tf
2
3x = tf.constant([1.0, 2.0, 3.0])
4tf.print("x =", x)            # Prints: x = [1 2 3]
5tf.print("shape:", x.shape)    # Prints: shape: [3]
6tf.print("sum:", tf.reduce_sum(x))  # Prints: sum: 6

tf.print Inside tf.function

When using @tf.function (graph mode in TF 2.x), tf.print is traced into the graph and executes when the graph runs:

python
1@tf.function
2def compute(x):
3    tf.print("Input:", x)           # Prints during execution
4    result = x ** 2
5    tf.print("Result:", result)     # Prints during execution
6    return result
7
8compute(tf.constant(3.0))
9# Input: 3
10# Result: 9

Important: Python's built-in print() inside @tf.function only runs during tracing, not during every call:

python
1@tf.function
2def compute(x):
3    print("Tracing!")     # Only prints ONCE (during tracing)
4    tf.print("Running!")  # Prints EVERY call
5    return x * 2
6
7compute(tf.constant(1.0))  # Prints both "Tracing!" and "Running!"
8compute(tf.constant(2.0))  # Only prints "Running!"

tf.print Formatting Options

python
1x = tf.constant([[1.0, 2.0], [3.0, 4.0]])
2
3# Default output
4tf.print(x)
5# [[1 2]
6#  [3 4]]
7
8# Custom separator
9tf.print("a", "b", "c", sep="-")  # a-b-c
10
11# Summarize large tensors (show first/last N elements)
12large = tf.range(1000)
13tf.print(large, summarize=5)
14# [0 1 2 ... 997 998 999]
15
16# Output to stderr
17tf.print("Warning:", output_stream="stderr")
18
19# Output to file
20tf.print("log entry", output_stream="file:///tmp/tf_log.txt")

Debugging Tensors in tf.function

For complex debugging inside graph mode, combine tf.print with tf.debugging:

python
1@tf.function
2def train_step(x, y):
3    predictions = model(x)
4
5    # Print intermediate values
6    tf.print("Predictions min:", tf.reduce_min(predictions),
7             "max:", tf.reduce_max(predictions))
8
9    loss = loss_fn(y, predictions)
10    tf.print("Loss:", loss)
11
12    # Assert values are valid
13    tf.debugging.assert_all_finite(loss, "Loss contains NaN or Inf")
14
15    return loss

Using tf.py_function for Complex Debugging

When tf.print is not enough, use tf.py_function to call arbitrary Python code:

python
1def debug_print(tensor):
2    import numpy as np
3    arr = tensor.numpy()
4    print(f"Shape: {arr.shape}, dtype: {arr.dtype}")
5    print(f"Stats: mean={arr.mean():.4f}, std={arr.std():.4f}")
6    print(f"Has NaN: {np.isnan(arr).any()}")
7    return tensor
8
9@tf.function
10def compute(x):
11    x = tf.py_function(debug_print, [x], tf.float32)
12    return x * 2

Migration from TF 1.x to TF 2.x

TF 1.xTF 2.xNotes
tf.Print(input, data, message)tf.print(message, data)Lowercase, direct call
Must wire output into graphWorks immediately (eager)No graph wiring needed
sess.run() requiredEager by defaultNo session needed
Output to stdout onlystdout, stderr, or fileMore flexible output

If migrating legacy code:

python
1# TF 1.x
2printed_x = tf.Print(x, [x, y], message="debug: ", summarize=10)
3
4# TF 2.x equivalent
5tf.print("debug:", x, y, summarize=10)
6# No need to wire the output — just call tf.print wherever needed

Common Pitfalls

  • Using Python print() in @tf.function: Python print() only executes during graph tracing (the first call). Use tf.print() for output on every execution.
  • Forgetting to use tf.Print output (TF 1.x): The most common cause of "tf.Print doesn't print." The returned tensor must be part of the executed graph. In TF 2.x, this is no longer an issue.
  • tf.print in production: tf.print writes to stdout/stderr, which can flood logs and slow down training. Remove or gate debug prints behind a flag before deploying.
  • Summarize parameter: By default, tf.print shows only the first and last 3 elements of large tensors. Set summarize=-1 to print all elements (caution with large tensors).
  • Output buffering: tf.print may not appear immediately in Jupyter notebooks or buffered environments. Flush with import sys; sys.stdout.flush() or use output_stream="stderr".

Summary

  • tf.Print (capital P, TF 1.x) is removed — it required graph wiring to work
  • Use tf.print (lowercase, TF 2.x) for immediate tensor printing in eager mode
  • Inside @tf.function, use tf.print (not Python print()) to print on every execution
  • Use summarize parameter to control how many elements of large tensors are shown
  • Use tf.py_function for complex debugging that requires NumPy or Python-only operations

Course illustration
Course illustration

All Rights Reserved.