Spaces:
Sleeping
Sleeping
| """ | |
| LayerNorm (Layer Normalization). | |
| The original normalization technique for transformers (Ba et al., 2016). | |
| LayerNorm normalises each token's hidden state by subtracting the mean and | |
| dividing by the standard deviation, then applies a learnable affine | |
| transform: output = scale * (x - mean) / sqrt(var + eps) + shift. | |
| Compared to RMSNorm (which skips mean-centering and the shift parameter), | |
| LayerNorm has slightly higher compute cost due to the extra mean subtraction | |
| and additive bias. In practice, modern LLMs (LLaMA, Qwen3, Gemma) prefer | |
| RMSNorm because the mean-centering provides negligible benefit in pre-norm | |
| architectures, while the savings add up across dozens of layers. | |
| Included here for educational comparison with RMSNorm. | |
| Computation is done in float32 regardless of input dtype to avoid | |
| numerical instability in half-precision, then cast back. | |
| """ | |
| import torch | |
| import torch.nn as nn | |
| class LayerNorm(nn.Module): | |
| def __init__(self, emb_dim: int, eps: float = 1e-5, dtype=None): | |
| super().__init__() | |
| self.eps = eps | |
| self.scale = nn.Parameter(torch.ones(emb_dim, dtype=dtype)) | |
| self.shift = nn.Parameter(torch.zeros(emb_dim, dtype=dtype)) | |
| def forward(self, x): | |
| input_dtype = x.dtype | |
| # Force float32 for numerical stability (matches RMSNorm convention) | |
| x = x.to(torch.float32) | |
| mean = x.mean(dim=-1, keepdim=True) | |
| var = x.var(dim=-1, keepdim=True, unbiased=False) | |
| norm_x = (x - mean) / torch.sqrt(var + self.eps) | |
| return (self.scale.float() * norm_x + self.shift.float()).to(input_dtype) | |