Skip to content

Commit e8127d9

Browse files
committed
refactor
1 parent c3d6fdc commit e8127d9

1 file changed

Lines changed: 111 additions & 98 deletions

File tree

src/maxtext/layers/moe.py

Lines changed: 111 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)