Tutorial — MoE SER Expert Routing¶
Notebook: moe_ser_routing.ipynb
(download)
What you'll build¶
A sparse Mixture-of-Experts layer using SNEPPX's SER module: route each token to the top-2 of 8 experts, compute the load-balancing loss, and inspect the routing distribution to detect expert collapse.
Setup¶
$env:PYTHONPATH = "bindings/python"
import numpy as np
from SneppX_ALG import SERModel, SERConfig, Tensor
HAS_C = __import__("SneppX_ALG")._HAS_C_BACKEND
1. Configure an 8-expert, top-2 MoE¶
cfg = SERConfig()
cfg.num_experts = 8
cfg.num_active = 2 # top-k
cfg.input_dim = 64
cfg.expert_dim = 128
cfg.output_dim = 64
cfg.top_k_method = 0 # softmax routing
cfg.load_balance_coef = 0.01
cfg.dropout_rate = 0.0
moe = SERModel(cfg, seed=42, num_layers=1)
2. Forward pass¶
x = Tensor.randn((4, 16, cfg.input_dim)) # (batch, seq, dim)
out = moe.forward(x) # (4, 16, 64)
3. Inspect routing weights¶
With the C backend, the router probabilities are exposed via the
SNEPPXSERRouter; here we approximate the load-balancing signal with a
pure-NumPy router replica:
if not HAS_C:
# Pure-NumPy illustration of the top-k routing math
rng = np.random.default_rng(0)
router_logits = rng.standard_normal((16, 8)) # (seq, num_experts)
scores = np.softmax(router_logits, axis=-1)
top2 = np.argsort(-scores, axis=-1)[:, :2]
load = np.zeros(8)
for t in range(16):
load[top2[t]] += 1
print("tokens-per-expert:", load.astype(int))
4. Load-balancing loss¶
# C backend: moe.load_balance_loss(routing_weights)
# Pure-Python approximation:
routes = np.zeros(8)
for t in range(16):
routes[top2[t]] += 1
frac = routes / 16.0
p_avg = scores.mean(axis=0)
loss = float(np.sum(frac * p_avg) * cfg.load_balance_coef)
print("balance loss:", loss) # lower + uniform is better
5. Stacked MoE layers¶
class MoETransformer(Module):
def __init__(self):
super().__init__()
self.inp = Linear(64, 64)
self.moe = SERModel(SERConfig(), seed=1, num_layers=4) # 4 stacked MoE layers
self.out = Linear(64, 64)
def forward(self, x):
return self.out(self.moe.forward(self.inp(x)))
net = MoETransformer()
Key takeaways¶
num_active(top-k) must be ≤num_experts; increasing k raises FLOPs linearly but improves quality.load_balance_coeftrades quality for uniform expert usage; 0.01 is the default in the C config.- Expert parallelism (EP) shards experts across GPUs — set
ep_size = num_experts / tp_sizeinDistributedConfig. - Without the C backend (
_HAS_C_BACKEND is False),SERModel.forwardraisesRuntimeError: C backend not available— the illustration above shows the equivalent NumPy math.
Next steps¶
- Combine with Distributed Training for EP across
nodes (see
algorithms/ser/core/gater.call-to-all dispatch). - Add a learned MLP gater (
use_mlp_gater=1inSNEPPXSERConfig).