Personalize this lesson
Adapt explanations and teaching visuals to your background and preferred voice.
Serving pressure shows up as KV-cache memory, long contexts, batching, and GPU capacity. Mixture of Experts (MoE) attacks a different bottleneck inside the Transformer layer itself.
You've seen how a Transformer layer works: self-attention mixes information across tokens, then a Feed-Forward Network (FFN) processes each token independently. That FFN is dense. Every single weight in it participates in every single forward pass, no matter what the input says. This is simple, but it's also expensive. If you want the model to know more facts, handle more syntax, or reason about more domains, the standard recipe is to make the FFN wider or deeper. Every extra neuron adds parameters and adds compute for every token.
Mixture of Experts (MoE) breaks that link. Instead of one giant FFN, an MoE layer keeps many smaller FFNs in parallel and uses a lightweight router to decide which ones to run for each token. This means the model can have hundreds of billions of total parameters while only spending compute on a small subset of them for any given input.
MoE is one widely used way to separate model capacity from per-token compute. Switch Transformer[1] popularized sparse activation in trillion-parameter models. Open-weight systems now span Mixtral[2], DeepSeek-V2[3], DeepSeek-V3[4], Qwen3.6-35B-A3B[5], GLM-5.2[6], and DeepSeek V4 Flash 0731.[7] They share sparse activation, but expert counts, attention designs, active paths, and serving costs differ sharply.
What link does MoE break compared with a dense FFN layer?
Answer
A dense FFN uses all of its parameters for every token. MoE separates total capacity from active compute by storing many expert FFNs but routing each token to only a small top-k subset.
From one FFN to many experts
In a standard Transformer layer, the FFN sublayer is a single dense network. In an MoE layer, that one FFN is replaced by parallel "expert" FFNs, plus a small router (also called a gating network) that decides which experts handle each token. Those winners form a small top-k subset.[8]
In many modern LLMs, the experts replace the FFN sublayer while attention stays dense and shared across all tokens.[2][3] A common router design is a single linear projection from the token's hidden state down to scores.

Which parts of a Transformer layer are usually replicated in modern MoE LLMs?
Answer
The FFN sublayer is replaced by expert FFNs. Attention, embeddings, normalization, and most shared block logic usually stay dense and shared.
A concrete routing walkthrough
Before any formula or code, trace one token through an MoE layer by hand. This is the shape of the computation that happens inside models like Mixtral on every single token.
Setup
- One token arrives with a hidden state of dimension 4.
- There are 4 experts, each a small FFN.
- The router uses top- (it picks the 2 best experts).
Step 1: Router scores
The router multiplies the token by a learned weight matrix to get a raw score for each expert. Suppose the scores come out as:
| Expert | Raw score (logit) |
|---|---|
| 1 | -0.65 |
| 2 | -1.77 |
| 3 | -1.35 |
| 4 | -3.00 |
Step 2: Softmax probabilities
Apply softmax so the scores become probabilities that sum to 1. Approximate probabilities:
| Expert | Probability |
|---|---|
| 1 | 0.52 |
| 2 | 0.17 |
| 3 | 0.26 |
| 4 | 0.05 |
Step 3: Top-k selection
Pick the top 2 experts. That's Expert 1 (0.52) and Expert 3 (0.26).
Step 4: Renormalize
The selected weights are renormalized so they sum to 1 again within the chosen subset:
- Expert 1:
- Expert 3:
Step 5: Expert computation
Only Experts 1 and 3 run. Each processes the same input token through its own FFN weights.
- produces output vector
- produces output vector
Step 6: Weighted sum
The final layer output blends the two expert outputs using the renormalized gate weights:
That's it. The other two experts never process this token, so they contribute no expert-FFN FLOPs for this routing decision. Their weights still need to be stored or fetched by the serving system for other tokens that may select them.
1from math import exp
2
3logits = [-0.65, -1.77, -1.35, -3.00]
4unnormalized = [exp(score) for score in logits]
5probabilities = [value / sum(unnormalized) for value in unnormalized]
6selected = sorted(range(len(probabilities)), key=probabilities.__getitem__, reverse=True)[:2]
7selected_total = sum(probabilities[index] for index in selected)
8weights = [probabilities[index] / selected_total for index in selected]
9
10print("selected experts:", [index + 1 for index in selected])
11print("renormalized weights:", [round(weight, 2) for weight in weights])
12print("selected weight sum:", round(sum(weights), 2))1selected experts: [1, 3]
2renormalized weights: [0.67, 0.33]
3selected weight sum: 1.0What are the six steps for tracing one token through top-k MoE routing?
Answer
Compute router logits, apply softmax, select the top-k experts, renormalize the selected weights, run only the selected expert FFNs, then blend their outputs with the renormalized gate weights.
The general MoE layer formula
We can write the same walkthrough as a compact equation. For an input token , the MoE layer output is:
Reading the formula: the router computes a gate distribution over all experts. We keep only the configured top- entries, zero out the rest, and renormalize the survivors into so those remaining weights sum to 1. Mixtral uses top-2 out of 8, while other architectures choose different expert counts and routing policies.[2][3] Each selected expert processes independently, then their outputs are blended using the renormalized gates .
The architecture figure above is the visual form of this equation: the router scores every expert, keeps the top-, runs only those FFNs, then blends the selected outputs.
Why do selected expert weights need renormalization after top-k selection?
Answer
The original softmax probabilities include experts that are later zeroed out. Renormalization makes the surviving top-k weights sum to 1, so the blended output keeps the intended scale.
Why sparse activation can pay off
A dense feed-forward layer applies the same parameter matrix to every token. An MoE layer stores several expert matrices but routes each token through only top- experts. Per-token expert FLOPs therefore track active experts, while memory tracks all resident expert weights and distributed serving adds token-dispatch traffic.
| Property | Dense baseline (~active compute) | MoE Model (Mixtral-shaped) |
|---|---|---|
| Total parameters | ~13B illustrative dense peer | 46.7B (8 experts) |
| Active parameters/token | ~13B | ~12.9B (top-2 of 8) |
| Training FLOPs | Per total params | Per active params |
| Quality at fixed active compute | Baseline | Often stronger if routing trains well |
| Inference compute/token | Per total params | Roughly per active params |
The main benefit is that MoE can scale total parameters faster than per-token compute. By adding more experts while keeping top- fixed, the model gets a larger pool of FFN parameters, but each token still runs only a small subset. The expert FLOPs stay roughly tied to the active experts, not the full expert pool. Routing, batching, and communication still add overhead, so "same active parameters" doesn't mean identical latency.
That doesn't mean serving cost scales only with active parameters. Compute per token is sparse, but the system still needs access to the full expert pool, so memory footprint and communication often scale with total parameters, not active parameters.
Only the FFN blocks are replicated across experts. Attention layers, embeddings, normalization layers, and the router are still shared. That's why Mixtral 8x7B exposes 46.7B total parameters and about 12.9B active parameters per token, not the naive 56B and 14B you would get from multiplying everything by 8.[2]
The split matters: active parameters mostly drive per-token expert FLOPs, while total parameters drive weight memory and checkpoint size. Network traffic depends on where selected experts live.
1shared_parameters_b = 3.0
2expert_parameters_b = 2.0
3expert_count = 8
4top_k = 2
5
6total_parameters_b = shared_parameters_b + expert_count * expert_parameters_b
7active_parameters_b = shared_parameters_b + top_k * expert_parameters_b
8
9print("illustrative total parameters:", f"{total_parameters_b:.1f}B")
10print("illustrative active parameters/token:", f"{active_parameters_b:.1f}B")
11print("weights needed for residency:", f"{total_parameters_b:.1f}B")1illustrative total parameters: 19.0B
2illustrative active parameters/token: 7.0B
3weights needed for residency: 19.0BIf an MoE has 46.7B total parameters and 12.9B active parameters per token, which number drives FLOPs and which number drives memory residency?
Answer
Active parameters mostly drive per-token expert FLOPs. Total parameters drive checkpoint size and the amount of expert weight memory the serving system must keep available.
The router in code
Here's a basic PyTorch implementation of the standard top-k softmax router. It takes token embeddings, computes scores for each expert, and returns the indices and normalized weights for the top- choices.
1import torch
2import torch.nn as nn
3import torch.nn.functional as F
4
5class TopKRouter(nn.Module):
6 """
7 Routes tokens to the top-k experts based on learned gating weights.
8 """
9 def __init__(self, d_model: int, n_experts: int, top_k: int = 2):
10 super().__init__()
11 self.gate = nn.Linear(d_model, n_experts, bias=False)
12 self.top_k = top_k
13
14 def forward(self, x: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
15 # x: (batch, seq_len, d_model)
16 logits = self.gate(x) # (batch, seq_len, n_experts)
17 scores = F.softmax(logits, dim=-1)
18 top_scores, top_indices = scores.topk(self.top_k, dim=-1)
19
20 # Renormalize selected expert weights so they sum to 1
21 top_scores = top_scores / top_scores.sum(dim=-1, keepdim=True)
22
23 return top_scores, top_indices # Which experts, with what weight
24
25torch.manual_seed(0)
26torch.set_printoptions(precision=3, sci_mode=False)
27router = TopKRouter(d_model=4, n_experts=4, top_k=2)
28x = torch.randn(2, 3, 4)
29weights, indices = router(x)
30
31first_weights = [round(value, 3) for value in weights[0, 0].tolist()]
32weight_sums = [
33 [round(value, 3) for value in row]
34 for row in weights.sum(dim=-1).tolist()
35]
36
37print("first token experts:", indices[0, 0].tolist())
38print("first token weights:", first_weights)
39print("weight sums:", weight_sums)1first token experts: [3, 1]
2first token weights: [0.682, 0.318]
3weight sums: [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]Switch Transformer used top-1 routing, while Mixtral and DeepSeek-V2 use multiple selected routed experts per token.[1][2][3] Selecting more experts changes quality, compute, capacity, and communication trade-offs; it isn't automatically a better serving configuration.
What additional trade-off does top-2 routing introduce compared with top-1?
Answer
Top-2 lets a token blend two routed outputs, but it also executes and dispatches more expert work per token. Whether that trade improves quality or serving efficiency has to be measured for the architecture and hardware.
Alternative: expert choice routing
While the standard Top-K router forces each token to choose its top experts, Expert Choice Routing[9] flips the mechanism: each expert selects a fixed bucket of top-scoring tokens from the current batch.
Each expert processes a fixed token budget, so expert-side load is predictable and hardware utilization is easier to schedule. The trade-off moves to token coverage: one token may land in many expert buckets, one bucket, or none unless the design adds coverage rules. Token-choice routing with balancing losses remains the simpler mental model for open-weight MoE LLMs; expert-choice routing is still worth knowing when you read training-efficiency papers.
1expert_buckets = {
2 "E1": ["t0", "t1"],
3 "E2": ["t0", "t2"],
4 "E3": ["t2", "t3"],
5}
6all_tokens = {"t0", "t1", "t2", "t3", "t4"}
7selected_tokens = [token for bucket in expert_buckets.values() for token in bucket]
8uncovered = sorted(all_tokens - set(selected_tokens))
9
10print("tokens per expert:", [len(bucket) for bucket in expert_buckets.values()])
11print("t0 expert count:", selected_tokens.count("t0"))
12print("uncovered tokens:", uncovered)1tokens per expert: [2, 2, 2]
2t0 expert count: 2
3uncovered tokens: ['t4']What trade-off does expert choice routing make compared with token choice top-k routing?
Answer
Expert choice gives each expert a fixed token budget, so load balancing is easy. The risk moves to the token side: some tokens may get many experts while others may be skipped unless the design enforces coverage.
Why routers collapse without a balancing policy
During training, routers can drift toward expert collapse: many tokens route to a few "popular" experts while others are underutilized. Load statistics tell you whether this is occurring; they don't prove that a perfectly uniform router is best for model quality.
Start with four interchangeable experts labeled E1 through E4. Early in training, E1 happens to win slightly higher gate scores on common tokens. The router therefore assigns E1 more often. Because those tokens flow through E1, E1 receives more gradient updates and becomes even better at the tokens it already sees. The preference reinforces itself. After enough steps, E1 may take most assignments while E2 through E4 stay under-trained. The model still reserves memory for all four experts, but it's effectively operating with one overworked expert. That is load collapse, not proof that E1 became a "math expert" or that the idle ones own other domains.

The router is trained jointly alongside the rest of the network.[8] If a particular expert looks better for common tokens early in training, the router can send it more assignments. That expert then receives more gradient updates, which can reinforce the preference and leave other experts under-trained. The operational test isn't a story about specialization: inspect assignment shares, overflow, task loss, and communication load together.
1assignments = [0, 0, 0, 0, 0, 0, 1, 1, 2, 3]
2expert_count = 4
3counts = [assignments.count(expert) for expert in range(expert_count)]
4shares = [count / len(assignments) for count in counts]
5max_share = max(shares)
6
7print("assignment shares:", [round(share, 2) for share in shares])
8print("flag for investigation:", max_share > 0.50)1assignment shares: [0.6, 0.2, 0.1, 0.1]
2flag for investigation: TrueWhy does expert collapse reinforce itself during training?
Answer
The router sends more tokens to an expert that looks slightly better. That expert gets more gradient updates, improves faster, and becomes even more attractive to the router, starving other experts.
An auxiliary load-balancing loss
Switch Transformer uses a top-1 auxiliary loss that penalizes uneven routing.[1] This form is also a useful teaching calculation for top- routing when is normalized over routed assignments:
Reading the formula: multiply each expert's routed-assignment fraction by its average routing probability and sum them up. If the router sends too many assignments to one expert (high ) and gives it high probability (high ), this product is large, so the loss penalizes that concentration. It's a balancing pressure, not proof that equal utilization maximizes task quality.
where:
- ; with top-, the denominator is
- (average router probability)
- is a configurable coefficient (Switch reports experiments including )
- is the number of experts
A balanced reference point is (uniform distribution). A trained deployment still needs task-quality and systems measurements before you judge its observed specialization.
Here's a concrete top-1 numeric check. Suppose we have 4 experts and a mini-batch of 100 tokens:
| Expert | (actual fraction) | (average prob) | Product |
|---|---|---|---|
| 1 | 0.60 | 0.55 | 0.330 |
| 2 | 0.20 | 0.22 | 0.044 |
| 3 | 0.15 | 0.15 | 0.022 |
| 4 | 0.05 | 0.08 | 0.004 |
| Sum | 0.400 |
If the load were perfectly uniform, each expert would get , and the sum would be . With positive , this auxiliary term applies pressure against the imbalanced 0.400 case. Tune its weight with task-quality measurements because too much balancing pressure can conflict with the primary objective.
The auxiliary loss is a routing pressure, not the main learning objective. It says, "use the expert pool evenly enough," while the language-modeling loss still decides whether the model predicts the next token well.
1assignment_counts = [60, 20, 15, 5]
2mean_router_probability = [0.55, 0.22, 0.15, 0.08]
3expert_count = len(assignment_counts)
4assignment_total = sum(assignment_counts)
5fractions = [count / assignment_total for count in assignment_counts]
6
7concentration = expert_count * sum(
8 fraction * probability
9 for fraction, probability in zip(fractions, mean_router_probability)
10)
11uniform_reference = expert_count * sum((1 / expert_count) ** 2 for _ in fractions)
12
13print("scaled concentration:", round(concentration, 2))
14print("uniform reference:", round(uniform_reference, 2))
15print("excess balancing pressure:", round(concentration - uniform_reference, 2))1scaled concentration: 1.6
2uniform reference: 1.0
3excess balancing pressure: 0.6In the load-balancing loss, what do and measure?
Answer
measures how many tokens were actually routed to expert . measures the router's average probability for expert . A high value for both means the expert is both preferred and overloaded.
Capacity factor and overflow policy
In a batched environment, many MoE implementations use fixed-size expert buffers so the layer can run predictable tensor operations. This size is determined by the capacity factor:
This computes the average number of tokens each expert would receive under perfectly uniform routing, then multiplies by the capacity factor. A factor of means the buffer is exactly sized for uniform routing. Setting it to allows an expert to receive 20% more tokens than the average, providing a safety margin.
What happens if an expert is assigned more tokens than its capacity buffer allows depends on implementation:
- Dropping or pass-through: Switch-style designs can skip overflowed expert computations and rely on the residual path for those token-layer assignments.[1]
- Rerouting: A system can send overflow to another eligible expert, changing load and communication.
- Dropless execution: A system can execute all assignments with variable work, retaining quality paths while accepting less predictable workload.
This shows the trade-off: a higher capacity factor reduces overflow risk but reserves more buffer space and may waste compute on empty slots. A lower factor is more compact but makes whichever overflow policy you selected more important.
1from math import ceil
2
3tokens = 4096
4top_k = 2
5experts = 32
6capacity_factor = 1.0
7assigned_to_hot_expert = 400
8capacity = ceil(tokens * top_k / experts * capacity_factor)
9overflow = max(assigned_to_hot_expert - capacity, 0)
10
11print("per-expert capacity:", capacity)
12print("overflow assignments:", overflow)
13for policy in ("drop", "reroute", "dropless"):
14 print(policy, "must be evaluated for quality and throughput")1per-expert capacity: 256
2overflow assignments: 144
3drop must be evaluated for quality and throughput
4reroute must be evaluated for quality and throughput
5dropless must be evaluated for quality and throughputWhy does a capacity factor of 1.2 reduce overflow risk versus 1.0, and what must you know when an expert is full?
Answer
1.2 gives each expert a 20% buffer above uniformly distributed assignments, reducing overflow. The result of overflow is an implementation policy: it may drop, reroute, or execute extra assignments, with different quality and throughput costs.
How modern architectures scale the idea
The basic MoE pattern is consistent across modern models, but architects have refined it in interesting ways.
Mixtral 8x7B[2]
| Property | Value |
|---|---|
| Total params | 46.7B |
| Active params | ~12.9B |
| Experts | 8 |
| Top-K | 2 |
| Expert type | Standard FFN (SwiGLU activation[10]) |
| Performance | Mixtral paper (2024) reported matching or exceeding Llama 2 70B and GPT-3.5 on its evaluated suite[2] |
MoE is applied only to the Feed-Forward Network (FFN) layers. Attention layers are shared across all tokens, which is the standard approach. It uses a SwiGLU (Swish Gated Linear Unit) activation function, a variant of the Gated Linear Unit (GLU) that's been shown to improve Transformer performance.
DeepSeek-V2[3]
| Property | Value |
|---|---|
| Total params | 236B |
| Active params | 21B |
| Routed experts | 160 (fine-grained) |
| Shared experts | 2 (always-on) |
| Routed Top-K | 6 |
| Total active experts | 8 (6 routed + 2 shared) |
DeepSeek-V2 uses several extensions to coarse-grained MoE:
- Fine-grained experts: 160 smaller routed experts instead of a handful of coarse experts, which gives the router many more combinations to compose per token.[3]
- Shared experts: 2 experts are always active for all tokens. The design aims to capture common computation and reduce redundancy among routed experts; every token gets 2 shared expert outputs in addition to the 6 routed ones.[3]
- Device-limited routing: The selected routed experts for each token are constrained to a small number of devices, reducing cross-device communication overhead.[3]
- Multi-level balancing losses: DeepSeek-V2 adds separate expert-level, device-level, and communication-balance losses to keep routing efficient at cluster scale.[3]
- Multi-head Latent Attention (MLA): Compresses the KV cache into a low-rank latent vector, which the paper reports as a large KV-memory and throughput win relative to DeepSeek 67B.[3]
The diagram contrasts Mixtral's coarse-grained top-2 routing with DeepSeek-V2's fine-grained routed-plus-shared design. It shows the full expert counts, while tile sizes and the example selections are schematic.

DeepSeek-V3[4]
DeepSeek-V3 retains the DeepSeekMoE pattern at a larger reported scale.
| Property | Value |
|---|---|
| Total params | 671B |
| Active params | 37B |
| Routed experts | 256 |
| Shared experts | 1 |
| Routed Top-K | 8 |
| Total active experts | 9 (8 routed + 1 shared) |
| Main load balancing | Bias-adjusted auxiliary-loss-free strategy |
| Auxiliary guard | Sequence-wise balance loss |
| Other key component | Multi-head Latent Attention (MLA) |
Each MoE layer has 1 shared expert and 256 routed experts, with 8 routed experts activated per token.[4]
DeepSeek-V3 changes the routing details too. It computes token-to-expert affinity with sigmoid scores, normalizes the selected scores, and adds a per-expert bias only when choosing the top- routed experts. Training adjusts that bias from observed expert load. The weighted expert output still uses the original affinity score, not the routing bias.[4]
The paper calls this main batch-wise mechanism auxiliary-loss-free because it doesn't rely on an auxiliary loss to keep expert load balanced across a training batch. It still keeps a small complementary sequence-wise balance loss to prevent extreme imbalance inside one sequence.[4] The distinction matters: the standard softmax router above is a useful mental model, not a universal implementation contract.
GLM-5.2 and DeepSeek V4 Flash 0731
These releases make the stored-versus-active distinction impossible to ignore:
| Property | GLM-5.2 | DeepSeek V4 Flash 0731 |
|---|---|---|
| Vendor core-size label | 744B total / about 40B active[11] | 284B total / 13B active[12] |
| Released artifact metadata | About 753B BF16 parameters[6] | Hugging Face reports about 304B mixed-precision parameters; model card says DSpark module is attached[7] |
| Routed experts per MoE layer | 256[13] | 256[12] |
| Routed experts per token | 8[13] | 6[12] |
| Shared experts | 1[13] | 1[12] |
| Layers | 78[13] | 43[12] |
| Context | 1M text tokens[14] | 1M text tokens[12] |
| Long-context mechanism | Latent KV compression + DSA + IndexShare[13][15] | CSA + HCA hybrid attention[12] |
| Speculative path | One MTP module[13][15] | One MTP module plus attached DSpark module in 0731 artifact[12][16] |
| License | MIT[6] | MIT[7] |
This table is not a quality ranking. GLM-5.2 stores much more expert parameter capacity and targets long-horizon coding and tool workflows. Flash 0731 activates a smaller path and targets efficient agentic coding and serving. Both need full-checkpoint residency planning and workload-local evals. Inter-device expert communication and specialized sparse kernels may be needed for intended performance, depending on runtime and topology.[6][13][7][12]
Qwen3.6 sparse MoE checkpoint[5]
Qwen3.6 makes the active-versus-total split visible in the model name:
| Checkpoint | Total params | Activated params | What the suffix means |
|---|---|---|---|
| Qwen3.6-35B-A3B | 35B | 3B | 35B total, about 3B active per token |
This naming is a useful production reminder. "A3B" hints at active compute, not full deployment footprint. You still need enough memory, sharding, quantization, or offload capacity for the full checkpoint, and you still need serving support for routing, grouped expert execution, and any long-context KV-cache pressure.
What does DeepSeek-style fine-grained MoE add beyond "more experts"?
Answer
It uses many smaller routed experts, shared always-on experts, device-limited routing, and balancing policies designed for cluster-scale communication. The architecture problem is routing quality plus hardware efficiency, not parameter count alone.
When MoE is worth the complexity
Use MoE when the problem needs more model capacity at roughly fixed active compute, and the serving stack can absorb routing complexity. Prefer a dense model when the bottleneck is single-request latency, weak interconnect, or full-checkpoint memory.
| Decision signal | Dense is likely better | MoE is worth testing |
|---|---|---|
| Traffic shape | Low batch size, strict p95 latency | Large batches or offline throughput |
| Memory budget | One model must fit on a small fixed GPU set | Full checkpoint can be sharded, quantized, or offloaded |
| Network | All-to-all traffic already saturates links | Fast interconnect and device-aware routing are available |
| Quality target | Dense baseline already meets requirements | Extra capacity may improve harder tasks |
| Serving stack | Kernels lack grouped expert execution | Runtime supports routing, dispatch, combine, and expert placement |
| Observability | No routing, overflow, or per-expert metrics | You can inspect load balance, capacity, drops, and communication |
The wrong question is "does this model activate fewer parameters?" The useful question is whether the target workload gains enough quality or throughput after you account for full weight residency, routing overhead, interconnect cost, and operational visibility.
What is the fastest practical dense-vs-MoE gate?
Answer
Compare dense and MoE on the real serving regime. Require quality to meet the bar, p95 latency to fit the product budget, throughput to justify the extra routing machinery, and memory residency to fit the deployment plan.
The hardware reality of serving an MoE
Implementing MoE introduces complexities not present in dense models. The compute per token is sparse, but the system still faces several hard serving constraints.
Communication overhead
In distributed training and inference, experts often reside on different devices to meet memory requirements. Routing a token to an expert on another GPU requires transferring the token's hidden state over a high-bandwidth interconnect such as NVLink within a node or InfiniBand across nodes.
This communication can quickly become a bottleneck if not managed carefully. The process usually has an all-to-all dispatch phase that scatters tokens to the GPUs hosting their selected experts, followed by an all-to-all combine phase that returns the expert outputs to the original token order. To maintain high throughput, system designers try to overlap those transfers with useful compute so the network isn't stalling the whole layer.
1expert_device = {"E0": "GPU0", "E1": "GPU0", "E2": "GPU1", "E3": "GPU1"}
2routed_assignments = [
3 ("GPU0", "E0"),
4 ("GPU0", "E2"),
5 ("GPU1", "E2"),
6 ("GPU1", "E1"),
7 ("GPU0", "E3"),
8]
9remote = sum(
10 source_device != expert_device[expert]
11 for source_device, expert in routed_assignments
12)
13
14print("routed assignments:", len(routed_assignments))
15print("remote assignments:", remote)
16print("remote rate:", f"{remote / len(routed_assignments):.0%}")1routed assignments: 5
2remote assignments: 3
3remote rate: 60%Memory requirements
Unlike dense models where there's only one FFN per layer, MoE models carry many expert FFNs. Fast GPU deployments generally keep those expert weights resident somewhere in the serving pool so routing doesn't stall on weight fetches.
This creates the core MoE paradox: low active compute per token, but very high total weight residency. A model like Mixtral 8x7B only activates about 12.9B parameters per token, yet the serving system still needs the full 46.7B parameter checkpoint available across the cluster.[2] Tensor Parallelism (TP) splits individual layer computations across multiple GPUs, allowing larger shared layers to fit into memory, but it doesn't solve the unique structure of MoE. Expert Parallelism (EP) is needed to place different full experts on different GPUs while keeping every expert reachable when a token needs it.
Why doesn't tensor parallelism alone solve MoE serving?
Answer
Tensor parallelism shards individual matrix operations. MoE also needs expert placement, dispatch, and combine across whole expert FFNs, so serving systems use expert parallelism to keep different experts reachable across devices.
Training instability
MoE training can be more sensitive than training a comparable dense Transformer. The top- routing step introduces discontinuities at expert-selection boundaries, and small routing biases can snowball into expert collapse. Gradients still flow through the selected experts and their gate weights, but the router is noisier to optimize than a dense FFN.
To combat this, implementations may add stabilizers. Router z-loss[17] penalizes unnecessarily large routing logits; the ST-MoE paper reports improved training stability from this term. Input jitter is another candidate to test, but ST-MoE's XL-scale ablation improved stability while reducing quality.[17] The relevant evidence is training loss, routing distribution, overflow, and downstream quality rather than assuming one stabilizer is free or mandatory for every MoE.
Expert parallelism layout
Large distributed MoE deployments commonly use Expert Parallelism (EP). While Tensor Parallelism (TP) splits individual matrix multiplications, EP maps entire experts to specific GPUs. The layout below is deliberately schematic: it illustrates expert ownership and a shared attention path, not one universal sharding plan. Real deployments can combine EP with TP, sequence parallelism, data parallelism, and redundant expert placement. For example, DeepSeek-V3 describes a decoding layout with TP4 for attention and EP320 for the MoE path.[4]
The smaller 96-expert sketch looks like this:
1GPU 0: Attention layers (shared) + Experts 0-31
2GPU 1: Attention layers (shared) + Experts 32-63
3GPU 2: Attention layers (shared) + Experts 64-95
4...Each GPU stores a subset of experts. When a token routes to an expert on another GPU, an all-to-all communication sends the token there and retrieves the result.
Sizing EP traffic
A lower bound on dispatch + combine volume for tokens with top- routing, hidden size , and element size bytes is:
(plus small routing metadata). Compare that wire cost to expert GEMM work on a device that receives token-slots: roughly FLOPs for a two-projection FFN with intermediate size , counting one multiply and one add as two FLOPs in each of the up and down projections. A gated three-projection FFN is roughly FLOPs under the same convention. When interconnect is weak or is small (decode microbatches), the term can dominate even if active FLOPs look cheap.
Balanced global expert histograms are not enough. If many popular experts land on the same EP rank, that rank's per-device token histogram spikes, capacity overflows, and the all-to-all waits on a straggler. Device-limited routing and capacity policy should be checked against per-rank token counts as well as expert-ID frequencies.
Prefill vs decode under EP: large prefill batches can amortize dispatch/combine across many tokens per expert. Decode microbatches re-expose router, grouping, and all-to-all latency every step, which is why dense paths sometimes win p95 at batch size 1 even when MoE wins throughput.

Expert prefetching
For CPU-offloaded serving (for example, running a quantized MoE checkpoint on consumer hardware), one possible design is:
- Keep attention weights and router weights in GPU memory (always needed).
- Keep expert weights on CPU or SSD.
- After a layer's router decides which experts are needed, transfer those expert weights before its expert computation.
- Optionally use prediction or caching to stage likely later-layer experts, accepting misses or unused transfers.
This can make large MoE checkpoints fit where full GPU residency can't, especially when combined with weight quantization, but it trades memory for transfer-dependent latency. You can't know an exact next-layer route until that layer receives its hidden state, so unconditional "prefetch the next experts" isn't free.
Batch routing efficiency
In batch serving, different tokens in a batch may route to different experts. Batched expert execution is the serving trick:
- Router assigns all tokens in the batch to their top-k experts.
- Group tokens by expert assignment.
- Execute each expert as a batched matrix multiply over its assigned tokens.
- Scatter results back to original token positions.
This groups many per-token expert calls into a smaller number of larger matrix multiplies, which helps keep GPU utilization high with MoE models.
1from collections import defaultdict
2
3routes = [
4 ("t0", "E2"),
5 ("t1", "E0"),
6 ("t2", "E2"),
7 ("t3", "E1"),
8 ("t4", "E2"),
9]
10grouped = defaultdict(list)
11for token, expert in routes:
12 grouped[expert].append(token)
13
14for expert in sorted(grouped):
15 print(expert, "batch tokens:", grouped[expert], "gemm rows:", len(grouped[expert]))1E0 batch tokens: ['t1'] gemm rows: 1
2E1 batch tokens: ['t3'] gemm rows: 1
3E2 batch tokens: ['t0', 't2', 't4'] gemm rows: 3Benchmark slices instead of memorizing a crossover:
| Measurement slice | What it exposes |
|---|---|
| Single request, batch size 1 | Fixed router, grouping, and dispatch overhead |
| Moderate and large batches | How much grouped expert execution amortizes that overhead |
| Local versus remote expert routes | Cost of expert placement and all-to-all traffic |
| Strong versus weak interconnect | Whether network bandwidth changes the winner |
Exact outcomes depend on kernels, expert placement, interconnect, and request mix. MoE adds router computation, expert selection, token grouping, and sometimes all-to-all communication; batching can amortize that overhead, but only measurements on the target system establish whether MoE wins latency or throughput.
The next code block uses an illustrative measurement fixture. Replace these numbers with benchmark output from the serving stack under evaluation.
1dense = {"quality": 0.82, "p95_ms": 48, "tokens_per_second": 820}
2moe = {"quality": 0.83, "p95_ms": 55, "tokens_per_second": 1100}
3requirements = {"quality": 0.82, "max_p95_ms": 60, "min_tokens_per_second": 1000}
4
5approved = (
6 moe["quality"] >= requirements["quality"]
7 and moe["p95_ms"] <= requirements["max_p95_ms"]
8 and moe["tokens_per_second"] >= requirements["min_tokens_per_second"]
9)
10
11print("moe throughput improvement:", f"{moe['tokens_per_second'] / dense['tokens_per_second'] - 1:.1%}")
12print("moe p95 delta ms:", moe["p95_ms"] - dense["p95_ms"])
13print("candidate approved:", approved)1moe throughput improvement: 34.1%
2moe p95 delta ms: 7
3candidate approved: TrueWhy can dense models beat MoE on single-request latency even when MoE has fewer active parameters?
Answer
MoE adds router work, token grouping, expert dispatch, and often all-to-all communication. With batch size 1, that overhead may dominate. Larger batches amortize it across many routed tokens.
When MoE serving breaks down
"Active FLOPs are small, so deployment memory will be small too"
- Symptom: FLOP estimates look cheap, but deployment still runs out of VRAM.
- Cause: Team budgeted only for active parameters per token and forgot that the full expert pool must still be resident somewhere in the serving system.
- Fix: Separate active expert FLOPs from total weight residency. Size memory for the full expert pool as well as the routed path.
"Router imbalance will fix itself later"
- Symptom: One or two experts receive most tokens by early training.
- Cause: Router found a slightly better path, that expert got more gradients, and collapse reinforced itself.
- Fix: Track routing histograms from the start and tune the load-balancing policy before unused experts go stale. Evaluate router z-loss separately for numerical stability, and inspect capacity plus overflow policy separately for dropped or delayed work.
"Sparse compute guarantees lower latency"
- Symptom: MoE benchmark wins disappear at batch size 1.
- Cause: Sparse expert FLOPs aren't the whole latency story. Router work, grouping, dispatch, and all-to-all traffic can dominate single-request latency.
- Fix: Evaluate MoE on the real serving regime. Use dense models for low-latency single requests when routing overhead outweighs sparse compute gains.
"Expert placement is a later infra detail"
- Symptom: Throughput drops sharply after experts are split across GPUs.
- Cause: Expert placement created communication hotspots. Tokens now bounce across devices faster than grouped GEMMs can amortize the transfers.
- Fix: Treat routing and placement as one systems problem. Use expert parallelism, device-aware routing, and batching to keep all-to-all traffic under control.
"Balanced histograms mean routing is healthy"
- Symptom: Quality drops even though router histograms look balanced.
- Cause: Experts may be hitting capacity limits, and the configured overflow policy is dropping, rerouting, or delaying assignments.
- Fix: Inspect overflow counts and policy directly. Evaluate capacity factor, routing balance, burstiness, and throughput before assuming the issue is elsewhere.
"Expert-choice routing covers every token automatically"
- Symptom: Expert-choice routing leaves some tokens underprocessed.
- Cause: Experts select their favorite tokens first, so token coverage is no longer guaranteed automatically.
- Fix: Add explicit coverage rules or use token-choice top-k routing when every token must reliably receive expert computation.
"Experts are neat human-labeled topic buckets"
- Symptom: Teams describe experts as clean topic buckets like "math expert" or "biology expert."
- Cause: Human-friendly labels are being projected onto behavior that often follows token patterns, formatting, or structural clusters instead.
- Fix: Validate specialization with routing traces, activation analysis, and targeted prompts that test a claimed specialty before telling a story about it.
What's the simplest way to tell whether someone understands MoE serving cost?
Answer
They separate three quantities: active FLOPs per token, total expert weight residency, and communication cost from routing tokens to experts across devices.
Sparse routing checklist
The central trick behind large sparse MoE models should be concrete: replace selected dense FFNs with routed expert sets and activate only configured paths per token. A real serving claim still has to pass the router trace, total-parameter versus active-compute distinction, balance, overflow policy, memory residency, and communication checks.