main
py 90 lines 3.06 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 import torch
4 import torch.nn as nn
5 from torch import Tensor
6
7 from vllm.model_executor.hw_agnostic.custom_op import CustomOp
8
9
10 @CustomOp.register("rms_norm")
11 class RMSNorm(CustomOp):
12 """``x -> w * x / sqrt(E[x^2] + eps)``. With ``residual``, fuses
13 ``residual += x`` then RMSNorm and returns ``(normalized, residual)``."""
14
15 def __init__(
16 self,
17 hidden_size: int,
18 eps: float = 1e-6,
19 var_hidden_size: int | None = None,
20 has_weight: bool = True,
21 dtype: torch.dtype | None = None,
22 ) -> None:
23 super().__init__()
24 self.hidden_size = hidden_size
25 self.variance_epsilon = eps
26 self.variance_size_override = (
27 None if var_hidden_size == hidden_size else var_hidden_size
28 )
29 weight_dtype = dtype or torch.get_default_dtype()
30 self.has_weight = has_weight
31 weight = torch.ones(hidden_size, dtype=weight_dtype)
32 if has_weight:
33 self.weight = nn.Parameter(weight)
34 else:
35 self.register_buffer("weight", weight, persistent=False)
36
37 def _rms_norm(
38 self,
39 x: Tensor,
40 weight: Tensor | None,
41 epsilon: float,
42 variance_size: int | None = None,
43 ) -> Tensor:
44 """Weighted root-mean-square layer normalization"""
45 orig_dtype = x.dtype
46 x = x.to(torch.float32)
47 x_var = x if variance_size is None else x[..., :variance_size]
48 variance = x_var.pow(2).mean(dim=-1, keepdim=True)
49 x = x * torch.rsqrt(variance + epsilon)
50 if weight is not None:
51 x = x.to(weight.dtype) * weight
52 return x.to(orig_dtype)
53
54 def _fused_add_rms_norm(
55 self,
56 x: Tensor,
57 x_residual: Tensor,
58 weight: Tensor | None,
59 epsilon: float,
60 variance_size: int | None = None,
61 ) -> tuple[Tensor, Tensor]:
62 """Fused add and weighted root-mean-square layer normalization"""
63 orig_dtype = x.dtype
64 x = x.to(torch.float32)
65 x = x + x_residual.to(torch.float32)
66 x_residual = x.to(orig_dtype)
67
68 x_var = x if variance_size is None else x[..., :variance_size]
69 variance = x_var.pow(2).mean(dim=-1, keepdim=True)
70 x = x * torch.rsqrt(variance + epsilon)
71 if weight is not None:
72 x = x.to(weight.dtype) * weight
73 return x.to(orig_dtype), x_residual
74
75 def forward_native(
76 self,
77 x: torch.Tensor,
78 residual: torch.Tensor | None = None,
79 ) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
80 weight = self.weight if self.has_weight else None
81 epsilon = self.variance_epsilon
82 variance_size = self.variance_size_override
83
84 if residual is None:
85 return self._rms_norm(x, weight, epsilon, variance_size)
86 else:
87 return self._fused_add_rms_norm(x, residual, weight, epsilon, variance_size)
88
89 def extra_repr(self) -> str:
90 return f"hidden_size={self.hidden_size}, eps={self.variance_epsilon}"