How frontier models store hundreds of billions of parameters and use a few billion per token, from the router's gradient to the all-to-all traffic, the balancing tricks, and the designs behind Mixtral and DeepSeek-V3.
Chapter 13 · Section 13.1 · 50 min

Conditional computation

Here is a puzzle about the model you built in Chapter 6. When it reads the token "the", every one of its parameters takes part. The weights that, in a trained model, store facts about protein folding, Python syntax, and the kings of France are all multiplied through, and almost all of that work is wasted on a token that needs none of it. Now suppose you want a model that knows eight times as much. A dense Transformer gives you exactly one way to get it, eight times the parameters, and with them eight times the arithmetic for every token, forever, in training and in serving.

Is there a way to have the parameters without paying for them on every token? That question is conditional computation, and the answer that took over frontier language models is the mixture of experts (MoE). Mixtral 8x7B stores 46.7 billion parameters and uses 12.9 billion of them per token. DeepSeek-V3 stores 671 billion and uses about 37 billion. By the end of this section you will be able to derive both pairs of numbers on a whiteboard, say exactly what an MoE layer computes, explain why it is not an ensemble, and trace the idea from a 1991 paper on vowel recognition to today's largest open models.

Parameters and FLOPs are welded together in a dense model

Recall the 6N rule from §5.6. Every weight in a matrix multiplication does one multiply and one add per token in the forward pass, so a model with NN such weights costs about 2N2N FLOPs per token forward and 6N6N to train, and 6ND6ND for DD training tokens. The rule has no slack in it. Each parameter is touched by each token, so parameters and compute are welded together.

That would not matter if parameters were cheap in some other way, but they are what a model knows. In §5.3 we read the feed-forward network as a key-value memory, with each hidden unit a key that fires on some pattern and writes a value back into the stream, and the FFNs hold about two thirds of each block's weights. Scaling laws (§9.2) say loss keeps falling as parameters grow. So we want more of them, and the dense recipe charges us for every one of them on every token.

Conditional computation breaks the weld. Keep many FFNs, and let each token use only a few of them, chosen by a small learned function of the token itself. The parameter count, and with it the capacity to store knowledge, grows with the number of FFNs. The compute per token grows only with the number used.

The MoE layer

An MoE layer replaces the FFN sublayer of a Transformer block. Attention, the norms, and the residual stream stay exactly as they were. For one token's input x∈Rd\mathbf{x} \in \R^{d} (a row, the output of the pre-FFN norm), the layer has

  • EE experts, each an ordinary FFN of the kind in §5.3. In modern models each is a SwiGLU network FFN⁡i(x)=(SiLU⁡(xWg(i))⊙xWu(i))Wd(i)\operatorname{FFN}_i(\mathbf{x}) = \big(\operatorname{SiLU}(\mathbf{x}\mathbf{W}_g^{(i)}) \odot \mathbf{x}\mathbf{W}_u^{(i)}\big)\mathbf{W}_d^{(i)} with Wg(i),Wu(i)∈Rd×de\mathbf{W}_g^{(i)}, \mathbf{W}_u^{(i)} \in \R^{d\times d_e} and Wd(i)∈Rde×d\mathbf{W}_d^{(i)} \in \R^{d_e\times d}, where ded_e is the expert's hidden width.
  • a router (also called the gate), a linear map Wr∈Rd×E\mathbf{W}_r \in \R^{d\times E} that gives one logit per expert, r=xWr∈RE\mathbf{r} = \mathbf{x}\mathbf{W}_r \in \R^{E}.
  • a number kk of experts to use per token, usually 1, 2, or 8.

The router picks the kk experts with the largest logits, the set K=TopK⁡(r,k)⊂[E]\mathcal{K} = \operatorname{TopK}(\mathbf{r}, k) \subset [E], turns their logits into weights gig_i that sum to one, and the layer returns the weighted sum of just those experts' outputs,

gi=eri∑j∈Kerj  for i∈K,gi=0  otherwise,MoE⁡(x)=∑i∈Kgi FFN⁡i(x).g_i = \frac{e^{r_i}}{\sum_{j \in \mathcal{K}} e^{r_j}} \ \text{ for } i \in \mathcal{K}, \qquad g_i = 0 \ \text{ otherwise}, \qquad \operatorname{MoE}(\mathbf{x}) = \sum_{i \in \mathcal{K}} g_i\, \operatorname{FFN}_i(\mathbf{x}).

In plain words, score every expert with one cheap matrix product, keep the best kk, run only those, and blend their answers in proportion to how strongly the router preferred them.

The block is otherwise unchanged, h=xin+MoE⁡(RMSNorm⁡(xin))\mathbf{h} = \mathbf{x}_{\text{in}} + \operatorname{MoE}(\operatorname{RMSNorm}(\mathbf{x}_{\text{in}})). Two details matter from the start. The experts that are not chosen are never evaluated, which is the whole point. And the router itself is evaluated for all EE experts, which costs 2dE2dE FLOPs per token, tiny next to an expert (about 6d de6d\,d_e) but not zero. There are several ways to turn router logits into weights (softmax over all experts, softmax over the chosen ones, sigmoids), and they behave differently in training. §13.2 takes them apart. Here we use the version above, which is Mixtral's.

A worked example small enough to check by hand

Take d=4d = 4, E=4E = 4, k=2k = 2, and a router whose logits for one token come out as r=(2.0,0.5,1.0,−1.0)\mathbf{r} = (2.0, 0.5, 1.0, -1.0). The top two are experts 0 and 2. Their weights are a two-way softmax,

g0=e2e2+e1=11+e−1=0.7311,g2=0.2689,g_0 = \frac{e^{2}}{e^{2} + e^{1}} = \frac{1}{1 + e^{-1}} = 0.7311, \qquad g_2 = 0.2689,

and g1=g3=0g_1 = g_3 = 0. The layer runs experts 0 and 2 and returns 0.7311 FFN⁡0(x)+0.2689 FFN⁡2(x)0.7311\,\operatorname{FFN}_0(\mathbf{x}) + 0.2689\,\operatorname{FFN}_2(\mathbf{x}). The cell below does exactly this, then checks it against the wasteful version that runs all four experts and multiplies the unused ones by zero.

Python · cell 1

Total and active parameters

Two counts describe an MoE model, and confusing them is the most common mistake people make about these models.

  • The total parameters NtotalN_{\text{total}} are everything stored. They set the memory needed to hold the model.
  • The active parameters NactiveN_{\text{active}} are the ones a single token actually multiplies through. They set the FLOPs per token, so they play the role of NN in the 6N rule.

For one MoE layer with EE SwiGLU experts of width ded_e, a bias-free router, and kk experts per token,

Ntotallayer=3 d de E+d E,Nactivelayer=3 d de k+d E.N^{\text{layer}}_{\text{total}} = 3\,d\,d_e\,E + d\,E, \qquad N^{\text{layer}}_{\text{active}} = 3\,d\,d_e\,k + d\,E .

In plain words, storage grows with the number of experts, compute grows with the number used, and the router is the only part every token pays for in full.

Mixtral 8x7B, counted exactly

Mixtral (Jiang et al. 2024) is Mistral 7B with each FFN replaced by eight copies of the same shape and top-2 routing. Its published configuration is d=4096d = 4096, L=32L = 32 layers, h=32h = 32 query heads and nkv=8n_{kv} = 8 key-value heads of width dk=128d_k = 128, de=14,336d_e = 14{,}336, E=8E = 8, k=2k = 2, a vocabulary of V=32,000V = 32{,}000, and separate (untied) input and output embeddings. Count one layer.

  • Attention with grouped-query attention (§4.5). WQ\mathbf{W}_Q and WO\mathbf{W}_O are 4096×40964096\times4096 (since hdk=4096h d_k = 4096), and WK\mathbf{W}_K, WV\mathbf{W}_V are 4096×10244096 \times 1024 (since nkvdk=1024n_{kv} d_k = 1024), so 2⋅40962+2⋅4096⋅1024=41,943,0402\cdot 4096^2 + 2\cdot 4096\cdot 1024 = 41{,}943{,}040.
  • One expert. Three matrices of 4096×14,3364096 \times 14{,}336, so 176,160,768176{,}160{,}768. Eight of them are 1,409,286,1441{,}409{,}286{,}144.
  • Router. 4096×8=32,7684096 \times 8 = 32{,}768.
  • Two RMSNorm gains. 8,1928{,}192.

That is 1,451,270,1441{,}451{,}270{,}144 per layer and 46,440,644,60846{,}440{,}644{,}608 for 32 layers. Add the input and output embeddings, 2×32,000×4096=262,144,0002 \times 32{,}000 \times 4096 = 262{,}144{,}000, and the final norm's 4,0964{,}096, and the total is

Ntotal=46,702,792,704≈46.7B.N_{\text{total}} = 46{,}702{,}792{,}704 \approx 46.7\text{B}.

For the active count, replace eight experts by two in every layer, 2×176,160,768=352,321,5362 \times 176{,}160{,}768 = 352{,}321{,}536, which gives 394,305,536394{,}305{,}536 per layer and

Nactive=32×394,305,536+262,144,000+4,096=12,879,925,248≈12.9B,N_{\text{active}} = 32 \times 394{,}305{,}536 + 262{,}144{,}000 + 4{,}096 = 12{,}879{,}925{,}248 \approx 12.9\text{B},

counting both embedding matrices in full. (Leave out the input embedding, which is a lookup and costs no FLOPs, and it is 12.7B. Both round to the paper's "13B active".)

Why is "8x7B" not 56 billion? Because only the FFNs were multiplied by eight. Mistral 7B has 7.24B parameters, of which 1.60B are attention, norms, and embeddings, and those are shared by all experts. Eight copies of the 5.64B of FFN weights plus one copy of the shared 1.60B is 46.7B.

DeepSeek-V3, counted exactly

DeepSeek-V3 (DeepSeek-AI 2024) has d=7168d = 7168 and L=61L = 61 layers. The first three layers keep a dense SwiGLU FFN of width 18,432. The other 58 are MoE layers with E=256E = 256 routed experts of width de=2048d_e = 2048, k=8k = 8 of them per token, plus one shared expert of the same width that every token always uses (§13.5 explains why). Attention is multi-head latent attention (§12.5), whose projections, low-rank factors, and two small norms add up to 187,107,328187{,}107{,}328 per layer with h=128h = 128 heads. (That is a 7168×15367168\times1536 query down-projection, a 1536×(128⋅192)1536\times(128\cdot192) query up-projection, since each head's query has 128 content and 64 rotary dimensions, a 7168×5767168\times576 key-value down-projection that includes the shared rotary key, a 512×(128⋅256)512\times(128\cdot256) up-projection to the keys and values, a (128⋅128)×7168(128\cdot128)\times7168 output projection WO\mathbf{W}_O, and norms of sizes 1,536 and 512.) The vocabulary is V=129,280V = 129{,}280, untied.

  • One expert. 3×7168×2048=44,040,1923 \times 7168 \times 2048 = 44{,}040{,}192.
  • An MoE layer. Attention 187,107,328187{,}107{,}328, plus 257257 experts 11,318,329,34411{,}318{,}329{,}344, plus the router 256×7168=1,835,008256\times7168 = 1{,}835{,}008, plus two norms 14,33614{,}336, is 11,507,286,01611{,}507{,}286{,}016.
  • A dense layer. Attention plus 3×7168×18,432=396,361,7283\times7168\times18{,}432 = 396{,}361{,}728 plus norms, 583,483,392583{,}483{,}392.

So Ntotal=3×583,483,392+58×11,507,286,016+2×129,280×7168+7168=671,026,404,352N_{\text{total}} = 3 \times 583{,}483{,}392 + 58 \times 11{,}507{,}286{,}016 + 2\times129{,}280\times7168 + 7168 = 671{,}026{,}404{,}352, the paper's 671B. Over 97% of it is routed experts. Per token, an MoE layer uses attention, the router, the norms, and nine experts (eight routed and the shared one), 585,318,400585{,}318{,}400 parameters, so

Nactive=3×583,483,392+58×585,318,400+1,853,358,080+7,168=37,552,282,624,N_{\text{active}} = 3\times583{,}483{,}392 + 58\times585{,}318{,}400 + 1{,}853{,}358{,}080 + 7{,}168 = 37{,}552{,}282{,}624,

or 36.6B without the input embedding, the paper's "37B activated". (The released checkpoint also contains a multi-token prediction module used in training, which the 671B leaves out.)

Python · cell 2
Interview

Total and active parameters of an MoE model

Implement moe_param_count(cfg) returning the pair (total, active) for a decoder whose config is a dict with keys V (vocabulary), d (width), L (layers), attn (attention parameters per layer, given), n_dense (how many of the first layers keep a dense FFN), d_ff (that dense FFN's hidden width), E (routed experts per MoE layer), E_shared (shared experts, always active), k (routed experts per token), d_e (expert hidden width), and tied (whether input and output embeddings are one matrix). Every FFN and expert is a bias-free SwiGLU, every layer has two RMSNorm gains of size dd, there is one final norm, and the router is a bias-free d×Ed\times E matrix. Count the embedding matrices in full in both numbers.

Interviewers ask this as "how many parameters does Mixtral have, and how many does a token use?", and the tests check exactly that, plus DeepSeek-V3.

Hidden tests, hints, and AI help, from $1.99 a month.

FLOPs per token, and the 6N rule for MoE

Because the unchosen experts never run, the 6N rule carries over with NN replaced by the active matrix parameters. Training on DD tokens costs

Ctrain≈6 Nactive D(plus attention’s 12LTd per token, §5.6).C_{\text{train}} \approx 6\,N_{\text{active}}\,D \quad (\text{plus attention's } 12LTd \text{ per token, §5.6}).

In plain words, an MoE model trains at the price of a dense model the size of its active parameters, while storing many times more.

DeepSeek-V3 was pretrained on 14.8 trillion tokens. With Nactive≈37×109N_{\text{active}} \approx 37\times10^{9} that is 6×37×109×14.8×1012≈3.3×10246 \times 37\times10^{9}\times14.8\times10^{12} \approx 3.3\times10^{24} FLOPs. A dense model with all 671B parameters would have needed 6.0×10256.0\times10^{25}, eighteen times more. The paper reports 2.788 million H800 GPU hours for the whole run, 2.664 million of them for pretraining, which §8.9 turns into a model FLOPs utilization (the measure of §6.7) of about 35 percent of the BF16 peak.

Two caveats keep this honest. First, the router's 2dE2dE FLOPs per token are real but small. For DeepSeek-V3 they are 2×7168×256≈3.72\times 7168\times 256 \approx 3.7 million per layer against about 793 million for the nine experts, half a percent. Second, FLOPs are not time. An MoE layer has to move tokens to their experts, often across GPUs, and run many small matrix products instead of one big one. Those costs are the subject of §13.4, and they are why an MoE model with the FLOPs of a 37B dense model does not train quite as fast as one.

How many parameters does an MoE model store, and how many does one token use?
Pick a released model, then change its experts. Bars are on one scale. Highlighted squares are the experts one token uses in one layer.
Loading interactive figure…
Warm-up

Training compute of a dense model and its MoE counterpart

Implement train_flops(n_active, tokens) returning 6 Nactive D6\,N_{\text{active}}\,D as a float, and flops_ratio(n_total, n_active) returning how many times more compute a dense model with NtotalN_{\text{total}} parameters would need for the same tokens.

Hidden tests, hints, and AI help, from $1.99 a month.

An MoE layer is a wide FFN with blocks switched off

It is tempting to picture an MoE model as eight small models voting. That picture is wrong in a way that matters, and the right picture comes straight from §5.3.

An FFN is a sum over its hidden units. For a ReLU network, FFN⁡(x)=∑j=1dffϕ(x W1,:,j) W2,j,:\operatorname{FFN}(\mathbf{x}) = \sum_{j=1}^{d_{\text{ff}}} \phi(\mathbf{x}\,\mathbf{W}_{1,:,j})\,\mathbf{W}_{2,j,:}, one key-value memory per unit. Cut the dffd_{\text{ff}} hidden units into EE consecutive blocks of de=dff/Ed_e = d_{\text{ff}}/E, and the sum splits into EE smaller FFNs,

FFN⁡wide(x)=∑i=1EFFN⁡i(x),\operatorname{FFN}_{\text{wide}}(\mathbf{x}) = \sum_{i=1}^{E} \operatorname{FFN}_i(\mathbf{x}),

where FFN⁡i\operatorname{FFN}_i uses only block ii's columns of W1\mathbf{W}_1 and rows of W2\mathbf{W}_2. The same holds for SwiGLU, block by block. So an MoE layer is a single FFN of width E deE\,d_e in which, for each token, all but kk blocks of hidden units are switched off and the surviving blocks are rescaled by their gates. In plain words, the experts are slices of one very wide memory, and the router decides which slices each token may read.

This explains three things. It is why the experts share everything else (attention, embeddings, the residual stream). It is why routing happens independently in every layer, with no notion of "the model's expert 3". A token in Mixtral picks one of (82)=28\binom{8}{2} = 28 expert pairs in each of 32 layers, so there are 2832≈2×104628^{32} \approx 2\times10^{46} different paths through the network, which is nothing like an ensemble of eight models. And it is why an MoE model can be built from a dense one by copying its FFN into every expert (upcycling, §13.5), since that is a wide FFN with redundant blocks.

Python · cell 3
Core

Cut a wide FFN into experts

Implement split_into_experts(W1, W2, E) that takes a ReLU FFN with W1∈Rd×dff\mathbf{W}_1 \in \R^{d\times d_{\text{ff}}} and W2∈Rdff×d\mathbf{W}_2 \in \R^{d_{\text{ff}}\times d} and returns a list of EE pairs (A_i, B_i) with A_i of shape (d, d_ff // E) and B_i of shape (d_ff // E, d), so that summing relu(X @ A_i) @ B_i over all experts reproduces the wide FFN. Expert ii owns hidden units i dei\,d_e to (i+1) de−1(i+1)\,d_e - 1. Raise ValueError if EE does not divide dffd_{\text{ff}}.

Hidden tests, hints, and AI help, from $1.99 a month.

Where the idea came from

The 1991 paper contains an insight that every later MoE inherits, so it is worth one derivation. Suppose expert ii outputs oi\mathbf{o}_i for a training case with target d\mathbf{d}, and the gate gives it weight pip_i. The obvious loss blends the experts and compares the blend with the target, ∥d−∑ipioi∥2\lVert\mathbf{d} - \sum_i p_i\mathbf{o}_i\rVert^2. Jacobs et al. point out that this makes the experts cooperate. Each expert's gradient depends on the residual left by all the others, so every expert tries to fix everyone's errors, and many experts end up used for every case.

Their fix is to make the experts compete. Treat the gate as choosing one expert at random with probability pip_i, and treat each expert's output as the mean of a unit Gaussian over targets. The loss is the negative log-likelihood of the target under that mixture,

L=−log⁡∑ipi e−12∥d−oi∥2.\mathcal{L} = -\log \sum_{i} p_i\, e^{-\frac12 \lVert \mathbf{d} - \mathbf{o}_i\rVert^2}.

Differentiate with respect to one expert's output. Only the ii-th term depends on oi\mathbf{o}_i, and ∂e−12∥d−oi∥2/∂oi=e−12∥d−oi∥2(d−oi)\partial e^{-\frac12\lVert\mathbf{d}-\mathbf{o}_i\rVert^2}/\partial\mathbf{o}_i = e^{-\frac12\lVert\mathbf{d}-\mathbf{o}_i\rVert^2}(\mathbf{d}-\mathbf{o}_i), so

∂L∂oi=− hi (d−oi),hi=pi e−12∥d−oi∥2∑jpj e−12∥d−oj∥2.\frac{\partial\mathcal{L}}{\partial\mathbf{o}_i} = -\,h_i\,(\mathbf{d} - \mathbf{o}_i), \qquad h_i = \frac{p_i\, e^{-\frac12\lVert\mathbf{d}-\mathbf{o}_i\rVert^2}}{\sum_j p_j\, e^{-\frac12\lVert\mathbf{d}-\mathbf{o}_j\rVert^2}} .

In plain words, each expert is pulled toward the target, weighted by hih_i, the posterior probability that it was the expert responsible. The expert that already fits best gets the largest share of the update, so experts specialize. Compare the intermediate loss ∑ipi∥d−oi∥2\sum_i p_i\lVert\mathbf{d}-\mathbf{o}_i\rVert^2, whose gradient is −2pi(d−oi)-2p_i(\mathbf{d}-\mathbf{o}_i). When the gate starts uniform and every expert's error ∥d−oi∥\lVert\mathbf{d}-\mathbf{o}_i\rVert exceeds 1, the paper notes, that version adapts the best-fitting expert the slowest (its error is smallest), and the mixture likelihood adapts it the fastest. The cell shows it.

Python · cell 4

The best-fitting expert gets the smallest update under the first loss and nearly all of it under the second. Modern Transformer MoEs do not use this exact loss (they backpropagate the language-modeling loss through a weighted sum, closer to the cooperative form), and one consequence is that they need explicit help to keep experts from all doing the same thing or one expert doing everything. That help is §13.3.

Core

Responsibilities in a mixture of experts

Implement responsibilities(target, O, p) for a target of shape (m,), expert outputs O of shape (E, m), and gate probabilities p of shape (E,). Return the pair (h, grad) where h of shape (E,) holds the posterior responsibilities hih_i above and grad of shape (E, m) is ∂L/∂O\partial\mathcal{L}/\partial\mathbf{O} for L=−log⁡∑ipie−12∥d−oi∥2\mathcal{L} = -\log\sum_i p_i e^{-\frac12\lVert\mathbf{d}-\mathbf{o}_i\rVert^2}. It must stay finite when every expert is far from the target (squared errors in the thousands).

Hidden tests, hints, and AI help, from $1.99 a month.

In PyTorch

A readable MoE layer in PyTorch loops over experts, not tokens. For each expert it finds the tokens that chose it, runs them as one batch, and adds the weighted result back with index_add_. This is the shape of the reference Mixtral implementation in Hugging Face Transformers. §13.2 replaces the loop's bookkeeping with a sort, and §13.4 replaces the loop itself with a grouped matrix multiply.

🔥 In PyTorchfor a machine with PyTorch

Building the full-size layer on the meta device creates tensors with shapes but no storage, so you can count a 1.4-billion-parameter layer on a laptop. The count, 8×176,160,768+32,7688\times176{,}160{,}768 + 32{,}768, is the experts plus the router of the hand count above.

dense FFN, width dffd_{\text{ff}}MoE, EE experts of width ded_e, top-kk
parameters stored3 d dff3\,d\,d_{\text{ff}}3 d deE+dE3\,d\,d_e E + dE
parameters used per token3 d dff3\,d\,d_{\text{ff}}3 d dek+dE3\,d\,d_e k + dE
forward FLOPs per token6 d dff6\,d\,d_{\text{ff}}6 d dek+2dE6\,d\,d_e k + 2dE
memory to servesmalllarge, all experts must be resident somewhere
extra machinerynonerouter, load balancing, token dispatch

Read more

Watch next

🎬 Mixture of Experts (MoE), Visually Explained · Jia-Bin HuangAn animated, first-principles tour of the MoE layer inside a Transformer block, from the FFN to the router.
🎬 Mixture of Experts: How LLMs get bigger without getting slower · Julia TurcThe history from the 1991 vowel-recognition paper to trillion-parameter models, with the original idea reproduced in code.
🎬 A Visual Guide to Mixture of Experts (MoE) in LLMs · Maarten Grootendorst · starts at 10:40The segment that counts Mixtral's parameters, total and active, the same count this section derives.