@@ -401,8 +401,7 @@ def load_balance_updates_from_counts(expert_counts, num_experts, rate):
401401 total_tokens = jnp .sum (expert_counts , axis = - 1 , keepdims = True )
402402 average_load = total_tokens / num_experts
403403 direction = jnp .sign (average_load - expert_counts )
404- output = direction * rate
405- return output
404+ return direction * rate
406405
407406
408407def finalize_deferred_bias_signal (partial_counts , config ):
@@ -1022,6 +1021,7 @@ def __init__(
10221021 self .quant_einsums = None
10231022
10241023 gate_weight_dtype = ctypes .get_weight_dtype (self .config , "gate" )
1024+ self .use_gate_bias = self .config .routed_bias and not self .is_hash_routing
10251025 self .gate = GateLogit (
10261026 in_features_shape = self .moe_expert_input_dim ,
10271027 out_features_shape = self .num_experts ,
@@ -1032,7 +1032,7 @@ def __init__(
10321032 quant = ctypes .get_quant (self .config , "gate" , self .quant ),
10331033 kernel_init = self .kernel_init ,
10341034 kernel_axes = self .kernel_axes ,
1035- use_bias = self .config . routed_bias and not self . is_hash_routing ,
1035+ use_bias = self .use_gate_bias ,
10361036 bias_dtype = jnp .float32 if self .config .float32_gate_logits else gate_weight_dtype ,
10371037 # tpu-inference applies the score function in the fused_moe_gmm kernel,
10381038 # so we don't apply it here to avoid redundant computation.
@@ -4867,6 +4867,8 @@ def _te_moe_block(
48674867 w0_bias : jax .Array | None ,
48684868 w1_bias : jax .Array | None ,
48694869 wo_bias : jax .Array | None ,
4870+ routing_indices : jax .Array | None = None ,
4871+ routing_weights : jax .Array | None = None ,
48704872 out_sharding : NamedSharding | None = None ,
48714873 ) -> tuple [jax .Array , Optional [jax .Array ], Optional [jax .Array ]]:
48724874 """Run TransformerEngine's fused EP MoEBlock using MaxText-owned params."""
@@ -4881,10 +4883,10 @@ def _te_moe_block(
48814883
48824884 if self .quant is None or not hasattr (self .quant , "get_moe_block_quantizer_sets" ):
48834885 raise ValueError ("te_moe_block=True requires TransformerEngine quantization or te_gmm_quantization=te_no_quant." )
4886+ if self .is_hash_routing and (routing_indices is None or routing_weights is None ):
4887+ raise ValueError ("TE MoE hash routing requires precomputed routing indices and weights." )
48844888
4885- expert_bias = None
4886- if self .config .routed_bias :
4887- expert_bias = jnp .asarray (self .gate .bias [...], jnp .float32 )
4889+ expert_bias = jnp .asarray (self .gate .bias [...], jnp .float32 ) if self .use_gate_bias else None
48884890
48894891 fsdp_size = self .mesh .shape .get ("fsdp" , 1 )
48904892 ep_size = self .mesh .shape .get (self ._expert_parallelism_name , 1 )
@@ -4908,44 +4910,104 @@ def _te_moe_block(
49084910 checkpoint_kwargs = _get_te_moe_checkpoint_kwargs (te_moe .moe )
49094911 cudnn_gmm_fusion_kwargs = _get_te_moe_cudnn_gmm_fusion_kwargs (self .config .te_moe_disable_cudnn_gmm_fusion )
49104912
4911- output , lb_loss , total_recv_tokens = te_moe .moe (
4913+ # Older TE versions take the router arguments directly and do not return expert counts.
4914+ supports_router_info = hasattr (te_moe , "RouterComputationInfo" )
4915+ if not supports_router_info :
4916+ if self .is_hash_routing :
4917+ raise ImportError (
4918+ "te_moe_block=True with hash routing requires TransformerEngine with "
4919+ "moe.RoutingMapInfo support. Please upgrade TransformerEngine."
4920+ )
4921+ if self .should_update_load_balance ():
4922+ raise ImportError (
4923+ "te_moe_block=True with routed_bias_update_rate > 0 requires TransformerEngine with "
4924+ "MoE expert-count support. Please upgrade TransformerEngine."
4925+ )
4926+ router_kwargs = {
4927+ "gate_kernel" : gate_kernel ,
4928+ "num_experts_per_tok" : self .num_experts_per_tok ,
4929+ "expert_bias" : expert_bias ,
4930+ "score_function" : self .config .routed_score_func or "softmax" ,
4931+ "use_pre_softmax" : False ,
4932+ "num_groups" : None if self .config .n_routing_groups <= 0 else self .config .n_routing_groups ,
4933+ "group_topk" : None if self .config .topk_routing_group <= 0 else self .config .topk_routing_group ,
4934+ "scaling_factor" : self .config .routed_scaling_factor ,
4935+ "aux_loss_coeff" : self .config .load_balance_loss_weight ,
4936+ "gate_kernel_axes" : self .kernel_axes ,
4937+ }
4938+ elif self .is_hash_routing :
4939+ router_kwargs = {
4940+ "router_info" : te_moe .RoutingMapInfo (
4941+ routing_indices = routing_indices ,
4942+ routing_weights = routing_weights ,
4943+ ),
4944+ "collect_expert_counts" : False ,
4945+ }
4946+ else :
4947+ router_kwargs = {
4948+ "router_info" : te_moe .RouterComputationInfo (
4949+ gate_kernel = gate_kernel ,
4950+ num_experts_per_tok = self .num_experts_per_tok ,
4951+ expert_bias = expert_bias ,
4952+ score_function = self .config .routed_score_func or "softmax" ,
4953+ use_pre_softmax = False ,
4954+ num_groups = None if self .config .n_routing_groups <= 0 else self .config .n_routing_groups ,
4955+ group_topk = None if self .config .topk_routing_group <= 0 else self .config .topk_routing_group ,
4956+ scaling_factor = self .config .routed_scaling_factor ,
4957+ aux_loss_coeff = self .config .load_balance_loss_weight ,
4958+ gate_kernel_axes = self .kernel_axes ,
4959+ ),
4960+ "collect_expert_counts" : self .should_update_load_balance (),
4961+ }
4962+
4963+ # Pass the weights by keyword: the older interface has gate_kernel in the second positional slot.
4964+ te_moe_outputs = te_moe .moe (
49124965 inputs ,
4913- gate_kernel ,
4914- wi_kernel ,
4915- wo_kernel ,
4916- w0_bias ,
4917- w1_bias ,
4918- wo_bias ,
4919- expert_bias ,
4966+ wi = wi_kernel ,
4967+ wo = wo_kernel ,
4968+ wi_0_bias = w0_bias ,
4969+ wi_1_bias = w1_bias ,
4970+ wo_bias = wo_bias ,
49204971 num_experts = self .num_experts ,
4921- num_experts_per_tok = self .num_experts_per_tok ,
49224972 activation_type = self .config .mlp_activations [0 ],
4923- score_function = self .config .routed_score_func or "softmax" ,
4924- use_pre_softmax = False ,
4925- num_groups = None if self .config .n_routing_groups <= 0 else self .config .n_routing_groups ,
4926- group_topk = None if self .config .topk_routing_group <= 0 else self .config .topk_routing_group ,
4927- scaling_factor = self .config .routed_scaling_factor ,
4928- aux_loss_coeff = self .config .load_balance_loss_weight ,
49294973 apply_topk_weights_early = True ,
49304974 quantizer_sets = (fc1_quantizer_set , fc2_quantizer_set ),
49314975 mesh_resource = MeshResource (dp_resource = "data" , fsdp_resource = "fsdp" , ep_resource = self ._expert_parallelism_name ),
49324976 input_axes = ("activation_batch" , "activation_norm_length" , None ),
4933- gate_kernel_axes = self .kernel_axes ,
49344977 wi_kernel_axes = self .wi_kernel_axes ,
49354978 wo_kernel_axes = self .wo_kernel_axes ,
49364979 dtype = self .dtype ,
49374980 recv_capacity_per_rank = max_utils .get_te_moe_recv_capacity_per_rank (),
49384981 quant_before_fsdp_ag = self .config .te_moe_quantize_before_fsdp_all_gather ,
4982+ ** router_kwargs ,
49394983 ** cudnn_gmm_fusion_kwargs ,
49404984 ** checkpoint_kwargs ,
49414985 )
4986+ if supports_router_info :
4987+ output , lb_loss , total_recv_tokens , expert_counts = te_moe_outputs
4988+ else :
4989+ output , lb_loss , total_recv_tokens = te_moe_outputs
4990+ expert_counts = None
49424991 recv_capacity_per_rank = max_utils .get_te_moe_recv_capacity_per_rank ()
49434992 output = output .astype (self .dtype )
49444993 if lb_loss is not None :
49454994 lb_loss = lb_loss .astype (self .dtype )
49464995 if out_sharding is not None :
49474996 output = jax .lax .with_sharding_constraint (output , out_sharding )
4948- return output , lb_loss , (total_recv_tokens , jnp .asarray (recv_capacity_per_rank , dtype = jnp .int32 ))
4997+ bias_updates = None
4998+ if self .should_update_load_balance ():
4999+ bias_updates = load_balance_updates_from_counts (
5000+ expert_counts , self .num_experts , self .config .routed_bias_update_rate
5001+ )
5002+ return (
5003+ output ,
5004+ lb_loss ,
5005+ (
5006+ total_recv_tokens ,
5007+ jnp .asarray (recv_capacity_per_rank , dtype = jnp .int32 ),
5008+ bias_updates ,
5009+ ),
5010+ )
49495011
49505012 def __call__ (
49515013 self ,
@@ -4980,6 +5042,16 @@ def __call__(
49805042 routing_inputs = inputs if gate_inputs is None else gate_inputs .astype (gate_dtype )
49815043
49825044 if cfg .te_moe_block :
5045+ routing_indices = None
5046+ routing_weights = None
5047+ if self .is_hash_routing :
5048+ gate_logits , pre_bias_logits = self .gate (routing_inputs )
5049+ routing_weights , routing_indices = self .get_topk (
5050+ gate_logits ,
5051+ pre_bias_logits ,
5052+ self .rngs ,
5053+ input_ids = input_ids ,
5054+ )
49835055 gate_kernel = jnp .asarray (self .gate .kernel [...], self .dtype )
49845056 wi_kernel = jnp .asarray (self .wi [...], self .dtype )
49855057 wo_kernel = jnp .asarray (self .wo [...], self .dtype )
@@ -4999,7 +5071,9 @@ def __call__(
49995071 w0_bias ,
50005072 w1_bias ,
50015073 wo_bias ,
5002- out_sharding ,
5074+ routing_indices = routing_indices ,
5075+ routing_weights = routing_weights ,
5076+ out_sharding = out_sharding ,
50035077 )
50045078
50055079 gate_logits , pre_bias_logits = self .gate (routing_inputs )
0 commit comments