CadetX
CX Learn | Complete Neural Networks Guide
TensorFlow · Keras
CadetX logo CadetX CX Learn
NN-101 · Module 7 Intermediate about 45 minutes 10 Lessons Prereq: Modules 1 to 6

Training Better Networks

Neural networks are powerful enough to memorise their training data, noise and all. That makes overfitting the biggest practical challenge in deep learning. This module gives you the toolkit professionals use to train networks that work well on new data, and to keep training stable and fast.

  • Level: Intermediate
  • Time: about 45 minutes
  • Needs: Modules 1 to 6

By the end of this module you will be able to

  • Spot overfitting in a training history
  • Use a validation set and early stopping
  • Explain and apply dropout
  • Explain and apply L2 weight decay
  • Explain what batch normalisation does
  • Use data augmentation to create more training examples
  • Prevent exploding gradients with good initialisation and gradient clipping
  • Use learning rate schedules
  • Combine these techniques in Keras

7.1Overfitting in neural networks

You met overfitting in the Machine Learning track: a model that scores brilliantly on its training data but poorly on new data, because it memorised instead of learning. Neural networks are especially prone to it, because they have so many weights. The network in this module's Python example has over 76,000 weights but only 200 training examples to learn from: plenty of room to memorise every one.

Sign in the training historyWhat it means
Training and validation loss both fall togetherHealthy learning
Training loss keeps falling, but validation loss starts risingOverfitting has started
Both losses stay highUnderfitting: the network is too small or not trained enough

The techniques that fight overfitting are called regularisation. Try them in the lab below, using real training histories.

7.2See it happen: five ways to train

We trained the same big network five times on the same small, noisy dataset. Choose an experiment to see its real training and validation loss.

Try it: compare regularisation methods

Training lossValidation loss

Without regularisation, the validation loss bottoms out around epoch 6, then climbs steadily for the rest of training, even though the training loss keeps falling towards zero. The network is becoming more and more confident about patterns that only exist in its training data.

7.3Early stopping

The simplest fix: stop training when the validation loss stops improving, and keep the weights from the best epoch.

early_stopping.py
early_stop = keras.callbacks.EarlyStopping(
    monitor="val_loss",          # watch the validation loss
    patience=15,                 # wait 15 epochs for an improvement
    restore_best_weights=True)   # then roll back to the best epoch

model.fit(X, y, epochs=500, validation_split=0.2, callbacks=[early_stop])

patience gives the network a few chances, because validation loss naturally wobbles. Early stopping also saves time: set epochs high and let it decide when to stop.

7.4Dropout

Dropout randomly switches off a share of neurons in a layer at every training step. A different random set each time.

Dropout. On the left, a full network with every neuron active. On the right, the same network during one training step with dropout: about half the hidden neurons are temporarily switched off, and their connections are removed.Without dropoutWith dropout (one training step)×××××Every neuron takes partRandom neurons switched off; different ones each step
Figure 1. With a dropout rate of 0.5, each hidden neuron has a 50% chance of being ignored in any training step. When the network is used for predictions, all neurons are switched back on.

Why switching neurons off helps

Imagine a team where one star player does everything. If that player is off sick, the team collapses. Now imagine the coach randomly benches different players at every practice. Everyone has to learn to contribute, and the team becomes robust. Dropout stops the network relying on a few neurons that have memorised quirks of the training data.

dropout.py
layers.Dense(256, activation="relu"),
layers.Dropout(0.5),    # switch off 50% of the previous layer's outputs while training

Typical rates are 0.2 to 0.5. Dropout was one of the ideas behind AlexNet's breakthrough in 2012 (Module 8).

7.5L2 weight decay

You met this as Ridge regularisation in the Machine Learning track. L2 regularisation (also called weight decay) adds a penalty to the loss for large weights:

total loss = normal loss + strength × (sum of all weights²)

Big weights let a network make sharp, extreme decisions based on tiny details. Keeping weights small makes the network smoother and less likely to latch onto noise.

l2.py
from keras import regularizers
layers.Dense(256, activation="relu",
             kernel_regularizer=regularizers.l2(0.01))

7.6Data augmentation

The best cure for overfitting is more data. If you can't collect more, you can often create it. Data augmentation makes new training examples by changing existing ones in ways that don't change the answer.

Data augmentation. One handwritten 7 becomes six training examples: the original, shifted, rotated 15 degrees, zoomed in, rotated the other way, and with added noise.OriginalShiftedRotated 15°Zoomed inRotated −12°NoisySame label ("7") for all six: the network learns what really makes a 7
Figure 2. Six versions of one training image of a handwritten 7 (written with a crossbar), all still the same digit. The network sees a slightly different version every epoch, so it can't simply memorise the exact pixels.
augmentation.py
augment = keras.Sequential([
    layers.RandomTranslation(0.1, 0.1),   # shift up to 10%
    layers.RandomRotation(0.05),          # rotate up to about 18 degrees
    layers.RandomZoom(0.1),               # zoom in or out up to 10%
])
# Put these layers at the start of your model: they only act during training

Only change what doesn't change the answer

Flipping a photo of a cat left-to-right still shows a cat. Flipping a handwritten 6 upside down makes a 9! Always check that your augmentations make sense for your data.

Augmentation works for other data too: adding background noise to audio, or swapping words for synonyms in text.

7.7Batch normalisation

In the Machine Learning track, you scaled inputs so that every feature had a similar range. Batch normalisation does the same thing inside the network: it rescales the outputs of a layer for each mini-batch, so the next layer always receives numbers in a steady, sensible range.

BenefitWhy
Faster, more stable trainingEach layer isn't constantly adapting to wildly changing inputs
Allows higher learning ratesValues are less likely to blow up
Helps deep networks train at allReduces vanishing and exploding signals
A little regularisationThe mini-batch statistics add a small amount of noise
batchnorm.py
layers.Dense(256),
layers.BatchNormalization(),
layers.Activation("relu"),

7.8Keeping training stable

In Modules 3 and 5 you saw that gradients can vanish or explode as they travel back through many layers. Here are the standard fixes:

TechniqueWhat it doesIn Keras
ReLU activationsSlope of 1 for active neurons, so gradients don't shrink (Module 3)activation="relu"
Good weight initialisationStarts weights at a sensible size for each layer, so signals neither shrink nor grow. "He" initialisation suits ReLUKeras uses good defaults; kernel_initializer="he_normal"
Gradient clippingCaps the size of gradients, so one bad batch can't cause a giant, destructive stepkeras.optimizers.Adam(clipnorm=1.0)
Batch normalisationKeeps values in a steady range inside the networklayers.BatchNormalization()
Skip connectionsLet the signal jump over layers, as in ResNet (Module 8)Functional API: layers.Add()

Learning rate schedules

A big learning rate makes fast progress early on; a small one helps settle precisely into the valley later. A learning rate schedule lowers the rate as training goes on.

schedule.py
reduce_lr = keras.callbacks.ReduceLROnPlateau(
    monitor="val_loss", factor=0.5, patience=5)   # halve the rate when progress stalls

7.9Regularisation in Python

Here's the code behind the lab. It trains the same big network five ways on a small, noisy dataset (250 examples, with 10% of labels deliberately wrong, as real data often has).

regularisation.py
import os
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
import keras
from keras import layers, regularizers

# 1. A small, noisy dataset: only 250 training examples, 40 features,
#    and 10% of labels deliberately wrong. A recipe for overfitting.
X, y = make_classification(n_samples=2000, n_features=40, n_informative=8,
                           n_redundant=4, flip_y=0.1, random_state=3)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, train_size=250, random_state=0, stratify=y)

# 2. A big network (over 76,000 weights) that can easily memorise 250 rows
def make_model(dropout=0.0, l2=0.0):
    reg = regularizers.l2(l2) if l2 else None
    model = keras.Sequential([keras.Input(shape=(40,))])
    for _ in range(2):
        model.add(layers.Dense(256, activation="relu", kernel_regularizer=reg))
        if dropout:
            model.add(layers.Dropout(dropout))
    model.add(layers.Dense(1, activation="sigmoid"))
    model.compile(optimizer="adam", loss="binary_crossentropy",
                  metrics=["accuracy"])
    return model

early_stop = keras.callbacks.EarlyStopping(
    monitor="val_loss", patience=15, restore_best_weights=True)

# 3. Train the same network five ways
experiments = {
    "No regularisation": (dict(), []),
    "Dropout (0.5)":     (dict(dropout=0.5), []),
    "L2 (0.01)":         (dict(l2=0.01), []),
    "Early stopping":    (dict(), [early_stop]),
    "Dropout + L2 + ES": (dict(dropout=0.5, l2=0.01), [early_stop]),
}
for name, (settings, callbacks) in experiments.items():
    keras.utils.set_random_seed(0)
    model = make_model(**settings)
    hist = model.fit(X_train, y_train, epochs=150, batch_size=32, verbose=0,
                     validation_split=0.2, callbacks=callbacks)
    _, train_acc = model.evaluate(X_train, y_train, verbose=0)
    test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
    print(f"{name:18} epochs={len(hist.history['loss']):3}  train acc={train_acc:.3f}  "
          f"test acc={test_acc:.3f}  test loss={test_loss:.3f}")
Output
No regularisation  epochs=150  train acc=0.964  test acc=0.815  test loss=1.084
Dropout (0.5)      epochs=150  train acc=0.968  test acc=0.822  test loss=1.158
L2 (0.01)          epochs=150  train acc=0.968  test acc=0.825  test loss=0.609
Early stopping     epochs= 21  train acc=0.948  test acc=0.822  test loss=0.424
Dropout + L2 + ES  epochs=150  train acc=0.972  test acc=0.834  test loss=0.624

What the output tells us

  • Every version scores 95% or more on training data but only 81 to 83% on test data. With only 250 noisy examples, some overfitting is unavoidable.
  • Test loss tells the bigger story. Without regularisation it's 1.08: the network is confidently wrong on many test examples. L2 cuts it to 0.61, and early stopping to 0.42, by stopping at epoch 21 before memorisation set in.
  • Dropout alone didn't help here (test loss 1.16). With so little data it wasn't enough by itself. Regularisation isn't magic: each technique helps in different situations, which is why you test them.
  • Combining dropout, L2 and early stopping gave the best test accuracy (83.4%).

A practical recipe

Start with a network that's big enough to overfit (so you know it can learn the task), then add regularisation: early stopping always, then dropout and/or L2, plus data augmentation for images, audio and text. Tune using the validation set, and only look at the test set at the very end.

SummaryKey takeaways

  • Neural networks overfit easily. Watch for validation loss rising while training loss falls.
  • Early stopping stops at the best validation epoch and restores those weights.
  • Dropout randomly switches off neurons during training, so the network can't rely on a few.
  • L2 weight decay penalises large weights, giving smoother decisions.
  • Data augmentation creates new training examples that keep the same label.
  • Batch normalisation keeps values steady inside the network, for faster, more stable training.
  • Prevent exploding and vanishing gradients with ReLU, good initialisation, gradient clipping and skip connections.
  • Learning rate schedules lower the learning rate as training progresses.

Check your understanding

Your neural networks roadmap

  1. 01
    Introduction to Neural NetworksWhat neural networks are and how they work
  2. 02
    The Perceptron and the Artificial NeuronBuild a single neuron from scratch
  3. 03
    Activation FunctionsSigmoid, tanh, ReLU and softmax
  4. 04
    Loss Functions and Gradient DescentHow networks measure and reduce error
  5. 05
    BackpropagationHow every weight learns its share of the blame
  6. 06
    Building Networks with KerasYour first deep learning library
  7. 07
    Training Better NetworksYou are here
  8. 08
    Convolutional Neural NetworksTeaching computers to see
  9. 09
    Recurrent Neural Networks and LSTMsWorking with sequences
  10. 10
    Transformers and AttentionThe architecture behind ChatGPT and Claude
  11. 11
    Transfer Learning and Pretrained ModelsStanding on the shoulders of giants
  12. 12
    Capstone ProjectBuild and present a deep learning project