MediumNeural Networks

Batch Normalization (Forward)

Neural Networks

Medium

Problem

Implement the training-time BatchNorm forward pass. For input shape (N,D), normalize each feature over the batch axis. For input shape (N,C,H,W), normalize each channel over the batch and spatial axes.

\mu = \frac{1}{m} \sum_{i=1}^{m} x_i

\sigma^2 = \frac{1}{m} \sum_{i=1}^{m}(x_i-\mu)^2

\hat{x}_i = \frac{x_i-\mu}{\sqrt{\sigma^2+\varepsilon}}

y_i = \gamma\hat{x}_i+\beta

Here, m is the number of values in one feature or channel, \mu is its mean, \sigma^2 is its population variance, \varepsilon is eps, and \gamma and \beta are per-feature or per-channel scale and shift values. Return the normalized result as a NumPy array with the same shape as x.

Theory

Training deep neural networks is difficult because the distribution of each layer's inputs changes during training. As earlier layers update their weights, the statistics of their outputs shift. Later layers must constantly adapt to these shifting distributions.

This phenomenon is called internal covariate shift. It slows training because:

Batch Normalization (BatchNorm) addresses this by normalizing layer inputs to have consistent statistics.


The Core Idea

For each mini-batch, normalize the activations to have zero mean and unit variance:

\hat{x} = \frac{x - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}

where:

This normalization is applied independently to each feature/channel.


The Full BatchNorm Transform

After normalization, BatchNorm applies a learnable scale and shift:

y = \gamma \hat{x} + \beta

where:

Why scale and shift?

Pure normalization (forcing mean=0, variance=1) might limit what the layer can represent. The learnable parameters allow the network to undo the normalization if needed. If \gamma = \sigma and \beta = \mu, the original activation is recovered.


Step-by-Step Computation

Input: Mini-batch of activations x with shape (batch_size, features)

Step 1: Compute batch mean

\mu_B = \frac{1}{m} \sum_{i=1}^{m} x_i

Step 2: Compute batch variance

\sigma_B^2 = \frac{1}{m} \sum_{i=1}^{m} (x_i - \mu_B)^2

Step 3: Normalize

\hat{x}_i = \frac{x_i - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}

Step 4: Scale and shift

y_i = \gamma \hat{x}_i + \beta


Worked Example

Mini-batch of 4 samples, 1 feature:

x = [2, 4, 6, 8]

Step 1: Mean \mu_B = (2 + 4 + 6 + 8) / 4 = 5

Step 2: Variance \sigma_B^2 = ((2-5)^2 + (4-5)^2 + (6-5)^2 + (8-5)^2) / 4 = (9 + 1 + 1 + 9) / 4 = 5

Step 3: Normalize (with \epsilon = 0) \hat{x} = [\frac{2-5}{\sqrt{5}}, \frac{4-5}{\sqrt{5}}, \frac{6-5}{\sqrt{5}}, \frac{8-5}{\sqrt{5}}] = [-1.34, -0.45, 0.45, 1.34]

Step 4: Scale and shift (with \gamma = 2, \beta = 1) y = 2 \cdot [-1.34, -0.45, 0.45, 1.34] + 1 = [-1.68, 0.10, 1.90, 3.68]


BatchNorm for Convolutional Layers

For conv layers with shape (batch, channels, height, width):

This means spatial locations within a channel share the same normalization statistics.


Training vs. Inference

During training:

During inference:

This is why you must set the model to "eval mode" during inference.


Benefits of Batch Normalization

1. Faster training

2. Regularization effect

3. Reduces vanishing/exploding gradients

4. Less sensitivity to hyperparameters


Limitations

1. Batch size dependence

2. Different behavior train/test

3. Not ideal for RNNs


Alternatives to BatchNorm

Layer Normalization: Normalize across features, not batch. Works with batch size = 1. Preferred for Transformers and RNNs.

Instance Normalization: Normalize each sample independently (across spatial dimensions). Used in style transfer.

Group Normalization: Normalize across groups of channels. Compromise between Layer and Instance norm.

Weight Normalization: Normalize weights instead of activations.


Where to Place BatchNorm

Common placement: After linear/conv layer, before activation

Conv -> BatchNorm -> ReLU

Alternative: After activation

Conv -> ReLU -> BatchNorm

Both work; the first is more common. Recent architectures sometimes omit BatchNorm entirely (using other techniques).


Learnable Parameters

For a layer with C features/channels:

Total: 2C learnable parameters per BatchNorm layer.

Non-learnable (tracking only):


The Gradient Through BatchNorm

Backpropagation through BatchNorm is more complex than regular layers because each output depends on all inputs in the batch (through \mu_B and \sigma_B^2).

The gradients are:

\frac{\partial L}{\partial \gamma} = \sum_i \frac{\partial L}{\partial y_i} \hat{x}_i

\frac{\partial L}{\partial \beta} = \sum_i \frac{\partial L}{\partial y_i}

The gradient w.r.t. input involves the chain rule through the normalization statistics.

Examples

Example 1

Input
x = [[1, 2], [3, 6], [5, 10]], gamma = [1, 0.5], beta = [0, 1], eps = 1e-5
Output
[[-1.224743, 0.387628], [0.0, 1.0], [1.224743, 1.612372]]
Explanation
Each column is normalized across the three rows, then scaled by its gamma and shifted by its beta.

Example 2

Input
x = [[[[1]], [[2]]], [[[3]], [[4]]]], gamma = [1, 0.5], beta = [0, -1], eps = 1e-5
Output
[[[[-0.999995]], [[-1.499998]]], [[[0.999995]], [[-0.500002]]]]

Hints

  1. Use keepdims=True when computing the mean and variance.
  2. For four-dimensional input, reshape gamma and beta to (1, C, 1, 1).

Requirements

Constraints

Starter Code

import numpy as np

def batch_norm_forward(x: list, gamma: list, beta: list, eps: float = 1e-5) -> np.ndarray:
    """
    Returns a NumPy array with the same shape as x.
    """
    # Write code here
    pass

Test Cases

CaseMatches
2D case (N,D)public
4D case (N,C,H,W)public