Tensorboard
Scalar Plotting
Epoch Axis
Deep Learning
Data Visualization

Tensorboard scalar plotting with epoch number on the horizontal axis

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

TensorBoard plots scalars against a step value, not against a special built-in epoch axis. If you want epoch numbers on the horizontal axis, the practical solution is to log your metric once per epoch and use the epoch index as the summary step.

Understand What TensorBoard Uses on the X Axis

TensorBoard's scalar dashboard always has a step-like x-axis. In many training setups that step is the global batch step, which is why loss curves often look very dense.

To make the x-axis represent epochs instead, you do not change TensorBoard itself. You change the step value you write with the summary.

That means the rule is:

  • one summary event per batch gives batch-step plots
  • one summary event per epoch with step=epoch gives epoch-based plots

Log Epoch Metrics Manually with tf.summary

A direct TensorFlow example makes this clear.

python
1import tensorflow as tf
2import numpy as np
3
4logdir = "logs/epoch_scalars"
5writer = tf.summary.create_file_writer(logdir)
6
7x = np.random.rand(200, 1).astype("float32")
8y = 3.0 * x + 1.0
9
10model = tf.keras.Sequential([
11    tf.keras.layers.Input(shape=(1,)),
12    tf.keras.layers.Dense(1)
13])
14model.compile(optimizer="adam", loss="mse")
15
16for epoch in range(10):
17    history = model.fit(x, y, epochs=1, batch_size=16, verbose=0)
18    epoch_loss = history.history["loss"][0]
19
20    with writer.as_default():
21        tf.summary.scalar("loss_by_epoch", epoch_loss, step=epoch)
22
23writer.flush()

When you start TensorBoard on this log directory, the x-axis for loss_by_epoch will show the epoch index because that is the step value you provided.

Use a Keras Callback for Cleaner Training Loops

If you already train with model.fit, a callback is often the cleanest way to log epoch-level metrics.

python
1import tensorflow as tf
2
3class EpochScalarLogger(tf.keras.callbacks.Callback):
4    def __init__(self, logdir):
5        super().__init__()
6        self.writer = tf.summary.create_file_writer(logdir)
7
8    def on_epoch_end(self, epoch, logs=None):
9        logs = logs or {}
10        with self.writer.as_default():
11            for name, value in logs.items():
12                tf.summary.scalar(name, value, step=epoch)
13        self.writer.flush()
14
15logger = EpochScalarLogger("logs/callback_epoch_scalars")

Then pass it to training:

python
model.fit(x, y, epochs=10, batch_size=16, callbacks=[logger], verbose=0)

This keeps the training code simple while ensuring that the x-axis in TensorBoard corresponds to epochs.

Be Consistent Across Runs

If you compare several experiments, the step semantics must be consistent. If one run logs per batch and another logs per epoch using the same tag name, the comparison becomes misleading.

A good convention is to make the tag reflect the logging granularity, for example:

  • 'loss_batch'
  • 'loss_epoch'
  • 'val_accuracy_epoch'

That removes ambiguity when several dashboards and runs are open.

Keras History Versus TensorBoard Logs

Some developers assume that because Keras reports one loss value per epoch in History, TensorBoard will automatically plot against epoch number. That only happens if the summaries are written at epoch boundaries with epoch-based steps.

TensorBoard is not inferring "epoch" from your training loop. It is reading whatever numeric step you wrote into the event file.

That is why explicit control of the step is the reliable answer.

Common Pitfalls

  • Expecting TensorBoard to have a special epoch axis independent of the summary step.
  • Logging every batch while still expecting the x-axis to represent epochs.
  • Mixing per-batch and per-epoch metrics under the same tag name.
  • Forgetting to flush the writer, which can make new points appear late or not at all during short runs.
  • Comparing runs where the same metric tag uses different step semantics.

Summary

  • TensorBoard scalar plots use the summary step for the x-axis.
  • To show epoch numbers, log once per epoch and set step=epoch.
  • 'tf.summary.scalar and a Keras callback are both good ways to do this.'
  • Keep tag names and step semantics consistent across runs.
  • TensorBoard does not infer epochs automatically; it only displays the steps you write.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free 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.