Normalize a training batch
Batch normalization solves the same problem as layer normalization, but it looks in the other direction. It takes one feature, a column, and normalizes it across all the examples in the batch. So after it, each feature has an average of 0 and a spread of 1 over the batch. The price is that an example's result now depends on which other examples happen to be in the batch with it.
Learn it
Words to know
- batch
- A group of examples that the model processes together in one step.
- normalization
- Rescaling a group of numbers to a standard size, which keeps training stable.
- variance
- A measure of spread: the average of the squared distances from the mean.
How it works
- For one column, find the mean of its values over all rows.
- Find the variance of that column, dividing by the number of rows
N. - Subtract the column's mean from each of its values and divide by
sqrt(variance + epsilon). - In PyTorch this is the layer normalization code with one change:
dim=0in place ofdim=-1. Dimension 0 runs down the rows.
Worked example
Input rows = [[1, 10], [2, 20], [3, 60]] epsilon = 1e-8 Output [[-1.22474, -0.92582], [0, -0.46291], [1.22474, 1.38873]]
| Column | Mean | Variance | Square root | Normalized |
|---|---|---|---|---|
| 1, 2, 3 | 2 | 0.6667 | 0.8165 | -1.2247, 0, 1.2247 |
| 10, 20, 60 | 30 | 466.67 | 21.602 | -0.9258, -0.4629, 1.3887 |
| feature 0 | feature 1 | |
|---|---|---|
| example 0 | 1 | 10 |
| example 1 | 2 | 20 |
| example 2 | 3 | 60 |
The second column is far larger than the first, but after normalizing both are on the same scale. Each column now averages 0.
Why it matters
Batch normalization is common in image models. Transformers prefer layer normalization, because it gives the same result for an example whatever else is in the batch.
Your turn
Using PyTorch, normalize each column of a table across its rows, as batch normalization does during training.
rows- a table of numbers with at least one row; each row is one example
epsilon- a positive number added to the variance; tiny in practice
- Returns
- A table of the same shape, as nested Python lists. Each column has its own mean subtracted and is divided by
sqrt(variance + epsilon). For the variance, divide the sum of the squared distances by the number of rows.
This lesson needs PyTorch, which does not run in the browser. The app gives you the exercise as a file with its tests, to run on your own computer.
Example 1
Input rows = [[1, 10], [2, 20], [3, 60]] epsilon = 1e-8 Output [[-1.22474, -0.92582], [0, -0.46291], [1.22474, 1.38873]]
The first column 1, 2, 3 has mean 2. The second column 10, 20, 60 has mean 30. Each is normalized with its own numbers.
Example 2
Input rows = [[1, 2], [3, 4]] epsilon = 1e-8 Output [[-1, -1], [1, 1]]
Each column has two values, one below its mean and one above, so each becomes -1 and 1.
Example 3
Input rows = [[1, 2], [3, 4]] epsilon = 3 Output [[-0.5, -0.5], [0.5, 0.5]]
The same table with a large epsilon, to show where it goes: each variance is 1, plus 3 is 4, and its square root is 2.
Example 4
Input rows = [[5, 5]] epsilon = 0.00001 Output [[0, 0]]
With one row, every value equals its column's mean. The result is 0, and epsilon keeps the division safe.
Hints
Each hint gives away a little more. Open one only when you need it.
Hint 1: Where to start
This is the layer normalization exercise turned on its side. The mean and the variance now come from columns.
Hint 2: The key step
Take the mean and the variance along dimension 0, again with
keepdim=Trueandunbiased=False.Hint 3: The outline
Make
xafloat64tensor. Setmean = x.mean(0, keepdim=True)andvariance = x.var(0, unbiased=False, keepdim=True). Return((x - mean) / torch.sqrt(variance + epsilon)).tolist().
Solution
From here on the page gives the method away. If you are still solving, go back to the hints.
Step by step
- One mean and one variance per column, taken down the rows. Dimension 0 is the one that collapses. What is left has shape
[1, columns]: one number per feature. - Centre each column on 0 and scale its spread to 1. The
[1, columns]means and variances line up under the columns, so each value is normalized with the numbers of its own feature.
The same numbered steps are the comments in the solution.
Python
import torch
def solve(rows, epsilon):
x = torch.tensor(rows, dtype=torch.float64)
# 1. One mean and one variance per column, taken down the rows
mean = x.mean(0, keepdim=True)
variance = x.var(0, unbiased=False, keepdim=True)
# 2. Centre each column on 0 and scale its spread to 1
normalized = (x - mean) / torch.sqrt(variance + epsilon)
return normalized.tolist()Watch out
- Mixing up the dimensions gives layer normalization instead.
dim=0goes down the rows, across examples;dim=-1goes along a row, across features. - With a batch of one row every result is 0, because each value is its own mean. With a small batch the mean and the variance say little about the feature.
- This is the training behaviour. When the model is used later, PyTorch's batch normalization takes the mean and variance from averages it saved during training, not from the batch.
Check yourself
What is the difference between batch and layer normalization?
Batch normalization uses one feature across all examples in the batch. Layer normalization uses all features of one example.
Why does a batch-normalized result depend on the other examples?
The mean and variance are taken over the whole batch, so changing any example changes the numbers every example is normalized with.