@@ -1640,6 +1640,84 @@ def gmm_up(x, w0, w1, w0_bias, w1_bias, gmm_fn, weight_gather):
16401640 layer_w1 = adc .checkpoint_name (layer_w1 , "moe_mlpwi_1" )
16411641 return self .apply_ffn_activation (layer_w0 , layer_w1 )
16421642
1643+ def get_gmm_for_local_experts (x , routing , route_metadata ):
1644+ """Return a partial GMM function with preconfigured routing params."""
1645+ num_ep = self .get_expert_parallelism_size ()
1646+ num_experts_per_shard = self .config .num_experts // num_ep
1647+ if self .config .use_ring_of_experts and x .shape [0 ] < routing .sorted_selected_experts .shape [0 ]:
1648+ local_group_sizes = routing .local_group_sizes
1649+ return functools .partial (
1650+ gmm ,
1651+ group_sizes = local_group_sizes ,
1652+ expert_assignments = routing .selected_experts ,
1653+ group_offset = 0 ,
1654+ )
1655+ if self .config .use_ragged_sort and self .config .use_ring_of_experts :
1656+ experts_start = route_metadata .expert_shard_id * num_experts_per_shard
1657+ else :
1658+ experts_start = 0
1659+ return functools .partial (
1660+ gmm ,
1661+ group_sizes = routing .group_sizes ,
1662+ expert_assignments = routing .selected_experts ,
1663+ group_offset = experts_start ,
1664+ )
1665+
1666+ def unsort_output_and_ra2a (intermediate_output , routing , route_metadata , output_shape , is_batch_sharded_by_expert ):
1667+ """Unsort tokens and return them to original shards using ragged all-to-all."""
1668+ if is_batch_sharded_by_expert :
1669+ # locally unpermute back to the original order
1670+ if self .config .use_ragged_sort :
1671+ # Mirror the ragged-prefix gather used in `local_permute`. The
1672+ # un-permute can use the same valid-prefix length because the
1673+ # routed token count is identical for forward and backward.
1674+ valid_end = jnp .sum (routing .group_sizes ).astype (jnp .int32 )
1675+ local_output = a2a_ragged_unsort (
1676+ intermediate_output ,
1677+ jnp .argsort (route_metadata .local_sorted_indices ), # pylint: disable=undefined-variable
1678+ valid_end ,
1679+ )
1680+ else :
1681+ local_output = _sort_activations (
1682+ intermediate_output ,
1683+ jnp .argsort (route_metadata .local_sorted_indices ),
1684+ self .config .use_custom_sort_vjp ,
1685+ )
1686+
1687+ input_offsets , send_sizes , output_offsets , recv_sizes = RoutedMoE .get_all_to_all_params (
1688+ jnp .transpose (route_metadata .all_shards_group_sizes ),
1689+ route_metadata .expert_shard_id ,
1690+ self .get_expert_parallelism_size (),
1691+ )
1692+ return jax .lax .ragged_all_to_all (
1693+ local_output ,
1694+ output_shape ,
1695+ input_offsets ,
1696+ send_sizes ,
1697+ output_offsets ,
1698+ recv_sizes ,
1699+ axis_name = self ._expert_parallelism_name ,
1700+ )
1701+
1702+ # If batch is replicated across EP shards then each shard should send
1703+ # 0..local_shard_size data to the other shards and receive the
1704+ # local_shard data from all of the other shards using ragged_all_to_all.
1705+ input_offsets , send_sizes , output_offsets , recv_sizes = RoutedMoE .get_all_to_all_params (
1706+ route_metadata .reshaped_group_sizes ,
1707+ route_metadata .expert_shard_id ,
1708+ self .get_expert_parallelism_size (),
1709+ is_batch_sharded = False ,
1710+ )
1711+ return jax .lax .ragged_all_to_all (
1712+ intermediate_output ,
1713+ output_shape ,
1714+ input_offsets ,
1715+ send_sizes ,
1716+ output_offsets ,
1717+ recv_sizes ,
1718+ axis_name = self ._expert_parallelism_name ,
1719+ )
1720+
16431721 @functools .partial (
16441722 jax .shard_map ,
16451723 mesh = self .mesh ,
@@ -1663,36 +1741,16 @@ def gmm_up(x, w0, w1, w0_bias, w1_bias, gmm_fn, weight_gather):
16631741 ),
16641742 check_vma = self .config .check_vma ,
16651743 )
1666- def wrapper (x , logits , pre_bias_logits , w0 , w1 , wo , w0_bias , w1_bias , wo_bias , sharded_input_ids , rngs ):
1744+ def sparse_matmul_route_and_compute (
1745+ x , logits , pre_bias_logits , w0 , w1 , wo , w0_bias , w1_bias , wo_bias , sharded_input_ids , rngs
1746+ ):
16671747 batch_size , sequence_length , _ = x .shape
16681748 x , routing , route_metadata = route (x , logits , pre_bias_logits , rngs , input_ids = sharded_input_ids )
16691749
16701750 if self .config .mlp_bias :
16711751 w0_bias , w1_bias , wo_bias = self .transform_bias (routing .selected_experts , w0_bias , w1_bias , wo_bias )
16721752
1673- num_ep = self .get_expert_parallelism_size ()
1674- num_experts_per_shard = self .config .num_experts // num_ep
1675-
1676- use_truncated_buffer = self .config .use_ring_of_experts and x .shape [0 ] < routing .sorted_selected_experts .shape [0 ]
1677- if use_truncated_buffer :
1678- local_group_sizes = routing .local_group_sizes
1679- gmm_fn = functools .partial (
1680- gmm ,
1681- group_sizes = local_group_sizes ,
1682- expert_assignments = routing .selected_experts ,
1683- group_offset = 0 ,
1684- )
1685- else :
1686- if self .config .use_ragged_sort and self .config .use_ring_of_experts :
1687- experts_start = route_metadata .expert_shard_id * num_experts_per_shard
1688- else :
1689- experts_start = 0
1690- gmm_fn = functools .partial (
1691- gmm ,
1692- group_sizes = routing .group_sizes ,
1693- expert_assignments = routing .selected_experts ,
1694- group_offset = experts_start ,
1695- )
1753+ gmm_fn = get_gmm_for_local_experts (x , routing , route_metadata )
16961754 intermediate_layer = gmm_up (x , w0 , w1 , w0_bias , w1_bias , gmm_fn , weight_gather )
16971755
16981756 wo_gather_axes , wo_tile_size = get_wo_gmm_params ()
@@ -1727,83 +1785,38 @@ def wrapper(x, logits, pre_bias_logits, w0, w1, wo, w0_bias, w1_bias, wo_bias, s
17271785 output , (- 1 , sequence_length , self .moe_expert_input_dim // self .get_tensor_parallelism_size ())
17281786 )
17291787 output = jax .lax .psum_scatter (output , self ._expert_parallelism_name , scatter_dimension = 0 , tiled = True )
1788+ return output , routing .lb_loss , routing .bias_updates
1789+
1790+ if self .get_expert_parallelism_size () > 1 :
1791+ original_inputs_first_dim = batch_size * sequence_length * self .config .num_experts_per_tok
1792+ if routing .sorted_selected_experts .shape [0 ] != original_inputs_first_dim :
1793+ raise ValueError ("original_inputs_first_dim does not match the original tensor" " shape!" )
1794+ output_shape = jax .lax .empty (
1795+ (
1796+ original_inputs_first_dim ,
1797+ self .moe_expert_input_dim // self .get_tensor_parallelism_size (),
1798+ ),
1799+ dtype = intermediate_output .dtype ,
1800+ )
17301801
1731- else :
1732- if self .get_expert_parallelism_size () > 1 :
1733- original_inputs_first_dim = batch_size * sequence_length * self .config .num_experts_per_tok
1734- if routing .sorted_selected_experts .shape [0 ] != original_inputs_first_dim :
1735- raise ValueError ("original_inputs_first_dim does not match the original tensor" " shape!" )
1736- output_shape = jax .lax .empty (
1737- (
1738- original_inputs_first_dim ,
1739- self .moe_expert_input_dim // self .get_tensor_parallelism_size (),
1740- ),
1741- dtype = intermediate_output .dtype ,
1742- )
1743-
1744- if is_batch_sharded_by_expert :
1745- # locally unpermute back to the original order
1746- if self .config .use_ragged_sort :
1747- # Mirror the ragged-prefix gather used in `local_permute`. The
1748- # un-permute can use the same valid-prefix length because the
1749- # routed token count is identical for forward and backward.
1750- valid_end = jnp .sum (routing .group_sizes ).astype (jnp .int32 )
1751- local_output = a2a_ragged_unsort (
1752- intermediate_output ,
1753- jnp .argsort (route_metadata .local_sorted_indices ), # pylint: disable=undefined-variable
1754- valid_end ,
1755- )
1756- else :
1757- local_output = _sort_activations (
1758- intermediate_output ,
1759- jnp .argsort (route_metadata .local_sorted_indices ),
1760- self .config .use_custom_sort_vjp ,
1761- )
1762-
1763- input_offsets , send_sizes , output_offsets , recv_sizes = RoutedMoE .get_all_to_all_params (
1764- jnp .transpose (route_metadata .all_shards_group_sizes ),
1765- route_metadata .expert_shard_id ,
1766- self .get_expert_parallelism_size (),
1767- )
1768- intermediate_output = jax .lax .ragged_all_to_all (
1769- local_output ,
1770- output_shape ,
1771- input_offsets ,
1772- send_sizes ,
1773- output_offsets ,
1774- recv_sizes ,
1775- axis_name = self ._expert_parallelism_name ,
1776- )
1777- else :
1778- # If batch is replicated across EP shards then each shard should send
1779- # 0..local_shard_size data to the other shards and receive the
1780- # local_shard data from all of the other shards using ragged_all_to_all.
1781- input_offsets , send_sizes , output_offsets , recv_sizes = RoutedMoE .get_all_to_all_params (
1782- route_metadata .reshaped_group_sizes ,
1783- route_metadata .expert_shard_id ,
1784- self .get_expert_parallelism_size (),
1785- is_batch_sharded = False ,
1786- )
1787- intermediate_output = jax .lax .ragged_all_to_all (
1788- intermediate_output ,
1789- output_shape ,
1790- input_offsets ,
1791- send_sizes ,
1792- output_offsets ,
1793- recv_sizes ,
1794- axis_name = self ._expert_parallelism_name ,
1795- )
1796-
1797- output = self .unpermute (
1802+ intermediate_output = unsort_output_and_ra2a (
17981803 intermediate_output ,
1799- routing .sorted_selected_experts ,
1800- routing .weights ,
1801- batch_size = batch_size ,
1802- sequence_length = sequence_length ,
1803- use_custom_sort_vjp = self .config .use_custom_sort_vjp ,
1804- group_sizes = routing .group_sizes ,
1804+ routing ,
1805+ route_metadata ,
1806+ output_shape ,
1807+ is_batch_sharded_by_expert ,
18051808 )
18061809
1810+ output = self .unpermute (
1811+ intermediate_output ,
1812+ routing .sorted_selected_experts ,
1813+ routing .weights ,
1814+ batch_size = batch_size ,
1815+ sequence_length = sequence_length ,
1816+ use_custom_sort_vjp = self .config .use_custom_sort_vjp ,
1817+ group_sizes = routing .group_sizes ,
1818+ )
1819+
18071820 return output , routing .lb_loss , routing .bias_updates
18081821
18091822 if self .config .moe_fsdp_use_two_stage_all_gather :
@@ -1851,7 +1864,7 @@ def wrapper(x, logits, pre_bias_logits, w0, w1, wo, w0_bias, w1_bias, wo_bias, s
18511864 if wo_bias is not None :
18521865 wo_bias = self ._maybe_shard_with_pspec (wo_bias , wo_bias_pspec )
18531866
1854- return wrapper (
1867+ return sparse_matmul_route_and_compute (
18551868 inputs ,
18561869 gate_logits ,
18571870 pre_bias_logits ,
0 commit comments