@@ -142,6 +142,20 @@ def calculate_layer_counts():
142142 """Calculate the number of attention, Mamba, MLP, MoE, and GDN layers."""
143143 if hasattr (cfg .model , "hybrid_layer_pattern" ) and cfg .model .hybrid_layer_pattern :
144144 counts = {"M" : 0 , "G" : 0 , "*" : 0 , "-" : 0 , "E" : 0 }
145+ try :
146+ hybrid_allocation = importlib .import_module ("megatron.core.models.hybrid.hybrid_layer_allocation" )
147+ layer_counts = hybrid_allocation .get_hybrid_layer_counts (cfg .model .hybrid_layer_pattern )
148+ symbols = hybrid_allocation .Symbols
149+ return (
150+ layer_counts [symbols .ATTENTION ],
151+ layer_counts [symbols .MAMBA ],
152+ layer_counts [symbols .MLP ],
153+ layer_counts [symbols .MOE ],
154+ layer_counts [symbols .GDN ],
155+ )
156+ except (AttributeError , ImportError , KeyError , ModuleNotFoundError ):
157+ pass
158+
145159 try :
146160 parse_hybrid_pattern = importlib .import_module (
147161 "megatron.core.ssm.mamba_hybrid_layer_allocation"
@@ -155,7 +169,7 @@ def calculate_layer_counts():
155169 for layer_type in parsed .mtp_pattern :
156170 if layer_type in counts :
157171 counts [layer_type ] += parsed .mtp_num_depths
158- except (ImportError , ModuleNotFoundError ):
172+ except (AttributeError , ImportError , ModuleNotFoundError ):
159173 for layer_type in cfg .model .hybrid_layer_pattern :
160174 if layer_type in counts :
161175 counts [layer_type ] += 1
@@ -206,19 +220,81 @@ def attn_layer_flops(
206220 num_heads ,
207221 gqa_groups = 8 ,
208222 kv_channels = None ,
223+ core_seq_factor = None ,
209224 ):
210225 """Calculate FLOPs for an attention layer."""
211226 p = (kv_channels * num_heads / hidden_size ) if kv_channels else 1
212227 g = gqa_groups
228+ core_seq_factor = seq_len if core_seq_factor is None else core_seq_factor
213229 return (
214- 4
215- * batch_size
216- * seq_len
217- * hidden_size
218- * p
219- * (hidden_size + (hidden_size * (g / num_heads )) + (seq_len / 2 ))
230+ 4 * batch_size * seq_len * hidden_size * p * (hidden_size + (hidden_size * (g / num_heads )))
231+ + 2 * batch_size * seq_len * hidden_size * p * core_seq_factor
220232 )
221233
234+ def calculate_swa_context ():
235+ """Calculate the average causal sliding-window context length."""
236+ window_size = getattr (cfg .model , "window_size" , None )
237+ if window_size is None :
238+ return None
239+ if isinstance (window_size , (list , tuple )):
240+ effective_window = window_size [0 ] + window_size [1 ] + 1
241+ else :
242+ effective_window = window_size
243+
244+ if effective_window < effective_seq_length :
245+ return effective_window - effective_window * (effective_window - 1 ) / (2 * effective_seq_length )
246+ return core_attn_seq_factor / 2
247+
248+ def is_swa_layer (layer_number : int ) -> bool :
249+ """Return whether the 1-indexed physical layer uses sliding-window attention."""
250+ window_size = getattr (cfg .model , "window_size" , None )
251+ if window_size is None :
252+ return False
253+ window_attn_skip_freq = getattr (cfg .model , "window_attn_skip_freq" , None )
254+ if window_attn_skip_freq is None :
255+ return True
256+ if isinstance (window_attn_skip_freq , int ):
257+ return layer_number % window_attn_skip_freq != 0
258+ if isinstance (window_attn_skip_freq , list ):
259+ return layer_number <= len (window_attn_skip_freq ) and bool (window_attn_skip_freq [layer_number - 1 ])
260+ return False
261+
262+ def count_hybrid_swa_attention_layers (num_attn_layers : int ) -> int :
263+ """Count SWA attention symbols in the main physical hybrid pattern."""
264+ hybrid_pattern = getattr (cfg .model , "hybrid_layer_pattern" , None )
265+ if not hybrid_pattern or getattr (cfg .model , "window_size" , None ) is None :
266+ return 0
267+ try :
268+ hybrid_allocation = importlib .import_module ("megatron.core.models.hybrid.hybrid_layer_allocation" )
269+ parsed = hybrid_allocation .parse_hybrid_pattern (hybrid_pattern )
270+ main_pattern = parsed .main_pattern or ""
271+ attention_symbol = hybrid_allocation .Symbols .ATTENTION
272+ pipe_symbol = hybrid_allocation .Symbols .PIPE
273+ except (AttributeError , ImportError , ModuleNotFoundError ):
274+ try :
275+ parse_hybrid_pattern = importlib .import_module (
276+ "megatron.core.ssm.mamba_hybrid_layer_allocation"
277+ ).parse_hybrid_pattern
278+ parsed = parse_hybrid_pattern (hybrid_pattern )
279+ main_pattern = parsed .main_pattern or ""
280+ except (AttributeError , ImportError , ModuleNotFoundError ):
281+ main_pattern = hybrid_pattern .split ("/" , 1 )[0 ]
282+ attention_symbol = "*"
283+ pipe_symbol = "|"
284+
285+ num_swa_layers = 0
286+ num_main_attn_layers = 0
287+ for layer_number , layer_type in enumerate (main_pattern .replace (pipe_symbol , "" ), start = 1 ):
288+ if layer_type != attention_symbol :
289+ continue
290+ num_main_attn_layers += 1
291+ if is_swa_layer (layer_number ):
292+ num_swa_layers += 1
293+
294+ # MTP attention layers are counted in num_attn_layers, but they do not
295+ # correspond to main-pattern layer numbers for window_attn_skip_freq.
296+ return min (num_swa_layers , num_attn_layers , num_main_attn_layers )
297+
222298 def mamba_layer_flops (
223299 batch_size ,
224300 seq_len ,
@@ -296,18 +372,38 @@ def hybrid_flops(
296372 gdn_conv_kernel_dim = 4 ,
297373 vocab_size = 256000 ,
298374 mtp_num_layers = 0 ,
375+ core_seq_factor = None ,
376+ num_swa_attn_layers = 0 ,
377+ swa_context = None ,
299378 ):
300379 """Calculate total FLOPs for the hybrid model."""
301- flops_fwd = (
302- num_attn_layers
303- * attn_layer_flops (
380+ num_full_attn_layers = num_attn_layers - num_swa_attn_layers
381+ full_attn_flops = num_full_attn_layers * attn_layer_flops (
382+ batch_size ,
383+ seq_len ,
384+ hidden_size ,
385+ num_attn_heads ,
386+ gqa_groups ,
387+ kv_channels ,
388+ core_seq_factor = core_seq_factor ,
389+ )
390+ swa_attn_flops = 0
391+ if num_swa_attn_layers > 0 :
392+ if swa_context is None :
393+ raise ValueError ("swa_context must be set when num_swa_attn_layers > 0" )
394+ swa_attn_flops = num_swa_attn_layers * attn_layer_flops (
304395 batch_size ,
305396 seq_len ,
306397 hidden_size ,
307398 num_attn_heads ,
308399 gqa_groups ,
309400 kv_channels ,
401+ core_seq_factor = 2 * swa_context ,
310402 )
403+
404+ flops_fwd = (
405+ full_attn_flops
406+ + swa_attn_flops
311407 + num_mlp_layers * mlp_layer_flops (batch_size , seq_len , hidden_size , mlp_expansion , swiglu )
312408 + num_mamba_layers
313409 * mamba_layer_flops (
@@ -781,8 +877,9 @@ def _compute_vit_flops():
781877 patches_per_image = num_vision_patches / batch_size if batch_size > 0 else num_vision_patches
782878 return vit_flops (cfg , batch_size , patches_per_image )
783879
784- # Main entrypoint for FLOPs calculation.
785- if getattr (cfg .model , "is_hybrid_model" , False ):
880+ # Main entrypoint for FLOPs calculation. Mirror MCore's hybrid detection:
881+ # a physical hybrid pattern is sufficient to select hybrid accounting.
882+ if getattr (cfg .model , "is_hybrid_model" , False ) or getattr (cfg .model , "hybrid_layer_pattern" , None ):
786883 # Calculate the number of each type of layer.
787884 num_attn_layers , num_mamba_layers , num_mlp_layers , num_moe_layers , num_gdn_layers = calculate_layer_counts ()
788885 mtp_num_layers = getattr (cfg .model , "mtp_num_layers" , None )
@@ -809,6 +906,8 @@ def _compute_vit_flops():
809906 num_query_groups = (
810907 cfg .model .num_attention_heads if cfg .model .num_query_groups is None else cfg .model .num_query_groups
811908 )
909+ num_swa_attn_layers = count_hybrid_swa_attention_layers (num_attn_layers )
910+ swa_context = calculate_swa_context () if num_swa_attn_layers > 0 else None
812911
813912 # Compute hybrid model FLOPs.
814913 llm_flops = hybrid_flops (
@@ -848,6 +947,9 @@ def _compute_vit_flops():
848947 gdn_conv_kernel_dim = getattr (cfg .model , "linear_conv_kernel_dim" , None ) or 4 ,
849948 vocab_size = padded_vocab_size ,
850949 mtp_num_layers = mtp_num_layers ,
950+ core_seq_factor = core_attn_seq_factor ,
951+ num_swa_attn_layers = num_swa_attn_layers ,
952+ swa_context = swa_context ,
851953 )
852954 return llm_flops + _compute_vit_flops ()
853955 else :
0 commit comments