@@ -733,31 +733,49 @@ def __init__(self, config: MiniMaxH3Config, hf_config: dict[str, Any]) -> None:
733733 )
734734 self .__post_init__ ()
735735
736+ @staticmethod
737+ def _compile_setup_device (attention : MiniMaxH3Attention ) -> torch .device :
738+ """Return the loaded device even when FP8 replaced the query weight."""
739+ query_state = next (attention .to_q .parameters (), None )
740+ if query_state is None :
741+ query_state = next (attention .to_q .buffers (), None )
742+ if query_state is None :
743+ raise RuntimeError ("MiniMax H3 to_q has no materialized parameter or buffer for compile setup." )
744+ return query_state .device
745+
736746 def prepare_for_compile (self ) -> None :
737747 """Pipeline hook, called once right before torch.compile wraps the blocks.
738748
739- Resolve each loaded VSA compression gate eagerly. Generic and training
740- compile retain their established attention dispatch; only the
741- inference loader's separate ``prepare_for_regional_compile`` hook may
742- preselect the inference-only sm_100a path.
749+ Resolve each loaded VSA compression gate eagerly and tensorize its
750+ layer identity so repeated blocks share one Dynamo graph. Generic and
751+ training compile retain their established attention dispatch; only
752+ the inference loader's separate ``prepare_for_regional_compile`` hook
753+ may preselect the inference-only sm_100a path.
743754
744755 The inference-only Triton fusions expose fake-backed custom operators,
745756 so Dynamo can keep them active as opaque nodes inside each fullgraph
746757 block instead of tracing into their launcher implementation.
747758 """
748759 gate_states : list [bool ] = []
760+ prepared_vsa_impls = 0
749761 for block in self .transformer_blocks :
750762 attention = block .attn
751763 if attention .to_gate_compress is not None :
752764 attention ._resolve_gate_compress_for_compile ()
753765 assert attention ._gate_compress_active is not None
754766 gate_states .append (attention ._gate_compress_active )
767+ prepare_vsa = getattr (attention .distributed_attention .attn_impl , "prepare_for_compile" , None )
768+ if callable (prepare_vsa ):
769+ prepare_vsa (self ._compile_setup_device (attention ))
770+ prepared_vsa_impls += 1
755771 if gate_states :
756772 logger .info (
757773 "Resolved MiniMax H3 VSA compression gates before torch.compile: %d active, %d inactive" ,
758774 sum (gate_states ),
759775 len (gate_states ) - sum (gate_states ),
760776 )
777+ if prepared_vsa_impls :
778+ logger .info ("Prepared %d MiniMax H3 VSA layer indices for torch.compile" , prepared_vsa_impls )
761779 if self .enabled_fusions :
762780 logger .info (
763781 "MiniMax H3 inference fusions remain active under torch.compile through custom-op boundaries: %s" ,
@@ -774,14 +792,7 @@ def prepare_for_regional_compile(self) -> str | None:
774792 prepare_vsa = getattr (attention .distributed_attention .attn_impl , "prepare_for_regional_compile" , None )
775793 if not callable (prepare_vsa ):
776794 continue
777- # Post-load FP8 conversion may replace to_q.weight with packed
778- # buffers. Either representation identifies the local device.
779- query_state = next (attention .to_q .parameters (), None )
780- if query_state is None :
781- query_state = next (attention .to_q .buffers (), None )
782- if query_state is None :
783- raise RuntimeError ("MiniMax H3 to_q has no materialized parameter or buffer for compile setup." )
784- unsupported = prepare_vsa (query_state .device )
795+ unsupported = prepare_vsa (self ._compile_setup_device (attention ))
785796 if unsupported :
786797 unsupported_reasons .add (str (unsupported ))
787798 prepared_vsa_impls += 1
0 commit comments