Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / components / modules / rms_norm.py: 65%
48 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-10-25 05:45 +0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-10-25 05:45 +0800
1# Copyright 2026 Huawei Technologies Co., Ltd
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ============================================================================
15"""Root mean square normalization module."""
17from __future__ import annotations
19from collections.abc import Mapping
20from typing import Any
22import torch # pylint: disable=forbidden-backend-import
23from hyper_parallel.components.checkpoint.weight_conversion import WeightConverter
25from hyper_parallel.components.checkpoint.conversion_ops import AddScalar
26from hyper_parallel.models.replacement import module_replacement
27from hyper_parallel.components.functional import rms_norm
30@module_replacement
31class RMSNorm(torch.nn.Module):
32 """NPU-accelerated replacement for direct-scale RMSNorm."""
34 def __init__(
35 self,
36 hidden_size: int | None = None,
37 eps: float = 1e-5,
38 *,
39 module: torch.nn.Module | None = None,
40 module_fqn: str = "",
41 context: Mapping[str, Any] | None = None,
42 ) -> None:
43 """Build a direct-scale RMSNorm or replace an existing module.
45 Args:
46 hidden_size: Size of the normalized dimension for direct construction.
47 eps: Epsilon added to the variance.
48 module: Optional source module whose parameter layout is preserved.
49 module_fqn: Fully qualified source-module name supplied by replacement.
50 context: Replacement context supplied by Trainer.
52 Raises:
53 TypeError: If the source module does not expose a supported RMSNorm contract.
54 ValueError: If neither a source module nor a positive hidden size is supplied.
55 """
56 super().__init__()
57 del module_fqn, context
58 if module is not None:
59 if not isinstance(getattr(module, "weight", None), torch.nn.Parameter):
60 raise TypeError("RMSNorm source module must expose an nn.Parameter weight")
61 source_eps = getattr(module, "eps", None)
62 if source_eps is None:
63 source_eps = getattr(module, "variance_epsilon", None)
64 if source_eps is None:
65 raise TypeError(
66 "RMSNorm source module must expose eps or variance_epsilon"
67 )
68 self.eps = float(source_eps)
69 self.weight = module.weight
70 self.train(module.training)
71 return
72 if hidden_size is None or hidden_size <= 0:
73 raise ValueError("RMSNorm hidden_size must be a positive integer")
74 self.eps = eps
75 self.weight = torch.nn.Parameter(torch.ones(hidden_size))
77 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
78 """Apply NPU-accelerated RMS normalization."""
79 return rms_norm(hidden_states, self.weight, self.eps)
82@module_replacement
83class OffsetRMSNorm(torch.nn.Module):
84 """High-performance replacement for RMSNorm using ``1 + weight``."""
86 def __init__(
87 self,
88 *,
89 module: torch.nn.Module,
90 module_fqn: str = "",
91 context: Mapping[str, Any] | None = None,
92 ) -> None:
93 """Build a direct-scale RMSNorm from a unit-offset source module."""
94 super().__init__()
95 del module_fqn, context
96 if not hasattr(module, "weight") or not hasattr(module, "eps"):
97 raise TypeError(
98 "OffsetRMSNorm source module must expose weight and eps"
99 )
100 self.eps = module.eps
101 weight = (
102 torch.empty_like(module.weight)
103 if module.weight.is_meta
104 else module.weight.detach() + 1.0
105 )
106 self.weight = torch.nn.Parameter(
107 weight,
108 requires_grad=module.weight.requires_grad,
109 )
110 self.train(module.training)
112 def reset_parameters(self) -> None:
113 """Initialize the direct scale used by randomly initialized models."""
114 torch.nn.init.ones_(self.weight)
116 def make_transforms(self) -> list[WeightConverter]:
117 """Convert the unit-offset weight to the NPU operator's direct scale."""
118 return [
119 WeightConverter(
120 source_patterns=["weight"],
121 target_patterns="weight",
122 operations=[AddScalar(1.0)],
123 )
124 ]
126 def forward(self, x: torch.Tensor) -> torch.Tensor:
127 """Apply unit-offset RMSNorm with the NPU operator."""
128 return rms_norm(x, self.weight, self.eps)