Module neuralops.utils.layer_norm_fix
Numerically Stable Layer Normalization and RMS Normalization Modules.
Eliminates FP16 variance underflow and sum-of-squares overflow by forcing all mean, variance, and reduction accumulators into torch.float32 prior to reciprocal square root.
Functions
def fix_layernorm_naming(model: nn.Module) ‑> None-
Expand source code
def fix_layernorm_naming(model: nn.Module) -> None: """ Fix LayerNorm parameter naming (e.g. HuggingFace gamma/beta to weight/bias). """ for module in model.modules(): if isinstance(module, (nn.LayerNorm, LayerNorm)): state = dict(module.named_parameters()) if "beta" in state and "bias" not in state: bias = module._parameters.pop("beta") module.register_parameter("bias", bias) if "gamma" in state and "weight" not in state: weight = module._parameters.pop("gamma") module.register_parameter("weight", weight)Fix LayerNorm parameter naming (e.g. HuggingFace gamma/beta to weight/bias).
def replace_layernorm_with_safe_norm(model: nn.Module) ‑> torch.nn.modules.module.Module-
Expand source code
def replace_layernorm_with_safe_norm(model: nn.Module) -> nn.Module: """ Recursively replaces all standard PyTorch nn.LayerNorm instances in a model with FP32 accumulator SafeLayerNorm instances. """ for name, child in model.named_children(): if isinstance(child, nn.LayerNorm) and not isinstance(child, LayerNorm): has_bias = child.bias is not None safe_ln = LayerNorm( normalized_shape=child.normalized_shape, eps=child.eps, elementwise_affine=child.elementwise_affine, bias=has_bias, ) if child.elementwise_affine: with torch.no_grad(): if child.weight is not None: safe_ln.weight.copy_(child.weight) if has_bias and child.bias is not None: safe_ln.bias.copy_(child.bias) setattr(model, name, safe_ln) else: replace_layernorm_with_safe_norm(child) return modelRecursively replaces all standard PyTorch nn.LayerNorm instances in a model with FP32 accumulator SafeLayerNorm instances.
Classes
class LayerNorm (normalized_shape: int | tuple[int, ...] | list[int] | torch.Size,
eps: float = 1e-05,
elementwise_affine: bool = True,
bias: bool = True,
device: torch.device | str | None = None,
dtype: torch.dtype | None = None)-
Expand source code
class LayerNorm(nn.Module): """ Standard Layer Normalization with FP32 accumulator precision. Prevents FP16 numerical instability and variance underflow by computing mean and centered variance in `torch.float32`: $$y = \\frac{x - \\mu}{\\sqrt{\\sigma^2 + \\epsilon}} \\odot \\gamma + \\beta$$ """ def __init__( self, normalized_shape: int | tuple[int, ...] | list[int] | torch.Size, eps: float = 1e-5, elementwise_affine: bool = True, bias: bool = True, device: torch.device | str | None = None, dtype: torch.dtype | None = None, ) -> None: super().__init__() if isinstance(normalized_shape, int): self.normalized_shape = (normalized_shape,) else: self.normalized_shape = tuple(normalized_shape) self.eps: float = float(eps) self.elementwise_affine: bool = elementwise_affine if elementwise_affine: self.weight = nn.Parameter( torch.ones(self.normalized_shape, device=device, dtype=dtype) ) if bias: self.bias = nn.Parameter( torch.zeros(self.normalized_shape, device=device, dtype=dtype) ) else: self.register_parameter("bias", None) else: self.register_parameter("weight", None) self.register_parameter("bias", None) def forward(self, x: torch.Tensor) -> torch.Tensor: """ Forward pass with FP32 accumulator computation. Args: x: Input tensor of shape `(..., *normalized_shape)`. Returns: Normalized tensor with matching input dtype and shape. """ input_dtype = x.dtype reduction_dims = tuple(range(-len(self.normalized_shape), 0)) # FIX: Explicitly cast accumulators to torch.float32 for mean and variance to prevent FP16 variance underflow x_fp32 = x.float() mean = torch.mean(x_fp32, dim=reduction_dims, keepdim=True) variance = torch.mean((x_fp32 - mean) ** 2, dim=reduction_dims, keepdim=True) x_normed = ((x_fp32 - mean) * torch.rsqrt(variance + self.eps)).to(input_dtype) if self.weight is not None: x_normed = x_normed * self.weight.to(input_dtype) if self.bias is not None: x_normed = x_normed + self.bias.to(input_dtype) return x_normed.to(input_dtype) def extra_repr(self) -> str: return ( f"{self.normalized_shape}, eps={self.eps}, elementwise_affine={self.elementwise_affine}" )Standard Layer Normalization with FP32 accumulator precision.
Prevents FP16 numerical instability and variance underflow by computing mean and centered variance in
torch.float32: $$y = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \odot \gamma + \beta$$Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def extra_repr(self) ‑> str-
Expand source code
def extra_repr(self) -> str: return ( f"{self.normalized_shape}, eps={self.eps}, elementwise_affine={self.elementwise_affine}" )Return the extra representation of the module.
To print customized extra information, you should re-implement this method in your own modules. Both single-line and multi-line strings are acceptable.
def forward(self, x: torch.Tensor) ‑> torch.Tensor-
Expand source code
def forward(self, x: torch.Tensor) -> torch.Tensor: """ Forward pass with FP32 accumulator computation. Args: x: Input tensor of shape `(..., *normalized_shape)`. Returns: Normalized tensor with matching input dtype and shape. """ input_dtype = x.dtype reduction_dims = tuple(range(-len(self.normalized_shape), 0)) # FIX: Explicitly cast accumulators to torch.float32 for mean and variance to prevent FP16 variance underflow x_fp32 = x.float() mean = torch.mean(x_fp32, dim=reduction_dims, keepdim=True) variance = torch.mean((x_fp32 - mean) ** 2, dim=reduction_dims, keepdim=True) x_normed = ((x_fp32 - mean) * torch.rsqrt(variance + self.eps)).to(input_dtype) if self.weight is not None: x_normed = x_normed * self.weight.to(input_dtype) if self.bias is not None: x_normed = x_normed + self.bias.to(input_dtype) return x_normed.to(input_dtype)Forward pass with FP32 accumulator computation.
- Args
- -----=
x- Input tensor of shape
(..., *normalized_shape).
Returns -----= Normalized tensor with matching input dtype and shape.
class SafeLayerNorm (normalized_shape: int | tuple[int, ...] | list[int] | torch.Size,
eps: float = 1e-05,
elementwise_affine: bool = True,
bias: bool = True,
device: torch.device | str | None = None,
dtype: torch.dtype | None = None)-
Expand source code
class LayerNorm(nn.Module): """ Standard Layer Normalization with FP32 accumulator precision. Prevents FP16 numerical instability and variance underflow by computing mean and centered variance in `torch.float32`: $$y = \\frac{x - \\mu}{\\sqrt{\\sigma^2 + \\epsilon}} \\odot \\gamma + \\beta$$ """ def __init__( self, normalized_shape: int | tuple[int, ...] | list[int] | torch.Size, eps: float = 1e-5, elementwise_affine: bool = True, bias: bool = True, device: torch.device | str | None = None, dtype: torch.dtype | None = None, ) -> None: super().__init__() if isinstance(normalized_shape, int): self.normalized_shape = (normalized_shape,) else: self.normalized_shape = tuple(normalized_shape) self.eps: float = float(eps) self.elementwise_affine: bool = elementwise_affine if elementwise_affine: self.weight = nn.Parameter( torch.ones(self.normalized_shape, device=device, dtype=dtype) ) if bias: self.bias = nn.Parameter( torch.zeros(self.normalized_shape, device=device, dtype=dtype) ) else: self.register_parameter("bias", None) else: self.register_parameter("weight", None) self.register_parameter("bias", None) def forward(self, x: torch.Tensor) -> torch.Tensor: """ Forward pass with FP32 accumulator computation. Args: x: Input tensor of shape `(..., *normalized_shape)`. Returns: Normalized tensor with matching input dtype and shape. """ input_dtype = x.dtype reduction_dims = tuple(range(-len(self.normalized_shape), 0)) # FIX: Explicitly cast accumulators to torch.float32 for mean and variance to prevent FP16 variance underflow x_fp32 = x.float() mean = torch.mean(x_fp32, dim=reduction_dims, keepdim=True) variance = torch.mean((x_fp32 - mean) ** 2, dim=reduction_dims, keepdim=True) x_normed = ((x_fp32 - mean) * torch.rsqrt(variance + self.eps)).to(input_dtype) if self.weight is not None: x_normed = x_normed * self.weight.to(input_dtype) if self.bias is not None: x_normed = x_normed + self.bias.to(input_dtype) return x_normed.to(input_dtype) def extra_repr(self) -> str: return ( f"{self.normalized_shape}, eps={self.eps}, elementwise_affine={self.elementwise_affine}" )Standard Layer Normalization with FP32 accumulator precision.
Prevents FP16 numerical instability and variance underflow by computing mean and centered variance in
torch.float32: $$y = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \odot \gamma + \beta$$Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def extra_repr(self) ‑> str-
Expand source code
def extra_repr(self) -> str: return ( f"{self.normalized_shape}, eps={self.eps}, elementwise_affine={self.elementwise_affine}" )Return the extra representation of the module.
To print customized extra information, you should re-implement this method in your own modules. Both single-line and multi-line strings are acceptable.
def forward(self, x: torch.Tensor) ‑> torch.Tensor-
Expand source code
def forward(self, x: torch.Tensor) -> torch.Tensor: """ Forward pass with FP32 accumulator computation. Args: x: Input tensor of shape `(..., *normalized_shape)`. Returns: Normalized tensor with matching input dtype and shape. """ input_dtype = x.dtype reduction_dims = tuple(range(-len(self.normalized_shape), 0)) # FIX: Explicitly cast accumulators to torch.float32 for mean and variance to prevent FP16 variance underflow x_fp32 = x.float() mean = torch.mean(x_fp32, dim=reduction_dims, keepdim=True) variance = torch.mean((x_fp32 - mean) ** 2, dim=reduction_dims, keepdim=True) x_normed = ((x_fp32 - mean) * torch.rsqrt(variance + self.eps)).to(input_dtype) if self.weight is not None: x_normed = x_normed * self.weight.to(input_dtype) if self.bias is not None: x_normed = x_normed + self.bias.to(input_dtype) return x_normed.to(input_dtype)Forward pass with FP32 accumulator computation.
- Args
- -----=
x- Input tensor of shape
(..., *normalized_shape).
Returns -----= Normalized tensor with matching input dtype and shape.
class FP32AccumulatorLayerNorm (normalized_shape: int | tuple[int, ...] | list[int] | torch.Size,
eps: float = 1e-05,
elementwise_affine: bool = True,
bias: bool = True,
device: torch.device | str | None = None,
dtype: torch.dtype | None = None)-
Expand source code
class LayerNorm(nn.Module): """ Standard Layer Normalization with FP32 accumulator precision. Prevents FP16 numerical instability and variance underflow by computing mean and centered variance in `torch.float32`: $$y = \\frac{x - \\mu}{\\sqrt{\\sigma^2 + \\epsilon}} \\odot \\gamma + \\beta$$ """ def __init__( self, normalized_shape: int | tuple[int, ...] | list[int] | torch.Size, eps: float = 1e-5, elementwise_affine: bool = True, bias: bool = True, device: torch.device | str | None = None, dtype: torch.dtype | None = None, ) -> None: super().__init__() if isinstance(normalized_shape, int): self.normalized_shape = (normalized_shape,) else: self.normalized_shape = tuple(normalized_shape) self.eps: float = float(eps) self.elementwise_affine: bool = elementwise_affine if elementwise_affine: self.weight = nn.Parameter( torch.ones(self.normalized_shape, device=device, dtype=dtype) ) if bias: self.bias = nn.Parameter( torch.zeros(self.normalized_shape, device=device, dtype=dtype) ) else: self.register_parameter("bias", None) else: self.register_parameter("weight", None) self.register_parameter("bias", None) def forward(self, x: torch.Tensor) -> torch.Tensor: """ Forward pass with FP32 accumulator computation. Args: x: Input tensor of shape `(..., *normalized_shape)`. Returns: Normalized tensor with matching input dtype and shape. """ input_dtype = x.dtype reduction_dims = tuple(range(-len(self.normalized_shape), 0)) # FIX: Explicitly cast accumulators to torch.float32 for mean and variance to prevent FP16 variance underflow x_fp32 = x.float() mean = torch.mean(x_fp32, dim=reduction_dims, keepdim=True) variance = torch.mean((x_fp32 - mean) ** 2, dim=reduction_dims, keepdim=True) x_normed = ((x_fp32 - mean) * torch.rsqrt(variance + self.eps)).to(input_dtype) if self.weight is not None: x_normed = x_normed * self.weight.to(input_dtype) if self.bias is not None: x_normed = x_normed + self.bias.to(input_dtype) return x_normed.to(input_dtype) def extra_repr(self) -> str: return ( f"{self.normalized_shape}, eps={self.eps}, elementwise_affine={self.elementwise_affine}" )Standard Layer Normalization with FP32 accumulator precision.
Prevents FP16 numerical instability and variance underflow by computing mean and centered variance in
torch.float32: $$y = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \odot \gamma + \beta$$Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def extra_repr(self) ‑> str-
Expand source code
def extra_repr(self) -> str: return ( f"{self.normalized_shape}, eps={self.eps}, elementwise_affine={self.elementwise_affine}" )Return the extra representation of the module.
To print customized extra information, you should re-implement this method in your own modules. Both single-line and multi-line strings are acceptable.
def forward(self, x: torch.Tensor) ‑> torch.Tensor-
Expand source code
def forward(self, x: torch.Tensor) -> torch.Tensor: """ Forward pass with FP32 accumulator computation. Args: x: Input tensor of shape `(..., *normalized_shape)`. Returns: Normalized tensor with matching input dtype and shape. """ input_dtype = x.dtype reduction_dims = tuple(range(-len(self.normalized_shape), 0)) # FIX: Explicitly cast accumulators to torch.float32 for mean and variance to prevent FP16 variance underflow x_fp32 = x.float() mean = torch.mean(x_fp32, dim=reduction_dims, keepdim=True) variance = torch.mean((x_fp32 - mean) ** 2, dim=reduction_dims, keepdim=True) x_normed = ((x_fp32 - mean) * torch.rsqrt(variance + self.eps)).to(input_dtype) if self.weight is not None: x_normed = x_normed * self.weight.to(input_dtype) if self.bias is not None: x_normed = x_normed + self.bias.to(input_dtype) return x_normed.to(input_dtype)Forward pass with FP32 accumulator computation.
- Args
- -----=
x- Input tensor of shape
(..., *normalized_shape).
Returns -----= Normalized tensor with matching input dtype and shape.
class RMSNorm (normalized_shape: int | tuple[int, ...] | list[int] | torch.Size,
eps: float = 1e-06,
elementwise_affine: bool = True,
device: torch.device | str | None = None,
dtype: torch.dtype | None = None)-
Expand source code
class RMSNorm(nn.Module): """ Root Mean Square Layer Normalization (RMSNorm) with FP32 accumulator precision. In standard FP16 mixed-precision training, squaring high-magnitude activations can exceed the FP16 maximum value (65504), causing overflow to `inf` / `nan`, or underflow to zero for small activations. This implementation explicitly casts the reduction accumulators to `torch.float32` before computing the sum-of-squares and reciprocal square root: $$y = \\frac{x}{\\sqrt{\\frac{1}{d} \\sum_{i=1}^d x_i^2 + \\epsilon}} \\odot \\gamma$$ """ def __init__( self, normalized_shape: int | tuple[int, ...] | list[int] | torch.Size, eps: float = 1e-6, elementwise_affine: bool = True, device: torch.device | str | None = None, dtype: torch.dtype | None = None, ) -> None: super().__init__() if isinstance(normalized_shape, int): self.normalized_shape = (normalized_shape,) else: self.normalized_shape = tuple(normalized_shape) self.eps: float = float(eps) self.elementwise_affine: bool = elementwise_affine if elementwise_affine: self.weight = nn.Parameter( torch.ones(self.normalized_shape, device=device, dtype=dtype) ) else: self.register_parameter("weight", None) def forward(self, x: torch.Tensor) -> torch.Tensor: """ Forward pass with FP32 accumulator computation. Args: x: Input tensor of shape `(..., *normalized_shape)`. Returns: Normalized tensor with matching input dtype and shape. """ input_dtype = x.dtype reduction_dims = tuple(range(-len(self.normalized_shape), 0)) # FIX: Explicitly cast accumulators to torch.float32 to avoid FP16 sum-of-squares overflow/underflow variance = torch.mean(x.float() ** 2, dim=reduction_dims, keepdim=True) x_normed = (x.float() * torch.rsqrt(variance + self.eps)).to(input_dtype) if self.weight is not None: x_normed = x_normed * self.weight.to(input_dtype) return x_normed.to(input_dtype) def extra_repr(self) -> str: return ( f"{self.normalized_shape}, eps={self.eps}, elementwise_affine={self.elementwise_affine}" )Root Mean Square Layer Normalization (RMSNorm) with FP32 accumulator precision.
In standard FP16 mixed-precision training, squaring high-magnitude activations can exceed the FP16 maximum value (65504), causing overflow to
inf/nan, or underflow to zero for small activations. This implementation explicitly casts the reduction accumulators totorch.float32before computing the sum-of-squares and reciprocal square root: $$y = \frac{x}{\sqrt{\frac{1}{d} \sum_{i=1}^d x_i^2 + \epsilon}} \odot \gamma$$Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def extra_repr(self) ‑> str-
Expand source code
def extra_repr(self) -> str: return ( f"{self.normalized_shape}, eps={self.eps}, elementwise_affine={self.elementwise_affine}" )Return the extra representation of the module.
To print customized extra information, you should re-implement this method in your own modules. Both single-line and multi-line strings are acceptable.
def forward(self, x: torch.Tensor) ‑> torch.Tensor-
Expand source code
def forward(self, x: torch.Tensor) -> torch.Tensor: """ Forward pass with FP32 accumulator computation. Args: x: Input tensor of shape `(..., *normalized_shape)`. Returns: Normalized tensor with matching input dtype and shape. """ input_dtype = x.dtype reduction_dims = tuple(range(-len(self.normalized_shape), 0)) # FIX: Explicitly cast accumulators to torch.float32 to avoid FP16 sum-of-squares overflow/underflow variance = torch.mean(x.float() ** 2, dim=reduction_dims, keepdim=True) x_normed = (x.float() * torch.rsqrt(variance + self.eps)).to(input_dtype) if self.weight is not None: x_normed = x_normed * self.weight.to(input_dtype) return x_normed.to(input_dtype)Forward pass with FP32 accumulator computation.
- Args
- -----=
x- Input tensor of shape
(..., *normalized_shape).
Returns -----= Normalized tensor with matching input dtype and shape.
class SafeRMSNorm (normalized_shape: int | tuple[int, ...] | list[int] | torch.Size,
eps: float = 1e-06,
elementwise_affine: bool = True,
device: torch.device | str | None = None,
dtype: torch.dtype | None = None)-
Expand source code
class RMSNorm(nn.Module): """ Root Mean Square Layer Normalization (RMSNorm) with FP32 accumulator precision. In standard FP16 mixed-precision training, squaring high-magnitude activations can exceed the FP16 maximum value (65504), causing overflow to `inf` / `nan`, or underflow to zero for small activations. This implementation explicitly casts the reduction accumulators to `torch.float32` before computing the sum-of-squares and reciprocal square root: $$y = \\frac{x}{\\sqrt{\\frac{1}{d} \\sum_{i=1}^d x_i^2 + \\epsilon}} \\odot \\gamma$$ """ def __init__( self, normalized_shape: int | tuple[int, ...] | list[int] | torch.Size, eps: float = 1e-6, elementwise_affine: bool = True, device: torch.device | str | None = None, dtype: torch.dtype | None = None, ) -> None: super().__init__() if isinstance(normalized_shape, int): self.normalized_shape = (normalized_shape,) else: self.normalized_shape = tuple(normalized_shape) self.eps: float = float(eps) self.elementwise_affine: bool = elementwise_affine if elementwise_affine: self.weight = nn.Parameter( torch.ones(self.normalized_shape, device=device, dtype=dtype) ) else: self.register_parameter("weight", None) def forward(self, x: torch.Tensor) -> torch.Tensor: """ Forward pass with FP32 accumulator computation. Args: x: Input tensor of shape `(..., *normalized_shape)`. Returns: Normalized tensor with matching input dtype and shape. """ input_dtype = x.dtype reduction_dims = tuple(range(-len(self.normalized_shape), 0)) # FIX: Explicitly cast accumulators to torch.float32 to avoid FP16 sum-of-squares overflow/underflow variance = torch.mean(x.float() ** 2, dim=reduction_dims, keepdim=True) x_normed = (x.float() * torch.rsqrt(variance + self.eps)).to(input_dtype) if self.weight is not None: x_normed = x_normed * self.weight.to(input_dtype) return x_normed.to(input_dtype) def extra_repr(self) -> str: return ( f"{self.normalized_shape}, eps={self.eps}, elementwise_affine={self.elementwise_affine}" )Root Mean Square Layer Normalization (RMSNorm) with FP32 accumulator precision.
In standard FP16 mixed-precision training, squaring high-magnitude activations can exceed the FP16 maximum value (65504), causing overflow to
inf/nan, or underflow to zero for small activations. This implementation explicitly casts the reduction accumulators totorch.float32before computing the sum-of-squares and reciprocal square root: $$y = \frac{x}{\sqrt{\frac{1}{d} \sum_{i=1}^d x_i^2 + \epsilon}} \odot \gamma$$Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def extra_repr(self) ‑> str-
Expand source code
def extra_repr(self) -> str: return ( f"{self.normalized_shape}, eps={self.eps}, elementwise_affine={self.elementwise_affine}" )Return the extra representation of the module.
To print customized extra information, you should re-implement this method in your own modules. Both single-line and multi-line strings are acceptable.
def forward(self, x: torch.Tensor) ‑> torch.Tensor-
Expand source code
def forward(self, x: torch.Tensor) -> torch.Tensor: """ Forward pass with FP32 accumulator computation. Args: x: Input tensor of shape `(..., *normalized_shape)`. Returns: Normalized tensor with matching input dtype and shape. """ input_dtype = x.dtype reduction_dims = tuple(range(-len(self.normalized_shape), 0)) # FIX: Explicitly cast accumulators to torch.float32 to avoid FP16 sum-of-squares overflow/underflow variance = torch.mean(x.float() ** 2, dim=reduction_dims, keepdim=True) x_normed = (x.float() * torch.rsqrt(variance + self.eps)).to(input_dtype) if self.weight is not None: x_normed = x_normed * self.weight.to(input_dtype) return x_normed.to(input_dtype)Forward pass with FP32 accumulator computation.
- Args
- -----=
x- Input tensor of shape
(..., *normalized_shape).
Returns -----= Normalized tensor with matching input dtype and shape.
class FP32AccumulatorRMSNorm (normalized_shape: int | tuple[int, ...] | list[int] | torch.Size,
eps: float = 1e-06,
elementwise_affine: bool = True,
device: torch.device | str | None = None,
dtype: torch.dtype | None = None)-
Expand source code
class RMSNorm(nn.Module): """ Root Mean Square Layer Normalization (RMSNorm) with FP32 accumulator precision. In standard FP16 mixed-precision training, squaring high-magnitude activations can exceed the FP16 maximum value (65504), causing overflow to `inf` / `nan`, or underflow to zero for small activations. This implementation explicitly casts the reduction accumulators to `torch.float32` before computing the sum-of-squares and reciprocal square root: $$y = \\frac{x}{\\sqrt{\\frac{1}{d} \\sum_{i=1}^d x_i^2 + \\epsilon}} \\odot \\gamma$$ """ def __init__( self, normalized_shape: int | tuple[int, ...] | list[int] | torch.Size, eps: float = 1e-6, elementwise_affine: bool = True, device: torch.device | str | None = None, dtype: torch.dtype | None = None, ) -> None: super().__init__() if isinstance(normalized_shape, int): self.normalized_shape = (normalized_shape,) else: self.normalized_shape = tuple(normalized_shape) self.eps: float = float(eps) self.elementwise_affine: bool = elementwise_affine if elementwise_affine: self.weight = nn.Parameter( torch.ones(self.normalized_shape, device=device, dtype=dtype) ) else: self.register_parameter("weight", None) def forward(self, x: torch.Tensor) -> torch.Tensor: """ Forward pass with FP32 accumulator computation. Args: x: Input tensor of shape `(..., *normalized_shape)`. Returns: Normalized tensor with matching input dtype and shape. """ input_dtype = x.dtype reduction_dims = tuple(range(-len(self.normalized_shape), 0)) # FIX: Explicitly cast accumulators to torch.float32 to avoid FP16 sum-of-squares overflow/underflow variance = torch.mean(x.float() ** 2, dim=reduction_dims, keepdim=True) x_normed = (x.float() * torch.rsqrt(variance + self.eps)).to(input_dtype) if self.weight is not None: x_normed = x_normed * self.weight.to(input_dtype) return x_normed.to(input_dtype) def extra_repr(self) -> str: return ( f"{self.normalized_shape}, eps={self.eps}, elementwise_affine={self.elementwise_affine}" )Root Mean Square Layer Normalization (RMSNorm) with FP32 accumulator precision.
In standard FP16 mixed-precision training, squaring high-magnitude activations can exceed the FP16 maximum value (65504), causing overflow to
inf/nan, or underflow to zero for small activations. This implementation explicitly casts the reduction accumulators totorch.float32before computing the sum-of-squares and reciprocal square root: $$y = \frac{x}{\sqrt{\frac{1}{d} \sum_{i=1}^d x_i^2 + \epsilon}} \odot \gamma$$Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def extra_repr(self) ‑> str-
Expand source code
def extra_repr(self) -> str: return ( f"{self.normalized_shape}, eps={self.eps}, elementwise_affine={self.elementwise_affine}" )Return the extra representation of the module.
To print customized extra information, you should re-implement this method in your own modules. Both single-line and multi-line strings are acceptable.
def forward(self, x: torch.Tensor) ‑> torch.Tensor-
Expand source code
def forward(self, x: torch.Tensor) -> torch.Tensor: """ Forward pass with FP32 accumulator computation. Args: x: Input tensor of shape `(..., *normalized_shape)`. Returns: Normalized tensor with matching input dtype and shape. """ input_dtype = x.dtype reduction_dims = tuple(range(-len(self.normalized_shape), 0)) # FIX: Explicitly cast accumulators to torch.float32 to avoid FP16 sum-of-squares overflow/underflow variance = torch.mean(x.float() ** 2, dim=reduction_dims, keepdim=True) x_normed = (x.float() * torch.rsqrt(variance + self.eps)).to(input_dtype) if self.weight is not None: x_normed = x_normed * self.weight.to(input_dtype) return x_normed.to(input_dtype)Forward pass with FP32 accumulator computation.
- Args
- -----=
x- Input tensor of shape
(..., *normalized_shape).
Returns -----= Normalized tensor with matching input dtype and shape.