1212from megatron .core .utils import get_attr_wrapped_model
1313
1414
15+ def validate_dynamic_inference_model (model : MegatronModule ) -> None :
16+ """Reject incompatible direct specs before model-global inference buffers are allocated."""
17+
18+ from megatron .core .models .hybrid .hybrid_architecture import ResolvedHybridArchitecture
19+
20+ try :
21+ architecture = get_attr_wrapped_model (model , "resolved_hybrid_architecture" )
22+ except RuntimeError :
23+ return
24+ if not isinstance (architecture , ResolvedHybridArchitecture ):
25+ return
26+ if architecture .source != "direct" :
27+ return
28+
29+ model_config = get_attr_wrapped_model (model , "config" , allow_none = False )
30+ if architecture .has_incompatible_dynamic_inference_shapes (model_config ):
31+ raise NotImplementedError (
32+ "Direct HybridModel occurrence configurations are incompatible with dynamic "
33+ "inference's model-global cache or runtime buffers (Mamba state/cache dimensions, "
34+ "attention KV dimensions, or MoE router top-k values)."
35+ )
36+
37+
1538@dataclass
1639class MambaInferenceStateConfig :
1740 """
@@ -49,14 +72,41 @@ def from_model(
4972 model : MegatronModule ,
5073 conv_states_dtype : Optional [torch .dtype ] = None ,
5174 ssm_states_dtype : Optional [torch .dtype ] = None ,
75+ * ,
76+ validate_dynamic_inference : bool = True ,
5277 ) -> Optional ["MambaInferenceStateConfig" ]:
53- """Returns Mamba inference state config from the model if it is a hybrid model."""
78+ """Returns Mamba inference state config from the model if it is a hybrid model.
79+
80+ Args:
81+ validate_dynamic_inference: Validate direct specs against the model-global buffers
82+ used by dynamic inference. The explicit legacy static engine disables this
83+ because its Mamba, attention, and MoE state is allocated by each layer.
84+ """
5485 from megatron .core .models .hybrid .hybrid_layer_allocation import Symbols
5586
87+ if validate_dynamic_inference :
88+ validate_dynamic_inference_model (model )
5689 decoder = get_attr_wrapped_model (model , "decoder" )
5790 layer_type_list = getattr (decoder , "layer_type_list" , None )
91+ # HybridStack's first-class API exposes stable semantic names, while
92+ # dynamic inference's layer maps intentionally retain legacy symbols.
93+ semantic_to_symbol = {
94+ "mamba" : Symbols .MAMBA ,
95+ "gdn" : Symbols .GDN ,
96+ "attention" : Symbols .ATTENTION ,
97+ "dsa" : Symbols .DS_ATTENTION ,
98+ "mla" : Symbols .MLA ,
99+ "mlp" : Symbols .MLP ,
100+ "moe" : Symbols .MOE ,
101+ }
102+ if layer_type_list is not None and any (
103+ layer_type in semantic_to_symbol for layer_type in layer_type_list
104+ ):
105+ layer_type_list = [
106+ semantic_to_symbol .get (layer_type , layer_type ) for layer_type in layer_type_list
107+ ]
58108 if layer_type_list is not None and Symbols .MAMBA in layer_type_list :
59- ( mamba_conv_states_shape , mamba_ssm_states_shape ) = (
109+ mamba_conv_states_shape , mamba_ssm_states_shape = (
60110 decoder .mamba_state_shapes_per_request ()
61111 )
62112 if conv_states_dtype is None :
@@ -73,7 +123,7 @@ def from_model(
73123 elif ssm_states_dtype is None :
74124 ssm_states_dtype = model .config .params_dtype
75125 mamba_chunk_size = 128
76- for layer_type , layer in zip (decoder . layer_type_list , decoder .layers ):
126+ for layer_type , layer in zip (layer_type_list , decoder .layers ):
77127 if layer_type == Symbols .MAMBA and hasattr (layer , 'mixer' ):
78128 mamba_chunk_size = layer .mixer .chunk_size
79129 break
0 commit comments