1# Copyright 2025 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"""Layer's blocks submodule"""
16from __future__ import annotations
17from typing import TYPE_CHECKING
18from hyper_parallel.auto_parallel.sapp_nd.nd.common.layer_type import LayerType
19from hyper_parallel.auto_parallel.sapp_nd.memory_estimation.evaluators.utils import EvalUtils
20
21if TYPE_CHECKING:
22 from hyper_parallel.auto_parallel.sapp_nd.nd.common.cost_model_preprocess import CostModelConfig
23 from hyper_parallel.auto_parallel.sapp_nd.memory_estimation._context import Context
24
25mb = EvalUtils.mb
26
27
28class EvalAttn:
29 """Attention formulas class"""
30
31 @staticmethod
32 def num_params_mla(ccfg: CostModelConfig, _) -> float:
33 """Parameters count for Multi-Head Latent Attention"""
34 # W_up_q = ccfg.dc_q * ccfg.dh * ccfg.a
35 # W_up_k = ccfg.dc_kv * ccfg.dh * ccfg.n_kv
36 # W_up_v = ccfg.dc_kv * ccfg.dh * ccfg.n_kv
37 # W_down_q = ccfg.dc_q * ccfg.h
38 # W_down_kv = ccfg.dc_kv * ccfg.h
39 # W_q_rope = ccfg.a * ccfg.dhr * ccfg.dc_q
40 # W_k_rope = ccfg.dhr * ccfg.h
41 # Wo = ccfg.h * ccfg.a * ccfg.dh
42
43 c_kv_fact = ccfg.dc_kv * (ccfg.n_kv * ccfg.dh + ccfg.h)
44 c_q_fact = ccfg.dc_q * (ccfg.a * ccfg.dh + ccfg.h + ccfg.a * ccfg.dhr)
45 rest_fact = (ccfg.h * ccfg.a * ccfg.dh) + (ccfg.h * ccfg.dhr)
46 res = (
47 0.5 * ccfg.n_attMM * c_kv_fact
48 + 0.25 * ccfg.n_attMM * c_q_fact
49 + 0.25 * ccfg.n_attMM * rest_fact
50 )
51 return res
52
53 @staticmethod
54 def num_params_attn(ccfg: CostModelConfig, ctx: Context) -> float:
55 """Parameters count for Multi-Head/Grouped-Q./Multi-Q. Attention"""
56 if ccfg.dc_kv == 0:
57 # Q,O and K,V have distinct shapes
58 return 0.5 * ccfg.n_attMM * (
59 ccfg.h * ccfg.h + ccfg.h
60 ) + 0.5 * ccfg.n_attMM * (ccfg.h * ccfg.n_kv * ccfg.dh + ccfg.h)
61 return EvalAttn.num_params_mla(ccfg, ctx)
62
63 @staticmethod
64 def attn_qkv_activations(ccfg: CostModelConfig, ctx: Context) -> float:
65 """QKV linear Activations"""
66 rec_layer = ctx.current_node == LayerType.SEL_REC_LAYER
67 att_qkv_size = 0
68 if ccfg.dc_kv == 0:
69 n_op = ccfg.n_attMM + ccfg.n_attParamCast
70 att_qkv_size = (
71 ccfg.s
72 * ccfg.b
73 * ccfg.bytes_compute
74 * (
75 0.25 * n_op * ccfg.h
76 + 0.5 * n_op * ccfg.dh * ccfg.n_kv
77 + EvalUtils.rec_coeff(rec_layer, ccfg.rec_op.attBMM)
78 * ccfg.n_attBMM
79 * ccfg.dh
80 )
81 )
82 else:
83 q_size = (
84 0.25
85 * (ccfg.n_attMM + ccfg.n_attParamCast)
86 * (ccfg.dc_q + 2 * ccfg.a * (ccfg.dh + ccfg.dhr))
87 )
88 k_size = (
89 0.25
90 * (ccfg.n_attMM + ccfg.n_attParamCast)
91 * (ccfg.dhr + ccfg.n_kv * (2 * ccfg.dh + ccfg.dhr))
92 )
93 v_size = (
94 0.25
95 * (ccfg.n_attMM + ccfg.n_attParamCast)
96 * (ccfg.n_kv * ccfg.dh + ccfg.dc_kv)
97 )
98 att_qkv_size = (
99 ccfg.s
100 * ccfg.b
101 * ccfg.bytes_compute
102 * (
103 q_size
104 + k_size
105 + v_size
106 + EvalUtils.rec_coeff(rec_layer, ccfg.rec_op.attBMM)
107 * ccfg.n_attBMM
108 * ccfg.dh
109 )
110 )
111 micro_factor = ctx.micro_factor
112 return micro_factor * att_qkv_size / (ccfg.t * ccfg.cp)
113
114 @staticmethod
115 def attn_score_activations(ccfg: CostModelConfig, ctx: Context) -> float:
116 """Score/Softmax Activations"""
117 rec_layer = ctx.current_node == LayerType.SEL_REC_LAYER
118 att_score = (
119 ccfg.s_fa
120 * ccfg.b
121 * ccfg.a
122 * ccfg.s
123 * (
124 ccfg.n_softmax
125 * (
126 ccfg.rec_op.softmax * ccfg.bytes_softmax
127 + EvalUtils.rec_coeff(rec_layer, ccfg.rec_op.dropout)
128 * ccfg.bytes_dropout
129 + EvalUtils.rec_coeff(rec_layer, ccfg.rec_op.headCast)
130 * ccfg.bytes_compute
131 )
132 )
133 )
134 micro_factor = ctx.micro_factor
135 return micro_factor * att_score / (ccfg.t * ccfg.cp)
136
137 @staticmethod
138 def attn_proj_activations(ccfg: CostModelConfig, ctx: Context) -> float:
139 """Output projection Activations"""
140 rec_layer = ctx.current_node == LayerType.SEL_REC_LAYER
141 att_proj = (
142 ccfg.s
143 * ccfg.b
144 * ccfg.h
145 * ccfg.bytes_compute
146 * (
147 0.25 * (ccfg.n_attMM + ccfg.n_attParamCast)
148 + EvalUtils.rec_coeff(rec_layer, ccfg.rec_op.dropout)
149 * ccfg.n_dropout
150 * ccfg.bytes_dropout
151 )
152 )
153 micro_factor = ctx.micro_factor
154 return micro_factor * att_proj / max(ccfg.sp, ccfg.cp)
155
156
157class EvalFFn:
158 """Feed-forward formulas class"""
159
160 @staticmethod
161 def num_params_ffn(ccfg: CostModelConfig, _) -> float:
162 """Parameters count"""
163 experts_param_size = (
164 (ccfg.n_exp + ccfg.n_shared_exp)
165 * max(ccfg.n_ffMM, ccfg.n_ffBMM)
166 * (ccfg.hff * ccfg.h + ccfg.hff)
167 )
168 return experts_param_size
169
170 @staticmethod
171 def num_params_routed_expert(ccfg: CostModelConfig, _) -> float:
172 """Routed expert parameters count (with ETP correction)"""
173 hff_sliced = ccfg.hff_exp / max(ccfg.etp, 1)
174 return ccfg.n_exp * max(ccfg.n_ffMM, ccfg.n_ffBMM) * (hff_sliced * ccfg.h + hff_sliced)
175
176 @staticmethod
177 def num_params_shared_expert(ccfg: CostModelConfig, _) -> float:
178 """Shared expert parameters count"""
179 return ccfg.n_shared_exp * max(ccfg.n_ffMM, ccfg.n_ffBMM) * (ccfg.hff * ccfg.h + ccfg.hff)
180
181 @staticmethod
182 def ffn_activations(ccfg: CostModelConfig, ctx: Context) -> float:
183 """ "Activations count"""
184 rec_layer = ctx.current_node == LayerType.SEL_REC_LAYER
185 tok_size = ccfg.s * ccfg.b
186 n_mm = max(ccfg.n_ffMM, ccfg.n_ffBMM)
187 if n_mm % 2 == 0:
188 matmul = 0.5 * ccfg.h + 0.5 * ccfg.hff
189 else:
190 matmul = 1 / 3 * ccfg.h + 2 / 3 * ccfg.hff
191 matmul *= ccfg.bytes_compute * n_mm
192 activ_fun = ccfg.bytes_compute * ccfg.hff
193 activ_fun *= EvalUtils.rec_coeff(rec_layer, ccfg.rec_op.ffAct)
194 pcast = ccfg.bytes_compute * ccfg.hff * ccfg.n_ffParamCast
195 activ_size = matmul + pcast + activ_fun
196 micro_factor = ctx.micro_factor
197 return micro_factor * tok_size * activ_size / (ccfg.t * ccfg.cp)
198
199 @staticmethod
200 def ffn_router_and_concat_activations(
201 ccfg: CostModelConfig, ctx: Context
202 ) -> float:
203 """MoE router and output activations"""
204 # Router activations (logits, probs, mask)
205 r = ccfg.s * ccfg.b * ccfg.bytes_compute
206 r *= 2 * ccfg.n_exp + ccfg.n_chosen_exp
207 # Concat all exp output
208 c = ccfg.s * ccfg.b * ccfg.bytes_compute * ccfg.h
209 micro_factor = ctx.micro_factor
210 return micro_factor * (r + c) / (ccfg.t * ccfg.cp)
211
212 @staticmethod
213 def shared_exp_activations(ccfg: CostModelConfig, ctx: Context) -> float:
214 """Shared expert activations"""
215 return ccfg.n_shared_exp * EvalFFn.ffn_activations(ccfg, ctx)
216
217 @staticmethod
218 def routed_exp_activations(ccfg: CostModelConfig, ctx: Context) -> float:
219 """MoE topK activations"""
220 tok_size = ccfg.s * ccfg.b
221 activ_size = EvalFFn.ffn_activations(ccfg, ctx) / tok_size
222 avg_num_toks = tok_size * ccfg.n_chosen_exp / ccfg.n_exp
223 if not ccfg.gmm: # Capacity mode
224 expert_capacity = avg_num_toks * ccfg.cap_fact * ccfg.n_exp
225 routed_activ = activ_size * expert_capacity
226 else: # Dropless mode
227 load = avg_num_toks * ccfg.n_exp * ctx.dropless_tok_factor
228 routed_activ = load * activ_size
229 return routed_activ
230
231 @staticmethod
232 def ffn_moe_activations(ccfg: CostModelConfig, ctx: Context) -> float:
233 """Sum of Activations"""
234 return (
235 EvalFFn.routed_exp_activations(ccfg, ctx)
236 + EvalFFn.shared_exp_activations(ccfg, ctx)
237 + EvalFFn.ffn_router_and_concat_activations(ccfg, ctx)
238 )
239
240
241class EvalNorm:
242 """Normalization formulas class"""
243
244 @staticmethod
245 def num_params_norm(ccfg: CostModelConfig, _) -> float:
246 """Parameters count"""
247 return ccfg.n_normOp * 2 * ccfg.h
248
249 @staticmethod
250 def norm_activations(ccfg: CostModelConfig, ctx: Context) -> float:
251 """Activations"""
252 rec_layer = ctx.current_node == LayerType.SEL_REC_LAYER
253 norm = (
254 ccfg.s
255 * ccfg.b
256 * ccfg.bytes_norm
257 * ccfg.h
258 * ccfg.n_normOp
259 * EvalUtils.rec_coeff(rec_layer, ccfg.rec_op.normOp)
260 )
261 micro_factor = ctx.micro_factor
262 return micro_factor * norm / (ccfg.t * ccfg.cp)