@@ -856,6 +856,7 @@ def __call__(
856856 kv_caches : list [jax .Array ] | None = None ,
857857 attention_metadata = None ,
858858 deepstack_visual_embeds : None | list [jnp .ndarray ] = None ,
859+ forced_routed_experts : jax .Array | None = None ,
859860 ):
860861 cfg = self .config
861862 mesh = self .mesh
@@ -877,6 +878,11 @@ def __call__(
877878 y = mhc_expand (y )
878879
879880 policy = self .get_remat_policy ()
881+ supports_forced_routing = cfg .decoder_block in (
882+ DecoderBlockType .QWEN3_MOE ,
883+ DecoderBlockType .QWEN3_NEXT ,
884+ DecoderBlockType .QWEN3_5 ,
885+ )
880886 RemattedBlockLayers = self .set_remat_policy (self .decoder_layer , policy )
881887 # scan does not support kwargs in layer call, passing broadcast_args as positional arg
882888 broadcast_args = (
@@ -1075,6 +1081,17 @@ def __call__(
10751081 current_broadcast_args = list (broadcast_args )
10761082 current_in_axes_tuple = list (in_axes_tuple )
10771083
1084+ if supports_forced_routing and forced_routed_experts is not None :
1085+ # Transpose [B, L, N, E] -> [N, B, L, E] for scan
1086+ forced_experts_t = jnp .transpose (forced_routed_experts , (2 , 0 , 1 , 3 ))
1087+ cycle_interval = cfg .inhomogeneous_layer_cycle_interval
1088+ forced_routed_experts_t = jnp .reshape (
1089+ forced_experts_t ,
1090+ (scan_length , cycle_interval ) + forced_experts_t .shape [1 :],
1091+ )
1092+ else :
1093+ forced_routed_experts_t = None
1094+
10781095 if kv_caches is not None :
10791096 # Stack kv_caches for scan: [num_layers, ...]
10801097 stacked_kv_cache = jnp .stack (kv_caches , axis = 0 )
@@ -1088,6 +1105,14 @@ def __call__(
10881105 current_broadcast_args .extend ([None , None , None , attention_metadata ])
10891106 current_in_axes_tuple .extend ([nn .broadcast ] * 4 )
10901107
1108+ if supports_forced_routing :
1109+ if forced_routed_experts_t is not None :
1110+ current_broadcast_args .append (forced_routed_experts_t )
1111+ current_in_axes_tuple .append (0 )
1112+ else :
1113+ current_broadcast_args .append (None )
1114+ current_in_axes_tuple .append (nn .broadcast )
1115+
10911116 max_logging .info (f"DEBUG: len(current_broadcast_args)={ len (current_broadcast_args )} " )
10921117 max_logging .info (f"DEBUG: current_broadcast_args={ [type (a ) for a in current_broadcast_args ]} " )
10931118
@@ -1109,8 +1134,19 @@ def __call__(
11091134 kv_caches [i ] = returned_kv_cache [i ]
11101135 else :
11111136 # Fallback to old behavior if kv_caches is None (not vLLM RPA)
1112- current_broadcast_args .append (None )
1113- current_in_axes_tuple .append (nn .broadcast )
1137+ if supports_forced_routing :
1138+ current_broadcast_args .extend ([None , None , None , None ])
1139+ current_in_axes_tuple .extend ([nn .broadcast ] * 4 )
1140+
1141+ if forced_routed_experts_t is not None :
1142+ current_broadcast_args .append (forced_routed_experts_t )
1143+ current_in_axes_tuple .append (0 )
1144+ else :
1145+ current_broadcast_args .append (None )
1146+ current_in_axes_tuple .append (nn .broadcast )
1147+ else :
1148+ current_broadcast_args .append (None )
1149+ current_in_axes_tuple .append (nn .broadcast )
11141150
11151151 y , _ = self .scan_decoder_layers (
11161152 cfg ,
@@ -1139,6 +1175,11 @@ def __call__(
11391175 global_layer_idx = global_layer_idx_offset + index
11401176 kv_cache = kv_caches [index ] if kv_caches is not None else None
11411177 input_tokens = decoder_input_tokens if cfg .engram_layers else None
1178+ extra_kwargs = {}
1179+ if layer_prefix == "moe_layers" and forced_routed_experts is not None :
1180+ forced_experts = forced_routed_experts [:, :, index , :]
1181+ extra_kwargs ["forced_routed_experts" ] = forced_experts
1182+
11421183 y , kv_cache = layer (
11431184 config = cfg ,
11441185 mesh = mesh ,
@@ -1157,6 +1198,7 @@ def __call__(
11571198 kv_cache = kv_cache ,
11581199 attention_metadata = attention_metadata ,
11591200 decoder_input_tokens = input_tokens ,
1201+ ** extra_kwargs ,
11601202 )
11611203 if kv_caches is not None and kv_cache is not None :
11621204 kv_caches [index ] = kv_cache
@@ -1176,6 +1218,7 @@ def __call__(
11761218 slot = slot ,
11771219 )
11781220 else :
1221+ moe_lyr_idx = 0
11791222 for lyr in range (cfg .num_decoder_layers ):
11801223 RemattedBlockLayer = RemattedBlockLayers [0 ]
11811224 layer_kwargs = {}
@@ -1212,6 +1255,17 @@ def __call__(
12121255 layer = RemattedBlockLayer (
12131256 config = cfg , mesh = mesh , name = f"layers_{ lyr } " , quant = self .quant , model_mode = self .model_mode , ** layer_kwargs
12141257 )
1258+ current_forced_routed_experts = None
1259+ if supports_forced_routing and forced_routed_experts is not None :
1260+ current_forced_routed_experts = forced_routed_experts [:, :, moe_lyr_idx , :]
1261+ moe_lyr_idx += 1
1262+ elif supports_forced_routing :
1263+ moe_lyr_idx += 1
1264+
1265+ extra_kwargs = {}
1266+ if supports_forced_routing and current_forced_routed_experts is not None :
1267+ extra_kwargs ["forced_routed_experts" ] = current_forced_routed_experts
1268+
12151269 y , returned_cache = layer (
12161270 y ,
12171271 decoder_segment_ids ,
@@ -1222,6 +1276,7 @@ def __call__(
12221276 slot = slot ,
12231277 kv_cache = kv_cache ,
12241278 attention_metadata = attention_metadata ,
1279+ ** extra_kwargs ,
12251280 ** layer_call_kwargs ,
12261281 )
12271282 if kv_caches is not None and returned_cache is not None :
0 commit comments