Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_multicore / modules / mega_mhc / module.py: 94%
49 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-11-15 05:03 +0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-11-15 05:03 +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"""Model-facing MegaMhc module for shifted BF16 mHC."""
17from __future__ import annotations
19from collections.abc import Callable
20from typing import Any
22import torch
24from .._precision import preserve_fp32_parameters
25from ..mega_mhc_common import (
26 MHC_MAPPINGS,
27 MHC_SINKHORN_ITERS,
28 MHC_STREAMS,
29 MegaMhcOutputs,
30 validate_mega_mhc_hidden_size,
31)
32from .function import hyper_mega_mhc
33from .graph import DEFAULT_TOKEN_TILE
36class MegaMhc(torch.nn.Module):
37 """Own the current layer's mapping predictor and input RMSNorm weight.
39 Note:
40 This trainable module requires the native backward hidden-size contract.
41 Forward-only callers can use ``hyper_mega_mhc(..., need_backward=False)``.
42 """
44 def __init__(
45 self,
46 hidden_size: int,
47 *,
48 hc_eps: float = 1e-6,
49 norm_eps: float = 1e-6,
50 num_iters: int = MHC_SINKHORN_ITERS,
51 token_tile: int = DEFAULT_TOKEN_TILE,
52 device: Any | None = None,
53 ) -> None:
54 """Initialize the fixed-four-stream shifted mHC parameters.
56 Args:
57 hidden_size: Stream width H, a positive multiple of 128, at most 5760.
58 The module enforces this training limit even in eval/no-grad mode.
59 hc_eps: Epsilon used by pre-mix and Sinkhorn mapping prediction.
60 norm_eps: Epsilon used by RMS normalization.
61 num_iters: Sinkhorn iteration count; must be 20.
62 token_tile: Positive integer tokens per scheduler task; defaults to 32.
63 device: Parameter device. None uses Torch's default device; execution
64 requires moving all parameters and inputs to the same NPU.
66 Note:
67 phi [24, 4*H], alpha [3] and bias [24] use FP32; norm_weight [H]
68 uses BF16. Module dtype conversions preserve the FP32 predictor
69 parameters and their existing gradients. Runtime tensors require NPU
70 and the native payload.
72 Raises:
73 ValueError: If hidden_size, num_iters or token_tile is unsupported.
74 """
75 super().__init__()
76 validate_mega_mhc_hidden_size(hidden_size, need_backward=True)
77 if num_iters != MHC_SINKHORN_ITERS:
78 raise ValueError(f"MegaMhc requires num_iters={MHC_SINKHORN_ITERS}, got {num_iters}.")
79 if not isinstance(token_tile, int) or isinstance(token_tile, bool) or token_tile <= 0:
80 raise ValueError(f"token_tile must be a positive integer, got {token_tile!r}.")
81 self.hidden_size = hidden_size
82 self.hc_eps = float(hc_eps)
83 self.norm_eps = float(norm_eps)
84 self.num_iters = num_iters
85 self.token_tile = token_tile
86 factory_kwargs = {"device": device, "dtype": torch.float32}
87 self.phi = torch.nn.Parameter(
88 torch.empty((MHC_MAPPINGS, MHC_STREAMS * hidden_size), **factory_kwargs)
89 )
90 self.alpha = torch.nn.Parameter(torch.ones((3,), **factory_kwargs))
91 self.bias = torch.nn.Parameter(torch.zeros((MHC_MAPPINGS,), **factory_kwargs))
92 self.norm_weight = torch.nn.Parameter(
93 torch.ones((hidden_size,), device=device, dtype=torch.bfloat16)
94 )
95 torch.nn.init.normal_(
96 self.phi,
97 mean=0.0,
98 std=(MHC_STREAMS * hidden_size) ** -0.5,
99 )
101 def _apply(self, fn: Callable, recurse: bool = True) -> MegaMhc:
102 """Keep mapping predictors FP32 when the enclosing model changes dtype or device."""
103 return super()._apply(preserve_fp32_parameters(self, fn, ("phi", "alpha", "bias")), recurse=recurse)
105 @classmethod
106 def from_module(cls, module: torch.nn.Module) -> MegaMhc:
107 """Bind an existing four-stream, shifted mHC module without replacing its Parameters.
109 Args:
110 module: Source with hidden_size, hc_eps, norm_eps, num_iters and Parameters
111 phi [24, 4H], alpha [3], bias [24], norm_weight [H]. Predictor Parameters must be FP32.
113 Returns:
114 Boundary sharing all original Parameters and mathematical configuration.
115 """
116 configuration = {}
117 for name in ("hidden_size", "hc_eps", "norm_eps", "num_iters"):
118 if not hasattr(module, name):
119 raise ValueError(f"source mHC module must expose {name}")
120 configuration[name] = getattr(module, name)
121 phi = getattr(module, "phi", None)
122 if not isinstance(phi, torch.nn.Parameter):
123 raise TypeError("source phi must be an FP32 Parameter [24, 4H]")
124 result = cls(**configuration, device=phi.device)
125 for name in ("phi", "alpha", "bias", "norm_weight"):
126 parameter = getattr(module, name, None)
127 expected = getattr(result, name)
128 if (not isinstance(parameter, torch.nn.Parameter) or parameter.shape != expected.shape
129 or parameter.dtype != expected.dtype or parameter.device != expected.device):
130 raise ValueError(f"source {name} must match shape={tuple(expected.shape)}, dtype={expected.dtype}")
131 setattr(result, name, parameter)
132 return result
134 def forward(
135 self,
136 previous_output: torch.Tensor,
137 residual: torch.Tensor,
138 previous_pre_mix: torch.Tensor,
139 previous_post_mix: torch.Tensor,
140 previous_residual_mix: torch.Tensor,
141 ) -> MegaMhcOutputs:
142 """Advance one shifted mHC block boundary and predict the next mappings.
144 Args:
145 previous_output: BF16 previous block output with shape [*S, H].
146 residual: BF16 residual streams with shape [*S, 4, H]. S contains
147 one or more token dimensions, all inputs share the same NPU.
148 previous_pre_mix: FP32 coefficients [*S, 4] used to form block_input.
149 previous_post_mix: FP32 coefficients [*S, 4] that distribute
150 previous_output into the residual streams.
151 previous_residual_mix: FP32 residual mixing matrices [*S, 4, 4].
153 Returns:
154 A five-tensor tuple, in order: new_residual (BF16, [*S, 4, H]),
155 next_pre_mix (FP32, [*S, 4]), next_post_mix (FP32, [*S, 4]),
156 next_residual_mix (FP32, [*S, 4, 4]), block_input (BF16, [*S, H]).
157 The new mappings are for the next boundary; block_input uses
158 previous_pre_mix to combine new_residual, then applies RMSNorm.
160 Note:
161 Training uses native autograd. The flattened token count must be
162 at least max(40, configured AIV core count) when backward is needed;
163 forward-only execution requires at least one token. Cross-stream
164 producers must establish dependencies before this call.
166 Raises:
167 TypeError: If tensors, dtypes or the NPU device type are invalid.
168 ValueError: If shapes, devices, hidden size or training token count
169 violate the native contract.
170 """
171 return hyper_mega_mhc(
172 previous_output,
173 residual,
174 previous_pre_mix,
175 previous_post_mix,
176 previous_residual_mix,
177 self.phi,
178 self.alpha,
179 self.bias,
180 self.norm_weight,
181 hc_eps=self.hc_eps,
182 norm_eps=self.norm_eps,
183 num_iters=self.num_iters,
184 token_tile=self.token_tile,
185 )