Part of Language AI Handbook
Explains how auxiliary balancing loss prevents expert collapse in MoE models. Topics include loss formulations, coefficient tuning, and PyTorch implementation.
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Auxiliary Balancing Loss
In the previous chapter, we explored why load balancing matters for Mixture of Experts models: without it, a few experts monopolize computation while others sit idle. But understanding the problem doesn't solve it. The gating network, trained purely to minimize task loss, has no incentive to spread tokens evenly. We need to explicitly tell the model that balance matters.
The solution is an auxiliary loss: a secondary objective added to the main task loss that penalizes imbalanced expert usage. Think of the auxiliary loss as a referee standing at the side of the training field, occasionally blowing a whistle whenever the team starts hogging the ball. The players (the router and experts) still focus on scoring goals (task performance), but they know that consistently ignoring teammates will cost them points. This chapter covers the mathematical formulation of balancing losses, how to tune the coefficient that controls their strength, the basic tension between balancing and task performance, and how to implement these losses in practice.
The auxiliary loss approach does not fundamentally change how MoE routing works. The router still selects the best expert for each token, and experts still learn to specialize. It changes the definition of the best training outcome: the task objective gains a penalty term that rises whenever the token distribution across experts becomes too lopsided. This soft pressure gives the system room to specialize while preventing the degenerate collapse observed in unregulated training.
Before we look at specific formulations, it helps to appreciate what makes the auxiliary loss problem interesting. We can't simply count tokens routed to each expert and penalize high counts, because that count is a discrete function of the argmax routing decision, and discrete operations have zero gradient almost everywhere. We need a differentiable proxy for "how much the router prefers each expert," and this turns out to be more subtle than it first appears. The formulations in this chapter each make specific choices about how to measure and penalize imbalance in a way that produces useful gradients, and understanding those choices helps you reason about when one formulation might be preferable to another.
Understanding auxiliary balancing loss has practical consequences. Training an MoE model without it, or with a poorly tuned coefficient, can lead to expert collapse. The training loss may look fine, but the model will use a fraction of its available capacity, and inference will be slower because the hardware cannot exploit the parallelism that MoE was designed to provide. This chapter gives you tools to prevent that outcome.
Why Gating Networks Cause Imbalance
Before diving into loss formulations, let's understand why the problem exists in the first place. The imbalance we observe in MoE models isn't a bug in the gating mechanism; rather, it's an emergent property of how neural networks learn through gradient descent. Understanding the root cause will make the solution much more intuitive. To see this clearly, consider what happens during early training when all experts and the router begin with random weights.
By chance, some experts receive slightly more tokens than others. This initial asymmetry might seem insignificant, perhaps one expert receives 27% of tokens while another receives 23%. However, this small difference sets in motion a cascade of effects. The experts that receive more tokens also receive more gradient updates, since each processed token generates gradients that flow back through the expert network. With more updates, these experts improve faster. Their weights adjust more quickly to the training distribution, and they become better at processing the token types they see.
The gating network, meanwhile, is doing its job diligently. It observes the reconstruction quality or task performance when tokens are routed to different experts, and it adjusts its weights to favor better-performing routes. When it notices that certain experts produce better outputs, it increases the routing probabilities toward those experts. This is exactly the behavior we want from a gating network when experts have different competencies, but during early training, this feedback creates a self-reinforcing cycle.
This creates a feedback loop: success breeds more success, failure breeds abandonment. Experts that received slightly more tokens initially improve, which makes them receive even more tokens and improve further. Meanwhile, experts that received fewer tokens fall behind. They update less frequently, improve more slowly, and become comparatively worse choices. The gating network, observing this growing gap, routes even fewer tokens to the struggling experts.
The gating network is doing exactly what we trained it to do: minimize task loss by routing tokens to the best experts. The problem is that "best" becomes self-fulfilling. Experts that receive no tokens never improve, so they remain poor choices, so they continue receiving no tokens. Left unchecked, this process converges to a degenerate state where one or two experts handle nearly all computation while the remaining experts contribute nothing. This represents a catastrophic waste of model capacity, as we've paid the memory cost of multiple expert networks but receive the computational benefit of only a few.

An auxiliary loss breaks this cycle by adding a cost for imbalance. The core insight is that we can modify what "success" means during training. Instead of optimizing purely for task performance, we add a secondary objective that penalizes concentration of expert usage. The total training objective becomes:
where:
- : the combined objective function used for training
- : the primary objective (e.g., cross-entropy loss)
- : a scalar coefficient controlling the weight of the balancing penalty
- : the auxiliary loss term that penalizes imbalanced expert usage
The balancing loss increases when expert usage becomes skewed, forcing the optimizer to consider both task performance and expert utilization. This formulation allows us to tune how much we care about balance relative to task performance through the coefficient . A small gently encourages balance while prioritizing task quality; a larger enforces stricter balance at the potential cost of task performance.
The optimizer minimizes this combined objective. The gradient of the total loss with respect to any parameter now includes contributions from both the task loss and the balancing loss, weighted by . The router weights receive nudges from "how well did the selected expert perform" and from "is the distribution of expert selections becoming too skewed." These two gradient signals compete, and the coefficient determines their relative influence.
Importance-Based Auxiliary Loss
The researchers working on Mixture of Experts models in the 2017 era faced a chicken-and-egg problem when designing the auxiliary loss: they needed a differentiable measure of expert load, but actual routing decisions are discrete. The original MoE paper by Shazeer et al. (2017) resolved this elegantly by measuring not which experts tokens are sent to, but how much attention the router pays to each expert. This led to the importance-based auxiliary loss, and understanding it provides an important foundation before we look at the more refined formulations that followed.
The intuition behind the importance approach is straightforward: if we can measure how much attention the router pays to each expert, we can penalize situations where some experts receive vastly more attention than others. The key insight is that router probabilities, before the hard selection of which expert to use, provide a soft measure of expert "importance" that we can aggregate and analyze across an entire batch.
For each token in a batch, the gating network produces probabilities for routing to expert . These probabilities sum to one across experts and represent the router's assessment of how suitable each expert is for processing that particular token. A high probability indicates the router considers that expert a good match; a low probability indicates a poor match. These probabilities exist for all experts, including those that do not win the argmax competition, and they are fully differentiable with respect to the router's parameters. The importance of expert across the batch is the sum of these probabilities:
where:
- : the total importance score for expert across the batch
- : a token in the current batch
- : the probability assigned to expert by the gating network for token
- : the summation over all tokens in the batch
To understand what this measures, consider a concrete example. If our batch contains 100 tokens and the router assigns an average probability of 0.4 to expert 3 across all tokens, then the importance of expert 3 would be 40. If all tokens strongly prefer expert 3, then will be large while other experts have small importance values. In a perfectly balanced scenario with 4 experts, each expert would have an importance of 25 (since probabilities must sum to 1 for each token, the total importance across all experts equals the batch size).
The importance measure reflects the router's preferences before any hard decisions are made. Even if a token ultimately gets routed to expert 1 because it has probability 0.35 compared to expert 2's 0.30, both experts contribute to the importance calculation. This provides a smoother signal than counting routing decisions. Think of importance as a measure of how often experts "come close to being selected."
To quantify the imbalance in importance scores, we need a metric that captures how spread out or concentrated the distribution is. We use the squared coefficient of variation (CV):
where:
- : the importance-based auxiliary loss
- : the standard deviation of importance scores across all experts
- : the mean importance score across all experts
- : the coefficient of variation, measuring relative dispersion
The coefficient of variation measures spread relative to the mean. This relative measure is important because we want the loss to be meaningful regardless of batch size. A standard deviation of 10 means something very different when the mean is 25 versus when the mean is 1000. By dividing by the mean, we get a dimensionless ratio that measures proportional variation. A CV of 0 means all experts have identical importance (perfect balance). A CV of 1 means the standard deviation equals the mean, showing substantial concentration.
Squaring the coefficient of variation serves two purposes. First, it ensures the loss is differentiable at zero, which matters for gradient-based optimization. Second, it penalizes large deviations more strongly than small ones, creating a steeper gradient when imbalance is severe and a gentler gradient when balance is nearly achieved. When all experts have equal importance, and the loss is zero. When importance is concentrated on one expert, the loss becomes large.
This formulation operates at the batch level rather than the token level. The model can route individual tokens wherever it wants, as long as the aggregate distribution remains balanced. This flexibility matters because different tokens benefit from different experts. The loss does not micromanage individual routing decisions; instead, it constrains the overall outcome. The router can make confident, lopsided decisions for individual tokens as long as those decisions average out across the batch.
The importance-based auxiliary loss first appeared in "Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer" by Shazeer et al. (2017), which demonstrated MoE models with up to 137 billion parameters on language modeling tasks. At the time, training models of this scale was only feasible because MoE allowed conditional computation: only a subset of parameters were activated per token. The auxiliary loss was needed to making this work in practice, as without it the models quickly collapsed to using only one or two experts regardless of how many were available. This paper established the blueprint that modern MoE architectures like Mixtral and GPT-4 still follow.
Load Balancing Loss Formulation
The Switch Transformer paper (Fedus et al., 2021) introduced a refined formulation that became the standard in modern MoE architectures. This newer approach addresses some limitations of the importance-based loss by more directly measuring actual routing behavior rather than just router preferences. Instead of using coefficient of variation, it directly measures two quantities and penalizes their correlation.
The Switch Transformer formulation separates two components of balance: routing outcomes, meaning how many tokens end up at each expert, and router intentions, meaning how much probability mass the router assigns to each expert. A well-balanced system should keep both in sync. If routing is balanced but router intentions are skewed, the balance is fragile and may break down. If router intentions are balanced but routing is skewed, the discrete selection step behaves unexpectedly.
For a batch of tokens and experts, we define two complementary measures of expert usage. The first captures what happens during routing, while the second captures what the router intended. Their product forms the balancing loss.
Fraction of tokens routed to expert :
where:
- : the fraction of tokens routed to expert
- : the total number of tokens in the batch
- : the indicator function, which is 1 if the condition is true and 0 otherwise
- : the index of the expert with the highest probability for token
- : the total count of tokens in the batch assigned to expert
This quantity measures the actual routing outcome. When the router makes its final decision for each token, selecting the expert with the highest probability, some experts will be chosen more frequently than others. The fraction counts how many tokens were ultimately sent to expert and normalizes by the total token count. This is the fraction of tokens where expert was selected (had the highest gate probability). It represents the actual load on each expert.
The important aspect of is that it reflects discrete decisions. A token is either routed to an expert or it isn't, and this binary nature means captures the ground truth of computational load. If expert 3 processes 40% of tokens, then , regardless of whether those routing decisions were made with high confidence (probability 0.9) or narrow margins (probability 0.26 versus 0.25 for the runner-up).
Fraction of router probability assigned to expert :
where:
- : the fraction of router probability assigned to expert
- : the routing probability assigned to expert for token
- : the total number of tokens in the batch
- : the sum of routing probabilities for expert across all tokens
This quantity measures the router's overall preference for each expert. Unlike , which counts discrete decisions, aggregates the continuous probability values. This is the average probability the router assigns to expert across all tokens. It represents the router's "intention" to use each expert, capturing which expert wins the argmax competition and how confident the router is in its choices.
The distinction between and is subtle but important. Consider a batch where half the tokens give expert 1 probability 0.51 and expert 2 probability 0.49, while the other half gives expert 2 probability 0.51 and expert 1 probability 0.49. The fractions and would both be approximately 0.5. This reflects balanced intentions. But if by chance the argmax consistently favors expert 1, then would be much larger than , revealing the imbalance in actual routing.
The load balancing loss is the scaled dot product of these vectors. Before writing the formula, note what we want to compute: a quantity that is small when both and are evenly distributed, and large when they concentrate on the same experts. The natural way to detect this joint concentration is to multiply the two vectors element-wise and sum:
where:
- : the auxiliary balancing loss
- : the total number of experts
- : the fraction of tokens routed to expert (actual load)
- : the average probability assigned to expert (intended load)
- : the summation over all experts
The factor normalizes the loss so that perfect balance gives . This normalization is a thoughtful design choice that makes the loss interpretable. A value of 1.0 means perfect balance, values above 1.0 indicate imbalance, and the magnitude tells us how severe the imbalance is. Under perfect balance, each expert receives fraction of both tokens and probability, so for all . We can verify the loss value:
When load is imbalanced, both and grow for popular experts and shrink for unpopular ones. The correlation between these quantities drives the loss increase. Since both terms are larger for popular experts, their product is even larger, and the sum exceeds 1.
Why This Formulation Works
This loss formulation works because of what it penalizes. The product structure creates a natural feedback mechanism that targets exactly the behavior we want to discourage. Consider what happens when expert is overused:
- More tokens are routed to it, so increases
- The router assigns higher probabilities to it, so increases
- The product grows quadratically
This quadratic growth matters. When an expert is slightly overused, both and increase slightly, and their product reflects this twice. When an expert is heavily overused, both quantities increase substantially, and their product amplifies the signal further. The loss creates a gradient that pushes the router to reduce probabilities for overused experts.
Only contributes gradients, since involves a discrete argmax and is non-differentiable. But amplifies the gradient signal: popular experts get stronger pushback. The non-differentiable acts as a weighting factor, directing optimization toward high-load experts. Experts with high load receive stronger gradient signals on their probability terms, while experts with low load receive weaker signals. This adaptive weighting helps the optimizer prioritize the most severe imbalances.
The formulation also avoids a subtle failure mode. If we only penalized variance, the router could game the system by assigning nearly uniform probabilities while still routing most tokens to one expert through tiny differences that favor the same expert. Imagine a scenario where the router learns to give expert 1 probability 0.251 and all other experts probability 0.2497. The probability distribution looks nearly uniform, so a variance penalty would be small. Yet the argmax would consistently select expert 1, creating severe imbalance. By including , we measure routing decisions rather than only intentions. The combined product catches this gaming attempt because would be large even if increases only slightly.


Worked Example: Computing the Balancing Loss by Hand
To solidify the mechanics of the load balancing loss, let's work through a small concrete example step by step, using numbers that are easy to follow. We will use a batch of 8 tokens and 3 experts, and trace through the entire computation manually.
Imagine we have a batch of 8 tokens and the router produces the following probabilities for each token. Each row sums to 1.0 because the probabilities come from a softmax operation.
| Token | Expert 0 | Expert 1 | Expert 2 | Selected |
|---|---|---|---|---|
| t1 | 0.70 | 0.20 | 0.10 | 0 |
| t2 | 0.60 | 0.25 | 0.15 | 0 |
| t3 | 0.15 | 0.65 | 0.20 | 1 |
| t4 | 0.10 | 0.70 | 0.20 | 1 |
| t5 | 0.55 | 0.30 | 0.15 | 0 |
| t6 | 0.20 | 0.15 | 0.65 | 2 |
| t7 | 0.65 | 0.25 | 0.10 | 0 |
| t8 | 0.25 | 0.60 | 0.15 | 1 |
Notice that Expert 0 is selected most often (4 out of 8 tokens), while Experts 1 and 2 receive 3 and 1 tokens respectively. This is a moderately imbalanced distribution that our loss should detect.
Step 1: Compute (fraction of tokens routed to each expert)
Count the tokens assigned to each expert via the argmax, then divide by 8:
Under perfect balance with 3 experts, we would expect each . Expert 0 is overloaded at 0.5, and Expert 2 is underloaded at 0.125.
Step 2: Compute (average router probability per expert)
Sum the probabilities in each expert's column, then divide by 8:
We can verify: . This must always hold because the softmax probabilities for each token sum to 1, so summing across all tokens and then averaging preserves this property.
Step 3: Compute the load balancing loss
We compute the dot product of and , scaled by :
The loss of 1.1156 is above the perfect-balance baseline of 1.0, confirming that the distribution is moderately imbalanced. The deviation is modest because the imbalance itself is moderate; if Expert 0 had received all 8 tokens, the loss would be much higher. Under perfect balance with experts, we would have for all , and the loss would compute to exactly 1.0.
Intuition check: The product is largest for Expert 0. It receives the most tokens and has the highest average probability. This is the "double penalty" mechanism: an overloaded expert contributes disproportionately to the sum because both factors increase.
Loss Coefficient Tuning
The coefficient in controls the strength of the balancing incentive. This single hyperparameter has outsized importance in MoE training, as it determines how the model allocates its optimization effort between learning useful representations and maintaining computational balance. Setting correctly is important: too small and experts collapse; too large and the model sacrifices task performance to achieve perfect balance.
To understand why matters so much, think about what gradient descent is doing at each update step. The gradient of has two components: one from the task loss that pushes the router toward routing decisions that improve task performance, and one from the balancing loss that pushes the router toward more uniform distributions. The coefficient sets the ratio of these two forces. If and the task loss gradient magnitude is 100 times larger than the balancing loss gradient magnitude, then both contributions are comparable in their effect. If is too small, the balancing force is drowned out and has negligible effect on the router's learned behavior.
Typical values used in practice and the reasoning behind them:
- : The default value from the Switch Transformer paper. Works well for most MoE configurations. At this setting, with a typical task loss around 2.0 and a balancing loss around 1.0, the balancing term contributes roughly 0.5% of the total gradient signal.
- : Appropriate for models where task quality is necessary and some imbalance is acceptable, or as a starting point for exploratory training.
- : More aggressive balancing. Use this if you observe persistent collapse with smaller values.
- Scale dependence: The appropriate depends on how large typically is. If task loss is around 2.0 and balancing loss is around 1.0, means balancing contributes about 0.5% of the total gradient signal.
- Number of experts: More experts require careful tuning, as the minimum achievable imbalance increases with expert count.
- Top-k value: With top-2 routing, each token contributes to two experts' load, which naturally improves balance compared to top-1.
Effects of Extreme Coefficients
When is too small, the model effectively ignores the balancing signal. The gradient contribution from the auxiliary loss becomes negligible compared to the task loss gradients. Expert collapse proceeds as if no auxiliary loss existed. You'll observe a few experts receiving most tokens while others remain unused throughout training. The training curves may look healthy in terms of task loss, but inspection of expert utilization reveals the underlying pathology. Essentially, the optimizer "prices in" the tiny balancing penalty and determines that the task loss improvement from putting tokens is worth it. You've told the model that balance matters a little, but the model has correctly concluded that it doesn't matter enough to change its behavior.
When is too large, the model prioritizes balance over task performance. The optimizer, faced with a strong gradient signal to equalize expert usage, adjusts the router weights primarily to reduce the balancing loss. In the extreme, the router learns to assign exactly uniform probabilities to all experts, achieving perfect balance but terrible task performance. The model loses its ability to specialize experts for different types of inputs. Every expert becomes equally mediocre at handling all tokens, squandering the capacity benefits that MoE architectures are designed to provide. In a language model, this would look like a model that routes all token types to all experts equally, preventing any expert from developing useful specialization for code, dialogue, or technical text.
The sweet spot achieves "soft" balance: experts receive roughly similar token counts, but the router retains freedom to assign non-uniform probabilities based on input characteristics. In this regime, the auxiliary loss prevents pathological collapse without overly constraining the router's flexibility. You can usually identify this regime by checking that the imbalance ratio (max expert usage divided by min expert usage) stays below about 3:1, while the router's probability distributions for individual tokens remain diverse rather than uniform.


Practical Tuning Strategy
Tuning requires monitoring both the task loss and expert utilization during training. You cannot rely on validation loss alone, because a model with severe expert collapse can sometimes achieve decent task loss by putting all computation in one or two strong experts. The hidden cost appears when you measure inference efficiency or examine whether the model uses its full capacity. A reliable approach is to start with and monitor both metrics during training:
- Track expert utilization (fraction of tokens per expert) across training
- Track the ratio
- If experts collapse (one expert gets >50% of tokens), increase by 2-3x
- If task loss plateaus while balance loss keeps dropping, decrease
We'll explore a related technique called Router Z-Loss in the next chapter, which provides additional stabilization with less impact on task performance.
Balancing vs Task Loss Tradeoffs
There is a basic tension between balancing and task performance that no formulation can eliminate. This tension is not a flaw in the auxiliary-loss approach; it reflects a tradeoff inherent to MoE architectures. Understanding this tradeoff helps set realistic expectations and informs practical decisions about coefficient values.
The core of the tension is this: the auxiliary loss treats uniform expert usage as the ideal, but task performance may favor non-uniform usage. Different input types benefit from different experts. A language model might naturally develop experts for code, dialogue, technical writing, and creative text. This specialization emerges because experts can become particularly good at certain patterns when they see them repeatedly. If code represents only 10% of training data, the code expert should receive only 10% of tokens. Forcing equal distribution means either routing non-code tokens to the code expert (hurting their performance) or routing code tokens away from the code expert (hurting code performance). In both cases, task quality is sacrificed for an arbitrary notion of fairness.
Why some imbalance is tolerable: In practice, moderate imbalance (say, a 2:1 ratio between most and least popular experts) has minimal impact on inference efficiency. Modern accelerators handle this gracefully through techniques like dynamic batching and load balancing at the infrastructure level. The goal is preventing pathological collapse, not achieving perfect uniformity. A model where all eight experts receive between 10% and 15% of tokens is functioning well, even though the distribution isn't perfectly uniform. The 2:1 ratio matters much less than the catastrophic 100:1 ratio that emerges without any auxiliary loss at all.
Empirical findings from the original papers provide useful benchmarks. The Switch Transformer paper found that achieved a good balance between utilization and task performance. At this setting, expert utilization variance was significantly reduced compared to no auxiliary loss, while perplexity degradation was minimal (less than 0.5%). Higher values of continued improving balance but with diminishing returns and increasing task performance cost. This empirical curve is important: it tells us that the first few units of balance improvement are cheap (small perplexity cost), but squeezing out the last bit of perfectly uniform distribution is expensive. The practical implication is that you should aim for "good enough" balance, not perfect balance.
The tradeoff also has a temporal dimension that practitioners often overlook. During early training, experts have not yet specialized, and the cost of forced uniformity is low because there is no useful specialization to destroy. During late training, experts may have developed meaningful specializations, and forcing uniformity becomes more costly. Some researchers experiment with annealing over the course of training: starting with a moderate value to establish initial balance, then reducing it slightly to allow specialization to solidify. This approach requires careful monitoring but can yield better final models than a fixed .
The Capacity Factor Interaction
As we discussed in the Load Balancing chapter, the capacity factor limits how many tokens each expert can process. This creates an important interaction with the auxiliary loss, as both mechanisms influence expert utilization but through different means.
The auxiliary loss and capacity factor work together but operate on different timescales and through different mechanisms. The auxiliary loss provides a soft incentive through gradients, nudging the router toward balance without forcing specific outcomes. The capacity factor provides a hard constraint that takes effect when soft incentives are insufficient. With a well-tuned auxiliary loss, fewer tokens hit the capacity cap, reducing wasted computation. But if the auxiliary loss is too weak, the capacity factor does most of the work, causing token dropping and information loss.
The interplay between these mechanisms suggests a practical principle: the auxiliary loss should be strong enough that the capacity factor rarely needs to drop tokens. Token dropping represents a failure mode where computation is wasted and information is lost. By tuning to achieve reasonable balance, we can keep most tokens below the capacity threshold while still letting meaningful expert specialization. A useful diagnostic during training is to monitor the fraction of tokens that are dropped due to capacity overflow. If this fraction is high (say, above 1-2%), the auxiliary loss is likely too weak and should be increased.
Another interaction to keep in mind: the capacity factor determines the maximum possible imbalance ratio. If the capacity factor is set to 1.25, then no expert can receive more than 25% above its fair share. This puts an upper bound on the imbalance that can occur, which affects how much work the auxiliary loss needs to do. With a tight capacity factor, even a weak auxiliary loss can maintain acceptable balance because the hard cap prevents catastrophic collapse. With a loose capacity factor, a stronger auxiliary loss is necessary. Understanding this relationship helps you reason about how to set both hyperparameters jointly rather than independently.
Implementation
Let's implement the auxiliary balancing loss step by step. We'll create a module that can be integrated into any MoE training loop.
import torch
import torch.nn.functional as F
def compute_load_balancing_loss(
router_probs: torch.Tensor, expert_indices: torch.Tensor, num_experts: int
) -> torch.Tensor:
"""
Compute the auxiliary load balancing loss.
Args:
router_probs: Gate probabilities, shape (batch_size, seq_len, num_experts)
expert_indices: Selected expert indices, shape (batch_size, seq_len)
num_experts: Number of expert networks
Returns:
Scalar auxiliary loss
"""
# Flatten batch and sequence dimensions
batch_size, seq_len, _ = router_probs.shape
num_tokens = batch_size * seq_len
router_probs_flat = router_probs.view(-1, num_experts) # (N, E)
expert_indices_flat = expert_indices.view(-1) # (N,)
# Compute fraction of tokens routed to each expert (f_i)
# One-hot encode the expert selections and average
expert_mask = F.one_hot(expert_indices_flat, num_experts).float() # (N, E)
tokens_per_expert = expert_mask.sum(dim=0) # (E,)
f = tokens_per_expert / num_tokens # (E,)
# Compute fraction of router probability per expert (P_i)
P = router_probs_flat.mean(dim=0) # (E,)
# Load balancing loss: scaled dot product
load_balancing_loss = num_experts * (f * P).sum()
return load_balancing_lossThis function computes the exact formulation from the Switch Transformer paper. Let's verify it works correctly with a simple example.
import torch
import torch.nn.functional as F
# Create example data: 4 tokens, 3 experts
batch_size, seq_len, num_experts = 2, 2, 3
num_tokens = batch_size * seq_len
# Simulate router probabilities (softmax output)
torch.manual_seed(42)
router_logits = torch.randn(batch_size, seq_len, num_experts)
router_probs = F.softmax(router_logits, dim=-1)
# Select top expert for each token
expert_indices = router_probs.argmax(dim=-1)
# Compute loss and breakdown for inspection
loss = compute_load_balancing_loss(router_probs, expert_indices, num_experts)
router_probs_flat = router_probs.view(-1, num_experts)
expert_indices_flat = expert_indices.view(-1)
expert_mask = F.one_hot(expert_indices_flat, num_experts).float()
f = expert_mask.sum(dim=0) / num_tokens
P = router_probs_flat.mean(dim=0)
f_P_product = f * PRouter probabilities:
tensor([[0.3683, 0.2992, 0.3325],
[0.5215, 0.1348, 0.3438],
[0.8114, 0.0471, 0.1415],
[0.2484, 0.3246, 0.4271]])
Selected experts: [0, 0, 0, 2]
Load balancing loss: 1.3300
Fraction of tokens per expert (f): ['0.7500', '0.0000', '0.2500']
Average probability per expert (P): ['0.4874', '0.2014', '0.3112']
f * P products: ['0.3655', '0.0000', '0.0778']The loss is above 1.0 because expert 2 receives most tokens (high ) and also has high average probability (high ). With perfect balance, we'd expect and loss .
Handling Top-K Routing
When using top-2 or top-k routing, each token contributes to multiple experts' load. We need to adjust the computation to account for the fact that each token sends computation to experts rather than just one. The normalization factor changes accordingly, since the total number of expert assignments is rather than just .
import torch
def compute_load_balancing_loss_topk(
router_probs: torch.Tensor, expert_indices: torch.Tensor, num_experts: int
) -> torch.Tensor:
"""
Compute auxiliary loss for top-k routing.
Args:
router_probs: Gate probabilities, shape (batch_size, seq_len, num_experts)
expert_indices: Selected expert indices, shape (batch_size, seq_len, k)
num_experts: Number of expert networks
Returns:
Scalar auxiliary loss
"""
batch_size, seq_len, k = expert_indices.shape
num_tokens = batch_size * seq_len
router_probs_flat = router_probs.view(-1, num_experts) # (N, E)
expert_indices_flat = expert_indices.view(-1, k) # (N, k)
# Count how many times each expert is selected across all tokens
# Each token contributes k selections total
tokens_per_expert = torch.zeros(num_experts, device=router_probs.device)
for i in range(k):
expert_counts = torch.bincount(
expert_indices_flat[:, i], minlength=num_experts
).float()
tokens_per_expert += expert_counts
# Normalize by total selections (N * k)
f = tokens_per_expert / (num_tokens * k)
# Average router probability per expert
P = router_probs_flat.mean(dim=0)
return num_experts * (f * P).sum()# Example with top-2 routing
k = 2
_, topk_indices = router_probs.topk(k, dim=-1)
loss_topk = compute_load_balancing_loss_topk(
router_probs, topk_indices, num_experts
)Top-2 expert indices:
tensor([[[0, 2],
[0, 2]],
[[0, 2],
[2, 1]]])
Top-k load balancing loss: 1.0907The top-k loss is typically lower than top-1 because selecting two experts per token naturally spreads load more evenly.
Integrating with Training
The following training loop incorporates the auxiliary loss:
import torch
import torch.nn as nn
import torch.nn.functional as F
class MoELayer(nn.Module):
"""Simplified MoE layer with auxiliary loss tracking."""
def __init__(self, hidden_size: int, num_experts: int, expert_size: int):
super().__init__()
self.num_experts = num_experts
# Router network
self.router = nn.Linear(hidden_size, num_experts)
# Expert networks (simplified as linear layers)
self.experts = nn.ModuleList(
[
nn.Sequential(
nn.Linear(hidden_size, expert_size),
nn.GELU(),
nn.Linear(expert_size, hidden_size),
)
for _ in range(num_experts)
]
)
# Store auxiliary loss
self.aux_loss = None
def forward(self, x: torch.Tensor) -> torch.Tensor:
batch_size, seq_len, hidden_size = x.shape
# Compute router probabilities
router_logits = self.router(x) # (B, S, E)
router_probs = F.softmax(router_logits, dim=-1)
# Select top-1 expert
expert_indices = router_probs.argmax(dim=-1) # (B, S)
# Compute auxiliary loss
self.aux_loss = compute_load_balancing_loss(
router_probs, expert_indices, self.num_experts
)
# Route tokens to experts (simplified dense computation for clarity)
output = torch.zeros_like(x)
x_flat = x.view(-1, hidden_size)
output_flat = output.view(-1, hidden_size)
indices_flat = expert_indices.view(-1)
for i in range(self.num_experts):
mask = indices_flat == i
if mask.any():
output_flat[mask] = self.experts[i](x_flat[mask])
return output.view(batch_size, seq_len, hidden_size)import torch
import torch.nn.functional as F
def train_step(model, x, y, optimizer, aux_loss_coef=0.01):
"""Single training step with auxiliary loss."""
optimizer.zero_grad()
# Forward pass
output = model(x)
# Task loss (e.g., cross-entropy for language modeling)
task_loss = F.mse_loss(output, y) # Simplified example
# Collect auxiliary losses from all MoE layers
total_aux_loss = 0
for module in model.modules():
if isinstance(module, MoELayer) and module.aux_loss is not None:
total_aux_loss += module.aux_loss
# Combined loss
total_loss = task_loss + aux_loss_coef * total_aux_loss
# Backward and update
total_loss.backward()
optimizer.step()
return {
"task_loss": task_loss.item(),
"aux_loss": total_aux_loss.item()
if isinstance(total_aux_loss, torch.Tensor)
else total_aux_loss,
"total_loss": total_loss.item(),
}import torch
# Create model and run training step
hidden_size, num_experts, expert_size = 64, 4, 128
model = MoELayer(hidden_size, num_experts, expert_size)
# Random input and target
x = torch.randn(2, 8, hidden_size)
y = torch.randn(2, 8, hidden_size)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
metrics = train_step(model, x, y, optimizer, aux_loss_coef=0.01)Training metrics: task_loss: 1.0804 aux_loss: 1.0224 total_loss: 1.0906
The total loss is the sum of task loss and weighted auxiliary loss. The auxiliary loss is initially high (>1.0). This reflects the random initialization of the router.
Monitoring Expert Utilization
Tracking expert utilization during training helps diagnose load balancing issues. The key metrics to watch are the auxiliary loss value and the actual distribution of tokens across experts. The auxiliary loss is a differentiable proxy for this distribution, but the actual distribution is what matters for inference efficiency and model capacity utilization.
import torch
def compute_expert_utilization(
router_probs: torch.Tensor, expert_indices: torch.Tensor, num_experts: int
) -> dict:
"""Compute expert utilization statistics."""
num_tokens = expert_indices.numel()
expert_indices_flat = expert_indices.view(-1)
# Count tokens per expert
counts = torch.bincount(expert_indices_flat, minlength=num_experts).float()
fractions = counts / num_tokens
# Compute statistics
mean_fraction = 1.0 / num_experts # Expected under perfect balance
max_fraction = fractions.max().item()
min_fraction = fractions.min().item()
# Imbalance ratio: max/min (1.0 = perfect balance)
imbalance_ratio = max_fraction / max(min_fraction, 1e-8)
return {
"tokens_per_expert": counts.tolist(),
"fraction_per_expert": fractions.tolist(),
"max_fraction": max_fraction,
"min_fraction": min_fraction,
"imbalance_ratio": imbalance_ratio,
}import torch
import torch.nn.functional as F
# Generate more data to see utilization patterns
torch.manual_seed(123)
batch_size, seq_len, num_experts = 8, 32, 4
router_logits = torch.randn(batch_size, seq_len, num_experts)
router_probs = F.softmax(router_logits, dim=-1)
expert_indices = router_probs.argmax(dim=-1)
utilization = compute_expert_utilization(
router_probs, expert_indices, num_experts
)Expert utilization statistics: Tokens per expert: [77.0, 65.0, 62.0, 52.0] Fraction per expert: ['0.301', '0.254', '0.242', '0.203'] Max/min fractions: 0.301 / 0.203 Imbalance ratio: 1.48x
With random initialization, some imbalance naturally occurs. The auxiliary loss should push this ratio closer to 1.0 during training.
Implementation Notes
Several practical issues arise when integrating auxiliary losses into real training pipelines. First, when a model has multiple MoE layers, each layer computes its own auxiliary loss, and the total auxiliary contribution should sum across all layers. The pattern shown in the train_step function above handles this correctly by iterating over all modules and accumulating. In a transformer with MoE layers at every other block, a 24-layer model might have 12 MoE layers, each contributing an auxiliary loss. The coefficient therefore applies to the sum of all these contributions, which means the effective balancing pressure scales with the number of MoE layers. Some implementations divide by the number of MoE layers to normalize this effect.
Second, the auxiliary loss should not be included in validation metrics. When you compute validation perplexity to assess model quality, you should report only the task loss, not the total loss including balancing. This is because the auxiliary loss measures a training artifact (routing distribution), not the quality of the model's predictions. Including it would obscure real performance trends during model development.
Third, gradient clipping can interact unexpectedly with auxiliary losses. If you clip gradients by global norm, the auxiliary loss gradients are included in the norm computation. A large auxiliary loss during early training can dominate the gradient norm, causing excessive clipping of task loss gradients. Some practitioners compute gradient norms separately for the task and auxiliary components, or apply the auxiliary loss only after a warmup period when the model has begun to stabilize.
Visualizing the Balancing Effect
Let's visualize how the auxiliary loss affects routing over training iterations:
import numpy as np
import torch
import torch.nn.functional as F
# Simulate training with auxiliary loss
torch.manual_seed(42)
np.random.seed(42)
hidden_size, num_experts, expert_size = 32, 4, 64
model = MoELayer(hidden_size, num_experts, expert_size)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
aux_losses = []
imbalance_ratios = []
for step in range(100):
x = torch.randn(4, 16, hidden_size)
y = torch.randn(4, 16, hidden_size)
optimizer.zero_grad()
output = model(x)
task_loss = F.mse_loss(output, y)
total_loss = (
task_loss + 0.1 * model.aux_loss
) # Higher coef for faster visualization
total_loss.backward()
optimizer.step()
# Track metrics
aux_losses.append(model.aux_loss.item())
# Compute utilization
with torch.no_grad():
router_probs = F.softmax(model.router(x), dim=-1)
expert_indices = router_probs.argmax(dim=-1)
util = compute_expert_utilization(
router_probs, expert_indices, num_experts
)
imbalance_ratios.append(util["imbalance_ratio"])

The auxiliary loss pushes the model toward more balanced routing. As training progresses, the auxiliary loss approaches 1.0 (perfect balance), and the imbalance ratio decreases.
Key Parameters
The key parameters for the auxiliary balancing loss implementation are closely interrelated, and understanding how they interact helps you make informed tuning decisions rather than treating each as independent.
- num_experts: Number of experts in the MoE layer. More experts increase the potential for imbalance (more chances for collapse) but also increase the model's capacity for specialization. As
num_expertsgrows, you may need to be more careful with tuning. - aux_loss_coef: Coefficient scaling the auxiliary loss (typically 0.01-0.1). This is the primary tuning knob. Start at 0.01 and adjust based on the imbalance ratio you observe during training.
- k: Number of experts selected per token (top-k routing). Larger naturally improves balance because each token contributes to more experts' loads. With , the natural imbalance is typically lower than with , which means you can often use a smaller .
- expert_size: Hidden dimension size of each expert network. Larger experts cost more compute per token, making load imbalance more expensive in practice. With larger experts, the economic argument for good balancing becomes stronger.
Limitations and Practical Considerations
While the auxiliary balancing loss is needed for stable MoE training, it has important limitations that are worth understanding deeply before deploying MoE models in practice. These limitations are not reasons to avoid the auxiliary loss, but they explain why it is never sufficient on its own and why complementary techniques have been developed.
The most basic limitation is that the auxiliary loss provides batch-level balancing only. The loss encourages balance within each mini-batch, but it provides no guarantee of global balance across the entire training dataset. If certain input types naturally cluster together in mini-batches (as often happens with structured data or when batches are formed from the same document), the router may learn to handle those input types well in batch but still exhibit skewed routing in deployment. Larger batch sizes help mitigate this issue by giving more representative samples, but they also increase memory requirements. In practice, the most reliable approach is to shuffle your training data aggressively and ensure that each batch contains diverse input types.
The gradient signal limitation is equally important. The fraction of tokens routed () doesn't contribute gradients because it involves a non-differentiable argmax operation. Only the router probabilities () receive gradient updates. This means the loss influences the router through probability adjustments, not through direct feedback about which routing decisions were made. The non-differentiability of is why we included it as a weighting factor rather than trying to backpropagate through it; the Switch Transformer design uses to amplify the gradient on for overloaded experts, but this is an indirect mechanism. Some tokens may still be misrouted if their probability distribution is nearly uniform, because small probability differences can be stable against gradient pressure.
There is also an important tension with expert specialization that the loss cannot fully resolve. An overly strong auxiliary loss can prevent meaningful expert specialization from ever emerging. If the model is forced to route all input types equally across experts, each expert becomes a generalist rather than developing specific competencies. The optimal balance point depends heavily on the data distribution and task requirements: a model trained on diverse data with many distinct input types may benefit from stronger specialization (and thus weaker balancing loss) than a model trained on homogeneous data. There is no single "correct" value of that works across all settings, which makes hyperparameter search important for novel architectures or data distributions.
Sensitivity to expert count is a practical concern that is often underappreciated. The loss formulation scales with the number of experts through the multiplier, but optimal values may still need adjustment as expert count changes. With 8 experts versus 64 experts, the same may have very different practical effects on routing behavior. With more experts, each individual expert represents a smaller fraction of total capacity, and the acceptable range of imbalance (as a ratio of max to min usage) changes. Models with many experts may require more aggressive balancing to prevent a few dominant experts from absorbing most of the load.
Finally, the interaction with capacity factor can create unexpected dynamics. When combined with capacity-based token dropping, the auxiliary loss and capacity factor can work at cross purposes. The loss pushes for balance while the capacity factor enforces hard limits. If is too weak, the capacity factor does most of the balancing work by dropping tokens, which wastes computation and loses information. If is too strong, the model achieves balance but at the cost of task performance. Finding the right combination of both hyperparameters simultaneously requires careful experimentation.
These limitations motivate additional techniques like Router Z-Loss (covered in the next chapter), which provides complementary stabilization by penalizing extreme router logits rather than targeting imbalance directly.
Summary
The auxiliary balancing loss is a necessary component of MoE training that prevents expert collapse and ensures efficient computation. The key concepts are:
- Problem: Gating networks naturally create feedback loops where successful experts receive more tokens and improve further, while unused experts stagnate. This "rich-get-richer" dynamic converges to degenerate states without intervention.
- Solution: Add an auxiliary loss term that penalizes imbalanced routing by measuring both actual token load () and router probability mass () per expert.
- Components: The loss combines token fraction (, actual load) with probability fraction (, intended load). Their product creates a quadratic penalty for concentration. The factor normalizes so that perfect balance gives a loss of exactly 1.0.
- Why it works: Only provides gradients (since involves a non-differentiable argmax), but amplifies those gradients for overloaded experts. The product formulation also prevents the router from gaming a pure probability-variance penalty.
- Coefficient tuning: Typical values of to balance load distribution against task performance. Too low causes collapse, too high forces unproductive uniformity. Start at 0.01 and monitor the imbalance ratio during training.
- Tradeoff: Some imbalance is natural and desirable when data distributions are non-uniform. The goal is preventing pathological collapse, not achieving perfect uniformity. A 2:1 max-to-min ratio is generally acceptable; a 10:1 ratio signals a problem.
- Implementation: Track both auxiliary loss and expert utilization during training to diagnose load balancing issues. Log the imbalance ratio alongside task loss to catch silent collapse.
- Limitations: Batch-level only, gradient limitations from non-differentiable argmax, tension with specialization, sensitivity to expert count, and interactions with capacity factor all require careful attention in practice.
With this foundation, the next chapter explores Router Z-Loss, which addresses router training stability by penalizing extreme logit values, complementing the auxiliary balancing loss in modern MoE architectures.
Quiz
Ready to test your understanding? Take this quick quiz to reinforce what you've learned about auxiliary balancing loss in Mixture of Experts models.
Auxiliary Balancing Loss
Reference
Citation details
Cite or share this article.
Continue with the full handbook
This chapter is part of Language AI Handbook. Use the handbook page to browse the complete table of contents and continue reading in sequence.
Explore Language AI HandbookStay up to date
Get articles, book updates, and news delivered to your inbox.
No spam, unsubscribe anytime.
Join the community
Sign in to remove popups, track your reading progress, and join the discussion.

Comments
No comments yet. Be the first to share your thoughts!