TensorFlow
machine learning
training monitoring
loss function
debugging

Printing the loss during TensorFlow training

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

Printing loss during training is one of the fastest ways to verify that a TensorFlow model is actually learning. The right method depends on whether you are using the high-level Keras training loop or a custom GradientTape loop, but in both cases the goal is the same: observe the loss at a cadence that is useful without flooding the console.

Keras Already Prints Loss

If you use model.fit, TensorFlow can print loss automatically through the verbose setting.

python
1import numpy as np
2import tensorflow as tf
3
4x = np.array([[0.0], [1.0], [2.0], [3.0]], dtype="float32")
5y = np.array([[0.0], [2.0], [4.0], [6.0]], dtype="float32")
6
7model = tf.keras.Sequential([
8    tf.keras.layers.Input(shape=(1,)),
9    tf.keras.layers.Dense(1)
10])
11
12model.compile(optimizer="adam", loss="mse")
13model.fit(x, y, epochs=5, verbose=1)

With verbose=1, Keras prints per-epoch progress, including the loss. That is often enough for ordinary training.

Custom Callback for Cleaner Output

If you want exactly one formatted line per epoch, use a callback.

python
1import tensorflow as tf
2
3class LossPrinter(tf.keras.callbacks.Callback):
4    def on_epoch_end(self, epoch, logs=None):
5        logs = logs or {}
6        print(f"epoch={epoch + 1}, loss={logs.get('loss'):.6f}")
7
8
9model.fit(x, y, epochs=5, verbose=0, callbacks=[LossPrinter()])

This is useful when you want stable, minimal logging or when you also want to print validation loss or custom metrics.

Printing Per Batch

For more granular debugging, print the loss at the end of each batch:

python
1class BatchLossPrinter(tf.keras.callbacks.Callback):
2    def on_train_batch_end(self, batch, logs=None):
3        logs = logs or {}
4        print(f"batch={batch}, loss={logs.get('loss'):.6f}")

Per-batch logging is helpful when:

  • debugging exploding gradients
  • checking that loss changes within an epoch
  • diagnosing a data pipeline issue

But it becomes noisy quickly on real datasets.

Custom Training Loop

If you are not using model.fit, print the loss directly from the custom training loop.

python
1import tensorflow as tf
2
3w = tf.Variable(0.0)
4optimizer = tf.keras.optimizers.SGD(learning_rate=0.1)
5
6for step in range(10):
7    with tf.GradientTape() as tape:
8        loss = (w - 5.0) ** 2
9
10    grads = tape.gradient(loss, [w])
11    optimizer.apply_gradients(zip(grads, [w]))
12
13    print(f"step={step}, loss={loss.numpy():.6f}, w={w.numpy():.6f}")

This gives you complete control over what is printed and when.

tf.print Inside Graph Code

If your training step is wrapped in @tf.function, plain Python print may not behave the way you expect. In those cases, use tf.print.

python
@tf.function
def train_step(x):
    tf.print("loss:", tf.reduce_mean(x))

tf.print is designed to work correctly inside TensorFlow graph execution.

Logging Validation Loss Too

For many real experiments, training loss alone is not enough. Add validation data to fit so Keras also reports val_loss:

python
model.fit(x, y, validation_data=(x, y), epochs=5, verbose=1)

That gives you a better signal about whether the model is merely fitting the training set or actually generalizing.

Common Pitfalls

The most common mistake is printing too often. Per-batch loss on a large dataset can overwhelm logs and slow training enough to distort the debugging session.

Another issue is assuming the printed loss should always decrease every single step. Stochastic training is noisy, so the overall trend matters more than every individual line.

A third pitfall is using Python print inside graph-traced code and then assuming nothing happened because no output appeared. In graph contexts, prefer tf.print.

Finally, do not monitor only training loss forever. Once the loop is basically working, add validation loss too, because a falling training loss can still hide overfitting.

Summary

  • 'model.fit(..., verbose=1) already prints loss for standard Keras training.'
  • Use callbacks when you want custom epoch or batch logging.
  • In custom loops, print the loss directly after each update step.
  • Use tf.print inside graph-traced TensorFlow functions.
  • Monitor the loss at a useful cadence rather than dumping every possible value.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.