2323import jax
2424import jax .numpy as jnp
2525import numpy as np
26+ import tokamax
2627from absl import logging
2728from jax import lax
2829from jax .experimental .pjit import pjit
@@ -80,6 +81,26 @@ class GateNoise(enum.Enum):
8081 GUMBEL = "GUMBEL"
8182
8283
84+ class GMMBackend (enum .Enum ):
85+ """Backend implementations for Grouped Matrix Multiplication (GMM).
86+
87+ Used in TransformerFeedForwardDropFreeMoE to select between different
88+ GMM implementations for experimentation and performance comparison.
89+ """
90+
91+ # Use Pallas/Triton-based GMM kernel.
92+ # Requires tiling configuration. Default backend.
93+ PALLAS = "PALLAS"
94+
95+ # Use JAX native jax.lax.ragged_dot.
96+ # Ignores tiling configuration. Useful for experimentation.
97+ RAGGED_DOT = "RAGGED_DOT"
98+
99+ # Use tokamax.ragged_dot (third-party implementation).
100+ # Has the same API as jax.lax.ragged_dot. Ignores tiling configuration.
101+ TOKAMAX = "TOKAMAX"
102+
103+
83104# Type definitions for configurable functions.
84105TopKFn = Callable [[Tensor , int ], Tuple [Tensor , Tensor ]]
85106ScoreFn = Callable [[Tensor , int ], Tensor ]
@@ -2229,11 +2250,19 @@ class TransformerFeedForwardDropFreeMoE(TransformerFeedForwardMoE):
22292250 class Config (TransformerFeedForwardMoE .Config ):
22302251 """Config for TransformerFeedForwardDropFreeMoE."""
22312252
2253+ # GMM backend selection for experimentation and performance comparison.
2254+ # PALLAS: Uses Pallas/Triton-based GMM kernel - requires tiling config.
2255+ # RAGGED_DOT: Uses JAX native jax.lax.ragged_dot - ignores tiling config.
2256+ # TOKAMAX: Uses Tokamax GMM kernel - ignores tiling config.
2257+ # None: Defaults to PALLAS for backward compatibility.
2258+ gmm_backend : Optional [GMMBackend ] = None
2259+
22322260 # Adjustable 3-tuple of ints to use the gmm kernel for the best performance.
22332261 # tiling[0] is the block size for the number of tokens dimension.
22342262 # tiling[1] is the block size for the model_dim.
22352263 # tiling[2] is the block size for the hidden_dim.
22362264 # The tiling blocks have to be multiples of 128.
2265+ # Note: This config is only used when gmm_backend is PALLAS (or None).
22372266 tiling : Required [Union [InstantiableConfig , tuple [int , int , int ]]] = REQUIRED
22382267 # How to partition the input batch with the expected keys below.
22392268 input_dim_to_partition_spec : dict [str , Optional [PartitionSpec ]] = {
@@ -2259,6 +2288,12 @@ class Config(TransformerFeedForwardMoE.Config):
22592288 # (so called Auxiliary-Loss-Free Load Balancing strategy) in DeepSeek V3.
22602289 # It's an experimental feature, so use it with caution.
22612290 seq_load_balance_loss_weight : Optional [float ] = None
2291+ # Implementation backends for tokamax.ragged_dot.
2292+ # When gmm_backend is TOKAMAX, this specifies which implementation(s) to use.
2293+ # If None, tokamax will use its default implementation selection.
2294+ # Example: ["triton", "xla"] to use triton first, falling back to xla.
2295+ # See tokamax documentation for available implementations.
2296+ tokamax_implementation : Optional [Sequence [str ]] = None
22622297
22632298 @classmethod
22642299 def default_config (cls ):
@@ -2284,6 +2319,96 @@ def __init__(self, cfg: Config, *, parent: Module):
22842319 ), "When interpret == True, please set preferred_element_type explicitly"
22852320
22862321 def _padded_gmm (self , lhs , rhs , tokens_per_expert ):
2322+ cfg = self .config
2323+ # Determine which backend to use (default to PALLAS for backward compatibility)
2324+ backend = cfg .gmm_backend if cfg .gmm_backend is not None else GMMBackend .PALLAS
2325+
2326+ if backend == GMMBackend .RAGGED_DOT :
2327+ return self ._ragged_dot_gmm (lhs , rhs , tokens_per_expert )
2328+ elif backend == GMMBackend .TOKAMAX :
2329+ return self ._tokamax_gmm (lhs , rhs , tokens_per_expert )
2330+ else :
2331+ return self ._pallas_gmm (lhs , rhs , tokens_per_expert )
2332+
2333+ def _ragged_dot_gmm (self , lhs , rhs , tokens_per_expert ):
2334+ """Performs grouped matrix multiplication using jax.lax.ragged_dot.
2335+
2336+ This is an alternative to the Pallas/Triton-based GMM kernel that uses
2337+ JAX's native ragged_dot operation. It ignores tiling configuration and
2338+ is useful for experimentation and performance comparison.
2339+
2340+ Args:
2341+ lhs: Left-hand side tensor of shape [num_tokens, input_dim].
2342+ rhs: Right-hand side tensor of shape [num_experts, input_dim, output_dim].
2343+ tokens_per_expert: Tensor of shape [num_experts] indicating the number
2344+ of tokens assigned to each expert.
2345+
2346+ Returns:
2347+ Output tensor of shape [num_tokens, output_dim].
2348+ """
2349+ cfg = self .config
2350+ preferred_element_type = cfg .preferred_element_type or jnp .bfloat16
2351+
2352+ # jax.lax.ragged_dot expects:
2353+ # - lhs: [num_tokens, input_dim]
2354+ # - rhs: [num_experts, input_dim, output_dim]
2355+ # - group_sizes: [num_experts] - number of tokens per expert
2356+ # Returns: [num_tokens, output_dim]
2357+ results = jax .lax .ragged_dot (
2358+ lhs ,
2359+ rhs ,
2360+ tokens_per_expert ,
2361+ preferred_element_type = preferred_element_type ,
2362+ )
2363+ return results
2364+
2365+ def _tokamax_gmm (self , lhs , rhs , tokens_per_expert ):
2366+ """Performs grouped matrix multiplication using tokamax.ragged_dot.
2367+
2368+ This is an alternative to the Pallas/Triton-based GMM kernel that uses
2369+ the tokamax library's ragged_dot operation. It has the same API as
2370+ jax.lax.ragged_dot and ignores tiling configuration.
2371+
2372+ Args:
2373+ lhs: Left-hand side tensor of shape [num_tokens, input_dim].
2374+ rhs: Right-hand side tensor of shape [num_experts, input_dim, output_dim].
2375+ tokens_per_expert: Tensor of shape [num_experts] indicating the number
2376+ of tokens assigned to each expert.
2377+
2378+ Returns:
2379+ Output tensor of shape [num_tokens, output_dim].
2380+ """
2381+
2382+ cfg = self .config
2383+ preferred_element_type = cfg .preferred_element_type or jnp .bfloat16
2384+
2385+ # tokamax.ragged_dot has the same API as jax.lax.ragged_dot.
2386+ # The implementation parameter controls which backend(s) to use.
2387+ # If None, tokamax uses its default selection.
2388+ # Example: ["triton", "xla"] uses triton first, falling back to xla
2389+ # if triton raises NotImplementedError (e.g., for non-default dimension
2390+ # numbers in the backward pass on B200/SM100 GPUs).
2391+ results = tokamax .ragged_dot (
2392+ lhs ,
2393+ rhs ,
2394+ tokens_per_expert ,
2395+ preferred_element_type = preferred_element_type ,
2396+ implementation = cfg .tokamax_implementation ,
2397+ )
2398+ return results
2399+
2400+ def _pallas_gmm (self , lhs , rhs , tokens_per_expert ):
2401+ """Performs grouped matrix multiplication using Pallas/Triton-based GMM kernel.
2402+
2403+ Args:
2404+ lhs: Left-hand side tensor of shape [num_tokens, input_dim].
2405+ rhs: Right-hand side tensor of shape [num_experts, input_dim, output_dim].
2406+ tokens_per_expert: Tensor of shape [num_experts] indicating the number
2407+ of tokens assigned to each expert.
2408+
2409+ Returns:
2410+ Output tensor of shape [num_tokens, output_dim].
2411+ """
22872412 cfg = self .config
22882413 if isinstance (cfg .tiling , tuple ):
22892414 tiling = cfg .tiling
0 commit comments