@@ -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,18 @@ def __call__(
10751081 current_broadcast_args = list (broadcast_args )
10761082 current_in_axes_tuple = list (in_axes_tuple )
10771083
1084+
1085+ if supports_forced_routing and forced_routed_experts is not None :
1086+ # Transpose [B, L, N, E] -> [N, B, L, E] for scan
1087+ forced_experts_t = jnp .transpose (forced_routed_experts , (2 , 0 , 1 , 3 ))
1088+ cycle_interval = cfg .inhomogeneous_layer_cycle_interval
1089+ forced_routed_experts_t = jnp .reshape (
1090+ forced_experts_t ,
1091+ (scan_length , cycle_interval ) + forced_experts_t .shape [1 :],
1092+ )
1093+ else :
1094+ forced_routed_experts_t = None
1095+
10781096 if kv_caches is not None :
10791097 # Stack kv_caches for scan: [num_layers, ...]
10801098 stacked_kv_cache = jnp .stack (kv_caches , axis = 0 )
@@ -1088,6 +1106,14 @@ def __call__(
10881106 current_broadcast_args .extend ([None , None , None , attention_metadata ])
10891107 current_in_axes_tuple .extend ([nn .broadcast ] * 4 )
10901108
1109+ if supports_forced_routing :
1110+ if forced_routed_experts_t is not None :
1111+ current_broadcast_args .append (forced_routed_experts_t )
1112+ current_in_axes_tuple .append (0 )
1113+ else :
1114+ current_broadcast_args .append (None )
1115+ current_in_axes_tuple .append (nn .broadcast )
1116+
10911117 max_logging .info (f"DEBUG: len(current_broadcast_args)={ len (current_broadcast_args )} " )
10921118 max_logging .info (f"DEBUG: current_broadcast_args={ [type (a ) for a in current_broadcast_args ]} " )
10931119
@@ -1109,8 +1135,19 @@ def __call__(
11091135 kv_caches [i ] = returned_kv_cache [i ]
11101136 else :
11111137 # 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 )
1138+ if supports_forced_routing :
1139+ current_broadcast_args .extend ([None , None , None , None ])
1140+ current_in_axes_tuple .extend ([nn .broadcast ] * 4 )
1141+
1142+ if forced_routed_experts_t is not None :
1143+ current_broadcast_args .append (forced_routed_experts_t )
1144+ current_in_axes_tuple .append (0 )
1145+ else :
1146+ current_broadcast_args .append (None )
1147+ current_in_axes_tuple .append (nn .broadcast )
1148+ else :
1149+ current_broadcast_args .append (None )
1150+ current_in_axes_tuple .append (nn .broadcast )
11141151
11151152 y , _ = self .scan_decoder_layers (
11161153 cfg ,
@@ -1139,6 +1176,11 @@ def __call__(
11391176 global_layer_idx = global_layer_idx_offset + index
11401177 kv_cache = kv_caches [index ] if kv_caches is not None else None
11411178 input_tokens = decoder_input_tokens if cfg .engram_layers else None
1179+ extra_kwargs = {}
1180+ if layer_prefix == "moe_layers" and forced_routed_experts is not None :
1181+ forced_experts = forced_routed_experts [:, :, index , :]
1182+ extra_kwargs ["forced_routed_experts" ] = forced_experts
1183+
11421184 y , kv_cache = layer (
11431185 config = cfg ,
11441186 mesh = mesh ,
@@ -1157,6 +1199,7 @@ def __call__(
11571199 kv_cache = kv_cache ,
11581200 attention_metadata = attention_metadata ,
11591201 decoder_input_tokens = input_tokens ,
1202+ ** extra_kwargs ,
11601203 )
11611204 if kv_caches is not None and kv_cache is not None :
11621205 kv_caches [index ] = kv_cache
@@ -1176,6 +1219,7 @@ def __call__(
11761219 slot = slot ,
11771220 )
11781221 else :
1222+ moe_lyr_idx = 0
11791223 for lyr in range (cfg .num_decoder_layers ):
11801224 RemattedBlockLayer = RemattedBlockLayers [0 ]
11811225 layer_kwargs = {}
@@ -1212,6 +1256,17 @@ def __call__(
12121256 layer = RemattedBlockLayer (
12131257 config = cfg , mesh = mesh , name = f"layers_{ lyr } " , quant = self .quant , model_mode = self .model_mode , ** layer_kwargs
12141258 )
1259+ current_forced_routed_experts = None
1260+ if supports_forced_routing and forced_routed_experts is not None :
1261+ current_forced_routed_experts = forced_routed_experts [:, :, moe_lyr_idx , :]
1262+ moe_lyr_idx += 1
1263+ elif supports_forced_routing :
1264+ moe_lyr_idx += 1
1265+
1266+ extra_kwargs = {}
1267+ if supports_forced_routing and current_forced_routed_experts is not None :
1268+ extra_kwargs ["forced_routed_experts" ] = current_forced_routed_experts
1269+
12151270 y , returned_cache = layer (
12161271 y ,
12171272 decoder_segment_ids ,
@@ -1222,6 +1277,7 @@ def __call__(
12221277 slot = slot ,
12231278 kv_cache = kv_cache ,
12241279 attention_metadata = attention_metadata ,
1280+ ** extra_kwargs ,
12251281 ** layer_call_kwargs ,
12261282 )
12271283 if kv_caches is not None and returned_cache is not None :
0 commit comments