@@ -1660,6 +1660,84 @@ def gmm_up(x, w0, w1, w0_bias, w1_bias, gmm_fn, weight_gather):
16601660 layer_w1 = adc .checkpoint_name (layer_w1 , "moe_mlpwi_1" )
16611661 return self .apply_ffn_activation (layer_w0 , layer_w1 )
16621662
1663+ def get_gmm_for_local_experts (x , routing , route_metadata ):
1664+ """Return a partial GMM function with preconfigured routing params."""
1665+ num_ep = self .get_expert_parallelism_size ()
1666+ num_experts_per_shard = self .config .num_experts // num_ep
1667+ if self .config .use_ring_of_experts and x .shape [0 ] < routing .sorted_selected_experts .shape [0 ]:
1668+ local_group_sizes = routing .local_group_sizes
1669+ return functools .partial (
1670+ gmm ,
1671+ group_sizes = local_group_sizes ,
1672+ expert_assignments = routing .selected_experts ,
1673+ group_offset = 0 ,
1674+ )
1675+ if self .config .use_ragged_sort and self .config .use_ring_of_experts :
1676+ experts_start = route_metadata .expert_shard_id * num_experts_per_shard
1677+ else :
1678+ experts_start = 0
1679+ return functools .partial (
1680+ gmm ,
1681+ group_sizes = routing .group_sizes ,
1682+ expert_assignments = routing .selected_experts ,
1683+ group_offset = experts_start ,
1684+ )
1685+
1686+ def unsort_output_and_ra2a (intermediate_output , routing , route_metadata , output_shape , is_batch_sharded_by_expert ):
1687+ """Unsort tokens and return them to original shards using ragged all-to-all."""
1688+ if is_batch_sharded_by_expert :
1689+ # locally unpermute back to the original order
1690+ if self .config .use_ragged_sort :
1691+ # Mirror the ragged-prefix gather used in `local_permute`. The
1692+ # un-permute can use the same valid-prefix length because the
1693+ # routed token count is identical for forward and backward.
1694+ valid_end = jnp .sum (routing .group_sizes ).astype (jnp .int32 )
1695+ local_output = a2a_ragged_unsort (
1696+ intermediate_output ,
1697+ jnp .argsort (route_metadata .local_sorted_indices ), # pylint: disable=undefined-variable
1698+ valid_end ,
1699+ )
1700+ else :
1701+ local_output = _sort_activations (
1702+ intermediate_output ,
1703+ jnp .argsort (route_metadata .local_sorted_indices ),
1704+ self .config .use_custom_sort_vjp ,
1705+ )
1706+
1707+ input_offsets , send_sizes , output_offsets , recv_sizes = RoutedMoE .get_all_to_all_params (
1708+ jnp .transpose (route_metadata .all_shards_group_sizes ),
1709+ route_metadata .expert_shard_id ,
1710+ self .get_expert_parallelism_size (),
1711+ )
1712+ return jax .lax .ragged_all_to_all (
1713+ local_output ,
1714+ output_shape ,
1715+ input_offsets ,
1716+ send_sizes ,
1717+ output_offsets ,
1718+ recv_sizes ,
1719+ axis_name = self ._expert_parallelism_name ,
1720+ )
1721+
1722+ # If batch is replicated across EP shards then each shard should send
1723+ # 0..local_shard_size data to the other shards and receive the
1724+ # local_shard data from all of the other shards using ragged_all_to_all.
1725+ input_offsets , send_sizes , output_offsets , recv_sizes = RoutedMoE .get_all_to_all_params (
1726+ route_metadata .reshaped_group_sizes ,
1727+ route_metadata .expert_shard_id ,
1728+ self .get_expert_parallelism_size (),
1729+ is_batch_sharded = False ,
1730+ )
1731+ return jax .lax .ragged_all_to_all (
1732+ intermediate_output ,
1733+ output_shape ,
1734+ input_offsets ,
1735+ send_sizes ,
1736+ output_offsets ,
1737+ recv_sizes ,
1738+ axis_name = self ._expert_parallelism_name ,
1739+ )
1740+
16631741 @functools .partial (
16641742 jax .shard_map ,
16651743 mesh = self .mesh ,
@@ -1683,36 +1761,16 @@ def gmm_up(x, w0, w1, w0_bias, w1_bias, gmm_fn, weight_gather):
16831761 ),
16841762 check_vma = self .config .check_vma ,
16851763 )
1686- def wrapper (x , logits , pre_bias_logits , w0 , w1 , wo , w0_bias , w1_bias , wo_bias , sharded_input_ids , rngs ):
1764+ def sparse_matmul_route_and_compute (
1765+ x , logits , pre_bias_logits , w0 , w1 , wo , w0_bias , w1_bias , wo_bias , sharded_input_ids , rngs
1766+ ):
16871767 batch_size , sequence_length , _ = x .shape
16881768 x , routing , route_metadata = route (x , logits , pre_bias_logits , rngs , input_ids = sharded_input_ids )
16891769
16901770 if self .config .mlp_bias :
16911771 w0_bias , w1_bias , wo_bias = self .transform_bias (routing .selected_experts , w0_bias , w1_bias , wo_bias )
16921772
1693- num_ep = self .get_expert_parallelism_size ()
1694- num_experts_per_shard = self .config .num_experts // num_ep
1695-
1696- use_truncated_buffer = self .config .use_ring_of_experts and x .shape [0 ] < routing .sorted_selected_experts .shape [0 ]
1697- if use_truncated_buffer :
1698- local_group_sizes = routing .local_group_sizes
1699- gmm_fn = functools .partial (
1700- gmm ,
1701- group_sizes = local_group_sizes ,
1702- expert_assignments = routing .selected_experts ,
1703- group_offset = 0 ,
1704- )
1705- else :
1706- if self .config .use_ragged_sort and self .config .use_ring_of_experts :
1707- experts_start = route_metadata .expert_shard_id * num_experts_per_shard
1708- else :
1709- experts_start = 0
1710- gmm_fn = functools .partial (
1711- gmm ,
1712- group_sizes = routing .group_sizes ,
1713- expert_assignments = routing .selected_experts ,
1714- group_offset = experts_start ,
1715- )
1773+ gmm_fn = get_gmm_for_local_experts (x , routing , route_metadata )
17161774 intermediate_layer = gmm_up (x , w0 , w1 , w0_bias , w1_bias , gmm_fn , weight_gather )
17171775
17181776 wo_gather_axes , wo_tile_size = get_wo_gmm_params ()
@@ -1747,83 +1805,38 @@ def wrapper(x, logits, pre_bias_logits, w0, w1, wo, w0_bias, w1_bias, wo_bias, s
17471805 output , (- 1 , sequence_length , self .moe_expert_input_dim // self .get_tensor_parallelism_size ())
17481806 )
17491807 output = jax .lax .psum_scatter (output , self ._expert_parallelism_name , scatter_dimension = 0 , tiled = True )
1808+ return output , routing .lb_loss , routing .bias_updates
1809+
1810+ if self .get_expert_parallelism_size () > 1 :
1811+ original_inputs_first_dim = batch_size * sequence_length * self .config .num_experts_per_tok
1812+ if routing .sorted_selected_experts .shape [0 ] != original_inputs_first_dim :
1813+ raise ValueError ("original_inputs_first_dim does not match the original tensor" " shape!" )
1814+ output_shape = jax .lax .empty (
1815+ (
1816+ original_inputs_first_dim ,
1817+ self .moe_expert_input_dim // self .get_tensor_parallelism_size (),
1818+ ),
1819+ dtype = intermediate_output .dtype ,
1820+ )
17501821
1751- else :
1752- if self .get_expert_parallelism_size () > 1 :
1753- original_inputs_first_dim = batch_size * sequence_length * self .config .num_experts_per_tok
1754- if routing .sorted_selected_experts .shape [0 ] != original_inputs_first_dim :
1755- raise ValueError ("original_inputs_first_dim does not match the original tensor" " shape!" )
1756- output_shape = jax .lax .empty (
1757- (
1758- original_inputs_first_dim ,
1759- self .moe_expert_input_dim // self .get_tensor_parallelism_size (),
1760- ),
1761- dtype = intermediate_output .dtype ,
1762- )
1763-
1764- if is_batch_sharded_by_expert :
1765- # locally unpermute back to the original order
1766- if self .config .use_ragged_sort :
1767- # Mirror the ragged-prefix gather used in `local_permute`. The
1768- # un-permute can use the same valid-prefix length because the
1769- # routed token count is identical for forward and backward.
1770- valid_end = jnp .sum (routing .group_sizes ).astype (jnp .int32 )
1771- local_output = a2a_ragged_unsort (
1772- intermediate_output ,
1773- jnp .argsort (route_metadata .local_sorted_indices ), # pylint: disable=undefined-variable
1774- valid_end ,
1775- )
1776- else :
1777- local_output = _sort_activations (
1778- intermediate_output ,
1779- jnp .argsort (route_metadata .local_sorted_indices ),
1780- self .config .use_custom_sort_vjp ,
1781- )
1782-
1783- input_offsets , send_sizes , output_offsets , recv_sizes = RoutedMoE .get_all_to_all_params (
1784- jnp .transpose (route_metadata .all_shards_group_sizes ),
1785- route_metadata .expert_shard_id ,
1786- self .get_expert_parallelism_size (),
1787- )
1788- intermediate_output = jax .lax .ragged_all_to_all (
1789- local_output ,
1790- output_shape ,
1791- input_offsets ,
1792- send_sizes ,
1793- output_offsets ,
1794- recv_sizes ,
1795- axis_name = self ._expert_parallelism_name ,
1796- )
1797- else :
1798- # If batch is replicated across EP shards then each shard should send
1799- # 0..local_shard_size data to the other shards and receive the
1800- # local_shard data from all of the other shards using ragged_all_to_all.
1801- input_offsets , send_sizes , output_offsets , recv_sizes = RoutedMoE .get_all_to_all_params (
1802- route_metadata .reshaped_group_sizes ,
1803- route_metadata .expert_shard_id ,
1804- self .get_expert_parallelism_size (),
1805- is_batch_sharded = False ,
1806- )
1807- intermediate_output = jax .lax .ragged_all_to_all (
1808- intermediate_output ,
1809- output_shape ,
1810- input_offsets ,
1811- send_sizes ,
1812- output_offsets ,
1813- recv_sizes ,
1814- axis_name = self ._expert_parallelism_name ,
1815- )
1816-
1817- output = self .unpermute (
1822+ intermediate_output = unsort_output_and_ra2a (
18181823 intermediate_output ,
1819- routing .sorted_selected_experts ,
1820- routing .weights ,
1821- batch_size = batch_size ,
1822- sequence_length = sequence_length ,
1823- use_custom_sort_vjp = self .config .use_custom_sort_vjp ,
1824- group_sizes = routing .group_sizes ,
1824+ routing ,
1825+ route_metadata ,
1826+ output_shape ,
1827+ is_batch_sharded_by_expert ,
18251828 )
18261829
1830+ output = self .unpermute (
1831+ intermediate_output ,
1832+ routing .sorted_selected_experts ,
1833+ routing .weights ,
1834+ batch_size = batch_size ,
1835+ sequence_length = sequence_length ,
1836+ use_custom_sort_vjp = self .config .use_custom_sort_vjp ,
1837+ group_sizes = routing .group_sizes ,
1838+ )
1839+
18271840 return output , routing .lb_loss , routing .bias_updates
18281841
18291842 if self .config .moe_fsdp_use_two_stage_all_gather :
@@ -1871,7 +1884,7 @@ def wrapper(x, logits, pre_bias_logits, w0, w1, wo, w0_bias, w1_bias, wo_bias, s
18711884 if wo_bias is not None :
18721885 wo_bias = self ._maybe_shard_with_pspec (wo_bias , wo_bias_pspec )
18731886
1874- return wrapper (
1887+ return sparse_matmul_route_and_compute (
18751888 inputs ,
18761889 gate_logits ,
18771890 pre_bias_logits ,
0 commit comments