batch normalization
TensorFlow
machine learning
neural networks
deep learning

How could I use batch normalization in TensorFlow?

Master System Design with Codemia

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

Introduction

Batch normalization is used in TensorFlow to stabilize training and often let models converge faster. In practice, you usually add a BatchNormalization layer between a linear layer and its activation, then let TensorFlow manage the moving statistics during training and inference.

Add BatchNormalization as a Layer

In Keras-style TensorFlow, batch normalization is just another layer:

python
1import tensorflow as tf
2
3model = tf.keras.Sequential([
4    tf.keras.layers.Dense(128, input_shape=(784,), use_bias=False),
5    tf.keras.layers.BatchNormalization(),
6    tf.keras.layers.Activation("relu"),
7    tf.keras.layers.Dense(10, activation="softmax"),
8])
9
10model.compile(
11    optimizer="adam",
12    loss="sparse_categorical_crossentropy",
13    metrics=["accuracy"],
14)

This is the most common pattern for dense networks. The normalization layer learns scale and shift parameters while also tracking moving averages for inference.

Place It Before the Activation in Most Cases

A common rule of thumb is:

  • linear layer
  • batch normalization
  • activation

That is why the example uses a Dense layer without inline activation first, then BatchNormalization, then Activation.

The same idea applies to convolutional models:

python
1inputs = tf.keras.Input(shape=(32, 32, 3))
2x = tf.keras.layers.Conv2D(32, 3, padding="same", use_bias=False)(inputs)
3x = tf.keras.layers.BatchNormalization()(x)
4x = tf.keras.layers.ReLU()(x)
5x = tf.keras.layers.GlobalAveragePooling2D()(x)
6outputs = tf.keras.layers.Dense(10, activation="softmax")(x)
7
8model = tf.keras.Model(inputs, outputs)

Using use_bias=False is common here because batch normalization already adds a learned shift term.

Understand Training Versus Inference Behavior

Batch normalization behaves differently during training and inference:

  • during training, it uses batch statistics
  • during inference, it uses stored moving averages

TensorFlow handles this automatically when you use model.fit() and model.predict(). In custom loops, make sure the training flag is correct:

python
1@tf.function
2def train_step(x, y):
3    with tf.GradientTape() as tape:
4        logits = model(x, training=True)
5        loss = loss_fn(y, logits)
6    grads = tape.gradient(loss, model.trainable_variables)
7    optimizer.apply_gradients(zip(grads, model.trainable_variables))
8
9@tf.function
10def eval_step(x):
11    return model(x, training=False)

If you get this wrong, the moving statistics may not update correctly or inference may behave inconsistently.

Batch Size Still Matters

Batch normalization estimates mean and variance from the current mini-batch during training. If the batch is extremely small, those estimates can become noisy and the normalization effect may be unstable. That is one reason very small-batch training sometimes works better with other normalization strategies.

It is also worth remembering that batch normalization is not only about speed. In some models it changes optimization behavior enough that learning rates, regularization choices, and dropout usage may need retuning after you add it.

That means "just add batch normalization" is not always the end of the tuning process. It is often the beginning of a slightly different training regime that should be validated with fresh experiments rather than assumed to be automatically better.

Common Pitfalls

The biggest mistake is placing batch normalization blindly without understanding the layer order. Putting it after an activation is not always wrong, but the standard and most common pattern is before the activation.

Another common issue is forgetting the difference between training and inference mode in custom loops. Batch normalization needs the correct training flag to behave properly.

People also expect batch normalization to fix every training problem. It can help stability and learning speed, but it does not replace sensible learning rates, good data, or a reasonable model architecture.

Finally, very small batch sizes can make batch statistics noisy. In those cases, layer normalization or group normalization may be better options depending on the model.

Summary

  • Use tf.keras.layers.BatchNormalization() as a normal TensorFlow layer.
  • Place it before the activation in the common dense and convolutional patterns.
  • Let TensorFlow manage moving statistics during fit() and predict().
  • In custom loops, pass the correct training flag.
  • Batch normalization helps training, but it is not a substitute for sound model design.

Course illustration
Course illustration

All Rights Reserved.