TensorFlow
Machine Learning
Model Validation
Testing
Deep Learning

Validation and Test with 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 workflows, validation and test data serve different purposes even though both are "not training data." Validation data helps you make model decisions during development. Test data is held back until the end to estimate how the final model behaves on unseen examples. Mixing those roles leads to misleading metrics.

The Split Matters More Than the API

TensorFlow gives you several ways to evaluate a model, but the essential rule is conceptual:

  • training data updates weights
  • validation data guides model selection
  • test data is used only for final evaluation

If you tune hyperparameters after looking at test results, your test set stops being a real test set.

Validation During Training with Keras

The most common TensorFlow path is Keras fit with validation data. This computes validation metrics after each epoch without using the validation set for gradient updates.

python
1import tensorflow as tf
2import numpy as np
3
4x = np.random.randn(200, 4).astype("float32")
5y = (x.sum(axis=1) > 0).astype("float32")
6
7x_train, x_val = x[:160], x[160:]
8y_train, y_val = y[:160], y[160:]
9
10model = tf.keras.Sequential([
11    tf.keras.Input(shape=(4,)),
12    tf.keras.layers.Dense(8, activation="relu"),
13    tf.keras.layers.Dense(1, activation="sigmoid"),
14])
15
16model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])
17
18history = model.fit(
19    x_train,
20    y_train,
21    validation_data=(x_val, y_val),
22    epochs=5,
23    verbose=0,
24)
25
26print(history.history["val_accuracy"])

This is useful for:

  • early stopping
  • comparing architectures
  • monitoring overfitting

validation_split Versus Explicit Splits

Keras also supports validation_split, which carves a validation slice out of array data passed to fit.

python
1history = model.fit(
2    x,
3    y,
4    validation_split=0.2,
5    epochs=5,
6    verbose=0,
7)

This is convenient for quick experiments, but explicit train-validation-test splits are usually better because:

  • you control exactly which examples go where
  • the split logic is reproducible
  • it works naturally with tf.data pipelines and multiple input arrays

For real projects, explicit splitting is usually the safer choice.

Testing After Model Selection

Once you finish choosing the model and hyperparameters, evaluate on the held-out test set exactly once or as rarely as practical.

python
1import numpy as np
2
3x_test = np.random.randn(40, 4).astype("float32")
4y_test = (x_test.sum(axis=1) > 0).astype("float32")
5
6test_loss, test_accuracy = model.evaluate(x_test, y_test, verbose=0)
7print(test_loss, test_accuracy)

The test result is meant to answer, "How well does the chosen model generalize?" It is not another knob for model tuning.

Using tf.data for Validation and Test Sets

When data pipelines are larger or streaming-based, keep train, validation, and test datasets separate.

python
1import tensorflow as tf
2import numpy as np
3
4x = np.random.randn(300, 4).astype("float32")
5y = (x.sum(axis=1) > 0).astype("float32")
6
7train_ds = tf.data.Dataset.from_tensor_slices((x[:200], y[:200])).batch(32)
8val_ds = tf.data.Dataset.from_tensor_slices((x[200:250], y[200:250])).batch(32)
9test_ds = tf.data.Dataset.from_tensor_slices((x[250:], y[250:])).batch(32)
10
11model = tf.keras.Sequential([
12    tf.keras.Input(shape=(4,)),
13    tf.keras.layers.Dense(8, activation="relu"),
14    tf.keras.layers.Dense(1, activation="sigmoid"),
15])
16
17model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])
18model.fit(train_ds, validation_data=val_ds, epochs=3, verbose=0)
19
20print(model.evaluate(test_ds, verbose=0))

This keeps the data flow explicit and avoids accidental leakage between stages.

What Validation Tells You

Validation metrics are for development-time decisions. Typical uses include:

  • detecting overfitting when training metrics improve but validation metrics degrade
  • choosing model depth, learning rate, batch size, or regularization
  • triggering early stopping

Example:

python
1callback = tf.keras.callbacks.EarlyStopping(
2    monitor="val_loss",
3    patience=2,
4    restore_best_weights=True,
5)

That is a validation-driven decision. It is appropriate because the validation set exists for that purpose.

What Test Metrics Should Not Do

Test metrics should not drive repeated experimentation. If you keep changing the model after every test result, you are effectively using the test set as validation data and biasing the estimate.

The clean workflow is:

  1. split data
  2. train on training set
  3. tune using validation set
  4. evaluate once on test set

In research or model competitions, people sometimes add extra holdout sets for even stronger separation.

Common Pitfalls

  • Using the test set during model tuning. That invalidates the final estimate.
  • Assuming validation data updates the model weights. It does not; it is only evaluated.
  • Relying on validation_split without understanding how the data is ordered or sampled.
  • Forgetting to keep preprocessing consistent across train, validation, and test data.
  • Comparing models on different random splits and treating the metrics as directly equivalent without controlling the split.

Summary

  • Validation data supports training-time decisions; test data supports final evaluation.
  • Use validation_data in fit to monitor generalization during training.
  • Use evaluate on a held-out test set only after model selection is finished.
  • Prefer explicit data splits over convenience features when reproducibility matters.
  • The biggest mistake is not API misuse but data leakage between training, validation, and test stages.

Course illustration
Course illustration

All Rights Reserved.