Keras
TensorFlow
numpy
data visualization
machine learning

Convert a KerasTensor object to a numpy array to visualize predictions in Callback

Master System Design with Codemia

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

Introduction

KerasTensor values are symbolic placeholders created during model construction, not concrete prediction results. That is why trying to convert them directly to NumPy fails. In callbacks, the correct pattern is to run the model on real sample data during training, obtain an eager tensor or NumPy output, and only then pass it to plotting or logging code.

Why a KerasTensor Cannot Be Converted Directly

You usually encounter a KerasTensor when you are still defining the model graph.

python
1import tensorflow as tf
2
3inputs = tf.keras.Input(shape=(4,))
4x = tf.keras.layers.Dense(8, activation="relu")(inputs)
5print(type(x))

That object describes symbolic computation. It does not hold actual numeric values yet, so this kind of code is conceptually wrong:

python
1import numpy as np
2
3# do not do this
4# arr = np.array(x)

If you want NumPy data, you need a runtime tensor produced from real inputs.

The Right Mental Model for Callbacks

Callbacks run during training or evaluation, when the model can actually produce predictions for concrete samples. That means the callback should own a small fixed input batch and run the model on that batch.

A good pattern is:

  1. Store sample input in the callback.
  2. Call the model in on_epoch_end.
  3. Convert the resulting tensor with .numpy() or use model.predict(...).
  4. Visualize or log the resulting array.

That keeps the code entirely in the execution phase, not the model-definition phase.

Direct Tensor Execution in a Callback

If eager execution is active, a model call returns a real tensor that you can convert to NumPy.

python
1import numpy as np
2import tensorflow as tf
3
4class PreviewCallback(tf.keras.callbacks.Callback):
5    def __init__(self, sample_x):
6        super().__init__()
7        self.sample_x = tf.convert_to_tensor(sample_x, dtype=tf.float32)
8
9    def on_epoch_end(self, epoch, logs=None):
10        preds = self.model(self.sample_x, training=False)
11        preds_np = preds.numpy()
12        print(f"epoch {epoch} preview:", preds_np[:3].ravel())
13
14x = np.random.rand(64, 4).astype("float32")
15y = (x.sum(axis=1) > 2).astype("float32")
16
17model = tf.keras.Sequential([
18    tf.keras.layers.Dense(8, activation="relu"),
19    tf.keras.layers.Dense(1, activation="sigmoid"),
20])
21model.compile(optimizer="adam", loss="binary_crossentropy")
22
23callback = PreviewCallback(sample_x=x[:8])
24model.fit(x, y, epochs=2, callbacks=[callback], verbose=0)

This works because preds is an executed tensor, not a symbolic construction-time placeholder.

Using model.predict Instead

If you want NumPy output immediately and do not care about the intermediate tensor, model.predict is also valid inside a callback.

python
1import tensorflow as tf
2
3class PredictPreview(tf.keras.callbacks.Callback):
4    def __init__(self, sample_x):
5        super().__init__()
6        self.sample_x = sample_x
7
8    def on_epoch_end(self, epoch, logs=None):
9        preds_np = self.model.predict(self.sample_x, verbose=0)
10        print("preview:", preds_np[:3].ravel())

This is often convenient, though it can be heavier than a direct model call if used too frequently.

Plotting the Predictions

Once you have a NumPy array, visualization becomes ordinary Python plotting work.

python
1import matplotlib.pyplot as plt
2
3preds_np = preds.numpy().ravel()
4plt.plot(preds_np)
5plt.title("Prediction preview")
6plt.savefig("preview.png")
7plt.close()

Keep callback visualization lightweight. Heavy plotting at every epoch can slow training significantly.

Graph Mode and Execution Context

Most standard TensorFlow 2 training runs execute callbacks in a context where .numpy() is usable, but you should still keep a clear separation:

  • Symbolic tensors belong to model-building code.
  • Concrete tensors belong to execution-time code.

If you accidentally move NumPy conversion into traced graph code or model construction, you will hit the same class of errors again.

Practical Performance Guidance

Prediction previews are useful, but they should not become part of the hot path.

Safer practices:

  • Use a tiny fixed sample batch.
  • Run visualization once per epoch, not once per batch.
  • Save plots to disk or log them asynchronously if possible.
  • Avoid using the full validation set inside a preview callback.

Diagnostics should help training, not dominate it.

Common Pitfalls

  • Trying to convert a symbolic KerasTensor during model construction. Fix by waiting until you have runtime predictions from actual sample data.
  • Assuming all tensors inside callbacks are symbolic. Fix by distinguishing definition-time tensors from executed tensors.
  • Running predict on large datasets every epoch. Fix by using a small preview batch.
  • Mixing NumPy operations into graph-building code. Fix by keeping plotting and conversion strictly in callback execution paths.
  • Forgetting to set training=False when previewing inference behavior with layers such as dropout. Fix by calling the model in inference mode for visualization.

Summary

  • A KerasTensor is symbolic and cannot be converted directly to NumPy.
  • In callbacks, generate predictions from real sample inputs first.
  • Use .numpy() on executed tensors or use model.predict(...) for direct NumPy output.
  • Keep visualization code lightweight and separate from graph construction.
  • The key distinction is symbolic model definition versus concrete runtime execution.

Course illustration
Course illustration

All Rights Reserved.