@@ -793,9 +793,12 @@ def __call__(
793793 kv_caches : list [jax .Array ] | None = None ,
794794 attention_metadata = None ,
795795 deepstack_visual_embeds : None | list [jnp .ndarray ] = None ,
796+ forced_routed_experts : jax .Array | None = None ,
796797 ):
797798 cfg = self .config
798799 mesh = self .mesh
800+ if cfg .use_batch_split_schedule and forced_routed_experts is not None :
801+ raise NotImplementedError ("Forced routing mismatch measurement is not supported with batch split schedule." )
799802 assert decoder_input_tokens .ndim == 2 # [batch, len]
800803
801804 # [batch, length] -> [batch, length, emb_dim]
@@ -882,24 +885,44 @@ def __call__(
882885 }
883886 dense_layer = RemattedBlockLayers [0 ]
884887 moe_layer = RemattedBlockLayers [1 ]
885- if cfg .engram_layers :
886- original_dense_call = dense_layer .__call__
887- original_moe_call = moe_layer .__call__
888- dense_layer .__call__ = functools .partial (dense_layer .__call__ , ** layer_call_kwargs )
889- moe_layer .__call__ = functools .partial (moe_layer .__call__ , ** layer_call_kwargs )
890888
889+ dense_broadcast_args = list (broadcast_args )
890+ dense_in_axes_tuple = [nn .broadcast ] * len (broadcast_args )
891+ input_tokens = decoder_input_tokens if cfg .engram_layers else None
892+ dense_broadcast_args .extend ([previous_chunk , slot , None , attention_metadata , input_tokens ])
893+ dense_in_axes_tuple .extend ([nn .broadcast ] * 5 )
894+
895+ moe_broadcast_args = list (broadcast_args )
896+ moe_in_axes_tuple = [nn .broadcast ] * len (broadcast_args )
897+ moe_broadcast_args .extend ([previous_chunk , slot , None , attention_metadata , input_tokens ])
898+ moe_in_axes_tuple .extend ([nn .broadcast ] * 5 )
899+
900+ num_moe_layers = cfg .num_decoder_layers - cfg .first_num_dense_layers
901+
902+ forced_routed_experts_t = None
903+ if forced_routed_experts is not None :
904+ forced_routed_experts_t = jnp .transpose (forced_routed_experts , (2 , 0 , 1 , 3 ))
905+ moe_broadcast_args .append (forced_routed_experts_t )
906+ moe_in_axes_tuple .append (0 )
907+ else :
908+ moe_broadcast_args .append (None )
909+ moe_in_axes_tuple .append (nn .broadcast )
910+
911+ if cfg .engram_layers :
891912 common_kwargs = {
892913 "dense_layer" : dense_layer ,
893914 "moe_layer" : moe_layer ,
894- "original_dense_call" : original_dense_call ,
895- "original_moe_call" : original_moe_call ,
896915 "layer_call_kwargs" : layer_call_kwargs ,
897916 "decoder_segment_ids" : decoder_segment_ids ,
898917 "decoder_positions" : decoder_positions ,
899918 "deterministic" : deterministic ,
900919 "model_mode" : model_mode ,
901920 "decoder_input_tokens" : decoder_input_tokens ,
902- "broadcast_args" : broadcast_args ,
921+ "dense_broadcast_args" : dense_broadcast_args ,
922+ "dense_in_axes" : dense_in_axes_tuple ,
923+ "moe_broadcast_args" : moe_broadcast_args ,
924+ "moe_in_axes" : moe_in_axes_tuple ,
925+ "forced_routed_experts" : forced_routed_experts_t ,
903926 }
904927
905928 # Apply Dense Layers
@@ -922,23 +945,22 @@ def __call__(
922945 ** common_kwargs ,
923946 )
924947 else :
925- dense_layer .__call__ = functools .partial (dense_layer .__call__ , ** layer_call_kwargs )
926948 y , _ = self .scan_decoder_layers (
927949 cfg ,
928950 dense_layer ,
929951 cfg .first_num_dense_layers ,
930952 "dense_layers" ,
931953 mesh ,
932- in_axes_tuple = ( nn . broadcast ,) * len ( broadcast_args ),
954+ in_axes_tuple = tuple ( dense_in_axes_tuple ),
933955 model_mode = model_mode ,
934- )(y , * broadcast_args )
935- moe_layer .__call__ = functools .partial (moe_layer .__call__ , ** layer_call_kwargs )
936- num_moe_layers = cfg .num_decoder_layers - cfg .first_num_dense_layers
956+ )(y , * dense_broadcast_args )
937957
938958 # If batch-split schedule is used and initialization is complete,
939959 # as detected by immutable params, use deepseek_batchsplit custom
940960 # scan with initialized parameters.
941961 if cfg .use_batch_split_schedule and not self .is_mutable_collection ("params" ):
962+ if forced_routed_experts is not None :
963+ raise NotImplementedError ("Forced routing mismatch measurement is not supported with batch split schedule." )
942964 # old version of batch-split that fully uses qwix quantization.
943965 if cfg .use_qwix_quantization and not cfg .use_manual_quantization :
944966 y = deepseek_batchsplit_fp8 .scan_batch_split_layers (
@@ -971,9 +993,9 @@ def __call__(
971993 num_moe_layers ,
972994 "moe_layers" ,
973995 mesh ,
974- in_axes_tuple = ( nn . broadcast ,) * len ( broadcast_args ),
996+ in_axes_tuple = tuple ( moe_in_axes_tuple ),
975997 model_mode = model_mode ,
976- )(y , * broadcast_args )
998+ )(y , * moe_broadcast_args )
977999 elif cfg .decoder_block == DecoderBlockType .GEMMA3 :
9781000 bidirectional_mask_value = multimodal_input .bidirectional_mask if multimodal_input is not None else None
9791001 y = self ._apply_gemma3_scanned_blocks (
@@ -1012,19 +1034,35 @@ def __call__(
10121034 current_broadcast_args = list (broadcast_args )
10131035 current_in_axes_tuple = list (in_axes_tuple )
10141036
1037+ if forced_routed_experts is not None :
1038+ # Transpose [B, L, N, E] -> [N, B, L, E] for scan
1039+ forced_routed_experts_t = jnp .transpose (forced_routed_experts , (2 , 0 , 1 , 3 ))
1040+ cycle_interval = cfg .inhomogeneous_layer_cycle_interval
1041+ reshaped_forced = jnp .reshape (
1042+ forced_routed_experts_t ,
1043+ (scan_length , cycle_interval ) + forced_routed_experts_t .shape [1 :]
1044+ )
1045+ else :
1046+ reshaped_forced = None
1047+
10151048 if kv_caches is not None :
10161049 # Stack kv_caches for scan: [num_layers, ...]
10171050 stacked_kv_cache = jnp .stack (kv_caches , axis = 0 )
10181051
10191052 # We pass (y, stacked_kv_cache, 0) as the carry
10201053 carry = (y , stacked_kv_cache , 0 )
10211054
1022- # We don't pass kv_cache as a scanned argument anymore
1023-
10241055 # Pass None for previous_chunk, slot, kv_cache to align with __call__ signature
10251056 current_broadcast_args .extend ([None , None , None , attention_metadata ])
10261057 current_in_axes_tuple .extend ([nn .broadcast ] * 4 )
10271058
1059+ if reshaped_forced is not None :
1060+ current_broadcast_args .append (reshaped_forced )
1061+ current_in_axes_tuple .append (0 )
1062+ else :
1063+ current_broadcast_args .append (None )
1064+ current_in_axes_tuple .append (nn .broadcast )
1065+
10281066 max_logging .info (f"DEBUG: len(current_broadcast_args)={ len (current_broadcast_args )} " )
10291067 max_logging .info (f"DEBUG: current_broadcast_args={ [type (a ) for a in current_broadcast_args ]} " )
10301068
@@ -1046,8 +1084,15 @@ def __call__(
10461084 kv_caches [i ] = returned_kv_cache [i ]
10471085 else :
10481086 # Fallback to old behavior if kv_caches is None (not vLLM RPA)
1049- current_broadcast_args .append (None )
1050- current_in_axes_tuple .append (nn .broadcast )
1087+ current_broadcast_args .extend ([None , None , None , None ])
1088+ current_in_axes_tuple .extend ([nn .broadcast ] * 4 )
1089+
1090+ if reshaped_forced is not None :
1091+ current_broadcast_args .append (reshaped_forced )
1092+ current_in_axes_tuple .append (0 )
1093+ else :
1094+ current_broadcast_args .append (None )
1095+ current_in_axes_tuple .append (nn .broadcast )
10511096
10521097 y , _ = self .scan_decoder_layers (
10531098 cfg ,
@@ -1076,6 +1121,10 @@ def __call__(
10761121 global_layer_idx = global_layer_idx_offset + index
10771122 kv_cache = kv_caches [index ] if kv_caches is not None else None
10781123 input_tokens = decoder_input_tokens if cfg .engram_layers else None
1124+ extra_kwargs = {}
1125+ if layer_prefix == "moe_layers" and forced_routed_experts is not None :
1126+ extra_kwargs ["forced_routed_experts" ] = forced_routed_experts [:, :, index , :]
1127+
10791128 y , kv_cache = layer (
10801129 config = cfg ,
10811130 mesh = mesh ,
@@ -1094,6 +1143,7 @@ def __call__(
10941143 kv_cache = kv_cache ,
10951144 attention_metadata = attention_metadata ,
10961145 decoder_input_tokens = input_tokens ,
1146+ ** extra_kwargs ,
10971147 )
10981148 if kv_caches is not None and kv_cache is not None :
10991149 kv_caches [index ] = kv_cache
@@ -1113,6 +1163,7 @@ def __call__(
11131163 slot = slot ,
11141164 )
11151165 else :
1166+ moe_lyr_idx = 0
11161167 for lyr in range (cfg .num_decoder_layers ):
11171168 RemattedBlockLayer = RemattedBlockLayers [0 ]
11181169 layer_kwargs = {}
@@ -1149,6 +1200,30 @@ def __call__(
11491200 layer = RemattedBlockLayer (
11501201 config = cfg , mesh = mesh , name = f"layers_{ lyr } " , quant = self .quant , model_mode = self .model_mode , ** layer_kwargs
11511202 )
1203+
1204+ is_moe = False
1205+ if cfg .decoder_block in (
1206+ DecoderBlockType .MIXTRAL ,
1207+ DecoderBlockType .QWEN3_MOE ,
1208+ DecoderBlockType .QWEN3_NEXT ,
1209+ DecoderBlockType .QWEN3_5 ,
1210+ DecoderBlockType .QWEN3_CUSTOM_MOE ,
1211+ ):
1212+ is_moe = True
1213+ elif cfg .decoder_block == DecoderBlockType .LLAMA4 :
1214+ is_moe = llama4 .determine_is_moe_layer (lyr , self .config .interleave_moe_layer_step )
1215+
1216+ current_forced_routed_experts = None
1217+ if is_moe and forced_routed_experts is not None :
1218+ current_forced_routed_experts = forced_routed_experts [:, :, moe_lyr_idx , :]
1219+ moe_lyr_idx += 1
1220+ elif is_moe :
1221+ moe_lyr_idx += 1
1222+
1223+ extra_kwargs = {}
1224+ if is_moe and current_forced_routed_experts is not None :
1225+ extra_kwargs ["forced_routed_experts" ] = current_forced_routed_experts
1226+
11521227 y , returned_cache = layer (
11531228 y ,
11541229 decoder_segment_ids ,
@@ -1159,6 +1234,7 @@ def __call__(
11591234 slot = slot ,
11601235 kv_cache = kv_cache ,
11611236 attention_metadata = attention_metadata ,
1237+ ** extra_kwargs ,
11621238 ** layer_call_kwargs ,
11631239 )
11641240 if kv_caches is not None and returned_cache is not None :
@@ -1466,10 +1542,12 @@ def _apply_single_engram_layer(self, y, current_idx, layer_type, **kwargs):
14661542 """Applies a single, unscanned Engram layer."""
14671543 layer = kwargs ["dense_layer" ] if layer_type == "dense" else kwargs ["moe_layer" ]
14681544 layer_prefix = "dense_layers" if layer_type == "dense" else "moe_layers"
1469- original_call = kwargs ["original_dense_call" ] if layer_type == "dense" else kwargs ["original_moe_call" ]
1470- layer_call_kwargs = kwargs ["layer_call_kwargs" ]
14711545
1472- layer .__call__ = original_call
1546+ extra_kwargs = {}
1547+ if layer_type == "moe" and kwargs .get ("forced_routed_experts" ) is not None :
1548+ moe_idx = current_idx - self .config .first_num_dense_layers
1549+ extra_kwargs ["forced_routed_experts" ] = kwargs ["forced_routed_experts" ][moe_idx ]
1550+
14731551 y , _ = layer (
14741552 config = self .config ,
14751553 mesh = self .mesh ,
@@ -1483,27 +1561,35 @@ def _apply_single_engram_layer(self, y, current_idx, layer_type, **kwargs):
14831561 kwargs ["decoder_positions" ],
14841562 kwargs ["deterministic" ],
14851563 kwargs ["model_mode" ],
1564+ previous_chunk = kwargs ["layer_call_kwargs" ]["previous_chunk" ],
1565+ slot = kwargs ["layer_call_kwargs" ]["slot" ],
14861566 decoder_input_tokens = kwargs ["decoder_input_tokens" ],
1487- ** layer_call_kwargs ,
1567+ ** extra_kwargs ,
14881568 )
1489- layer .__call__ = functools .partial (original_call , ** layer_call_kwargs )
14901569 return y
14911570
14921571 def _apply_scanned_chunk (self , y , current_idx , next_boundary , layer_type , ** kwargs ):
14931572 """Applies a contiguous chunk of layers using the scan operation."""
14941573 layer = kwargs ["dense_layer" ] if layer_type == "dense" else kwargs ["moe_layer" ]
14951574 layer_prefix = "dense_layers" if layer_type == "dense" else "moe_layers"
1496- broadcast_args = kwargs ["broadcast_args" ]
1575+ broadcast_args = kwargs ["dense_broadcast_args" ] if layer_type == "dense" else list (kwargs ["moe_broadcast_args" ])
1576+ in_axes_tuple = kwargs ["dense_in_axes" ] if layer_type == "dense" else list (kwargs ["moe_in_axes" ])
14971577 scan_length = next_boundary - current_idx
14981578
14991579 if scan_length > 0 :
1580+ if layer_type == "moe" and broadcast_args [- 1 ] is not None :
1581+ moe_start = current_idx - self .config .first_num_dense_layers
1582+ moe_end = next_boundary - self .config .first_num_dense_layers
1583+ sliced_forced = broadcast_args [- 1 ][moe_start :moe_end ]
1584+ broadcast_args [- 1 ] = sliced_forced
1585+
15001586 y , _ = self .scan_decoder_layers (
15011587 self .config ,
15021588 layer ,
15031589 scan_length ,
15041590 f"{ layer_prefix } _{ current_idx } _{ next_boundary - 1 } " ,
15051591 self .mesh ,
1506- in_axes_tuple = ( nn . broadcast ,) * len ( broadcast_args ),
1592+ in_axes_tuple = tuple ( in_axes_tuple ),
15071593 model_mode = kwargs ["model_mode" ],
15081594 )(y , * broadcast_args )
15091595 return y
0 commit comments