TensorFlow
machine learning
training accuracy
validation accuracy
graph visualization

Show training and validation accuracy in TensorFlow using same graph

Master System Design with Codemia

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

Introduction

Showing training and validation accuracy on the same graph is one of the simplest ways to spot overfitting. In TensorFlow 2, the easiest path is to let Keras track both metrics during fit() and then plot the recorded history after training.

Use One Model with Training and Validation Data

You do not need separate models. The same model weights are trained on the training set and evaluated on the validation set at the end of each epoch.

python
1import matplotlib.pyplot as plt
2import tensorflow as tf
3
4train_ds = tf.data.Dataset.from_tensor_slices((
5    tf.random.normal([200, 8]),
6    tf.random.uniform([200], minval=0, maxval=2, dtype=tf.int32)
7)).shuffle(200).batch(16)
8
9val_ds = tf.data.Dataset.from_tensor_slices((
10    tf.random.normal([80, 8]),
11    tf.random.uniform([80], minval=0, maxval=2, dtype=tf.int32)
12)).batch(16)
13
14model = tf.keras.Sequential([
15    tf.keras.layers.Input(shape=(8,)),
16    tf.keras.layers.Dense(32, activation="relu"),
17    tf.keras.layers.Dense(2, activation="softmax"),
18])
19
20model.compile(
21    optimizer="adam",
22    loss="sparse_categorical_crossentropy",
23    metrics=["accuracy"],
24)
25
26history = model.fit(
27    train_ds,
28    validation_data=val_ds,
29    epochs=5,
30    verbose=0,
31)

The history object stores both accuracy and val_accuracy, which are the values you plot.

Plot Both Curves on the Same Figure

Once training is done, plot the two metrics against epoch number.

python
1plt.plot(history.history["accuracy"], label="Training Accuracy")
2plt.plot(history.history["val_accuracy"], label="Validation Accuracy")
3
4plt.xlabel("Epoch")
5plt.ylabel("Accuracy")
6plt.title("Training vs Validation Accuracy")
7plt.legend()
8plt.grid(True)
9plt.show()

This makes it easy to compare how learning behaves over time. If training accuracy rises while validation accuracy stalls or drops, the model may be overfitting.

Use Separate Metrics in a Custom Training Loop

If you are not using model.fit(), keep separate metric objects for training and validation. Do not reuse one metric accumulator for both datasets.

python
1train_acc = tf.keras.metrics.SparseCategoricalAccuracy()
2val_acc = tf.keras.metrics.SparseCategoricalAccuracy()
3
4for epoch in range(3):
5    train_acc.reset_state()
6    val_acc.reset_state()
7
8    for xb, yb in train_ds:
9        preds = model(xb, training=True)
10        train_acc.update_state(yb, preds)
11
12    for xb, yb in val_ds:
13        preds = model(xb, training=False)
14        val_acc.update_state(yb, preds)
15
16    print(epoch, float(train_acc.result()), float(val_acc.result()))

The graphing step is the same after you collect the epoch values.

Why Plotting Both Curves Matters

The value of a shared graph is not just convenience. It helps you interpret training behavior quickly:

  • both curves rising together usually means the model is still learning
  • training rising while validation stalls can indicate overfitting
  • both curves staying low can indicate underfitting or data issues

That makes the graph a useful debugging tool, not just a presentation artifact.

Common Pitfalls

The biggest mistake is mixing training and validation data accidentally. The point of the validation curve is that it measures generalization on separate data.

Another common issue is forgetting to reset metric state between epochs in custom loops. If metrics accumulate forever, the graph no longer represents per-epoch accuracy.

People also read too much into accuracy alone. For imbalanced problems, accuracy can look fine while the model still behaves badly on the classes you care about most.

Finally, make sure validation runs with training=False in custom loops so dropout, batch normalization, and similar layers behave correctly.

It is also worth saving the history values alongside the model artifact when experiments matter. That makes later comparisons across runs much easier than relying on screenshots alone.

Small plotting decisions help too. Keep the epoch axis clear, label both lines directly in the legend, and use the same chart style across experiments so comparisons stay honest.

Summary

  • In TensorFlow 2, model.fit() already tracks training and validation accuracy for you.
  • Plot history.history["accuracy"] and history.history["val_accuracy"] on the same figure.
  • Use one model, but evaluate it separately on train and validation datasets.
  • In custom loops, keep separate metric objects and reset them each epoch.
  • Compare the two curves to spot overfitting or underfitting trends.

Course illustration
Course illustration

All Rights Reserved.