Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / components / modules / swiglu_mlp.py: 0%
84 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"""Transformers-compatible SwiGLU MLP with a fused Gate/Up projection."""
17from __future__ import annotations
19from collections.abc import Mapping
20from typing import Any
22# This package provides PyTorch-specific high-performance modules.
23# pylint: disable=forbidden-backend-import
24import torch # pylint: disable=forbidden-backend-import
25import torch.nn.functional as F
26from torch import nn
27from hyper_parallel.components.checkpoint.weight_conversion import (
28 WeightConverter,
29 WeightRenaming,
30)
32from hyper_parallel.components.checkpoint import ConcatenateWithSections
33from hyper_parallel.models.replacement import module_replacement
34from hyper_parallel.components.functional import swiglu
37@module_replacement
38class SwiGLUMLP(nn.Module):
39 """Transformers-compatible SwiGLU MLP using one fused Gate/Up matmul."""
41 @staticmethod
42 def _source_projections(module: nn.Module) -> tuple[nn.Linear, nn.Linear, nn.Linear]:
43 """Validate and return the source Gate, Up, and Down projections."""
44 required = ("gate_proj", "up_proj", "down_proj")
45 missing = [name for name in required if not hasattr(module, name)]
46 if missing:
47 raise TypeError(f"SwiGLUMLP source module is missing: {missing}")
48 projections = (module.gate_proj, module.up_proj, module.down_proj)
49 if not all(isinstance(projection, nn.Linear) for projection in projections):
50 raise TypeError("SwiGLUMLP requires Gate, Up, and Down projections to be nn.Linear")
51 return projections
53 @staticmethod
54 def _validate_projection_contract(
55 gate_proj: nn.Linear,
56 up_proj: nn.Linear,
57 down_proj: nn.Linear,
58 ) -> None:
59 """Validate source projection shapes, placement, and training policy."""
60 if gate_proj.in_features != up_proj.in_features:
61 raise ValueError("Gate and Up projections must have the same input size")
62 if gate_proj.out_features != up_proj.out_features:
63 raise ValueError("Gate and Up projections must have the same output size")
64 if down_proj.in_features != gate_proj.out_features:
65 raise ValueError("Down projection input size must equal the SwiGLU intermediate size")
66 if down_proj.out_features != gate_proj.in_features:
67 raise ValueError("Down projection output size must equal the MLP hidden size")
68 if gate_proj.weight.device != up_proj.weight.device or gate_proj.weight.dtype != up_proj.weight.dtype:
69 raise ValueError("Gate and Up projection weights must share device and dtype")
70 if gate_proj.weight.device != down_proj.weight.device or gate_proj.weight.dtype != down_proj.weight.dtype:
71 raise ValueError("Gate, Up, and Down projection weights must share device and dtype")
72 if gate_proj.weight.requires_grad != up_proj.weight.requires_grad:
73 raise ValueError("Gate and Up projection weights must share a training policy")
74 if (gate_proj.bias is None) != (up_proj.bias is None):
75 raise ValueError("Gate and Up projections must use the same bias policy")
76 if gate_proj.bias is not None and gate_proj.bias.requires_grad != up_proj.bias.requires_grad:
77 raise ValueError("Gate and Up projection biases must share a training policy")
79 def _initialize_fc1(self, gate_proj: nn.Linear, up_proj: nn.Linear) -> None:
80 """Create the packed Gate/Up projection with source parameter values."""
81 pack = ConcatenateWithSections((self.intermediate_size, self.intermediate_size))
82 packed_weight = pack.convert(
83 {"gate": gate_proj.weight.detach(), "up": up_proj.weight.detach()},
84 ["gate", "up"],
85 ["linear_fc1.weight"],
86 )["linear_fc1.weight"]
87 self.linear_fc1 = nn.Linear(
88 self.hidden_size,
89 2 * self.intermediate_size,
90 bias=gate_proj.bias is not None,
91 device=gate_proj.weight.device,
92 dtype=gate_proj.weight.dtype,
93 )
94 self.linear_fc1.weight = nn.Parameter(packed_weight, requires_grad=gate_proj.weight.requires_grad)
95 if gate_proj.bias is not None:
96 packed_bias = pack.convert(
97 {"gate": gate_proj.bias.detach(), "up": up_proj.bias.detach()},
98 ["gate", "up"],
99 ["linear_fc1.bias"],
100 )["linear_fc1.bias"]
101 self.linear_fc1.bias = nn.Parameter(packed_bias, requires_grad=gate_proj.bias.requires_grad)
103 def _initialize_fc2(self, down_proj: nn.Linear) -> None:
104 """Create the Down projection and reuse its source parameters."""
105 self.linear_fc2 = nn.Linear(
106 down_proj.in_features,
107 down_proj.out_features,
108 bias=down_proj.bias is not None,
109 device=down_proj.weight.device,
110 dtype=down_proj.weight.dtype,
111 )
112 self.linear_fc2.weight = down_proj.weight
113 self.linear_fc2.bias = down_proj.bias
115 def __init__(
116 self,
117 *,
118 module: nn.Module,
119 module_fqn: str = "",
120 context: Mapping[str, Any] | None = None,
121 ) -> None:
122 """Build the high-performance MLP from separate source projections.
124 Args:
125 module: Source MLP exposing ``gate_proj``, ``up_proj``, and ``down_proj``.
126 module_fqn: Fully qualified source-module name supplied by replacement.
127 context: Replacement context supplied by Trainer.
129 Raises:
130 TypeError: If the source projection modules are missing or unsupported.
131 ValueError: If projection layouts, training policies, or activation differ.
132 """
133 super().__init__()
134 del module_fqn, context
135 gate_proj, up_proj, down_proj = self._source_projections(module)
136 self._validate_projection_contract(gate_proj, up_proj, down_proj)
138 config = getattr(module, "config", None)
139 hidden_act = getattr(config, "hidden_act", getattr(config, "hidden_activation", None))
140 if hidden_act is not None and hidden_act not in ("silu", "swiglu"):
141 raise ValueError(f"SwiGLUMLP requires a SiLU activation, but got {hidden_act}")
142 self.config = config
143 self.hidden_size = gate_proj.in_features
144 self.intermediate_size = gate_proj.out_features
146 self._initialize_fc1(gate_proj, up_proj)
147 self._initialize_fc2(down_proj)
148 self.train(module.training)
150 def make_transforms(self) -> list[WeightRenaming | WeightConverter]:
151 """Describe reversible source-checkpoint to high-performance conversion."""
152 transforms: list[WeightRenaming | WeightConverter] = [
153 WeightConverter(
154 source_patterns=["gate_proj.weight", "up_proj.weight"],
155 target_patterns="linear_fc1.weight",
156 operations=[
157 ConcatenateWithSections((self.intermediate_size, self.intermediate_size))
158 ],
159 )
160 ]
161 if self.linear_fc1.bias is not None:
162 transforms.append(
163 WeightConverter(
164 source_patterns=["gate_proj.bias", "up_proj.bias"],
165 target_patterns="linear_fc1.bias",
166 operations=[
167 ConcatenateWithSections((self.intermediate_size, self.intermediate_size))
168 ],
169 )
170 )
171 transforms.append(WeightRenaming("down_proj.weight", "linear_fc2.weight"))
172 if self.linear_fc2.bias is not None:
173 transforms.append(WeightRenaming("down_proj.bias", "linear_fc2.bias"))
174 return transforms
176 def forward(self, x: torch.Tensor) -> torch.Tensor:
177 """Apply the fused Gate/Up projection, SwiGLU, and Down projection."""
178 intermediate_parallel = self.linear_fc1(x)
179 if intermediate_parallel.device.type == "npu":
180 intermediate_parallel = swiglu( # pylint: disable=not-callable
181 intermediate_parallel
182 )
183 else:
184 gate, up = intermediate_parallel.chunk(2, dim=-1)
185 intermediate_parallel = F.silu(gate) * up
186 return self.linear_fc2(intermediate_parallel)