@@ -794,6 +794,7 @@ def __call__(
794794 kv_caches : list [jax .Array ] | None = None ,
795795 attention_metadata = None ,
796796 deepstack_visual_embeds : None | list [jnp .ndarray ] = None ,
797+ forced_routed_experts : jax .Array | None = None ,
797798 ):
798799 cfg = self .config
799800 mesh = self .mesh
@@ -1013,6 +1014,23 @@ def __call__(
10131014 current_broadcast_args = list (broadcast_args )
10141015 current_in_axes_tuple = list (in_axes_tuple )
10151016
1017+ supports_forced_routing = cfg .decoder_block in (
1018+ DecoderBlockType .QWEN3_MOE ,
1019+ DecoderBlockType .QWEN3_NEXT ,
1020+ DecoderBlockType .QWEN3_5 ,
1021+ )
1022+
1023+ if supports_forced_routing and forced_routed_experts is not None :
1024+ # Transpose [B, L, N, E] -> [N, B, L, E] for scan
1025+ forced_experts_t = jnp .transpose (forced_routed_experts , (2 , 0 , 1 , 3 ))
1026+ cycle_interval = cfg .inhomogeneous_layer_cycle_interval
1027+ forced_routed_experts_t = jnp .reshape (
1028+ forced_experts_t ,
1029+ (scan_length , cycle_interval ) + forced_experts_t .shape [1 :],
1030+ )
1031+ else :
1032+ forced_routed_experts_t = None
1033+
10161034 if kv_caches is not None :
10171035 # Stack kv_caches for scan: [num_layers, ...]
10181036 stacked_kv_cache = jnp .stack (kv_caches , axis = 0 )
@@ -1026,6 +1044,14 @@ def __call__(
10261044 current_broadcast_args .extend ([None , None , None , attention_metadata ])
10271045 current_in_axes_tuple .extend ([nn .broadcast ] * 4 )
10281046
1047+ if supports_forced_routing :
1048+ if forced_routed_experts_t is not None :
1049+ current_broadcast_args .append (forced_routed_experts_t )
1050+ current_in_axes_tuple .append (0 )
1051+ else :
1052+ current_broadcast_args .append (None )
1053+ current_in_axes_tuple .append (nn .broadcast )
1054+
10291055 max_logging .info (f"DEBUG: len(current_broadcast_args)={ len (current_broadcast_args )} " )
10301056 max_logging .info (f"DEBUG: current_broadcast_args={ [type (a ) for a in current_broadcast_args ]} " )
10311057
@@ -1047,8 +1073,19 @@ def __call__(
10471073 kv_caches [i ] = returned_kv_cache [i ]
10481074 else :
10491075 # Fallback to old behavior if kv_caches is None (not vLLM RPA)
1050- current_broadcast_args .append (None )
1051- current_in_axes_tuple .append (nn .broadcast )
1076+ if supports_forced_routing :
1077+ current_broadcast_args .extend ([None , None , None , None ])
1078+ current_in_axes_tuple .extend ([nn .broadcast ] * 4 )
1079+
1080+ if forced_routed_experts_t is not None :
1081+ current_broadcast_args .append (forced_routed_experts_t )
1082+ current_in_axes_tuple .append (0 )
1083+ else :
1084+ current_broadcast_args .append (None )
1085+ current_in_axes_tuple .append (nn .broadcast )
1086+ else :
1087+ current_broadcast_args .append (None )
1088+ current_in_axes_tuple .append (nn .broadcast )
10521089
10531090 y , _ = self .scan_decoder_layers (
10541091 cfg ,
@@ -1077,6 +1114,11 @@ def __call__(
10771114 global_layer_idx = global_layer_idx_offset + index
10781115 kv_cache = kv_caches [index ] if kv_caches is not None else None
10791116 input_tokens = decoder_input_tokens if cfg .engram_layers else None
1117+ extra_kwargs = {}
1118+ if layer_prefix == "moe_layers" and forced_routed_experts is not None :
1119+ forced_experts = forced_routed_experts [:, :, index , :]
1120+ extra_kwargs ["forced_routed_experts" ] = forced_experts
1121+
10801122 y , kv_cache = layer (
10811123 config = cfg ,
10821124 mesh = mesh ,
@@ -1095,6 +1137,7 @@ def __call__(
10951137 kv_cache = kv_cache ,
10961138 attention_metadata = attention_metadata ,
10971139 decoder_input_tokens = input_tokens ,
1140+ ** extra_kwargs ,
10981141 )
10991142 if kv_caches is not None and kv_cache is not None :
11001143 kv_caches [index ] = kv_cache
@@ -1114,6 +1157,7 @@ def __call__(
11141157 slot = slot ,
11151158 )
11161159 else :
1160+ moe_lyr_idx = 0
11171161 for lyr in range (cfg .num_decoder_layers ):
11181162 RemattedBlockLayer = RemattedBlockLayers [0 ]
11191163 layer_kwargs = {}
@@ -1150,6 +1194,25 @@ def __call__(
11501194 layer = RemattedBlockLayer (
11511195 config = cfg , mesh = mesh , name = f"layers_{ lyr } " , quant = self .quant , model_mode = self .model_mode , ** layer_kwargs
11521196 )
1197+ is_moe = False
1198+ if cfg .decoder_block in (
1199+ DecoderBlockType .QWEN3_MOE ,
1200+ DecoderBlockType .QWEN3_NEXT ,
1201+ DecoderBlockType .QWEN3_5 ,
1202+ ):
1203+ is_moe = True
1204+
1205+ current_forced_routed_experts = None
1206+ if is_moe and forced_routed_experts is not None :
1207+ current_forced_routed_experts = forced_routed_experts [:, :, moe_lyr_idx , :]
1208+ moe_lyr_idx += 1
1209+ elif is_moe :
1210+ moe_lyr_idx += 1
1211+
1212+ extra_kwargs = {}
1213+ if is_moe and current_forced_routed_experts is not None :
1214+ extra_kwargs ["forced_routed_experts" ] = current_forced_routed_experts
1215+
11531216 y , returned_cache = layer (
11541217 y ,
11551218 decoder_segment_ids ,
@@ -1160,6 +1223,7 @@ def __call__(
11601223 slot = slot ,
11611224 kv_cache = kv_cache ,
11621225 attention_metadata = attention_metadata ,
1226+ ** extra_kwargs ,
11631227 ** layer_call_kwargs ,
11641228 )
11651229 if kv_caches is not None and returned_cache is not None :
0 commit comments