@@ -373,8 +373,7 @@ def load_balance_updates_from_counts(expert_counts, num_experts, rate):
373373 total_tokens = jnp .sum (expert_counts , axis = - 1 , keepdims = True )
374374 average_load = total_tokens / num_experts
375375 direction = jnp .sign (average_load - expert_counts )
376- output = direction * rate
377- return output
376+ return direction * rate
378377
379378
380379def finalize_deferred_bias_signal (partial_counts , config ):
@@ -924,6 +923,7 @@ def __init__(
924923 else :
925924 self .quant_einsums = None
926925
926+ self .use_gate_bias = self .config .routed_bias and not self .is_hash_routing
927927 self .gate = GateLogit (
928928 in_features_shape = self .moe_expert_input_dim ,
929929 out_features_shape = self .num_experts ,
@@ -934,7 +934,7 @@ def __init__(
934934 quant = self .quant ,
935935 kernel_init = self .kernel_init ,
936936 kernel_axes = self .kernel_axes ,
937- use_bias = self .config . routed_bias and not self . is_hash_routing ,
937+ use_bias = self .use_gate_bias ,
938938 # tpu-inference applies the score function in the fused_moe_gmm kernel,
939939 # so we don't apply it here to avoid redundant computation.
940940 # See https://github.com/vllm-project/tpu-inference/blob/main/tpu_inference/layers/common/fused_moe_gmm.py#L58.
@@ -4398,6 +4398,8 @@ def _te_moe_block(
43984398 w0_bias : jax .Array | None ,
43994399 w1_bias : jax .Array | None ,
44004400 wo_bias : jax .Array | None ,
4401+ routing_indices : jax .Array | None = None ,
4402+ routing_weights : jax .Array | None = None ,
44014403 out_sharding : NamedSharding | None = None ,
44024404 ) -> tuple [jax .Array , Optional [jax .Array ], Optional [jax .Array ]]:
44034405 """Run TransformerEngine's fused EP MoEBlock using MaxText-owned params."""
@@ -4411,10 +4413,10 @@ def _te_moe_block(
44114413
44124414 if self .quant is None or not hasattr (self .quant , "get_moe_block_quantizer_sets" ):
44134415 raise ValueError ("te_moe_block=True requires TransformerEngine quantization or te_gmm_quantization=te_no_quant." )
4416+ if self .is_hash_routing and (routing_indices is None or routing_weights is None ):
4417+ raise ValueError ("TE MoE hash routing requires precomputed routing indices and weights." )
44144418
4415- expert_bias = None
4416- if self .config .routed_bias :
4417- expert_bias = jnp .asarray (self .gate .bias [...], jnp .float32 )
4419+ expert_bias = jnp .asarray (self .gate .bias [...], jnp .float32 ) if self .use_gate_bias else None
44184420
44194421 fsdp_size = self .mesh .shape .get ("fsdp" , 1 )
44204422 ep_size = self .mesh .shape .get (self ._expert_parallelism_name , 1 )
@@ -4430,42 +4432,68 @@ def _te_moe_block(
44304432 n_expert_groups = self .num_experts ,
44314433 )
44324434
4433- output , lb_loss , total_recv_tokens = te_moe .moe (
4435+ if self .is_hash_routing :
4436+ router_info = te_moe .RoutingMapInfo (
4437+ routing_indices = routing_indices ,
4438+ routing_weights = routing_weights ,
4439+ )
4440+ collect_expert_counts = False
4441+ else :
4442+ router_info = te_moe .RouterComputationInfo (
4443+ gate_kernel = gate_kernel ,
4444+ num_experts_per_tok = self .num_experts_per_tok ,
4445+ expert_bias = expert_bias ,
4446+ score_function = self .config .routed_score_func or "softmax" ,
4447+ use_pre_softmax = False ,
4448+ num_groups = None if self .config .n_routing_groups <= 0 else self .config .n_routing_groups ,
4449+ group_topk = None if self .config .topk_routing_group <= 0 else self .config .topk_routing_group ,
4450+ scaling_factor = self .config .routed_scaling_factor ,
4451+ aux_loss_coeff = self .config .load_balance_loss_weight ,
4452+ gate_kernel_axes = self .kernel_axes ,
4453+ )
4454+ collect_expert_counts = self .should_update_load_balance ()
4455+
4456+ output , lb_loss , total_recv_tokens , expert_counts = te_moe .moe (
44344457 inputs ,
4435- gate_kernel ,
4458+ router_info ,
44364459 wi_kernel ,
44374460 wo_kernel ,
44384461 w0_bias ,
44394462 w1_bias ,
44404463 wo_bias ,
4441- expert_bias ,
44424464 num_experts = self .num_experts ,
4443- num_experts_per_tok = self .num_experts_per_tok ,
44444465 activation_type = self .config .mlp_activations [0 ],
4445- score_function = self .config .routed_score_func or "softmax" ,
4446- use_pre_softmax = False ,
4447- num_groups = None if self .config .n_routing_groups <= 0 else self .config .n_routing_groups ,
4448- group_topk = None if self .config .topk_routing_group <= 0 else self .config .topk_routing_group ,
4449- scaling_factor = self .config .routed_scaling_factor ,
4450- aux_loss_coeff = self .config .load_balance_loss_weight ,
44514466 apply_topk_weights_early = True ,
44524467 quantizer_sets = (fc1_quantizer_set , fc2_quantizer_set ),
44534468 ep_axis = self ._expert_parallelism_name ,
44544469 data_parallelism_axes = ("fsdp" ,),
44554470 input_axes = ("activation_batch" , "activation_norm_length" , None ),
4456- gate_kernel_axes = self .kernel_axes ,
44574471 wi_kernel_axes = self .wi_kernel_axes ,
44584472 wo_kernel_axes = self .wo_kernel_axes ,
44594473 dtype = self .dtype ,
44604474 recv_capacity_per_rank = max_utils .get_te_moe_recv_capacity_per_rank (),
4475+ collect_expert_counts = collect_expert_counts ,
44614476 )
44624477 recv_capacity_per_rank = max_utils .get_te_moe_recv_capacity_per_rank ()
44634478 output = output .astype (self .dtype )
44644479 if lb_loss is not None :
44654480 lb_loss = lb_loss .astype (self .dtype )
44664481 if out_sharding is not None :
44674482 output = jax .lax .with_sharding_constraint (output , out_sharding )
4468- return output , lb_loss , (total_recv_tokens , jnp .asarray (recv_capacity_per_rank , dtype = jnp .int32 ))
4483+ bias_updates = None
4484+ if self .should_update_load_balance ():
4485+ bias_updates = load_balance_updates_from_counts (
4486+ expert_counts , self .num_experts , self .config .routed_bias_update_rate
4487+ )
4488+ return (
4489+ output ,
4490+ lb_loss ,
4491+ (
4492+ total_recv_tokens ,
4493+ jnp .asarray (recv_capacity_per_rank , dtype = jnp .int32 ),
4494+ bias_updates ,
4495+ ),
4496+ )
44694497
44704498 def __call__ (
44714499 self ,
@@ -4500,6 +4528,16 @@ def __call__(
45004528 routing_inputs = inputs if gate_inputs is None else gate_inputs .astype (gate_dtype )
45014529
45024530 if cfg .te_moe_block :
4531+ routing_indices = None
4532+ routing_weights = None
4533+ if self .is_hash_routing :
4534+ gate_logits , pre_bias_logits = self .gate (routing_inputs )
4535+ routing_weights , routing_indices = self .get_topk (
4536+ gate_logits ,
4537+ pre_bias_logits ,
4538+ self .rngs ,
4539+ input_ids = input_ids ,
4540+ )
45034541 gate_kernel = jnp .asarray (self .gate .kernel [...], self .dtype )
45044542 wi_kernel = jnp .asarray (self .wi [...], self .dtype )
45054543 wo_kernel = jnp .asarray (self .wo [...], self .dtype )
@@ -4519,7 +4557,9 @@ def __call__(
45194557 w0_bias ,
45204558 w1_bias ,
45214559 wo_bias ,
4522- out_sharding ,
4560+ routing_indices = routing_indices ,
4561+ routing_weights = routing_weights ,
4562+ out_sharding = out_sharding ,
45234563 )
45244564
45254565 gate_logits , pre_bias_logits = self .gate (routing_inputs )
0 commit comments