TensorFlow Training a Model

Training a model is the process of showing your neural network many examples and letting it adjust its internal numbers (weights) until its predictions become accurate. This topic covers the complete training process in TensorFlow: how to prepare data for training, what happens inside each training step, how to track progress, and how to avoid the most common training mistakes.

The Learning Process: A School Exam Analogy

Imagine a student studying for an exam. The student reads a practice question (input data), writes an answer (prediction), checks it against the answer key (loss calculation), identifies what they got wrong (backpropagation), and studies those specific mistakes (weight update). After hundreds of practice questions, the student's answers become reliable. TensorFlow training works exactly this way.

The model.fit() Method

The model.fit() method handles the entire training loop. You call it once, and TensorFlow runs forward passes, computes loss, runs backpropagation, and updates weights automatically for every batch and every epoch.

history = model.fit(
    x_train,          # Training inputs
    y_train,          # Correct labels
    epochs=50,        # How many full passes through the training data
    batch_size=32,    # How many samples to process at once
    validation_data=(x_val, y_val),  # Data for measuring generalization
    shuffle=True      # Shuffle training data each epoch
)

Understanding Epochs and Batches

Dataset: 10,000 training samples
Batch size: 100
Batches per epoch: 10,000 ÷ 100 = 100 batches

Timeline for 3 Epochs:

Epoch 1:
  Batch 1 (samples 1–100)   → forward pass → loss → update weights
  Batch 2 (samples 101–200) → forward pass → loss → update weights
  ...
  Batch 100 (samples 9901–10000) → forward pass → loss → update weights
  → Print epoch 1 training loss and accuracy

Epoch 2:
  Shuffle data
  Batch 1 (different 100 samples) → ...
  ...

Epoch 3: Same pattern

Smaller batch sizes update weights more frequently but with noisier gradients. Larger batch sizes produce smoother gradient estimates but require more memory. Batch sizes of 32 or 64 work well in most situations.

Training vs. Validation Data

You always split your dataset into at least two parts:

  • Training set — the model learns from this data (typically 70–80% of your data)
  • Validation set — the model never trains on this; you use it to measure how well the model generalizes (typically 10–15%)
  • Test set — held back until the very end for final evaluation (typically 10–15%)
Full Dataset (1,000 samples)
│
├── Training Set (800 samples) — model adjusts weights here
├── Validation Set (100 samples) — monitored after each epoch
└── Test Set (100 samples) — evaluated only once, at the very end

Why Validation Data Matters

A model can memorize training data without actually learning patterns. If you only measure accuracy on training data, you cannot detect this problem. Validation accuracy reveals whether the model truly learned or just memorized.

Signal to watch for:

Healthy training:
  Epoch 1:  train_loss=0.90, val_loss=0.88
  Epoch 10: train_loss=0.45, val_loss=0.47
  Epoch 30: train_loss=0.22, val_loss=0.24
  → Both losses decrease together ✓

Overfitting (memorization):
  Epoch 1:  train_loss=0.90, val_loss=0.88
  Epoch 10: train_loss=0.30, val_loss=0.32
  Epoch 30: train_loss=0.05, val_loss=0.65 ← val_loss rising!
  → Model memorized training data, fails on new data ✗

The History Object

model.fit() returns a history object that stores training metrics for every epoch. Use it to plot training progress:

history = model.fit(x_train, y_train, epochs=50,
                    validation_data=(x_val, y_val))

# Access stored metrics
train_loss = history.history['loss']
val_loss   = history.history['val_loss']
train_acc  = history.history['accuracy']
val_acc    = history.history['val_accuracy']

# Each list has one value per epoch
print(f"Final training accuracy:   {train_acc[-1]:.3f}")
print(f"Final validation accuracy: {val_acc[-1]:.3f}")

Splitting Data in TensorFlow

import tensorflow as tf
import numpy as np

# Create fake data
X = np.random.random((1000, 20)).astype('float32')
y = np.random.randint(0, 2, size=1000)

# Manual split
split = 800
x_train, x_val = X[:split], X[split:]
y_train, y_val = y[:split], y[split:]

# Or use sklearn for a cleaner split
from sklearn.model_selection import train_test_split
x_train, x_val, y_train, y_val = train_test_split(
    X, y, test_size=0.2, random_state=42
)

Training with tf.data Datasets

For large datasets that do not fit in memory, use the tf.data.Dataset API to stream data from disk during training.

# Create training dataset from arrays
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(1000).batch(32).prefetch(
    tf.data.AUTOTUNE
)

val_dataset = tf.data.Dataset.from_tensor_slices((x_val, y_val))
val_dataset = val_dataset.batch(32)

# model.fit accepts tf.data.Dataset directly
model.fit(train_dataset, epochs=50, validation_data=val_dataset)

The prefetch(AUTOTUNE) call prepares the next batch on the CPU while the current batch trains on the GPU, eliminating wait time between batches.

Dealing With Class Imbalance

If your training data has many more examples of one class than another (for example, 950 healthy patients and only 50 sick patients), the model may learn to always predict "healthy" and achieve 95% accuracy while being completely useless for detecting disease.

Fix this by passing class weights to model.fit():

# Tell TensorFlow to penalize mistakes on the minority class more heavily
class_weight = {
    0: 1.0,   # healthy — normal weight
    1: 19.0   # sick — 19× more important (950/50 = 19)
}

model.fit(x_train, y_train, epochs=50, class_weight=class_weight)

Monitoring Training With Verbose Settings

  • verbose=0 — silent; no output printed (useful in production scripts)
  • verbose=1 — shows a progress bar for each epoch (default)
  • verbose=2 — shows one line per epoch without the progress bar

Common Training Problems and Fixes

Loss Is NaN (Not a Number)

The learning rate is too large and the model diverged. Reduce the learning rate by 10× and restart training.

Loss Stops Decreasing Early

The model hit a local minimum or the learning rate is too small. Try a learning rate warmup schedule or a different optimizer.

Training Is Very Slow

Make sure TensorFlow uses your GPU. Also increase the batch size to make better use of parallel hardware, and use prefetch(AUTOTUNE) in your data pipeline.

Validation Loss Much Higher Than Training Loss

The model is overfitting. Add Dropout layers, reduce model capacity (fewer layers or neurons), use data augmentation, or collect more training data.

A Complete Training Example

import tensorflow as tf
import numpy as np

# Data
x = np.random.random((2000, 30)).astype('float32')
y = (x[:, 0] + x[:, 1] > 1).astype(int)  # Simple rule to generate labels
x_train, x_val = x[:1600], x[1600:]
y_train, y_val = y[:1600], y[1600:]

# Model
model = tf.keras.Sequential([
    tf.keras.layers.Dense(64, activation='relu', input_shape=(30,)),
    tf.keras.layers.Dropout(0.3),
    tf.keras.layers.Dense(32, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

# Train
history = model.fit(
    x_train, y_train,
    epochs=40,
    batch_size=32,
    validation_data=(x_val, y_val),
    verbose=2
)

# Evaluate
final_val_acc = history.history['val_accuracy'][-1]
print(f"\nFinal Validation Accuracy: {final_val_acc:.2%}")

This complete workflow — prepare data, define model, compile, train, evaluate — is the foundation of every TensorFlow project. The next topic shows you how to formally evaluate a trained model on the test set and interpret what the metrics mean for your specific problem.

Leave a Comment

Your email address will not be published. Required fields are marked *