back

Layer Normalization

Issues with BatchNorm that LayerNorm Addresses

LayerNorm addresses a few shortcomings of BatchNorm:

  1. RNNs or any language-based tasks might have different sequences/lengths of data →\rightarrow We can’t simply calculate the statistics across our batches, we also need to consider the time steps.
  2. As BatchNorm calculates statistics across the batch for each feature, the batch sizes need to be relatively large.
  3. BatchNorm relies on batch statistics during training and stored running statistics at inference. LayerNorm works independently for each sample, which is useful for online learning and small batches.

Layer Normalization

alt text

Implementation Details

class LayerNorm(nn.Module):
    def __init__(self, eps=1e-5):
        super().__init__()
        self.eps = eps

    def forward(self, x):
        batch_size, length, feature_dim = x.shape
        output = torch.zeros_like(x)

        for i in range(batch_size):
            for t in range(length):
                word_vector = x[i, t, :]

                mu = word_vector.sum() / feature_dim

                var = ((word_vector - mu) ** 2).sum() / feature_dim

                output[i, t, :] = (word_vector - mu) / torch.sqrt(var + self.eps)

        return output
# Assume feature vecs from a batch 32, sentence of length 64, and feature dim. of 512.
# We want to normalize across each word in a batch.
# randn() -> mean 0, variance 1; scaled input has mean 10, variance 25
sample_batch = torch.randn(32, 64, 512) * 5 + 10

print(sample_batch[0, 0, :])

ln_layer = LayerNorm()
out = ln_layer.forward(sample_batch)

print(f"dim(out): {out.shape}") # >>> (32, 64, 512)
print(out[0, 0, :])

alt text

class LayerNorm2(nn.Module):
    def __init__(self, eps=1e-5):
        super().__init__()
        self.eps = eps

    def forward(self, x):
        batch_size, length, feature_dim = x.shape
        output = torch.zeros_like(x)

        # dim=-1 so we squish along last idx(feature_dim)
        # keepdim=True so we get (batch_size, length, 1)
        mu = x.mean(dim=-1, keepdim=True)
        var = x.var(dim=-1, keepdim=True, unbiased=False)

        output = (x - mu) / torch.sqrt(var + self.eps)

        return output