Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / core / shard / ops / parallel_swiglu.py: 100%
33 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-07-13 05:07 +0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-07-13 05:07 +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"""
16SwiGLU distributed operator implementation.
18SwiGLU splits the input along an axis into gate and up halves, applies silu to the
19gate, and multiplies element-wise with up. The split is performed on the local shard.
20When the split axis is sharded, the producer layout strategy is expected to make each
21local shard contain paired gate/up halves.
22"""
24import copy
25from typing import Tuple
27from .parallel_ops import DistributedOp
30def _normalize_swiglu_args(x, axis=-1, dim=None):
31 """Normalize SwiGLU arguments across platform call sites.
33 Args:
34 x: Input tensor.
35 axis: The split axis (default -1).
36 dim: Alias for axis; when provided, overrides axis.
38 Returns:
39 tuple: ((x, axis), {})
40 """
41 if dim is not None:
42 axis = dim
43 return (x, axis), {}
46class SwiGLUDistributedOp(DistributedOp):
47 """
48 Distributed implementation for the SwiGLU operator.
50 Rules:
51 1. Input must not have Partial status.
52 2. axis must be an int within the valid range [-ndim, ndim-1].
53 3. The split axis may be sharded. The split is performed on the local shard;
54 when the split axis is sharded, the producer layout strategy is expected
55 to make each local shard contain paired gate/up halves.
56 4. The split axis must have an even global size so it can be halved.
57 5. Output keeps the same sharding mapping as input.
58 """
60 def preprocess(self, args: tuple, kwargs: dict) -> tuple:
61 """
62 Preprocess arguments for SwiGLU.
64 Args:
65 args (tuple): Positional arguments (x,), with optional axis or dim in kwargs.
66 kwargs (dict): Keyword arguments, optionally containing 'axis' or 'dim'.
68 Returns:
69 tuple: (local_args, local_kwargs, cache_values)
70 """
71 args, _ = _normalize_swiglu_args(*args, **kwargs)
72 input_tensor, axis = args
74 local_args = (input_tensor.to_local(), axis)
75 local_kwargs = {}
76 # Cache the global shape to validate the split axis is even in infer_layout.
77 cache_values = [input_tensor.layout, axis, input_tensor.shape]
78 return local_args, local_kwargs, cache_values
80 def infer_layout(self, cache_values: list) -> Tuple[tuple, None]: # pylint: disable=W0221
81 """
82 Infer output layout for SwiGLU.
84 Args:
85 cache_values (list): [input_layout, axis, input_shape]
87 Returns:
88 tuple: ((output_layout,), None)
90 Raises:
91 ValueError: If input has Partial status, axis is invalid, or the split
92 axis length is not divisible by 2.
93 """
94 layout = cache_values[0]
95 axis = cache_values[1]
96 input_shape = cache_values[2]
98 if not self._allow_partial_inputs:
99 self._check_partial_inputs([layout])
101 if not isinstance(axis, int):
102 raise ValueError(
103 f"For {self.op_name}, axis should be int, but got {type(axis)}"
104 )
106 # Use alias_tensor_map to support StridedShard multi-axis mappings.
107 alias_map = layout.alias_tensor_map
108 ndim = len(alias_map)
110 if axis < 0:
111 axis += ndim
112 if axis < 0 or axis >= ndim:
113 raise ValueError(
114 f"For {self.op_name}, axis out of range "
115 f"(expected to be in range of [{-ndim}, {ndim - 1}], but got {cache_values[1]})"
116 )
118 # The split axis may be sharded — the split is performed on the local
119 # shard. When the split axis is sharded, the producer layout strategy is
120 # expected to make each local shard contain paired gate/up halves.
121 #
122 # The split axis must have an even global length so it can be halved into
123 # gate and up within each shard.
124 axis_size = input_shape[axis]
125 if axis_size % 2 != 0:
126 raise ValueError(
127 f"For {self.op_name}, the split axis (dim {axis}) must have an even size, "
128 f"but got {axis_size}. SwiGLU splits the input along this axis "
129 f"into two equal halves for gate and up."
130 )
132 return (copy.deepcopy(layout),), None