Introduction

DeepSeek-V3 co-designs model architecture, numerical precision, and distributed training around a single goal: scaling model capacity without scaling per-token compute or memory traffic at the same rate. It pairs a large pool of finely segmented Mixture-of-Experts (MoE) feed-forward networks with a compressed Multi-head Latent Attention (MLA) cache, trains with a multi-token prediction objective and fine-grained FP8 quantization, and maps the resulting workload onto a custom pipeline and all-to-all communication schedule. A multi-stage post-training pipeline—combining supervised fine-tuning, reasoning distillation, and reinforcement learning—turns the pretrained base model into a general-purpose assistant.

This book is a technical study of the DeepSeek-V3 Technical Report (arXiv:2412.19437v2, revised February 18, 2025). It covers the original V3 release described in that paper rather than subsequent point releases, the standalone DeepSeek-R1 model, or later architectural revisions, and treats benchmark numbers as historical snapshots from the paper's evaluation setup.

Each chapter derives the core equations from first principles, traces concrete numerical examples, and connects architectural equations to the hardware constraints that motivated them. You can read the chapters sequentially or jump directly to individual topics using the table below.

Contents

Chapter Subject Question answered
1. The problem V3 sets out to solve Capacity, cost, and co-design Why is this report more than a bigger model announcement?
2. The foundations the paper assumes Tokens, Transformers, training, and hardware What knowledge makes the rest of the report readable?
3. A complete map of the model Dimensions and parameter accounting What is inside 671B parameters, and what does 37B mean?
4. Attention and rotary position Causal attention and RoPE How do tokens exchange information and know their positions?
5. Deriving Multi-head Latent Attention Joint KV compression and matrix absorption How can many heads share a compact stored representation?
6. The economics of attention memory KV bytes, compute, and kernel choices Which attention costs does MLA actually reduce?
7. Fine-grained and shared experts DeepSeekMoE and conditional computation How can the model have enormous capacity with limited per-token work?
8. Routing and load balancing Bias updates, auxiliary loss, and topology How does routing reconcile learning with hardware utilization?
9. Multi-token prediction as training Sequential MTP and causal supervision Why predict an additional future token?
10. Data, tokenization, and infilling Corpus construction, BPE, FIM, packing What does 14.8T tokens mean, and how are those tokens organized?
11. The pre-training recipe Optimizer, schedules, batch size, and stability How does the model learn over a long training run?
12. Extending the context window YaRN and long-context adaptation How does a model trained at 4K become a 128K model?
13. Distributed training fundamentals DP, PP, EP, TP, and ZeRO How is one model spread over 2,048 GPUs?
14. DualPipe and the critical path Pipeline scheduling and overlap How can communication take time without adding as much elapsed time?
15. Moving tokens to experts All-to-all, IB, NVLink, and warp specialization How does topology-aware routing become an efficient kernel?
16. Understanding FP8 numbers Formats, scales, outliers, and accumulation What can go wrong when learning with eight-bit inputs?
17. The actual mixed-precision pipeline Forward/backward GEMMs and storage Which computations are FP8, and which remain higher precision?
18. Memory management and reliability Recomputation, optimizer states, EMA Why does saving memory change the feasible training architecture?
19. Instruction tuning and reasoning distillation Domain teachers, rejection sampling, SFT How does the base model become a useful assistant?
20. Rewards, GRPO, and self-feedback Rule/model rewards and policy optimization What does reinforcement learning change after SFT?
21. Serving prefill and decode Disaggregation, parallelism, redundant experts Why does the paper use different clusters for reading and generating?
22. Speculative decoding with MTP Drafting, verification, acceptance, speed How can predicting extra tokens accelerate generation correctly?
23. Base-model evidence and ablations Benchmarks and controlled comparisons Which improvements have the strongest supporting evidence?
24. What the chat evaluations establish Knowledge, code, math, preferences, judges Where is V3 strong, and what do the scores leave uncertain?
25. Costs, limitations, and practical use Training accounting and deployment choices What conclusions can a researcher or operator act on?
26. One request and one training step Integrated traces through the whole system How do all the pieces cooperate in practice?
27. Reference, questions, and source map Glossary, notation, exercises, provenance Where can a reader verify a detail or test their understanding?

Reading paths

Chapters 1–3 lay the groundwork for the rest of the book. From there, readers focused on model architecture can concentrate on Chapters 4–9 and 12; training practitioners can focus on Chapters 8–20 and 23; systems engineers can read Chapters 3, 5–6, 13–18, and 21–22; and engineers evaluating V3 for deployment can focus on Chapters 1, 3, 12, 21–25, and the end-to-end request trace in Chapter 26. Core definitions are restated in context so that later chapters on FP8 quantization or expert routing remain self-contained.

Conventions and source archives

Throughout the book, a multiply-accumulate operation counts as two FLOPs. Decimal GB denotes 10910^9 bytes and GiB denotes 2302^{30} bytes. In explicit context-length calculations, 4K = 4,096, 32K = 32,768, and 128K = 131,072 tokens, even where the paper uses those labels loosely.

The TeX source archive for 2412.19437v2 is preserved in the parent directory (main.tex for the main text, content/fp8.tex for low-precision numerics, and tables/ for benchmark results), alongside supplementary release metadata in reference/. Where the paper omits proprietary details—such as exact corpus mixtures, internal RL hyperparameters, or production kernel code—or where the released Hugging Face configuration differs slightly from the paper's prose, the text notes the discrepancy directly; Chapter 27 catalogs the source files and configuration differences in one place.

Sources: DeepSeek-V3 Technical Report, version 2. Start with Chapter 1: The Problem V3 Sets Out to Solve.

1. The Problem V3 Sets Out to Solve

Scaling a language model's parameter count, training corpus, and context length drives up costs across every part of the stack. Parameters occupy high-bandwidth GPU memory; pre-training requires quadrillions of matrix multiplications and synchronized gradient updates; long contexts bloat the key-value (KV) attention cache; and sharding the workload across thousands of accelerators introduces network bottlenecks.

DeepSeek-V3 attacks these bottlenecks simultaneously. The technical report describes a 671-billion-parameter model that activates roughly 37 billion parameters per token, trains on 14.8 trillion tokens, and completes its main pre-training, context-extension, and post-training runs in 2.788 million H800 GPU hours (Report, §1). Making sense of those numbers requires looking closely at how conditional computation, memory compression, and hardware scheduling interact.

Decoupling capacity from per-token compute

A dense Transformer applies almost all of its layer weights to every token in the sequence, tying total parameter capacity directly to per-token floating-point operations (FLOPs). A Mixture-of-Experts (MoE) architecture breaks this coupling by replacing each dense feed-forward network (FFN) with a bank of expert FFNs and routing each token to only a small subset. That allows the model to store a massive repertoire of learned transformations while keeping per-token arithmetic modest.

You can picture the expert pool as a multi-room reference library where each query visits only a handful of rooms. Total shelf space determines what the system can store, while the number of rooms visited determines the work spent per query—with the crucial caveat that MoE experts are continuous numerical transformations rather than static lookup tables, and the router re-selects experts at each of the 58 MoE layers for every single token.

Consequently, "671B total parameters with 37B active" does not mean V3 behaves like a 37B dense model from a systems perspective. The remaining 634B parameters still have to sit in GPU memory, and across a large batch of diverse tokens, nearly all 256 routed experts in a layer will be triggered by at least some tokens. A system running V3 pays the per-token compute cost of a 37B model alongside the memory footprint and network dispatch overhead of a 671B model.

Why isolated optimizations fall short

Cutting per-token FFN FLOPs via sparse routing only shifts the bottleneck elsewhere. If the network saturates while dispatching tokens to experts on remote nodes, the GPUs sit idle waiting for data. If the network keeps up, long-context KV caches can still exhaust HBM capacity during inference, or activation memory and optimizer states can force expensive tensor parallelism during training. And if activations and weights are quantized to 8-bit floating point (FP8) to speed up matrix multiplication and shrink network traffic, activation outliers can destabilize training unless quantization scales are tightly localized.

DeepSeek-V3 pairs each architectural or numerical optimization with a compensating mechanism to handle the side effects it creates:

Bottleneck Primary mechanism New constraint introduced
Dense feed-forward compute Fine-grained routed + shared experts All-to-all token dispatch and load balancing
KV cache memory footprint Multi-head Latent Attention (MLA) Up-projection compute or matrix absorption in attention kernels
Uneven expert utilization Auxiliary-loss-free bias updates Per-sequence imbalance and domain shift at inference
Sparse next-token supervision Sequential Multi-Token Prediction (MTP) Extra training parameters and compute overhead
16-bit matrix multiply and bandwidth limits Fine-grained tile/block FP8 mixed precision Quantization scale management and FP32 accumulation
Cross-node all-to-all communication latency DualPipe bidirectional pipeline overlap Doubled model-chunk state and strict 4-node routing caps
Activation and optimizer memory pressure RMSNorm/MLA recomputation, ZeRO-1, BF16 optimizer states Extra recomputation FLOPs and reduced-precision state
Raw base-model behavior SFT, R1 reasoning distillation, and GRPO RL Teacher-model compute cost and reward design

None of these choices stands alone. Fine-grained experts are only viable because DualPipe hides the cross-node all-to-all dispatch behind computation, and because FP8 quantization halves the volume of activation traffic crossing InfiniBand and NVLink. Likewise, aggressive activation recomputation and MLA compression save enough HBM that the model can train without tensor parallelism, eliminating all-reduce synchronization inside every layer. During pre-training, batch-level bias updates keep experts balanced without distorting gradients; during inference, when real-world traffic patterns shift, the serving system deploys redundant copies of hot experts instead.

Training vs. serving workloads

Pre-training and live serving pull the hardware in opposite directions. Pre-training processes massive, uniform batches of 4,096-token sequences with a single goal: maximizing sustained token throughput per dollar while keeping optimization numerically stable. Every token in a training batch must pass through both forward and backward passes on schedule.

Live inference faces unpredictable request arrivals, variable prompt lengths, and strict latency targets—both time-to-first-token (TTFT) and inter-token latency (ITL). Waiting to accumulate a massive batch improves GPU matrix utilization during MoE execution, but directly degrades user-facing latency.

To handle both regimes, V3 disaggregates serving into separate prefill and decode stages running on differently configured GPU pools. Prefill ingests the user's entire prompt in parallel, generating enough token volume to keep expert matrix multiplications compute-bound even on smaller node groups. Decode generates one token at a time per active request; because each step reads vast expert weights for very few tokens, it is memory-bandwidth-bound and latency-sensitive, requiring a much wider pool of GPUs with high-bandwidth all-to-all interconnects.

Inherited foundations vs. new contributions

DeepSeek-V3 does not start from a blank slate; it directly inherits its two signature architectural blocks—Multi-head Latent Attention (MLA) and DeepSeekMoE—from DeepSeek-V2. What V3 adds on top of the V2 backbone are four main contributions:

  1. Auxiliary-loss-free load balancing, which replaces gradient-distorting token-drop or auxiliary penalties with a dynamically adjusted per-expert routing bias.
  2. Multi-Token Prediction (MTP), which attaches a sequential prediction module during training to densify supervision signals and optionally draft tokens for speculative decoding.
  3. Fine-grained FP8 mixed-precision training, validated for the first time on a frontier-scale MoE model using 1×1281 \times 128 activation tiles and 128×128128 \times 128 weight blocks.
  4. DualPipe and topology-aware communication kernels, which overlap bidirectional pipeline stages with cross-node InfiniBand and intra-node NVLink expert dispatch.

When reading the benchmark results later in the book, it helps to keep this lineage in mind. The paper provides controlled smaller-scale ablations isolating the gains from auxiliary-loss-free balancing, MTP, and FP8 quantization, whereas the end-to-end capability of the 671B checkpoint reflects the combined effect of the V2 architecture, the 14.8T-token corpus, the new V3 training mechanisms, and reasoning distillation from DeepSeek-R1.

Unpacking the $5.576M training cost figure

The widely cited $5.576M training cost comes from multiplying 2.788 million H800 GPU hours by a benchmark rental rate of $2.00 per GPU hour. In the paper's accounting, that total covers three specific phases of the final production run:

A GPU hour measures device-hours of compute: running 2,048 H800 GPUs continuously for one wall-clock hour consumes 2,048 GPU hours. At full cluster utilization, 2.664 million GPU hours translates to roughly 54.2 days of continuous wall-clock run time on a 2,048-GPU cluster.

As the authors explicitly note, this figure measures the marginal compute bill of the final successful training run. It does not include capital expenditure for the cluster, data acquisition and filtering pipelines, salary overhead, prior architectural ablations, or the compute spent training the teacher models used during post-training distillation. Chapter 25 examines this cost breakdown in detail.

Base model vs. post-trained assistant

The original V3 release consists of two distinct artifacts evaluated under different protocols: DeepSeek-V3-Base, which models raw token continuation probabilities after pre-training and long-context extension, and DeepSeek-V3 (the chat checkpoint), which undergoes supervised fine-tuning, reasoning distillation, and reinforcement learning.

When the chat model solves a competition math problem or writes working code, its output reflects the interplay of three stages: domain knowledge absorbed during the 14.8T-token pre-training run, chain-of-thought formatting and verification habits distilled during post-training, and the decoding parameters used at runtime. Chapters 23 and 24 separate the empirical evidence for the base model from the post-trained chat evaluations so we can see precisely where each stage moves the needle.


Sources: main.tex, lines 151–267 (Report, §1) for parameter counts, token budgets, and training cost tables; §3.4 for prefill/decode disaggregation; §6 for deployment characteristics. Continue to Chapter 2: The Foundations the Paper Assumes or Chapter 3: A Complete Map of the Model.

2. The Foundations the Paper Assumes

DeepSeek-V3 is an autoregressive, decoder-only Transformer whose dense feed-forward blocks are largely replaced by Mixture-of-Experts layers and whose attention mechanism compresses key-value states into low-rank latents. Before diving into V3's specific equations and systems engineering, this chapter reviews the mathematical and hardware building blocks that the technical report takes as given.

From text to token embeddings

A language model does not ingest raw strings directly; a tokenizer first segments text into a sequence of integer IDs x1,x2,…,xTx_1, x_2, \ldots, x_T, where each xtx_t belongs to a fixed vocabulary of size VV. Depending on how common a character sequence is, a single token might represent an entire word, a subword root, a punctuation mark, or a fallback byte. Because different models use different vocabularies and segmentation rules, token counts are only directly comparable within the same tokenizer.

At the entrance to the network, an embedding matrix maps each discrete token ID xtx_t to a continuous vector ht∈Rdh_t \in \mathbb{R}^d. The hidden dimension dd sets the width of the residual stream that runs through the entire model; in DeepSeek-V3, d=7168d = 7168. As the vector passes through successive layers, attention and feed-forward blocks add context-dependent updates directly onto this 7,168-dimensional stream.

Autoregressive factorization

An autoregressive language model factors the joint probability of a token sequence into a product of conditional next-token probabilities via the chain rule:

p(x1,…,xT)=∏t=1Tp(xt∣x1,…,xt−1).p(x_1,\ldots,x_T)=\prod_{t=1}^{T}p(x_t\mid x_1,\ldots,x_{t-1}).

This single equation governs both training and inference, even though their execution patterns look completely different on hardware. During generation, the model only knows the tokens produced so far: it computes p(xt∣x1,…,xt−1)p(x_t \mid x_1, \ldots, x_{t-1}), samples or selects xtx_t, appends it to the input sequence, and repeats the loop one token at a time. During training, the entire ground-truth sequence x1,…,xTx_1, \ldots, x_T is already known up front, so the GPU can evaluate the conditional distributions for all TT positions in a single parallel forward pass—using a causal mask inside the attention layers to prevent position tt from peeking at positions t+1t+1 and beyond.

Logits, softmax, and cross-entropy loss

After the final Transformer layer, an output projection matrix maps the normalized hidden state at position tt to a vector of VV unnormalized scores called logits, z∈RVz \in \mathbb{R}^V. The softmax function converts these logits into a normalized probability distribution over the vocabulary:

pj=exp⁡zj∑k=1Vexp⁡zk.p_j=\frac{\exp z_j}{\sum_{k=1}^{V}\exp z_k}.

Because shifting every logit by a constant cc multiplies both numerator and denominator by exp⁡(c)\exp(c), software kernels subtract max⁡kzk\max_k z_k before exponentiating to avoid floating-point overflow.

During training, if the actual next token in the corpus is yy, the model incurs a cross-entropy loss of −log⁡py-\log p_y. Assigning probability 0.50.5 to the true token yields a loss of −ln⁡(0.5)≈0.693 nats-\ln(0.5) \approx 0.693\text{ nats}, while assigning 0.010.01 yields 4.605 nats4.605\text{ nats}. Minimizing average cross-entropy over trillions of tokens teaches the model the statistical structure, facts, and reasoning patterns embedded in the training corpus. Because raw web text also contains noise, unverified claims, and unfinished fragments, a low pre-training cross-entropy does not by itself make the model a reliable conversational assistant; shaping how the model responds requires subsequent instruction tuning and reinforcement learning.

The pre-norm decoder block

Each layer in a modern decoder-only Transformer follows a two-stage pre-normalization residual layout:

ht′=ht+Attention⁡(Norm⁡(h))t,h'_t=h_t+\operatorname{Attention}(\operatorname{Norm}(h))_t, ht′′=ht′+FFN⁡(Norm⁡(ht′)).h''_t=h'_t+\operatorname{FFN}(\operatorname{Norm}(h'_t)).

The first sub-block normalizes the residual stream, mixes information across token positions up to tt via causal self-attention, and adds the result back to hth_t. The second sub-block normalizes the updated state ht′h'_t, applies a position-wise feed-forward network (FFN) to each token independently, and adds that output back to the residual stream.

DeepSeek-V3 preserves this exact macro-structure across all 61 layers, substituting Multi-head Latent Attention (MLA) for standard multi-head attention in every layer and replacing the dense FFN with a DeepSeekMoE block in layers 4 through 61.

RMSNorm and SwiGLU feed-forward networks

Rather than centering activations by subtracting their mean as in classic LayerNorm, DeepSeek-V3 uses Root Mean Square Normalization (RMSNorm), which scales each vector by its root-mean-square magnitude and applies a learned per-channel gain g∈Rdg \in \mathbb{R}^d:

RMSNorm⁡(h)j=hj1d∑k=1dhk2+ϵgj.\operatorname{RMSNorm}(h)_j= \frac{h_j}{\sqrt{\frac{1}{d}\sum_{k=1}^{d}h_k^2+\epsilon}}g_j.

Here ϵ\epsilon is a small constant (such as 10−610^{-6}) that guards against division by zero. Because divisions and square roots are sensitive to rounding error, V3 keeps RMSNorm computations in higher precision even when the surrounding matrix multiplications run in FP8.

Both the dense FFNs and individual MoE experts in V3 use the SwiGLU architecture, which gates one linear projection with the SiLU activation of another before projecting back to the residual width dd:

E(h)=Wd[SiLU⁡(Wgh)⊙Wuh],SiLU⁡(x)=xsigmoid⁡(x),E(h)=W_d\left[\operatorname{SiLU}(W_g h)\odot W_u h\right], \qquad \operatorname{SiLU}(x)=x\operatorname{sigmoid}(x),

where ⊙\odot denotes elementwise multiplication. If the input vector hh has dimension dd and the intermediate projections WghW_g h and WuhW_u h have dimension ff, then each SwiGLU unit comprises three matrices—gate Wg∈Rf×dW_g \in \mathbb{R}^{f \times d}, up Wu∈Rf×dW_u \in \mathbb{R}^{f \times d}, and down Wd∈Rd×fW_d \in \mathbb{R}^{d \times f}—totaling 3df3df parameters.

Multi-head attention and the KV cache

Inside an attention layer, each token state produces query (qq), key (kk), and value (vv) vectors across nhn_h parallel heads. At step tt, the query vector qtq_t scores its compatibility with the key vectors k1,…,ktk_1, \ldots, k_t of all preceding tokens, turns those scores into attention weights via softmax, and computes a weighted sum of the corresponding value vectors v1,…,vtv_1, \ldots, v_t.

When generating tokens one by one at inference time, the keys and values for earlier positions 1,…,t−11, \ldots, t-1 never change. Rather than recomputing them on every step, serving engines store them in GPU memory in a KV cache. While model weights are static and shared across all concurrent users, the KV cache is dynamic state tied to a specific request: its memory footprint grows linearly with batch size, sequence length, layer count, and the number of bytes cached per token. Shrinking that per-token cache footprint is the primary motivation behind MLA.

Backpropagation, GEMMs, and training memory

Training a linear layer Y=XWY = XW requires three general matrix multiplications (GEMMs) per step: one in the forward pass to compute activations Y=XWY = XW, one in the backward pass to propagate gradients to earlier layers (∇X=∇YW⊤\nabla_X = \nabla_Y W^\top), and one to compute the weight gradients (∇W=X⊤∇Y\nabla_W = X^\top \nabla_Y). Consequently, an effective FP8 training scheme cannot just quantize forward inference; it has to handle all three GEMM directions while keeping gradient accumulation accurate.

Furthermore, because computing ∇W=X⊤∇Y\nabla_W = X^\top \nabla_Y during the backward pass requires the forward activations XX, a training cluster must keep forward activations alive in memory across pipeline stages—or explicitly recompute them on the fly. On top of the model weights, gradients, and saved activations, the AdamW optimizer tracks two running statistics (first and second moments) for every parameter. A model's inference checkpoint size is therefore only a fraction of its peak training memory footprint.

Compute, memory bandwidth, and the roofline model

Whether an operation runs fast or slow on a GPU depends on the balance between three hardware limits: peak tensor-core arithmetic throughput (FLOPs/s), high-bandwidth memory (HBM) read/write speed (bytes/s), and interconnect bandwidth across NVLink or InfiniBand.

The ratio of floating-point operations performed to bytes read from memory is the operation's arithmetic intensity. A simplified roofline bound captures how arithmetic intensity dictates hardware utilization:

achievable FLOPs/s≤min⁡(compute peak,bandwidth×arithmetic intensity).\text{achievable FLOPs/s}\leq \min(\text{compute peak},\text{bandwidth}\times\text{arithmetic intensity}).

When processing a long prompt during prefill or a full micro-batch during training, thousands of tokens multiply the same weight matrix simultaneously. The weight bytes are read from HBM once and reused across thousands of vectors, yielding high arithmetic intensity and pushing the GPU toward its compute peak. During autoregressive decode, by contrast, only a handful of tokens may route to a given MoE expert on any single step. The GPU must stream tens of megabytes of expert weights out of HBM just to multiply a few vectors, making decode heavily memory-bandwidth-bound and communication-latency-bound. This fundamental shift in arithmetic intensity is why DeepSeek-V3 uses different cluster topologies and parallelism strategies for training, prefill, and decode.


Sources: Report §2 and §4.2 (main.tex, lines 270–455 and 714–744) for V3's Transformer structure and hyperparameters; content/fp8.tex for forward/backward GEMM and precision assignments. Continue to Chapter 3: A Complete Map of the Model.

3. A Complete Map of the Model

DeepSeek-V3's main backbone consists of 61 Transformer layers operating on a 7,168-dimensional residual stream. Every layer uses Multi-head Latent Attention (MLA) for context mixing. The first three layers use standard dense SwiGLU feed-forward networks, while the remaining 58 layers replace the dense FFN with a DeepSeekMoE block containing 1 shared expert and 256 routed experts (of which 8 are activated per token). Attached to the top of this backbone is a 1-step Multi-Token Prediction (MTP) module that provides auxiliary supervision during training and can optionally draft tokens during speculative decoding.

Rather than treating "671B total parameters and 37B active parameters" as opaque summary statistics, we can reconstruct both figures directly from the shapes of the weight matrices inside each block.

Original V3 architecture diagram showing residual attention and feed-forward blocks, shared and routed experts, and the cached MLA latent and positional key.

DeepSeek-V3 architecture diagram from Report §2. The hatched vectors (ctKVc_t^{KV} and ktRk_t^R) indicate the compressed representations stored in the KV cache during inference. While the diagram illustrates the general MoE block, the first three layers of V3 use dense FFNs instead.

Architectural hyperparameters

Table 1 consolidates the architectural dimensions reported in §4.2 alongside supplementary dimensions from the released Hugging Face configuration (reference/release-config.json):

Quantity Value Role in the architecture
Main Transformer layers (LL) 61 Total depth of the primary backbone
Hidden dimension (dd) 7,168 Width of the residual stream
Attention heads (nhn_h) 128 Parallel attention distributions per layer
Per-head content width (dhCd_h^C) 128 Non-positional query/key dimension per head
Per-head value width (dhVd_h^V) 128 Value dimension per head
Per-head RoPE width (dhRd_h^R) 64 Rotary position query/key dimension per head
KV compression dimension (dcd_c) 512 Shared low-rank latent width for keys and values
Query compression dimension (dc′d'_c) 1,536 Low-rank latent width for queries
Initial dense FFN layers 3 Layers 1–3 use standard dense SwiGLU FFNs
Dense FFN intermediate width 18,432 SwiGLU hidden width in layers 1–3 (from release config)
MoE layers 58 Layers 4–61 use DeepSeekMoE FFNs
Shared experts per MoE layer (NsN_s) 1 Always-active FFN applied to every token
Routed experts per MoE layer (NrN_r) 256 Pool of conditional FFNs per MoE layer
Active routed experts per token (KrK_r) 8 Number of routed FFNs evaluated per token
Expert intermediate width (ff) 2,048 SwiGLU hidden width inside each shared or routed expert
Node-limited routing cap (MM) 4 Maximum nodes a token's experts may span during training
MTP depth (DD) 1 Number of additional future tokens predicted during training
Vocabulary size (VV) 129,280 Token embedding and output head rows (from release config)
Context length 4K →\to 128K 4K pre-training window extended to 128K via YaRN

Tracing a token through the 61-layer stack

When an input token enters the model, the embedding table maps its integer ID to a vector ht(0)∈R7168h_t^{(0)} \in \mathbb{R}^{7168}. Each layer ℓ∈{1,…,61}\ell \in \{1, \ldots, 61\} applies RMSNorm, projects the normalized state into compressed query and key-value latents inside MLA, mixes context from positions ≤t\le t, and adds the projected attention output back to the residual stream.

In layers 1 through 3, the post-attention state passes through a single wide SwiGLU FFN with intermediate dimension 18,432. In layers 4 through 61, it enters the MoE block instead: a linear router scores all 256 routed experts, selects the top 8, and evaluates those 8 experts alongside the 1 shared expert. The weighted sum of the 8 routed expert outputs is added to the shared expert output and merged back into the residual stream. Notice that the choice of 8 routed experts is completely independent across tokens and across layers—token tt may visit one set of 8 experts in layer 4 and an entirely different set in layer 5.

After layer 61, a final RMSNorm and the unembedding matrix project the 7,168-dimensional state onto 129,280 vocabulary logits. During standard inference, the MTP module is not needed to produce this next-token distribution; its regularization effect is already baked into the backbone weights during training.

Parameter accounting: MoE and dense FFNs

Every expert in DeepSeek-V3 is a SwiGLU network with input/output width d=7168d = 7168 and intermediate width f=2048f = 2048. Because a SwiGLU block has three matrices (Wg,Wu∈Rf×dW_g, W_u \in \mathbb{R}^{f \times d} and Wd∈Rd×fW_d \in \mathbb{R}^{d \times f}) and no linear bias terms, a single expert contains:

PE=3df=3×7168×2048=44,040,192 parameters≈44.04M.P_E=3df=3\times7168\times2048=44{,}040{,}192\text{ parameters}\approx 44.04\text{M}.

Each MoE layer houses 256 routed experts plus 1 shared expert, for 257 experts total:

257×PE=257×44,040,192=11,318,329,344≈11.318B parameters per MoE layer.257\times P_E = 257\times 44{,}040{,}192 = 11{,}318{,}329{,}344\approx 11.318\text{B parameters per MoE layer}.

Multiplied across all 58 MoE layers, the expert pool accounts for:

58×11.318B≈656.94B parameters.58\times 11.318\text{B}\approx \mathbf{656.94\text{B}}\text{ parameters}.

Over 97.8% of DeepSeek-V3's total parameters live inside the MoE expert matrices. For any single token, however, only 9 experts (1 shared + 8 routed) run per MoE layer. Across all 58 MoE layers, the active expert parameters per token come to:

58×9×PE=522×44.04M≈22.99B parameters.58\times 9\times P_E = 522\times 44.04\text{M}\approx \mathbf{22.99\text{B}}\text{ parameters}.

What about the first three dense layers? With d=7168d = 7168 and intermediate width 18,43218{,}432 (equivalent to 9 experts worth of width), each dense FFN contains:

3×7168×18432=396,361,728≈396.36M parameters,3\times7168\times18432 = 396{,}361{,}728\approx 396.36\text{M parameters},

contributing 3×396.36M≈1.19B3 \times 396.36\text{M} \approx \mathbf{1.19\text{B}} parameters that are both stored and active for every token.

Parameter accounting: Multi-head Latent Attention

Next, we count the linear projections inside a single MLA layer (derived in detail in Chapter 5):

Projection matrix Matrix dimensions Parameters per layer
Query down-projection (WDQW^{DQ}) 1536×71681536\times7168 11.01M
Query content + RoPE up-projections (WUQ,WQRW^{UQ}, W^{QR}) 128×(128+64)×1536128\times(128+64)\times1536 37.75M
KV down-projection + decoupled key RoPE (WDKV,WKRW^{DKV}, W^{KR}) (512+64)×7168(512+64)\times7168 4.13M
KV content + value up-projections (WUK,WUVW^{UK}, W^{UV}) 128×(128+128)×512128\times(128+128)\times512 16.78M
Output projection (WOW^O) 7168×(128×128)7168\times(128\times128) 117.44M
Total per MLA layer 187.10M

Note how the output projection works: 128 heads each produce a 128-dimensional value vector, concatenating to an intermediate width of 128×128=16,384128 \times 128 = 16{,}384, which WOW^O projects back down to the 7,168-dimensional residual stream. Across all 61 layers, the attention projections contain 61×187.10M≈11.41B61 \times 187.10\text{M} \approx \mathbf{11.41\text{B}} parameters, all of which are active for every token.

Summing the backbone and the MTP module

Finally, the vocabulary embedding matrix and final output projection head each have shape 129,280×7,168≈0.927B129{,}280 \times 7{,}168 \approx 0.927\text{B} parameters. Because the release configuration specifies tie_word_embeddings: false, the two tables are stored separately, contributing 1.85B\mathbf{1.85\text{B}} parameters.

Summing the four major components of the 61-layer main model gives:

Total stored≈656.94B (MoE)+11.41B (MLA)+1.19B (dense FFN)+1.85B (embed/head)=671.39B.\text{Total stored} \approx 656.94\text{B (MoE)} + 11.41\text{B (MLA)} + 1.19\text{B (dense FFN)} + 1.85\text{B (embed/head)} = \mathbf{671.39\text{B}}.

Replacing the 257 stored experts per MoE layer with the 9 active experts per token gives the active parameter count:

Active per token≈22.99B (MoE)+11.41B (MLA)+1.19B (dense FFN)+1.85B (embed/head)=37.45B.\text{Active per token} \approx 22.99\text{B (MoE)} + 11.41\text{B (MLA)} + 1.19\text{B (dense FFN)} + 1.85\text{B (embed/head)} = \mathbf{37.45\text{B}}.

(Small router matrices of size 256×7168≈1.84M256 \times 7168 \approx 1.84\text{M} per MoE layer and 1D RMSNorm vectors account for the remaining ~0.1B fraction. Also note that while standard parameter-counting conventions include the embedding table in the active total, looking up a single token ID only reads one 7,168-element row rather than multiplying the full 0.927B embedding matrix.)

Why does the official Hugging Face repository list the downloadable checkpoint at 685B parameters instead of 671B? The extra ~14B parameters belong to the single-layer MTP module shipped alongside the main weights. An MTP depth of 1 adds one complete MoE Transformer layer (~11.32B in experts + ~0.19B in MLA) plus a 7168×143367168 \times 14336 linear projection matrix (~0.10B). In the repository's weight documentation, the MTP module is listed at ~11.5B unique parameters (or ~14B when counting its references to the shared input embedding and output head), bringing the combined checkpoint to ~685B.

Paper vs. release configuration nuances

When cross-referencing the paper against the released config.json and weight documentation, three minor implementation differences stand out:

  1. Maximum position embeddings: The paper describes context extension up to 128K tokens (131,072), whereas release-config.json sets max_position_embeddings: 163840 (160K). The larger buffer size in the config file sets an upper bound for RoPE table allocation, while 128K remains the benchmarked context ceiling in the report.
  2. Initialization standard deviation: Section 4.2 reports that weights were initialized from a normal distribution with standard deviation 0.0060.006, whereas release-config.json leaves the default Hugging Face field initializer_range: 0.02. Because a pretrained checkpoint loads trained weights from disk, the config field is merely a leftover default in the modeling script.
  3. Routed scaling factor: In release-config.json, the normalized router weights are multiplied by routed_scaling_factor: 2.5 before summing the 8 routed expert outputs, a constant inherited from the DeepSeekMoE implementation that is omitted from the simplified schematic equations in §2.1.2.

Sources: Report §4.2 (main.tex, lines 714–727) for layer and dimension counts; §2.1 (main.tex, lines 294–356) for MLA and DeepSeekMoE equations; reference/release-config.json and the official weight documentation for vocabulary size, dense FFN width, and MTP parameter breakdowns. Continue to Chapter 4: Attention and Rotary Position.

4. Attention and Rotary Position

Feed-forward layers transform each token's hidden state in isolation; causal self-attention is the mechanism that lets a token inspect earlier positions in the sequence, connecting a pronoun to its antecedent or a function call to an earlier import statement.

To see why DeepSeek-V3 structures Multi-head Latent Attention (MLA) the way it does, we first need to examine standard scaled dot-product attention and the linear-algebraic friction between Rotary Position Embeddings (RoPE) and low-rank key compression.

Scaled dot-product attention

Given an input state ht∈Rdh_t \in \mathbb{R}^d at token position tt, a standard attention head projects hth_t into a query, a key, and a value vector:

qt=WQht,kt=WKht,vt=WVht.q_t=W_Qh_t,\qquad k_t=W_Kh_t,\qquad v_t=W_Vh_t.

To aggregate context at step tt, the head takes the dot product between the current query qtq_t and the key kjk_j of every preceding position j≤tj \le t, scales by 1/dk1/\sqrt{d_k} (where dkd_k is the query/key width), normalizes the scores via softmax, and takes the weighted sum of the value vectors:

atj=exp⁡(qtTkj/dk)∑r≤texp⁡(qtTkr/dk),ot=∑j≤tatjvj.a_{tj}=\frac{\exp(q_t^Tk_j/\sqrt{d_k})} {\sum_{r\leq t}\exp(q_t^Tk_r/\sqrt{d_k})}, \qquad o_t=\sum_{j\leq t}a_{tj}v_j.

For example, if the scaled dot products for three positions are 00, 00, and log⁡2\log 2, their exponentials are 1,1,21, 1, 2, yielding attention weights 1/4,1/4,1/21/4, 1/4, 1/2: the third position contributes half the output vector while the first two contribute a quarter each.

Why divide by dk\sqrt{d_k}? If the entries of qtq_t and kjk_j have roughly zero mean and unit variance, the variance of their dkd_k-element dot product grows proportionally to dkd_k. Dividing by dk\sqrt{d_k} keeps the variance of the pre-softmax logits near 11 regardless of head width, preventing wide heads from saturating the softmax into near-one-hot distributions early in training. In DeepSeek-V3, each head concatenates a 128-dimensional content vector and a 64-dimensional positional vector, so the scaling denominator is 128+64=192\sqrt{128 + 64} = \sqrt{192} (further adjusted by a YaRN temperature scale during long-context extension).

Causal masking vs. document masking

During autoregressive training, position tt predicts token t+1t+1 and must never read information from positions j>tj > t. Hardware kernels enforce this causality during parallel training by adding −∞-\infty to all upper-triangle entries (j>tj > t) of the score matrix before applying softmax, zeroing out their attention weights atja_{tj}.

When multiple shorter documents are concatenated into a single 4,096-token training sequence to avoid padding waste, an implementation can also apply a block-diagonal document mask so tokens in one document cannot attend to tokens from a previous document in the same packed sequence. Notably, DeepSeek-V3 does not apply cross-sample attention masking during pre-training packing (allowing attention to bleed across packed document boundaries), whereas it does isolate packed samples during supervised fine-tuning (Chapter 10).

Encoding relative order with RoPE

Dot-product attention over raw content vectors qtq_t and kjk_j is permutation-equivariant: swapping the positions of two earlier tokens leaves their dot products with qtq_t unchanged. To make attention sensitive to token order, DeepSeek-V3 uses Rotary Position Embedding (RoPE).

RoPE partitions a vector into 2D coordinate pairs and rotates each pair in the plane by an angle proportional to the token's absolute position index tt. For a single 2D pair with base frequency ω\omega, the rotation matrix at position tt is:

R(t)=[cos⁡(tω)−sin⁡(tω)sin⁡(tω)cos⁡(tω)].R(t)= \begin{bmatrix} \cos(t\omega)&-\sin(t\omega)\\ \sin(t\omega)&\cos(t\omega) \end{bmatrix}.

Applying R(t)R(t) to the query and R(j)R(j) to the key yields a dot product that depends only on the relative distance j−tj - t:

(R(t)qt)T(R(j)kj)=qtTR(t)TR(j)kj=qtTR(j−t)kj,(R(t)q_t)^T(R(j)k_j)=q_t^TR(t)^TR(j)k_j=q_t^TR(j-t)k_j,

because the transpose of a 2D rotation by tωt\omega is a rotation by −tω-t\omega, and composing rotations adds their angles. Across a dhRd_h^R-dimensional vector, RoPE assigns a geometric progression of frequencies ωm\omega_m to the dhR/2d_h^R / 2 coordinate pairs, allowing attention heads to track both fine-grained local adjacency (high frequencies) and broad document-level distance (low frequencies).

Why standard RoPE collides with low-rank KV compression

Now consider what happens when we try to compress keys into a low-rank latent vector cj∈Rdcc_j \in \mathbb{R}^{d_c} so we don't have to cache full keys for all 128 heads. Suppose each head's key is reconstructed from the shared latent via a linear up-projection kj=UKcjk_j = U_K c_j.

If there is no positional rotation, the dot product between query qtq_t and key kjk_j factors cleanly:

qtTkj=qtT(UKcj)=(UKTqt)Tcj.q_t^T k_j = q_t^T (U_K c_j) = (U_K^T q_t)^T c_j.

Because UKTU_K^T does not depend on the historical position jj, we can multiply UKTqtU_K^T q_t once at step tt to form an absorbed query q~t=UKTqt∈Rdc\widetilde{q}_t = U_K^T q_t \in \mathbb{R}^{d_c}, and then take dot products directly against the cached latents cjc_j for all j≤tj \le t. We never have to materialize the expanded keys kjk_j in memory.

If we apply standard RoPE to the reconstructed key kj=R(j)UKcjk_j = R(j) U_K c_j, however, the position-dependent rotation matrix R(j)R(j) sits sandwiched between the query and the up-projection:

qtTR(j)UKcj.q_t^T R(j) U_K c_j.

Because R(j)R(j) varies with every historical token index jj and does not commute with the rectangular projection UKU_K, we can no longer absorb UKU_K into a single position-independent query vector q~t\widetilde{q}_t. To evaluate attention scores, the GPU would either have to recompute R(j)UKcjR(j) U_K c_j for every cached token jj at every decode step—destroying inference compute efficiency—or store the expanded, rotated keys R(j)UKcjR(j) U_K c_j for all 128 heads, destroying the KV cache savings.

V3's solution: decoupled RoPE

DeepSeek-V2 and V3 resolve this algebraic impasse by splitting each query and key into two separate slices: a head-specific content slice (qt,iC,kj,iC∈R128q_{t,i}^C, k_{j,i}^C \in \mathbb{R}^{128}) that undergoes low-rank compression without RoPE, and a narrower positional slice (qt,iR,kjR∈R64q_{t,i}^R, k_j^R \in \mathbb{R}^{64}) that carries RoPE.

For head ii, the complete query and key vectors are formed by concatenation:

qt,i=[qt,iC;qt,iR],kj,i=[kj,iC;kjR].q_{t,i}=[q^C_{t,i};q^R_{t,i}],\qquad k_{j,i}=[k^C_{j,i};k^R_j].

Crucially, the 64-dimensional rotated positional key kjRk_j^R is shared across all 128 heads (acting like a multi-query positional component), while each head ii retains its own rotated positional query qt,iRq_{t,i}^R. When taking the dot product, the score splits into the sum of a content term and a positional term:

qt,iTkj,i=(qt,iC)Tkj,iC+(qt,iR)TkjR.q_{t,i}^Tk_{j,i} =(q^C_{t,i})^Tk^C_{j,i}+(q^R_{t,i})^Tk^R_j.

Now both terms are cheap to store and evaluate:

  1. The unrotated content term (qt,iC)Tkj,iC(q_{t,i}^C)^T k_{j,i}^C has no R(j)R(j) matrix in the middle, so the key up-projection UKU_K absorbs directly into the query vector.
  2. The rotated positional key kjRk_j^R cannot be absorbed, but because it is only 64 elements wide and shared across all 128 heads, caching it outright adds just 64 scalars per token per layer alongside the 512-dimensional content latent.

Values vj,iC∈R128v_{j,i}^C \in \mathbb{R}^{128} only carry content—position affects which values are selected via the softmax weights atja_{tj}, so no positional value vector is needed. The next chapter steps through the full matrix algebra of this MLA pipeline.


Sources: Report §2.1.1 (main.tex, lines 294–332) for decoupled RoPE equations and attention scaling; §4.3 and Chapter 12 for YaRN long-context adjustments. Continue to Chapter 5: Deriving Multi-head Latent Attention.

5. Deriving Multi-head Latent Attention

Multi-head Latent Attention (MLA), introduced in DeepSeek-V2 and retained in DeepSeek-V3, replaces the per-head key and value projections of standard multi-head attention with a shared low-rank latent bottleneck. Rather than quantizing an existing KV cache into fewer bits per number, MLA changes the linear algebra of the attention projections so that the model caches a single 512-dimensional content latent and a 64-dimensional positional key per token, reconstructing or absorbing the 128 head-specific projections on the fly.

Dimensions of the MLA block

At layer ℓ\ell, let ht∈R7168h_t \in \mathbb{R}^{7168} be the normalized hidden state for token tt. DeepSeek-V3 configures MLA with nh=128n_h = 128 heads and the following per-head and latent widths:

In the actual architecture (§4.2), V3 applies an extra RMSNorm layer to the compressed latents ctQc_t^Q and ctKVc_t^{KV} immediately after their down-projections. In the derivations below, ctQc_t^Q and ctKVc_t^{KV} denote the latent vectors after this RMSNorm has been applied; because the KV cache stores the post-RMSNorm latent ctKVc_t^{KV}, all downstream up-projections remain purely linear maps that can be algebraically absorbed during inference.

Joint low-rank KV compression and decoupled key RoPE

To produce keys and values, MLA first projects hth_t down into a 512-dimensional latent vector (followed by RMSNorm):

ctKV=WDKVht,WDKV∈R512×7168.c_t^{KV}=W^{DKV}h_t,\qquad W^{DKV}\in\mathbb{R}^{512\times7168}.

From this single vector ctKVc_t^{KV}, each head i∈{1,…,128}i \in \{1, \ldots, 128\} generates its 128-dimensional content key and 128-dimensional value via head-specific linear up-projections:

kt,iC=UiKctKV,vt,iC=UiVctKV,UiK,UiV∈R128×512.k^C_{t,i}=U^K_i c_t^{KV},\qquad v^C_{t,i}=U^V_i c_t^{KV}, \qquad U^K_i, U^V_i \in \mathbb{R}^{128\times512}.

Stacking U1K,…,U128KU^K_1, \ldots, U^K_{128} forms the full content-key up-projection matrix WUK∈R16384×512W^{UK} \in \mathbb{R}^{16384 \times 512}, and stacking U1V,…,U128VU^V_1, \ldots, U^V_{128} forms WUV∈R16384×512W^{UV} \in \mathbb{R}^{16384 \times 512}.

In parallel, a separate projection maps hth_t directly to the shared 64-dimensional positional key and applies RoPE for position tt:

ktR=RoPE⁡t(WKRht),WKR∈R64×7168.k_t^R=\operatorname{RoPE}_t(W^{KR}h_t), \qquad W^{KR}\in\mathbb{R}^{64\times7168}.

During autoregressive decoding, only ctKV∈R512c_t^{KV} \in \mathbb{R}^{512} and ktR∈R64k_t^R \in \mathbb{R}^{64} are written to the KV cache—a total of 512+64=576512 + 64 = 576 scalars per token per layer.

Low-rank query compression

MLA also compresses the queries through a 1,536-dimensional bottleneck (again followed by RMSNorm):

ctQ=WDQht,WDQ∈R1536×7168.c_t^Q=W^{DQ}h_t,\qquad W^{DQ}\in\mathbb{R}^{1536\times7168}.

From ctQc_t^Q, each head reconstructs both its 128-dimensional content query and its 64-dimensional rotated positional query:

qt,iC=UiQctQ,qt,iR=RoPE⁡t(UiRctQ),q^C_{t,i}=U^Q_i c_t^Q, \qquad q^R_{t,i}=\operatorname{RoPE}_t(U^R_i c_t^Q),

where UiQ∈R128×1536U^Q_i \in \mathbb{R}^{128 \times 1536} (stacking to WUQ∈R16384×1536W^{UQ} \in \mathbb{R}^{16384 \times 1536}) and UiR∈R64×1536U^R_i \in \mathbb{R}^{64 \times 1536} (stacking to WQR∈R8192×1536W^{QR} \in \mathbb{R}^{8192 \times 1536}).

Why compress queries if queries are never stored in the KV cache? First, replacing a direct 7168→245767168 \to 24576 projection (176.16M176.16\text{M} parameters) with 7168→1536→245767168 \to 1536 \to 24576 (11.01M+37.75M=48.76M11.01\text{M} + 37.75\text{M} = 48.76\text{M} parameters) trims roughly 127M127\text{M} parameters per layer. Second, during training, caching the 1,536-dimensional query latent requires far less activation memory than keeping the 24,576-dimensional expanded queries alive for the backward pass.

The expanded attention equations

If we materialize all head vectors explicitly—as is typically done during training and large-batch prefill—the attention score between query position tt and key position j≤tj \le t for head ii is:

ztji=(qt,iC)Tkj,iC+(qt,iR)TkjR192.z_{tji}=\frac{(q^C_{t,i})^Tk^C_{j,i}+(q^R_{t,i})^Tk^R_j}{\sqrt{192}}.

Applying softmax over j≤tj \le t gives the attention weights atjia_{tji}, which combine the head values:

ot,i=∑j≤tatjivj,iC,ut=WO[ot,1;…;ot,128],WO∈R7168×16384.o_{t,i}=\sum_{j\leq t}a_{tji}v^C_{j,i}, \qquad u_t=W^O[o_{t,1};\ldots;o_{t,128}], \qquad W^O\in\mathbb{R}^{7168\times16384}.

During decode, however, materializing kj,iCk_{j,i}^C and vj,iCv_{j,i}^C for all past tokens j≤tj \le t and all 128 heads would force us either to store 32,768 numbers per token in the KV cache or to re-run the UiKU^K_i and UiVU^V_i matrix multiplications over the entire history at every single token step. Matrix absorption avoids both costs.

Matrix absorption for inference

1. Absorbing the key up-projection UiKU^K_i

Substitute kj,iC=UiKcjKVk_{j,i}^C = U^K_i c_j^{KV} into the content score term in ztjiz_{tji}:

(qt,iC)Tkj,iC=(qt,iC)TUiKcjKV=((UiK)Tqt,iC)TcjKV.(q^C_{t,i})^Tk^C_{j,i} = (q^C_{t,i})^TU^K_i c_j^{KV} =\left((U^K_i)^Tq^C_{t,i}\right)^Tc_j^{KV}.

For the current token tt, we compute the absorbed query for head ii:

q~t,i=(UiK)Tqt,iC=(UiK)TUiQctQ∈R512.\widetilde q_{t,i}=(U^K_i)^Tq^C_{t,i} = (U^K_i)^T U^Q_i c_t^Q \in \mathbb{R}^{512}.

Now, for every historical position j≤tj \le t, the content dot product for head ii is simply q~t,iTcjKV\widetilde{q}_{t,i}^T c_j^{KV}—an inner product between head ii's 512-dimensional absorbed query and the single shared 512-dimensional latent cjKVc_j^{KV} stored in the cache. All 128 heads read the exact same cached vector cjKVc_j^{KV} from HBM.

2. Absorbing the value up-projection UiVU^V_i

Next, substitute vj,iC=UiVcjKVv_{j,i}^C = U^V_i c_j^{KV} into the value aggregation sum:

ot,i=∑j≤tatjiUiVcjKV=UiV(∑j≤tatjicjKV).o_{t,i}=\sum_{j\le t} a_{tji}U^V_i c_j^{KV} =U^V_i\left(\sum_{j\le t} a_{tji}c_j^{KV}\right).

Because UiVU^V_i is constant with respect to the historical index jj, it factors outside the sum. Each head ii first computes a weighted sum of the 512-dimensional cached latents:

o~t,i=∑j≤tatjicjKV∈R512,\widetilde o_{t,i}=\sum_{j\le t} a_{tji}c_j^{KV} \in \mathbb{R}^{512},

and then multiplies the single resulting vector o~t,i\widetilde{o}_{t,i} by UiV∈R128×512U^V_i \in \mathbb{R}^{128 \times 512} (or directly by the fused output matrix W:,iOUiV∈R7168×512W^O_{:, i} U^V_i \in \mathbb{R}^{7168 \times 512}) once at the end of the attention step.

To see the identity on concrete numbers, take a 2D latent with c1KV=[1,0]Tc_1^{KV} = [1, 0]^T, c2KV=[0,3]Tc_2^{KV} = [0, 3]^T, attention weights a=[0.25,0.75]a = [0.25, 0.75], and a 1×21 \times 2 value projection UV=[2,−1]U^V = [2, -1]:

In exact arithmetic the two paths produce identical results; in finite precision, they differ only by floating-point rounding order.

How MLA differs from GQA and MQA

In Multi-Query Attention (MQA) or Grouped-Query Attention (GQA), heads within a group share identical key and value vectors, which restricts every head in the group to reading the exact same value subspace. In MLA, all 128 heads share the underlying 512-dimensional cached vector cjKVc_j^{KV}, but each head applies its own learned rank-128 readout matrices UiKU^K_i and UiVU^V_i. Thus, MLA achieves a smaller cache footprint than 8-group GQA while preserving 128 distinct per-head key and value projections.

Keep in mind what MLA does and does not compress: it shrinks the per-token channel width of the KV cache from 32,768 scalars down to 576 scalars, but the cache still stores one 576-element entry for every historical token j≤tj \le t. Cache memory still scales linearly with sequence length SS, and full causal attention still evaluates all j≤tj \le t pairs. The next chapter works out the exact memory and FLOP economics of this tradeoff.


Sources: Report §2.1.1 (main.tex, lines 294–332) for the MLA equations and §4.2 (main.tex, lines 716–726) for layer dimensions and latent RMSNorm. See also the MLA class (naive vs. absorb modes) in the official reference inference code. Continue to Chapter 6: The Economics of Attention Memory.

6. The Economics of Attention Memory

During long-context generation, the request-specific KV cache can easily rival or exceed the memory footprint of the model weights on a serving node. By compressing 128 heads of keys and values into a 512-dimensional content latent plus a 64-dimensional positional key, MLA drastically cuts the bytes read from HBM on every decode step—while simultaneously changing the arithmetic intensity and FLOP profile of the attention kernel.

Exact KV-cache byte accounting

If a model with LL layers caches cc scalar elements per token per layer at bb bytes per element, the raw KV cache size for a single sequence of length SS is:

M=L⋅S⋅c⋅b.M = L \cdot S \cdot c \cdot b.

In DeepSeek-V3, L=61L = 61 main layers and c=dc+dhR=512+64=576c = d_c + d_h^R = 512 + 64 = 576 elements per layer. Stored in BF16 (b=2b = 2 bytes), each retained token consumes:

61×576×2=70,272 bytes/token≈70.27 KB/token (decimal)≈68.63 KiB/token.61 \times 576 \times 2 = \mathbf{70{,}272\text{ bytes/token}} \approx 70.27\text{ KB/token (decimal)} \approx 68.63\text{ KiB/token}.

Across the standard context milestones reported in the paper, the raw BF16 cache footprint for a single sequence is:

Context length (SS) Raw BF16 bytes (61×576×2×S61 \times 576 \times 2 \times S) Decimal GB (10910^9 B) Binary GiB (2302^{30} B)
4,096 (4K) 287,834,112 B 0.288 GB 0.268 GiB
32,768 (32K) 2,302,672,896 B 2.303 GB 2.145 GiB
131,072 (128K) 9,210,691,584 B 9.211 GB 8.578 GiB

At 8.58 GiB for a full 128K-token context (before paged-attention metadata, alignment padding, or activation buffers), a serving cluster can hold dozens of long-context sessions in HBM alongside the sharded MoE weights. Quantizing the cached latents to FP8 (b=1b = 1 byte plus block scaling metadata) halves this footprint again to roughly 4.3 GiB at 128K.

Comparing MLA against MHA, GQA, and MQA

How does 576 scalars per token per layer compare against standard attention architectures with the same 128 heads and dh=128d_h = 128 content/value width?

Attention variant Cached elements per token per layer (cc) Ratio vs. V3 MLA 128K raw BF16 cache (61 layers)
Standard MHA (128 KV heads, width 128) 128×(128+128)=32,768128 \times (128 + 128) = 32{,}768 56.89×56.89\times 488.01 GiB
GQA with 8 KV groups (nKV=8n_{KV}=8, width 128) 8×(128+128)=2,0488 \times (128 + 128) = 2{,}048 3.56×3.56\times 30.50 GiB
DeepSeek-V3 MLA (dc=512,dhR=64d_c=512, d_h^R=64) 512+64=576512 + 64 = \mathbf{576} 1.00×1.00\times 8.58 GiB
MQA with 1 KV head (nKV=1n_{KV}=1, width 128) 1×(128+128)=2561 \times (128 + 128) = 256 0.44×0.44\times 3.81 GiB

Relative to full 128-head MHA, MLA shrinks the KV cache by nearly 57×57\times (and if the MHA baseline also cached a 64-dimensional RoPE key slice per head, its per-layer width would be 128×(192+128)=40,960128 \times (192 + 128) = 40{,}960, a 71.1×71.1\times reduction). Relative to an 8-head GQA layout common in large dense models, MLA uses 3.56×3.56\times less KV memory while allowing every head to maintain its own rank-128 key and value subspace rather than forcing 16 query heads to share a single static KV head.

The FLOP vs. memory-bandwidth tradeoff in absorbed MLA

While matrix absorption slashes KV cache memory traffic, it actually increases the number of floating-point operations per historical token inside the core attention loop.

To see why, count the multiply-accumulate FLOPs (2 FLOPs per multiply-add) per query head per historical token jj:

Why is a 3.4×3.4\times increase in inner-loop FLOPs a massive win during autoregressive decoding? Look at the arithmetic intensity across all 128 heads:

Why prefill and decode use different MLA execution paths

This difference in arithmetic intensity explains why the official DeepSeek-V3 reference implementation (inference/model.py) provides two distinct execution modes—and why production serving engines switch strategies between prefill and decode:

  1. Prefill / Training (unabsorbed expansion): When processing a 4,096-token prompt in parallel, the up-projections WUKcKVW^{UK} c^{KV} and WUVcKVW^{UV} c^{KV} are large dense matrix multiplications, and the core attention loop has 640640 FLOPs per head per pair instead of 2,1762{,}176. Because the expanded KV tensors are consumed immediately across thousands of query positions in SRAM (via FlashAttention tiling), expanding kCk^C and vCv^C avoids the 3.4×3.4\times pairwise FLOP penalty during prefill while only writing the compact 576-element vectors (ctKV,ktRc_t^{KV}, k_t^R) out to the persistent HBM cache for subsequent decoding.
  2. Decode (absorbed latent attention): When generating one token per sequence, matrix absorption (absorb mode) keeps the KV cache at 576 elements per token and converts the memory-bound KV scan into a compute-efficient batched matrix multiply over the shared latents in SRAM.

Even with MLA, causal prefill still performs O(S2)O(S^2) pairwise token comparisons across the prompt, and each decode step still scans O(S)O(S) historical latents. MLA removes the KV memory wall that previously capped long-context batch sizes, shifting the remaining long-context bottleneck from HBM capacity to attention compute.


Sources: Report §2.1.1 (main.tex, lines 294–332) and §4.2 (main.tex, lines 716–726); naive vs. absorb modes in inference/model.py. See Chapter 21 for how prefill and decode clusters manage KV cache and expert parallelism in production. Continue to Chapter 7: Fine-grained and Shared Experts.

7. Fine-grained and Shared Experts

In DeepSeek-V3, an "expert" is not a standalone domain-specific language model or an external agent; it is a single SwiGLU feed-forward network (FFN) living inside a Transformer layer. In 58 of the model's 61 layers (layers 4 through 61), the dense FFN is replaced by a DeepSeekMoE block containing 1 shared expert and 256 routed experts. For each token, a learned linear router selects 8 of the 256 routed experts, evaluates them in parallel alongside the shared expert, and sums their outputs back into the residual stream.

Anatomy and FLOP cost of a single expert

Let ut∈R7168u_t \in \mathbb{R}^{7168} be the normalized post-attention hidden state for token tt. Each expert ii—whether shared or routed—is a three-matrix SwiGLU transformation with input/output dimension d=7168d = 7168 and intermediate hidden dimension f=2048f = 2048:

Ei(ut)=Wd,i[SiLU⁡(Wg,iut)⊙Wu,iut],Wg,i,Wu,i∈R2048×7168,Wd,i∈R7168×2048.E_i(u_t)=W_{d,i}\left[\operatorname{SiLU}(W_{g,i}u_t)\odot W_{u,i}u_t\right], \qquad W_{g,i}, W_{u,i}\in\mathbb{R}^{2048\times7168},\quad W_{d,i}\in\mathbb{R}^{7168\times2048}.

As we calculated in Chapter 3, each expert holds 3×7168×2048≈44.04M3 \times 7168 \times 2048 \approx 44.04\text{M} parameters. Counting two FLOPs per multiply-accumulate across the three matrix-vector products, evaluating one expert for a single token requires:

CE=6df=6×7168×2048=88,080,384 FLOPs≈88.08M FLOPs.C_E = 6df = 6 \times 7168 \times 2048 = \mathbf{88{,}080{,}384\text{ FLOPs}} \approx 88.08\text{M FLOPs}.

Because each token visits 1 shared expert and 8 routed experts (9 experts total), its active FFN compute per MoE layer is:

9×88.08M≈792.72M FLOPs/token/layer,9 \times 88.08\text{M} \approx \mathbf{792.72\text{M FLOPs/token/layer}},

which exactly matches the FLOP cost of a single dense SwiGLU FFN in layers 1–3 (fdense=9×2048=18,432f_{\text{dense}} = 9 \times 2048 = 18{,}432). By contrast, evaluating all 257 stored experts in a layer would cost 257×88.08M≈22.64B257 \times 88.08\text{M} \approx 22.64\text{B} FLOPs per token. Sparse routing thus provides the parameter capacity of 257 experts for the per-token compute budget of 9.

Why DeepSeekMoE uses fine-grained and shared experts

Conventional MoE designs (such as Mixtral 8×78\times7B or GShard) typically use a small number of full-width experts (e.g., 8 or 16 experts, picking top-1 or top-2). DeepSeekMoE modifies that blueprint in two ways:

  1. Fine-grained expert segmentation: Instead of storing 32 full-sized experts of width f=16,384f = 16{,}384 and activating 1, DeepSeek-V3 slices the intermediate dimension into 8×8\times narrower units (f=2048f = 2048), creating 256 experts and activating 8 per token. Keeping the total stored and active parameter counts constant while splitting experts finer increases the number of possible expert combinations from (321)=32\binom{32}{1} = 32 to (2568)≈4.09×1014\binom{256}{8} \approx 4.09 \times 10^{14}. That combinatorial flexibility allows the router to compose distinct subsets of features for nuanced inputs rather than forcing a single monolithic expert to handle everything.
  2. Dedicated shared expert isolation: Every token needs certain common linguistic and structural transformations regardless of domain. In a purely routed MoE, dozens of routed experts end up learning redundant copies of these shared operations, wasting parameter capacity. Dedicating one always-active expert (Ns=1N_s = 1) to capture common cross-token transformations frees the 256 routed experts to specialize in rarer, conditional patterns.

Sigmoid affinity scoring and top-k gating

To decide which routed experts to run for token tt, the router computes the dot product between the token's hidden state ut∈R7168u_t \in \mathbb{R}^{7168} and a learned centroid vector ei∈R7168e_i \in \mathbb{R}^{7168} for each routed expert i∈{1,…,256}i \in \{1, \ldots, 256\}. Unlike DeepSeek-V2, which applied a softmax over all 256 expert logits, DeepSeek-V3 applies an independent sigmoid activation to each logit (§2.1.2):

si,t=sigmoid⁡(utTei)=11+exp⁡(−utTei).s_{i,t} = \operatorname{sigmoid}(u_t^T e_i) = \frac{1}{1 + \exp(-u_t^T e_i)}.

Why switch from softmax to sigmoid plus top-kk normalization? Under a 256-way softmax, experts compete globally before selection, which can compress score differences or make top-8 selection sensitive to the tail of the 248 unselected logits. With sigmoid scoring, each expert's raw affinity si,t∈(0,1)s_{i,t} \in (0, 1) is evaluated independently.

Once the top-8 set StS_t is chosen (incorporating the load-balancing biases and node constraints covered in Chapter 8), the router normalizes the raw sigmoid affinities only across the 8 selected experts:

gi,t′={si,t∑j∈Stsj,t,i∈St,0,i∉St.g'_{i,t} = \begin{cases} \dfrac{s_{i,t}}{\sum_{j \in S_t} s_{j,t}}, & i \in S_t, \\[10pt] 0, & i \notin S_t. \end{cases}

In the paper's schematic presentation, the layer output adds the residual stream, the shared expert output, and the weighted sum of the selected routed experts:

ht′=ut+Eshared(ut)+∑i∈Stgi,tEi(ut),h'_t = u_t + E_{\mathrm{shared}}(u_t) + \sum_{i \in S_t} g_{i,t} E_i(u_t),

where, in the released checkpoint (reference/release-config.json and inference/model.py), the normalized weights include a fixed scalar multiplier gi,t=α⋅gi,t′g_{i,t} = \alpha \cdot g'_{i,t} with routed_scaling_factor α=2.5\alpha = 2.5.

For a quick two-of-four numerical example: suppose four experts receive raw sigmoid affinities s=[0.8,0.6,0.3,0.1]s = [0.8, 0.6, 0.3, 0.1]. Selecting the top 2 picks experts 1 and 2, whose normalized weights are g1′=0.8/(0.8+0.6)≈0.571g'_1 = 0.8 / (0.8 + 0.6) \approx 0.571 and g2′=0.6/1.4≈0.429g'_2 = 0.6 / 1.4 \approx 0.429. If their scalar outputs are 1010 and −4-4, the unscaled routed sum is 0.571(10)+0.429(−4)=4.00.571(10) + 0.429(-4) = 4.0 (or 2.5×4.0=10.02.5 \times 4.0 = 10.0 with the 2.5 scaling factor), which is then added to ut+Eshared(ut)u_t + E_{\mathrm{shared}}(u_t).

How gradients train a discrete router

Because choosing the top-8 indices StS_t is a discrete operation, how does backpropagation update the router centroids eie_i? Look at the weighted sum ∑i∈Stgi,tEi(ut)\sum_{i \in S_t} g_{i,t} E_i(u_t): for the 8 selected experts i∈Sti \in S_t, the gating weight gi,tg_{i,t} multiplies Ei(ut)E_i(u_t) and is a smooth, differentiable function of the sigmoid affinities sj,ts_{j,t} (j∈Stj \in S_t) and hence of the dot products utTeju_t^T e_j.

If expert i∈Sti \in S_t produces an output vector Ei(ut)E_i(u_t) that reduces the downstream loss, the gradient with respect to gi,tg_{i,t} pushes si,ts_{i,t} upward (and the competing selected affinities slightly downward via the normalization denominator), teaching the centroid eie_i to align more strongly with utu_t. Unselected experts (i∉Sti \notin S_t) have gi,t=0g_{i,t} = 0 and receive zero gradient on that token—which is why an unbalanced router that never picks certain experts will starve them of gradient updates altogether unless a load-balancing mechanism intervenes.

Per-token sparsity vs. batch-level expert activation

A single token activates only 8/256=3.125%8 / 256 = 3.125\% of the routed experts in a layer. Across a batch of BB tokens, however, each token makes 88 selections, resulting in A=8BA = 8B total expert assignments. Even under a simplified uniform-selection model, after AA independent draws the expected number of distinct experts touched out of 256 is:

256[1−(1−1256)A].256\left[1-\left(1-\frac{1}{256}\right)^A\right].

With just B=32B = 32 tokens (A=256A = 256 assignments), over 63% of the 256 experts are already active; by B=128B = 128 tokens (A=1,024A = 1{,}024 assignments), more than 98% of all experts in the layer are triggered by at least one token.

This creates a fundamental tension for hardware execution:

Fine-grained MoE therefore shifts the systems challenge from raw FLOPs to token regrouping (all-to-all dispatch), load balancing, and wide expert parallelism. Chapter 8 examines how DeepSeek-V3 balances expert load and constrains network hops without hurting model quality.


Sources: Report §2.1.2 (main.tex, lines 334–356) for DeepSeekMoE and sigmoid gating equations; §4.2 (main.tex, lines 716–727) for expert counts and dimensions; reference/release-config.json and Gate in inference/model.py for routed_scaling_factor: 2.5. Continue to Chapter 8: Routing and Load Balancing.

8. Routing and Load Balancing

Left to optimize language modeling loss alone, an MoE router frequently suffers from routing collapse: it funnels the vast majority of tokens into a handful of favored experts while leaving the rest idle. That creates a double failure: the underused experts stop receiving gradients and waste parameter capacity, while the overloaded experts become stragglers that stall distributed all-to-all execution. Conversely, if a load-balancing penalty forces every sequence to distribute tokens uniformly across all 256 experts, experts cannot specialize by domain.

DeepSeek-V3 resolves this tension with an auxiliary-loss-free balancing controller that adjusts per-expert selection biases dynamically based on batch-level load, paired with a tiny sequence-level auxiliary penalty (α=0.0001\alpha = 0.0001) and a hard 4-node communication cap per token.

The flaw in conventional auxiliary balancing losses

Standard MoE architectures encourage uniform routing by adding an explicit load-balancing penalty to the training loss:

L=LLM+αLBal.\mathcal L=\mathcal L_{\mathrm{LM}}+\alpha\mathcal L_{\mathrm{Bal}}.

Because LBal\mathcal{L}_{\mathrm{Bal}} is differentiated with respect to the router parameters (and indirectly affects the upstream hidden representations), choosing the coefficient α\alpha forces an awkward compromise. If α\alpha is too small, routing remains skewed and hardware utilization suffers; if α\alpha is large enough to enforce uniform hardware loads, the balancing gradients pull the router away from the expert choices that minimize language modeling loss. Worse still, when LBal\mathcal{L}_{\mathrm{Bal}} is computed per sequence, a pure Python file or a pure math proof is penalized for routing primarily to code or math experts, actively suppressing domain specialization.

Decoupling expert selection from mixture weighting

DeepSeek-V3 removes the primary load-balancing pressure from the gradient path altogether. Instead, each routed expert i∈{1,…,256}i \in \{1, \ldots, 256\} maintains a non-differentiable scalar bias bib_i that is added to the raw sigmoid affinity si,t=sigmoid⁡(utTei)s_{i,t} = \operatorname{sigmoid}(u_t^T e_i) only when selecting the top-8 experts:

St=TopK⁡i(si,t+bi).S_t=\operatorname{TopK}_i(s_{i,t}+b_i).

Once the winning index set StS_t is determined, the gating weights that scale the expert outputs use the unbiased original affinities si,ts_{i,t}:

gi,t′=si,t∑j∈Stsj,tfor i∈St.g'_{i,t}=\frac{s_{i,t}}{\sum_{j\in S_t}s_{j,t}}\quad\text{for }i\in S_t.

Why keep bib_i out of gi,t′g'_{i,t}? Because bib_i tracks hardware queue pressure rather than semantic relevance. Adding bib_i during top-kk selection nudges marginal tokens toward underloaded experts so all 256 experts stay busy, while computing gi,t′g'_{i,t} from the pure affinity si,ts_{i,t} ensures that an expert admitted only because of a high positive bias does not receive an artificially inflated weight in the layer output.

To see the difference concretely, consider a top-2 router over four experts with raw affinities st=[0.80,0.70,0.60,0.10]s_t = [0.80, 0.70, 0.60, 0.10]. Without biases, experts 1 and 2 win. Now suppose expert 2 is overloaded (b2=−0.20b_2 = -0.20) and expert 3 is underloaded (b3=+0.05b_3 = +0.05), shifting the selection scores to st+b=[0.80,0.50,0.65,0.10]s_t + b = [0.80, 0.50, 0.65, 0.10]. The router now picks experts 1 and 3, but combines their outputs using their raw affinities 0.800.80 and 0.600.60, giving normalized weights 0.80/1.40≈0.5710.80 / 1.40 \approx 0.571 and 0.60/1.40≈0.4290.60 / 1.40 \approx 0.429.

Iterative bias feedback during pre-training

At the end of each training step, the system tallies how many tokens across the global batch were routed to each expert ii. If expert ii's observed load ℓi\ell_i exceeds the uniform target load ℓtarget\ell_{\mathrm{target}}, its bias bib_i is decremented by a step size γ\gamma; if ℓi\ell_i falls below ℓtarget\ell_{\mathrm{target}}, bib_i is incremented by γ\gamma:

bi←bi+γsign⁡(ℓtarget−ℓi).b_i\leftarrow b_i+\gamma\operatorname{sign}(\ell_{\mathrm{target}}-\ell_i).

This sign-based proportional feedback loop acts like a thermostat on expert occupancy. In DeepSeek-V3 (§4.2), the bias update rate is set to γ=0.001\gamma = 0.001 for the first 14.3T pre-training tokens, and then set to γ=0.0\gamma = 0.0 for the final 500B tokens so that the late-stage learning-rate decay refines weights against a frozen routing bias distribution.

The complementary sequence-wise balance loss

Although the paper calls this approach "auxiliary-loss-free," V3 does retain a very small complementary sequence-wise balance loss to guard against pathological cases where a single individual sequence routes every single one of its tokens to the exact same experts (§2.1.2):

LBal=α∑i=1NrfiPi,\mathcal L_{\mathrm{Bal}}=\alpha\sum_{i=1}^{N_r}f_iP_i,

where Nr=256N_r = 256, the loss coefficient is α=0.0001\alpha = 0.0001, and fif_i and PiP_i measure selection frequency and normalized affinity mass across the TT tokens of a single sequence:

fi=NrKrT∑t=1T1(si,t∈TopK⁡({sj,t}j=1Nr,Kr)),Pi=1T∑t=1Tsi,t∑j=1Nrsj,t.f_i=\frac{N_r}{K_rT}\sum_{t=1}^{T}\mathbf 1\left(s_{i,t}\in\operatorname{TopK}(\{s_{j,t}\}_{j=1}^{N_r}, K_r)\right), \qquad P_i=\frac{1}{T}\sum_{t=1}^{T}\frac{s_{i,t}}{\sum_{j=1}^{N_r} s_{j,t}}.

Under perfectly uniform routing, fi=1f_i = 1 and Pi=1/NrP_i = 1/N_r, making ∑ifiPi=1\sum_i f_i P_i = 1. Because α=0.0001\alpha = 0.0001 is orders of magnitude smaller than standard MoE auxiliary loss weights (which typically sit around 10−210^{-2}), LBal\mathcal{L}_{\mathrm{Bal}} barely perturbs the language modeling gradients while still preventing extreme single-sequence hot-spots.

Why batch-level balancing unlocks specialization

A key insight from the paper's ablations (§4.5.3) is why the auxiliary-loss-free controller improves validation perplexity and downstream benchmarks. A global training batch mixes thousands of sequences from diverse domains—code, mathematics, English prose, Chinese web text. When balance is enforced at the global batch level (as bib_i does), code sequences are free to route heavily to one subset of experts while prose sequences route to another, so long as the aggregate utilization across the entire batch averages out.

In fact, when the authors tested a standard differentiable auxiliary loss computed at the batch level rather than the sequence level on 1B and 3B MoE models, it achieved the exact same validation loss as the bias-based method (2.2532.253 vs. 2.2582.258 at 1B, and 2.0802.080 vs. 2.0852.085 at 3B). Moving the balancing scope from the individual sequence to the global batch is therefore a major driver of the specialization shown in Figure 1, while the bias update mechanism provides a clean, hyperparameter-insensitive way to enforce that batch balance at scale.

Expert-load heatmaps comparing auxiliary-loss-based and auxiliary-loss-free models on Wikipedia, GitHub, and mathematics, with more domain-specific peaks in the latter.

Relative expert load across domains from Report §4.5.3 (measured on 16B ablation models with 64 routed experts). Compared to sequence-level auxiliary loss (left), the auxiliary-loss-free bias controller (right) allows sharp domain-specific expert concentration on Wikipedia, GitHub, and math texts while keeping global batch load balanced.

Node-limited routing (M=4M = 4)

During pre-training, DeepSeek-V3 uses 64-way Expert Parallelism (EP) spread across 8 compute nodes (8 GPUs per node, 4 routed experts per GPU). If a token's 8 selected experts could land on all 8 nodes arbitrarily, every token would have to be broadcast across the inter-node InfiniBand fabric to up to 8 different machines.

To bound cross-node InfiniBand traffic, V3 restricts each token to at most M=4M = 4 nodes (§2.1.2). The 256 routed experts are partitioned into 8 node groups of 32 experts each. For each node group g∈{1,…,8}g \in \{1, \ldots, 8\}, the router sums the highest Kr/M=8/4=2K_r / M = 8 / 4 = 2 candidate scores within that group (using the biased scores si,t+bis_{i,t} + b_i in the reference Gate implementation). It selects the 4 node groups with the highest top-2 sums, masks out all experts on the remaining 4 nodes, and then selects the global top-8 experts from the 4×32=1284 \times 32 = 128 eligible candidates. (Note that a selected node is not forced to supply exactly 2 final experts; it could supply 1, 2, 3, or more, provided all 8 winning experts live on the 4 winning nodes.)

Because the bias controller keeps expert loads tightly balanced and the 4-node cap bounds network fan-out, DeepSeek-V3 never drops tokens during either training or inference. When live serving traffic diverges from the pre-training domain mix—for instance, during a spike in coding requests that hammers specific experts—the inference engine preserves exact routing semantics by replicating hot experts across GPUs rather than altering the learned bias values (Chapter 21).


Sources: Report §2.1.2 (main.tex, lines 358–397) for routing biases, LBal\mathcal{L}_{\mathrm{Bal}}, and node-limited routing; §4.2 (main.tex, lines 737–744) for the γ\gamma schedule; §4.5.3 (main.tex, lines 912–932) for batch-vs-sequence ablations; Gate class in inference/model.py. Continue to Chapter 9: Multi-token Prediction as Training.

9. Multi-token Prediction as Training

In standard autoregressive training, the hidden state at position ii only receives direct cross-entropy supervision from a single immediate target: token xi+1x_{i+1}. DeepSeek-V3 augments this objective with a sequential Multi-Token Prediction (MTP) module that asks each position ii to also predict xi+2x_{i+2} conditioned on the main model's hidden state and the ground-truth embedding of xi+1x_{i+1}.

MTP serves two distinct purposes across the lifecycle of the model: during pre-training, it acts as an auxiliary training objective that backpropagates denser supervision into the 61-layer main backbone; during inference, it can optionally be retained as a lightweight draft head for speculative decoding (Chapter 22) or discarded entirely so the main model runs with zero extra overhead.

Sequential vs. independent multi-token prediction

Earlier multi-token prediction architectures (such as Gloeckle et al., 2024) attach DD parallel, independent heads directly to the backbone hidden state hi0h_i^0, asking hi0h_i^0 to simultaneously guess xi+1,xi+2,…,xi+D+1x_{i+1}, x_{i+2}, \ldots, x_{i+D+1} without knowing which intermediate token xi+1x_{i+1} was actually chosen. Because natural language is highly multimodal—after the word "The", thousands of nouns are plausible for xi+1x_{i+1}, and the valid verb at xi+2x_{i+2} depends entirely on which noun appeared at xi+1x_{i+1}—forcing a single representation to predict xi+2x_{i+2} blindly mixes incompatible futures.

DeepSeek-V3 instead preserves the autoregressive causal chain across prediction depths (§2.2). For general depth k∈{1,…,D}k \in \{1, \ldots, D\}, the kk-th MTP module receives both the representation hik−1h_i^{k-1} from depth k−1k-1 and the ground-truth token embedding Emb⁡(xi+k)\operatorname{Emb}(x_{i+k}), combining them to predict xi+k+1x_{i+k+1}.

Sequential MTP diagram showing the main next-token path, shifted embeddings, shared vocabulary modules, and additional Transformer prediction modules.

Sequential Multi-Token Prediction architecture from Report §2.2. Each MTP module fuses the previous depth's hidden state at position ii with the shifted embedding of token i+ki+k, passes the result through a causal Transformer block, and reuses the shared output head to predict token i+k+1i+k+1. In DeepSeek-V3, D=1D=1.

Step-by-step equations for V3 (D=1D = 1)

In the production DeepSeek-V3 run, the MTP depth is set to D=1D = 1 (one extra future token beyond standard next-token prediction). At sequence position ii:

  1. Main backbone prediction (k=0k = 0): The 61-layer main model processes x1:ix_{1:i} to produce final representation hi0∈R7168h_i^0 \in \mathbb{R}^{7168}, which the output head maps to vocabulary probabilities for xi+1x_{i+1}: pi+10=OutHead⁡(hi0).p_{i+1}^{0}=\operatorname{OutHead}(h_i^0).
  2. Feature fusion with shifted embedding (k=1k = 1): The MTP module independently normalizes the backbone state hi0h_i^0 and the shared embedding of the ground-truth next token Emb⁡(xi+1)∈R7168\operatorname{Emb}(x_{i+1}) \in \mathbb{R}^{7168}, concatenates them into a 2d=14,3362d = 14{,}336-dimensional vector, and projects back to d=7168d = 7168 via a learned matrix M1∈R7168×14336M_1 \in \mathbb{R}^{7168 \times 14336}: hi′1=M1[RMSNorm⁡(hi0);RMSNorm⁡(Emb⁡(xi+1))].h_i^{\prime 1}=M_1\left[ \operatorname{RMSNorm}(h_i^0); \operatorname{RMSNorm}(\operatorname{Emb}(x_{i+1})) \right].
  3. MTP Transformer block and readout: The sequence of fused states h1:T−1′1h_{1:T-1}^{\prime 1} passes through a single causal Transformer block TRM⁡1\operatorname{TRM}_1 (identical in structure to a main V3 MoE layer, with MLA and 256 routed + 1 shared experts) to yield hi1h_i^1, which the shared output head maps to probabilities for xi+2x_{i+2}: h1:T−11=TRM⁡1(h1:T−1′1),pi+21=OutHead⁡(hi1).h_{1:T-1}^1=\operatorname{TRM}_1(h_{1:T-1}^{\prime 1}),\qquad p_{i+2}^{1}=\operatorname{OutHead}(h_i^1).

Verifying causal alignment

Does feeding the ground-truth embedding Emb⁡(xi+1)\operatorname{Emb}(x_{i+1}) into position ii of the MTP module leak future information? Walk through a concrete four-token sequence: x1=thex_1 = \texttt{the}, x2=catx_2 = \texttt{cat}, x3=satx_3 = \texttt{sat}, x4=downx_4 = \texttt{down}.

Thus, when predicting xi+2x_{i+2}, the MTP path has access only to x1:i+1x_{1 : i+1}—standard teacher forcing shifted by one step, with zero leakage of xi+2x_{i+2} or later tokens.

Loss computation and schedule

For a sequence of length TT (indexing tokens 1,…,T1, \ldots, T), the kk-th MTP module has valid targets x2+k:Tx_{2+k : T} corresponding to input indices i∈{1,…,T−1−k}i \in \{1, \ldots, T - 1 - k\}. The report defines the per-depth cross-entropy loss and overall MTP objective as:

LMTPk=−1T∑i=1T−1−klog⁡Pi+k+1k[xi+k+1],LMTP=λD∑k=1DLMTPk.\mathcal L_{\mathrm{MTP}}^k = -\frac{1}{T}\sum_{i=1}^{T-1-k}\log P_{i+k+1}^k[x_{i+k+1}], \qquad \mathcal L_{\mathrm{MTP}}= \frac{\lambda}{D}\sum_{k=1}^{D}\mathcal L_{\mathrm{MTP}}^k.

During DeepSeek-V3 pre-training (§4.2), the MTP weight is set to λ=0.3\lambda = 0.3 for the first 10T tokens and reduced to λ=0.1\lambda = 0.1 for the remaining 4.8T tokens so the final stage prioritizes the primary next-token objective LMain\mathcal{L}_{\mathrm{Main}}.

Parameter sharing and DualPipe co-location

Because the vocabulary size is V=129,280V = 129{,}280 and d=7168d = 7168, a separate embedding table and output projection head for the MTP module would add 1.85B1.85\text{B} dense parameters and require large dense gradient updates. Instead, MTP reuses the main model's Emb⁡(⋅)\operatorname{Emb}(\cdot) and OutHead⁡(⋅)\operatorname{OutHead}(\cdot) matrices directly.

In a pipeline-parallel training cluster, sharing weights between the very first layer (Emb⁡\operatorname{Emb}) and the very last layers (OutHead⁡\operatorname{OutHead} and MTP) normally requires extra cross-stage communication to synchronize activations and gradients. As we will see in Chapter 14, DeepSeek-V3's bidirectional DualPipe schedule naturally places the first pipeline stage (hosting the input embeddings) and the final pipeline stage (hosting the output head and the MTP module) on the same physical GPU rank, allowing the main path and MTP path to share the embedding and output matrices in local HBM without any network transfer.

How MTP shapes the main model—and what the ablations show

Why does an MTP module that is thrown away at inference time make the 61-layer main model smarter? Look at the gradient path: the MTP loss LMTP1\mathcal{L}_{\mathrm{MTP}}^1 differentiates through hi′1=M1[RMSNorm⁡(hi0);…]h_i^{\prime 1} = M_1[\operatorname{RMSNorm}(h_i^0); \ldots] directly into the main model's final hidden state hi0h_i^0. To minimize LMain+λLMTP1\mathcal{L}_{\mathrm{Main}} + \lambda \mathcal{L}_{\mathrm{MTP}}^1, the main backbone cannot merely encode features sufficient to classify xi+1x_{i+1}; hi0h_i^0 must also carry rich enough contextual features that, once combined with the bare token identity Emb⁡(xi+1)\operatorname{Emb}(x_{i+1}), a single Transformer layer TRM⁡1\operatorname{TRM}_1 can accurately predict xi+2x_{i+2}.

In Section 4.5.1, the authors validate this effect on two MoE baselines trained on 1.33T tokens: a small ~15.7B total (2.4B active) model and a large ~228.7B total (20.9B active) model, discarding the MTP module at test time so inference cost is identical:

Notice one caveat when interpreting this ablation: both the baseline and the MTP model were trained for the exact same number of tokens (1.33T), meaning the MTP run spent roughly one extra layer's worth of training FLOPs per token. Thus, the experiment proves that MTP increases inference quality at fixed deployment cost and fixed training tokens, rather than at strictly iso-training-FLOPs.


Sources: Report §2.2 (main.tex, lines 410–455) for MTP equations; §3.2.1 (main.tex, lines 574–577) for DualPipe embedding/MTP co-location; §4.2 (main.tex, lines 741–744) for the λ\lambda schedule; §4.5.1 (main.tex, lines 825–866) for MTP ablations. Continue to Chapter 10: Data, Tokenization, and Infilling.

10. Data, Tokenization, and Infilling

While DeepSeek-V3's attention and MoE equations are specified down to individual matrix dimensions, its 14.8-trillion-token pre-training corpus is described only at a high level. Even so, Section 4.1 of the technical report reveals several concrete engineering decisions—around corpus composition, byte-level BPE tokenization, token-boundary randomization, document packing, and Fill-in-the-Middle (FIM) formatting—that directly affect how the model processes sequences and how benchmarks must be evaluated.

Corpus scale and domain shift

Compared to DeepSeek-V2 (which trained on 8.1T tokens), DeepSeek-V3 expands the pre-training budget to 14.8 trillion tokens while shifting the mixture toward a higher share of mathematical and programming samples and broadening multilingual coverage beyond English and Chinese. The data pipeline also applies stricter deduplication and quality filtering designed to trim repetitive web boilerplate without discarding rare domain-specific text.

As is standard for frontier model reports, the paper does not release the underlying web crawl manifests, domain sampling weights, or quality-classifier thresholds. Consequently, when V3 outperforms V2 on math and coding benchmarks, the improvement reflects both the architectural/training upgrades and a substantially richer, larger domain corpus.

Byte-level BPE and the 128K vocabulary

DeepSeek-V3 uses a byte-level Byte-Pair Encoding (BPE) tokenizer with a vocabulary described in the paper as 128K tokens (specifically vocab_size: 129280 in reference/release-config.json, which includes special control tokens and padding to a hardware-friendly multiple of 64 or 128). Byte-level BPE starts from raw UTF-8 bytes and iteratively merges frequent byte pairs into subword and whole-word tokens, ensuring that any arbitrary string or binary sequence can be tokenized without <unk> fallbacks.

Because V3's 128K vocabulary is tweaked for higher multilingual compression efficiency than V2's 100K vocabulary, the same raw text requires fewer tokens in V3. That also means cross-model token budgets ("14.8T tokens" vs. another model's "15T tokens") are only approximate measures of raw text volume: a tokenizer that compresses Chinese or code into 15% fewer tokens packs correspondingly more characters into a 14.8T-token run and into a 128K-token context window.

Fixing token-boundary bias via random token splitting

To compress formatted text and code efficiently, V3's tokenizer merges common punctuation marks with adjacent line breaks (\n) into single combined tokens (for example, .\n or :\n). While that saves tokens inside multi-line documents, it creates a subtle trap at inference time known as token-boundary bias.

Consider a 5-shot multiple-choice prompt where the first four worked examples look like:

Answer: A\n

In the first four examples, :\n or A\n may be merged with the trailing newline into a single token ID. On the fifth (test) question, however, the prompt stops right after Answer: without a newline, waiting for the model to generate the answer. Because the final colon is not followed by \n, the tokenizer emits the standalone : token ID—a token sequence the model rarely saw at that boundary when every complete training line had its punctuation merged with \n.

To prevent the model from stumbling whenever a prompt ends mid-boundary, V3 randomly splits a fraction of combined punctuation/newline tokens back into their constituent pieces during pre-training (§4.1). That exposes the network to both the merged token and the split sequence during training, making prompt evaluation much less brittle to trailing whitespace.

Document packing without cross-sample masking

Pre-training runs on fixed-length tensors of S=4,096S = 4{,}096 tokens. Because most web pages and code files are shorter than 4,096 tokens, padding each document individually to 4,096 would waste a large fraction of GPU FLOPs on pad tokens. Instead, DeepSeek-V3 packs multiple documents end-to-end into each 4,096-token training sequence.

When packing documents AA and BB into one sequence, an implementation has two choices for the causal attention mask:

  1. Cross-sample document masking (block-diagonal causal mask): Tokens in document BB are masked from attending to tokens in document AA, resetting the effective context at every <eos> boundary.
  2. Unmasked causal packing (full lower-triangular mask): Tokens in document BB can attend back across the <eos> boundary into document AA, and the model simply learns from the <eos> token to ignore unrelated prior documents.

The report explicitly notes (§4.1) that DeepSeek-V3 does not use cross-sample attention masking during pre-training. That keeps the pre-training attention kernel simple and uniform across all 4,096 positions, whereas during supervised fine-tuning (SFT, §5.1.1), where prompt-response turns are short and sensitive to cross-talk, V3 does apply sample masking to isolate packed examples from one another.

Fill-in-the-Middle (FIM) training

Standard autoregressive training only teaches a model to predict text given a preceding prefix. Code completion and document editing, however, routinely require generating a missing middle block given both the preceding lines (prefix) and the following lines (suffix)—for example, filling in the body of a helper function when the caller below it is already written.

Following the DeepSeek-Coder-V2 findings that Prefix-Suffix-Middle (PSM) formatting improves infilling without hurting standard left-to-right capability, DeepSeek-V3 applies FIM transformation at the document level prior to packing at a 10% rate (0.10.1) (§4.1).

A selected document is randomly split into three spans—prefix fpref_{\mathrm{pre}}, middle fmidf_{\mathrm{mid}}, and suffix fsuff_{\mathrm{suf}}—and re-serialized using sentinel tokens in PSM order:

<|fim_begin|> f_pre <|fim_hole|> f_suf <|fim_end|> f_mid <|eos_token|>

For example, given the Python snippet:

def square(x):
    return x * x

print(square(5))

splitting return x * x into fmidf_{\mathrm{mid}} produces a training sequence where the model first reads def square(x):\n, then <|fim_hole|>, then \n\nprint(square(5)), then <|fim_end|>, and finally predicts return x * x autoregressively. Because fsuff_{\mathrm{suf}} appears before fmidf_{\mathrm{mid}} in the serialized token stream, standard causal self-attention lets the model condition on both prefix and suffix without any modification to the attention kernel.


Sources: Report §4.1 (main.tex, lines 692–712) for corpus construction, token-boundary splitting, packing, and FIM; §5.1.1 (main.tex, lines 970–973) for SFT sample masking; reference/release-config.json for vocab_size: 129280. Continue to Chapter 11: The Pre-training Recipe.

11. The Pre-training Recipe

Pre-training DeepSeek-V3 over 14.8 trillion tokens requires coordinating five simultaneous schedules: the learning rate, the global batch size, the auxiliary-loss-free routing bias step size γ\gamma, the Multi-Token Prediction loss weight λ\lambda, and the subsequent context-extension stages. Section 4.2 of the report specifies the exact trajectory for each of these knobs.

Optimizer and initialization settings

DeepSeek-V3 is trained with the AdamW optimizer using hyperparameters β1=0.9\beta_1 = 0.9, β2=0.95\beta_2 = 0.95, and decoupled weight decay λw=0.1\lambda_w = 0.1 (§4.2). At step tt, given parameter θt\theta_t and gradient gtg_t, AdamW updates the running first and second moments:

mt=β1mt−1+(1−β1)gt,vt=β2vt−1+(1−β2)gt2,m_t=\beta_1m_{t-1}+(1-\beta_1)g_t,\qquad v_t=\beta_2v_{t-1}+(1-\beta_2)g_t^2,

computes bias-corrected estimates m^t=mt/(1−β1t)\widehat{m}_t = m_t / (1 - \beta_1^t) and v^t=vt/(1−β2t)\widehat{v}_t = v_t / (1 - \beta_2^t), and applies the decoupled update:

θt+1=(1−ηtλw)θt−ηtm^tv^t+ϵ.\theta_{t+1}=(1-\eta_t\lambda_w)\theta_t -\eta_t\frac{\widehat m_t}{\sqrt{\widehat v_t}+\epsilon}.

All learnable parameters are initialized from a zero-mean normal distribution with standard deviation σ=0.006\sigma = 0.006, and global gradient norms are clipped at a maximum threshold of 1.01.0. To keep the 128-head attention and 256-expert bottlenecks numerically well-conditioned at initialization, V3 also inserts RMSNorm layers immediately after the compressed query and KV latents (ctQ,ctKVc_t^Q, c_t^{KV}) and applies scaling factors at width bottlenecks following DeepSeek-V2.

The five-phase learning-rate schedule

Rather than decaying the learning rate immediately after warmup across the entire 14.8T-token horizon, DeepSeek-V3 uses a multi-stage warmup-constant-cosine-step schedule indexed by consumed tokens:

Training phase Duration Learning rate (η\eta)
1. Linear warmup First 2,0002{,}000 optimizer steps 0→2.2×10−40 \to 2.2 \times 10^{-4}
2. Constant plateau Up to 10.0T10.0\text{T} cumulative tokens 2.2×10−42.2 \times 10^{-4}
3. Cosine decay Next 4.3T4.3\text{T} tokens (10.0T→14.3T10.0\text{T} \to 14.3\text{T}) 2.2×10−4→2.2×10−52.2 \times 10^{-4} \to 2.2 \times 10^{-5}
4. First cooldown plateau Next 333B333\text{B} tokens (14.3T→14.633T14.3\text{T} \to 14.633\text{T}) 2.2×10−52.2 \times 10^{-5}
5. Final cooldown step Final 167B167\text{B} tokens (14.633T→14.8T14.633\text{T} \to 14.8\text{T}) 7.3×10−67.3 \times 10^{-6} (≈13\approx \frac{1}{3} of 2.2×10−52.2\times 10^{-5})

Holding the peak learning rate (2.2×10−42.2 \times 10^{-4}) constant across the first 10T10\text{T} tokens (over two-thirds of the entire training run) allows the model to rapidly absorb the bulk of the corpus before annealing. During the 4.3T4.3\text{T}-token cosine decay phase, as token progress u∈[0,1]u \in [0, 1] advances from 10.0T10.0\text{T} to 14.3T14.3\text{T}, the learning rate follows:

η(u)=ηmin⁡+ηmax⁡−ηmin⁡2(1+cos⁡πu),ηmax⁡=2.2×10−4,ηmin⁡=2.2×10−5.\eta(u)=\eta_{\min} +\frac{\eta_{\max}-\eta_{\min}}{2}(1+\cos\pi u), \qquad \eta_{\max}=2.2\times10^{-4},\quad \eta_{\min}=2.2\times10^{-5}.

Finally, the last 500B500\text{B} tokens (14.3T→14.8T14.3\text{T} \to 14.8\text{T}) act as a two-step low-learning-rate cooldown (2.2×10−52.2 \times 10^{-5} for 333B333\text{B} tokens, then 7.3×10−67.3 \times 10^{-6} for 167B167\text{B} tokens) that sharpens weights at the end of pre-training.

Batch-size ramp and step counts

Pre-training runs at a sequence length of S=4,096S = 4{,}096 tokens. Instead of starting at the maximum batch size—which would starve early training of optimizer updates when gradients are noisy—V3 ramps the global batch size during the first 469B469\text{B} tokens:

How many optimizer steps does this represent? The steady-state phase covers 14,800B−469B=14,331B14{,}800\text{B} - 469\text{B} = 14{,}331\text{B} tokens at 62.91456M62.91456\text{M} tokens per step, which works out to roughly 227,785227{,}785 steps. Assuming an average batch size near the midpoint (∼9,216\sim 9{,}216 sequences, or 37.75M37.75\text{M} tokens/step) during the initial 469B469\text{B}-token ramp adds roughly 12,40012{,}400 steps, putting the full pre-training run at roughly 240,000240{,}000 optimizer updates.

For a 256-expert MoE model, ramping to a 62.9M62.9\text{M}-token global batch has a major secondary benefit: with 8 routed experts per token, a single global step generates 8×62.91M≈503.3M8 \times 62.91\text{M} \approx 503.3\text{M} expert assignments—an average of nearly 2 million2\text{ million} tokens per expert per global step, providing a clean, low-variance load signal for the batch-wise bias controller.

Coordinated schedule transitions across the 14.8T run

Putting the learning rate, batch size, routing bias, and MTP schedules side by side shows how the training regime shifts as the model matures:

Token milestone Learning rate η\eta Batch size (seqs) Bias step γ\gamma MTP weight λ\lambda Seq balance α\alpha
0→469B0 \to 469\text{B} Warmup →2.2×10−4\to 2.2\times 10^{-4} 3,072→15,3603{,}072 \to 15{,}360 0.0010.001 0.30.3 0.00010.0001
469B→10.0T469\text{B} \to 10.0\text{T} 2.2×10−42.2\times 10^{-4} 15,36015{,}360 (62.9M62.9\text{M} tok) 0.0010.001 0.30.3 0.00010.0001
10.0T→14.3T10.0\text{T} \to 14.3\text{T} Cosine →2.2×10−5\to 2.2\times 10^{-5} 15,36015{,}360 (62.9M62.9\text{M} tok) 0.0010.001 0.10.1 0.00010.0001
14.3T→14.633T14.3\text{T} \to 14.633\text{T} 2.2×10−52.2\times 10^{-5} 15,36015{,}360 (62.9M62.9\text{M} tok) 0.00.0 (frozen) 0.10.1 0.00010.0001
14.633T→14.8T14.633\text{T} \to 14.8\text{T} 7.3×10−67.3\times 10^{-6} 15,36015{,}360 (62.9M62.9\text{M} tok) 0.00.0 (frozen) 0.10.1 0.00010.0001

Notice the two synchronized transitions:

  1. At 10.0T10.0\text{T} tokens, just as the learning rate leaves its 2.2×10−42.2 \times 10^{-4} plateau to begin cosine decay, the auxiliary MTP loss weight drops from λ=0.3\lambda = 0.3 to λ=0.1\lambda = 0.1 so the decaying updates focus primarily on the main next-token head.
  2. At 14.3T14.3\text{T} tokens, as the model enters its final 500B500\text{B}-token cooldown, the routing bias update rate drops from γ=0.001\gamma = 0.001 to γ=0.0\gamma = 0.0. Freezing the bias vector bb prevents step-to-step routing boundary jitter while the model settles into its final minimum.

Training stability in practice

The report highlights that across the entire 14.8T-token FP8 training run, DeepSeek-V3 experienced zero irrecoverable loss spikes and never had to roll back to an earlier checkpoint and skip data batches (§1). In frontier LLM training, avoiding checkpoint rollbacks is a product of several interlocking defenses: the moderate 2.2×10−42.2 \times 10^{-4} peak learning rate, extra RMSNorm layers on the MLA latents, fine-grained 1×1281 \times 128 / 128×128128 \times 128 FP8 quantization scales with FP32 tensor-core accumulation (Chapters 16–17), and keeping sensitive router and normalization paths in higher precision.


Sources: Report §4.2 (main.tex, lines 714–744) for AdamW hyperparameters, initialization, gradient clipping, and all token-indexed schedules; §1 (main.tex, lines 174–180) for the zero-rollback stability report. Continue to Chapter 12: Extending the Context Window.

12. Extending the Context Window

DeepSeek-V3 runs its entire 14.8T-token pre-training phase at a 4K (4,0964{,}096-token) sequence length, and then expands its context window to 32K (32,76832{,}768) and 128K (131,072131{,}072) in two short post-pre-training stages (§4.3). Separating short-context pre-training from long-context adaptation saves massive amounts of quadratic attention compute during the 14.8T-token run, while teaching the model to handle 128K-token sequences in just 2,000 additional optimizer steps.

Why raw RoPE fails past the training window—and how YaRN fixes it

Recall from Chapter 4 that RoPE rotates the mm-th 2D coordinate pair of a query or key by angle tωmt \omega_m, where the frequencies ωm=θ−2m/dhR\omega_m = \theta^{-2m / d_h^R} form a geometric progression from fast (high-frequency) local rotations to slow (low-frequency) long-range rotations.

When a model trained exclusively on positions t<4,096t < 4{,}096 suddenly encounters t=100,000t = 100{,}000, its low-frequency coordinate pairs rotate into phase angles they never experienced during training, scrambling attention scores. Conversely, if we linearly compress all positions by a scale factor ss (Position Interpolation, replacing tt with t/st / s), we squeeze adjacent tokens tt and t+1t+1 so close together in phase space that high-frequency heads lose their ability to distinguish local word order.

Following DeepSeek-V2, DeepSeek-V3 uses YaRN (Yet another RoPE extensioN) to adapt frequencies selectively across three wavelength regimes:

  1. High-frequency dimensions (whose wavelengths are much shorter than the 4K training window) have already completed many full 2π2\pi cycles during pre-training; YaRN leaves them uninterpolated so local token resolution stays sharp.
  2. Low-frequency dimensions (whose wavelengths exceed the training window) are linearly interpolated by scale factor s=40s = 40 so their phases remain within the trained range.
  3. Mid-frequency dimensions between the two thresholds (α=1\alpha = 1 and β=32\beta = 32) are smoothly blended via a linear ramp between no interpolation and full 1/s1/s interpolation.

In addition, because spreading attention over 40×40\times more tokens increases the entropy of the softmax distribution, YaRN rescales the pre-softmax attention logits using a temperature correction factor:

tYaRN=1+0.1ln⁡(s)=1+0.1ln⁡(40)≈1.369.\sqrt{t_{\mathrm{YaRN}}} = 1 + 0.1 \ln(s) = 1 + 0.1 \ln(40) \approx 1.369.

In the official reference implementation (inference/model.py), this factor multiplies the query/key vectors (or scales the 1192\frac{1}{\sqrt{192}} softmax temperature by (1+0.1ln⁡s)2(1 + 0.1 \ln s)^2) whenever the configured context exceeds 4K.

Because DeepSeek-V3's MLA architecture decouples position from content, YaRN modifies only the 64-dimensional rotary pathway—specifically the shared positional key ktRk_t^R and the per-head positional queries qt,iRq_{t,i}^R—leaving the 512-dimensional compressed content latent ctKVc_t^{KV} completely untouched.

The two-stage extension schedule

DeepSeek-V3 adapts to 128K in two sequential 1,000-step stages, holding the YaRN hyperparameters fixed at s=40s = 40, α=1\alpha = 1, and β=32\beta = 32 across both stages and keeping the learning rate at the final pre-training cooldown value of η=7.3×10−6\eta = 7.3 \times 10^{-6}:

Extension stage Sequence length (SS) Batch size (BB, sequences) Tokens per step (B×SB \times S) Optimizer steps Total tokens per stage
Stage 1 (4K →\to 32K) 32,768 1,920 62,914,560 (≈62.9M\approx 62.9\text{M}) 1,000 ≈62.9B\approx 62.9\text{B}
Stage 2 (32K →\to 128K) 131,072 480 62,914,560 (≈62.9M\approx 62.9\text{M}) 1,000 ≈62.9B\approx 62.9\text{B}

Notice how the sequence count BB scales inversely with the sequence length SS:

1,920×32,768=480×131,072=62,914,560 tokens/step,1{,}920 \times 32{,}768 = 480 \times 131{,}072 = \mathbf{62{,}914{,}560\text{ tokens/step}},

which preserves the exact 62.9M-token global batch size used during steady-state 4K pre-training (15,360×4,096=62,914,56015{,}360 \times 4{,}096 = 62{,}914{,}560). Across all 2,000 steps, the two extension phases process roughly 125.8B125.8\text{B} tokens—less than 0.85%0.85\% of the 14.8T pre-training token budget—and consume 119K H800 GPU hours ($238K at $2/GPU-hour).

Why 128K steps cost more compute than 32K steps at equal token volume

Even though every step in Stage 1 and Stage 2 processes the exact same 62.9M62.9\text{M} tokens—meaning the linear projections and MoE experts perform identical total FLOPs per step—the causal attention cost rises sharply with sequence length.

For a sequence of length SS, causal self-attention evaluates S(S+1)/2≈S2/2S(S+1)/2 \approx S^2/2 query-key pairs per head. Across a batch of BB sequences, the total number of attention pairs evaluated per step is:

Attention pairs per step≈B⋅S22=(B⋅S)⋅S2.\text{Attention pairs per step} \approx B \cdot \frac{S^2}{2} = \frac{(B \cdot S) \cdot S}{2}.

Because the total token budget per step (B⋅S)=62.91M(B \cdot S) = 62.91\text{M} is held constant, the pairwise attention FLOPs per step grow linearly with SS:

That scaling explains why frontier runs pre-train at 4K first and only switch to 32K and 128K for the final 0.13B+62.9B+62.9B tokens.

Long-context retrieval and reasoning benchmarks

To verify that the extended model can retrieve information across the full 128K window, the authors evaluate the SFT checkpoint on the Needle In A Haystack (NIAH) pressure test, inserting a target fact at varying depths (0%0\% to 100%100\%) inside distractor contexts ranging from 2K to 128K tokens.

Needle-in-a-Haystack heatmap with context length from roughly 2K to 128K and insertion depth from zero to one hundred percent, showing consistently high scores.

Needle-in-a-Haystack evaluation across context lengths up to 128K from Report §4.3, showing uniform retrieval accuracy across all context depths.

Beyond single-fact needle retrieval, the post-trained chat evaluation (§5.3, tables/chat_evaluation.tex) tests multi-hop synthesis and long-document comprehension on two harder benchmarks:

Note that while reference/release-config.json sets max_position_embeddings: 163840 (160K) to provide headroom in the rotary embedding tables, 128K (131,072131{,}072 tokens) is the maximum sequence length trained and benchmarked in the report.


Sources: Report §4.3 (main.tex, lines 746–765) for YaRN hyperparameters, two-stage extension schedule, and NIAH results; tables/chat_evaluation.tex for FRAMES and LongBench v2 scores; precompute_freqs_cis and MLA in inference/model.py. Continue to Chapter 13: Distributed Training Fundamentals.

13. Distributed Training Fundamentals

Training a 671B-parameter MoE model requires partitioning weights, optimizer states, gradients, and intermediate activations across thousands of accelerators without letting network communication stall the tensor cores. DeepSeek-V3 runs pre-training on a cluster of 2,048 NVIDIA H800 GPUs organized into 256 compute nodes of 8 GPUs each (§3.1). Inside each 8-GPU node, accelerators are connected via high-bandwidth NVLink and NVSwitch; across nodes, communication travels over 400 Gbps InfiniBand (IB) NICs.

To map DeepSeek-V3 onto those 2,048 GPUs, the HAI-LLM training framework combines three parallelism dimensions—16-way Pipeline Parallelism (PP16), 64-way Expert Parallelism (EP64) spanning 8 nodes, and ZeRO-1 Data Parallelism—while deliberately eliminating Tensor Parallelism (TP = 1) during training (§3.2).

The four parallelism axes and how V3 uses them

1. Data Parallelism (DP) and ZeRO-1

In standard Data Parallelism, multiple model replicas process disjoint slices of the global token batch in parallel and sum their weight gradients via an AllReduce collective before each optimizer step. Because storing redundant copies of AdamW's FP32 master weights and BF16 first/second moments across every data-parallel rank wastes HBM, DeepSeek-V3 uses ZeRO-1 (Zero Redundancy Optimizer Stage 1), which partitions the optimizer states across the data-parallel group.

Under ZeRO-1, each DP rank holds the weights and computes gradients for its assigned layers, reduces gradients across its DP peers via ReduceScatter, updates only its 1/DP1/DP shard of the AdamW moments and master weights, and broadcasts the updated weights back via AllGather at the end of the step. Unlike ZeRO-2 or ZeRO-3, ZeRO-1 does not shard forward/backward weights during micro-batch execution, adding zero extra communication inside the micro-batch critical path.

2. Pipeline Parallelism (PP16)

Pipeline Parallelism partitions the model's 61 layers (plus the MTP module) vertically across PP=16PP = 16 pipeline stages. Stage 0 processes the embedding and initial layers, sends the resulting hidden states point-to-point (P2P) to Stage 1, and so on up to Stage 15; during the backward pass, activation gradients flow back down from Stage 15 to Stage 0.

To keep all 16 stages busy simultaneously, each global batch is split into smaller micro-batches that stream through the pipeline one after another. As we will see in Chapter 14, V3 replaces standard unidirectional schedules (such as 1F1B) with DualPipe, a bidirectional pipeline schedule that feeds micro-batches from both ends of the 16-stage pipeline and stores two mirrored model chunks per rank.

3. Expert Parallelism (EP64)

While dense layers (MLA projections, shared experts, RMSNorms) are replicated across data-parallel ranks within a pipeline stage, the 256 routed experts in each MoE layer are partitioned across EP=64EP = 64 GPUs (8 nodes ×\times 8 GPUs/node). Each GPU in the 64-way expert-parallel group hosts:

256 routed experts64 GPUs=4 routed experts per MoE layer.\frac{256\text{ routed experts}}{64\text{ GPUs}} = \mathbf{4\text{ routed experts per MoE layer}}.

Because each token's router can pick any 8 of the 256 experts (subject to the 4-node locality cap), evaluating an MoE layer requires an All-to-All dispatch step that ships token vectors from the GPU currently holding the sequence to the GPUs hosting the selected experts, followed by an All-to-All combine step that returns the expert outputs back to the originating GPU.

4. Why V3 avoids Tensor Parallelism (TP=1TP = 1) in training

Tensor Parallelism (Megatron-style TP) splits individual weight matrices across GPUs within a node (for example, slicing column-parallel and row-parallel projections across 8 GPUs), requiring an AllReduce or ReduceScatter/AllGather collective across NVLink inside every single attention and FFN block.

In DeepSeek-V3, NVLink bandwidth inside each node is already heavily tasked with forwarding MoE tokens during the cross-node + intra-node All-to-All dispatch/combine kernels (Chapter 15). If the training run also used TP, tensor-parallel collectives would contend directly with MoE All-to-All traffic on NVLink and prevent DualPipe from overlapping communication cleanly. By shrinking activation memory via MLA, FP8 quantization, and selective activation recomputation (Chapter 18), a single GPU can hold a full unsharded layer's MLA projections and shared expert plus 4 routed experts—making TP=1TP = 1 feasible across the entire 2,048-GPU training run. (At inference time, where workloads and batch sizes differ, V3 does use TP4 for attention during prefill; see Chapter 21.)

How the 2,048 GPUs fit together

Putting PP16, EP64, and DP together illustrates how dense parameters and expert parameters use different data-parallel group widths on the same 2,048 GPUs:

Tracing the four communication patterns in a training step

During a single optimizer step, four distinct types of network traffic occur across the cluster:

Communication type Collective / primitive Hardware fabric used When it happens
1. Pipeline stage transfer Point-to-point (P2P) send/recv InfiniBand / NVLink Between adjacent DualPipe stages on every micro-batch
2. MoE expert dispatch Irregular All-to-All (FP8 payload) IB (up to 4 nodes) →\to NVLink Before routed expert GEMMs in every MoE layer (fwd & bwd)
3. MoE expert combine Irregular All-to-All (BF16 payload) NVLink →\to IB After routed expert GEMMs in every MoE layer (fwd & bwd)
4. Gradient sync & ZeRO-1 update ReduceScatter + AllGather IB across DP group (DP=128DP=128 dense, DP=2DP=2 expert) Once per global optimizer step after micro-batches finish

During micro-batch execution, the dominant network cost is the MoE All-to-All dispatch and combine, which happens twice in the forward pass and twice in the backward pass of every single MoE layer. The next two chapters examine how DualPipe hides that communication latency behind computation (Chapter 14) and how custom warp-specialized PTX kernels saturate both InfiniBand and NVLink without stalling the GEMMs (Chapter 15).


Sources: Report §3.1–3.2 (main.tex, lines 460–476) for cluster hardware and PP16/EP64/ZeRO-1 configuration; §3.3 (main.tex, lines 560–577) for memory optimizations enabling TP-free training; §3.4 for serving parallelism. Continue to Chapter 14: DualPipe and the Critical Path.

14. DualPipe and the Critical Path

In DeepSeek-V3's 64-way expert-parallel setup, each MoE layer dispatches tokens across up to 8 compute nodes over InfiniBand and combines the returned expert outputs. Under a naive sequential execution schedule, the computation-to-communication ratio sits near 1:1 (§3.2)—meaning GPUs would spend roughly half of their wall-clock time waiting on network transfers.

To eliminate both cross-node communication stalls and pipeline startup/drain bubbles, the authors designed DualPipe (§3.2.1), a bidirectional pipeline parallelism algorithm that overlaps pairs of forward and backward micro-batches moving in opposite directions.

Within-micro-batch serial dependencies vs. cross-micro-batch overlap

Within any single micro-batch at a single layer, the four operations inside an MoE block are strictly sequential:

Attention (Compute)⟶All-to-All Dispatch (Comm)⟶MLP / Experts (Compute)⟶All-to-All Combine (Comm).\text{Attention (Compute)} \longrightarrow \text{All-to-All Dispatch (Comm)} \longrightarrow \text{MLP / Experts (Compute)} \longrightarrow \text{All-to-All Combine (Comm)}.

You cannot run a micro-batch's expert GEMMs until its tokens have finished arriving over the network, and you cannot start the next layer's attention until the expert outputs have been combined. Thus, a single micro-batch cannot hide its own All-to-All communication.

However, if a GPU rank is simultaneously executing two independent micro-batches—specifically, one forward chunk from micro-batch AA and one backward chunk from micro-batch BB—their compute and communication sub-steps can be interleaved like teeth on a zipper: while micro-batch AA is waiting on its All-to-All Dispatch over InfiniBand/NVLink, the GPU's tensor cores execute the MLP or Attention backward GEMMs of micro-batch BB, and vice versa.

Splitting backward chunks into BB (input gradient) and WW (weight gradient)

Like Zero-Bubble Pipeline Parallelism (ZB1P), DualPipe exploits a second structural property of backpropagation: every linear layer Y=XWY = XW has two backward matrix multiplications with very different dependency urgency:

  1. Backward for inputs (BB, computing ∇X=∇YWT\nabla_X = \nabla_Y W^T): The upstream pipeline stage is waiting on ∇X\nabla_X to continue backpropagating through earlier layers. Thus, BB sits directly on the inter-stage critical path.
  2. Backward for weights (WW, computing ∇W=XT∇Y\nabla_W = X^T \nabla_Y): No earlier layer depends on ∇W\nabla_W; it only needs to finish before the end-of-step AdamW optimizer update.

By splitting each backward chunk into a fine-grained sequence of sub-operations—MLP input-gradient (BMLPB_{\mathrm{MLP}}), MLP weight-gradient (WMLPW_{\mathrm{MLP}}), Attention input-gradient (BAttnB_{\mathrm{Attn}}), and Attention weight-gradient (WAttnW_{\mathrm{Attn}})—DualPipe can reorder and slot zero-dependency WW computations into any remaining pipeline gaps or communication windows.

How a DualPipe F&BF\&B overlapped pair works

Inside each overlapped Forward-and-Backward (F&BF\&B) block, DualPipe partitions the GPU's 132 Streaming Multiprocessors (SMs) into two cooperating teams: 20 SMs manage the InfiniBand and NVLink All-to-All transfers (Chapter 15), while the remaining 112 SMs execute the Attention and MLP tensor-core GEMMs.

Within a paired F&BF\&B unit, the fine-grained components of the forward micro-batch and the backward micro-batch are staggered so that every communication phase of one direction runs concurrently with a compute phase of the other:

Because both cross-node All-to-All transfers and inter-stage pipeline P2P transfers run inside the dedicated 20-SM communication channels while the 112 compute SMs stay busy on the partner chunk, neither All-to-All nor P2P communication extends the critical path.

Bidirectional scheduling across pipeline ranks

Why does DualPipe feed micro-batches from both ends of the pipeline rather than from Rank 0 alone? In a standard unidirectional 1F1B pipeline, early ranks carry heavier activation memory and different forward/backward phase alignments than late ranks, making it awkward to keep every rank paired with a symmetric F&BF\&B partner throughout the step.

DualPipe solves this by placing two mirrored sets of model chunks across the PPPP pipeline ranks: Stream 1 feeds micro-batches forward from Rank 0→Rank (PP−1)0 \to \text{Rank } (PP-1), while Stream 2 feeds micro-batches forward in the exact opposite physical direction from Rank (PP−1)→Rank 0\text{Rank } (PP-1) \to \text{Rank } 0. Consequently, Rank 0 holds both the first layer chunk (Stage 0) and the last layer chunk (Stage PP−1PP-1), Rank 1 holds Stage 1 and Stage PP−2PP-2, and so on.

DualPipe schedule over eight device ranks, with colored forward, input-backward, weight-backward, and overlapped chunks across time.

DualPipe bidirectional scheduling diagram from Report §3.2.1, illustrated for PP=8PP = 8 ranks and 20 micro-batches (10 in each direction). Dark green blocks denote mutually overlapped Forward & Backward (F&BF\&B) pairs; orange (FF), light green (BB), and blue (WW) blocks fill the startup and cooldown transitions.

Because Stream 1's forward wavefront and Stream 2's backward wavefront cross each other symmetrically across the middle of the schedule, every rank spends the bulk of each step executing tightly packed F&BF\&B pairs.

Comparing pipeline bubbles, weights, and activation memory

Table 1 in Report §3.2.1 compares DualPipe against standard 1F1B and Zero-Bubble 1P (ZB1P), where PPPP is the number of pipeline stages, FF is forward chunk execution time, BB is full backward chunk time, WW is weight-gradient time, and F&BF\&B is the execution time of two mutually overlapped forward and backward chunks:

Pipeline schedule Pipeline bubble time Parameter copies per GPU Peak saved activations (relative units)
1F1B (PP−1)(F+B)(PP - 1)(F + B) 1×1\times PPPP
ZB1P (PP−1)(F+B−2W)(PP - 1)(F + B - 2W) 1×1\times PPPP
DualPipe (PP2−1)(F&B+B−3W)\left(\dfrac{PP}{2} - 1\right)(F\&B + B - 3W) 2×2\times PP+1PP + 1

Look at the three tradeoffs in this table for DeepSeek-V3's production setting of PP=16PP = 16:

  1. Bubble reduction: The prefactor drops from (PP−1)=15(PP - 1) = 15 to (PP/2−1)=7(PP/2 - 1) = 7, and inside the parentheses F+BF + B is replaced by the overlapped F&B+B−3WF\&B + B - 3W, cutting pipeline startup/drain overhead by more than half while hiding All-to-All communication throughout the steady state.
  2. Peak activation memory: DualPipe increases peak live micro-batch activations from PP=16PP = 16 to PP+1=17PP + 1 = 17 units—an increase of just 1/16=6.25%1/16 = \mathbf{6.25\%}.
  3. Doubled parameter copies (2×2\times) and why EP64 makes it cheap: Because each GPU holds two mirrored stage chunks, it stores 2×2\times as many model parameters as a unidirectional pipeline. In a dense 671B model, doubling parameter storage would be prohibitive. In V3, however, 64-way Expert Parallelism shards the 657B routed expert parameters 64 ways, and 16-way Pipeline Parallelism shards depth 16 ways. One stage chunk of 4 routed experts per layer (~3.6 layers per chunk) plus dense weights is only around 0.7–0.8B parameters per GPU (∼1.5 GB\sim 1.5\text{ GB} in BF16 or ∼0.75 GB\sim 0.75\text{ GB} in FP8). Holding two mirrored chunks therefore costs less than 1.5–3 GB1.5\text{–}3\text{ GB} of extra HBM per 80 GB H800 GPU!

Better yet, mirrored placement gives DeepSeek-V3 a free bonus for Multi-Token Prediction (Chapter 9): because Rank 0 holds Stage 0 (the input embedding table) and Rank 15 holds Stage 15 (the output head and MTP module), mirroring Stage 0 and Stage 15 onto the same physical GPUs allows the MTP module to read the shared token embeddings and output head directly from local HBM without any cross-stage parameter transfer.


Sources: Report §3.2.1 (main.tex, lines 478–538) for DualPipe design, schedule diagram, and Table 1 comparison; §3.3 (main.tex, lines 574–577) for physical parameter sharing between Stage 0 and the MTP module. Continue to Chapter 15: Moving Tokens to Experts.

15. Moving Tokens to Experts

While DualPipe provides the schedule to overlap communication with computation, the underlying All-to-All dispatch and combine kernels still have to move terabytes of token activations across 64 GPUs (8 compute nodes) without saturating the InfiniBand fabric or starving the tensor cores of Streaming Multiprocessors (SMs) and L2 cache bandwidth. Section 3.2.2 of the report details how DeepSeek-V3 co-designs its routing topology and warp-specialized PTX kernels around the physical hierarchy of the H800 cluster.

On the H800 training cluster, each 8-GPU node has two distinct interconnect tiers (§3.2.2):

Notice the ratio between the two tiers:

NVLink bandwidthInfiniBand bandwidth=160 GB/s50 GB/s=3.2.\frac{\text{NVLink bandwidth}}{\text{InfiniBand bandwidth}} = \frac{160\text{ GB/s}}{50\text{ GB/s}} = \mathbf{3.2}.

If a token on Node 0 selected 8 routed experts that happened to sit on 8 different GPUs across 4 remote nodes, and the source GPU sent 8 separate point-to-point messages over InfiniBand, it would waste slow 50 GB/s IB bandwidth sending duplicate copies of the exact same token vector to the same remote node.

Instead, DeepSeek-V3 uses two-stage hierarchical forwarding paired with the M=4M = 4 node-limited routing constraint from Chapter 8:

  1. Stage 1 (Inter-node IB transfer to same-index peer): For each of the at most M=4M = 4 target nodes selected by a token, the originating GPU (say, local GPU index g∈{0,…,7}g \in \{0, \ldots, 7\} on the source node) sends only one copy of the token over InfiniBand to the GPU with the same local index gg on the target node.
  2. Stage 2 (Intra-node NVLink fan-out): As soon as that token copy arrives at GPU gg on the target node, GPU gg immediately forwards it over the fast 160 GB/s NVLink fabric to whichever local GPUs on that node host the token's selected experts.

Because NVLink is 3.2×3.2\times faster than InfiniBand and the two transfers run concurrently inside the kernel pipeline, each token arriving at a target node over IB can be duplicated to an average of 3.23.2 local experts over NVLink in the exact same time window. Across M=4M = 4 target nodes, this hierarchical pipe can sustain up to 4×3.2=12.8≈13 routed experts per token4 \times 3.2 = 12.8 \approx \mathbf{13\text{ routed experts per token}} without NVLink becoming the bottleneck! Because V3 uses Kr=8K_r = 8 routed experts (an average of 8/4=28 / 4 = 2 experts per target node, well below the 3.23.2 saturation limit), NVLink forwarding easily keeps pace with InfiniBand ingress.

To see the byte savings on a single token (d=7168d = 7168, quantized to 1-byte FP8 payload plus per-tile scales): sending 8 separate copies over IB would push 8×7,168=57,3448 \times 7{,}168 = 57{,}344 payload bytes across the slow inter-node network. With hierarchical forwarding and M=4M = 4 node-limiting, the source GPU sends at most 4×7,168=28,6724 \times 7{,}168 = 28{,}672 payload bytes over IB (fewer if one of the 4 nodes is the source node itself or if fewer than 4 nodes are selected), cutting peak cross-node IB traffic by at least 50%.

The Combine pass: hierarchical reduction in BF16

After the remote experts evaluate their SwiGLU matrices on the dispatched tokens, the Combine kernel reverses the two-stage pipeline:

  1. Expert-owning GPUs send their weighted expert outputs over intra-node NVLink back to the local relay GPU gg, which accumulates (sums) the partial expert contributions destined for the same originating token on that node.
  2. The relay GPU sends the pre-summed partial result over InfiniBand back to the originating GPU, which performs the final reduction across its target nodes.

Crucially, while Dispatch transmits token activations (and backward activation gradients) in FP8 (~1 byte/element), Combine transmits and accumulates expert outputs (and backward token-input gradients) in BF16 (2 bytes/element) so that summing the 8 weighted expert vectors does not suffer from 8-bit quantization rounding error (§3.3.1).

Warp specialization inside the 20 communication SMs

Running standard NCCL collectives for irregular MoE All-to-All transfers typically claims a large number of GPU SMs and stalls compute kernels. Instead, DeepSeek-V3 dedicates exactly 20 of the H800's 132 SMs (15.2% of the chip) to communication during overlapped F&BF\&B execution, organizing those 20 SMs into 10 communication channels (2 SMs per channel).

Within those 20 SMs, the kernels use warp specialization—partitioning the hardware thread warps into three distinct functional roles whose warp counts are dynamically rebalanced mid-execution based on queue pressure:

Kernel Role 1 warps Role 2 warps Role 3 warps
Dispatch IB Send: Read local tokens and push RDMA writes over InfiniBand IB →\to NVLink Forward: Poll arriving IB packets and immediately forward over NVLink NVLink Receive: Pull NVLink packets into expert input buffers
Combine NVLink Send: Push expert outputs from local GPUs to the node relay GPU NVLink →\to IB Forward & Reduce: Sum arriving NVLink vectors and push over IB IB Receive & Reduce: Sum arriving IB vectors with local expert outputs

To prevent the 20 communication SMs from thrashing the GPU's shared L2 cache and stealing memory bandwidth from the 112 compute SMs running Attention and Expert GEMMs concurrently, the communication kernels use custom PTX instructions (such as cache-bypassing streaming loads/stores) and carefully tuned chunk sizes.

Why decode serving switches to point-to-point IBGDA

Hierarchical IB →\to NVLink forwarding is designed for training and large-batch prefill, where thousands of tokens travel together in bulk and expert parallelism spans 64 GPUs across 8 nodes.

During low-latency autoregressive decoding (Chapter 21), DeepSeek-V3 scales expert parallelism out to 320 GPUs (where each GPU hosts just 1 expert) and processes small token batches where every microsecond of hop latency counts. Adding an extra intra-node NVLink forwarding hop on small messages would add unnecessary latency. Consequently, the decode cluster bypasses two-stage forwarding and uses IBGDA (InfiniBand GPUDirect Async), allowing GPU threads to issue direct point-to-point RDMA transfers over InfiniBand straight to the target expert GPU without CPU involvement or intermediate relay hops (§3.4.2).

Hardware design lessons for future accelerators

Reflecting on the engineering effort required to write warp-specialized IB-to-NVLink relay kernels that consume 20 SMs per H800, the authors conclude Section 3.5.1 with a concrete hardware recommendation for next-generation AI accelerators: unify the scale-up (intra-node) and scale-out (inter-node) network interfaces inside dedicated co-processor hardware. Offloading packet forwarding, address translation, fine-grained matrix transposition, and BF16 reduction to a dedicated network/DMA engine would free all 132 compute SMs (and the L2 cache) exclusively for tensor-core computation.


Sources: Report §3.2.2 (main.tex, lines 540–558) for IB/NVLink bandwidths, same-index forwarding, 20-SM channel allocation, and warp specialization; §3.4.2 (main.tex, lines 611–629) for IBGDA in decoding; §3.5.1 (main.tex, lines 632–658) for hardware recommendations. Continue to Chapter 16: Understanding FP8 Numbers.

16. Understanding FP8 Numbers

Quantizing matrix multiplications from 16-bit (BF16/FP16) to 8-bit floating point (FP8) doubles the peak tensor-core throughput of NVIDIA H800 GPUs and halves the byte footprint of quantized activations and weights. However, squeezing a floating-point number into 8 bits leaves very little room for dynamic range and precision. Without careful scaling and accumulation, activation outliers and tensor-core rounding errors will quickly derail a frontier training run.

Section 3.3 of the technical report (content/fp8.tex) details how DeepSeek-V3 overcomes two hardware-level obstacles in FP8 training: narrow dynamic range in 8-bit formats and limited accumulation precision inside Hopper FP8 Tensor Cores.

Floating-point formats: FP32, BF16, E4M3, and E5M2

A binary floating-point number encodes a sign bit s∈{0,1}s \in \{0, 1\}, an EE-bit biased exponent ee, and an MM-bit fractional mantissa (significand) mm:

x=(−1)s⋅(1+m)⋅2e.x = (-1)^s \cdot (1 + m) \cdot 2^e.

More exponent bits widen the dynamic range (the ratio between the largest and smallest representable magnitudes, guarding against overflow and underflow), whereas more mantissa bits increase precision (how finely adjacent numbers are spaced within each power-of-two bin).

Format Total bits Sign / Exponent / Mantissa Role in DeepSeek-V3
FP32 32 1s+8e+23m1\text{s} + 8\text{e} + 23\text{m} Master weights, accumulated gradients, CUDA-core GEMM accumulators
BF16 16 1s+8e+7m1\text{s} + 8\text{e} + 7\text{m} Optimizer moments, non-GEMM ops (RMSNorm, Attention, Router), MoE Combine
FP8 E4M3 8 1s+4e+3m1\text{s} + 4\text{e} + 3\text{m} All FP8 GEMM inputs (forward, backward input-grad, backward weight-grad)
FP8 E5M2 8 1s+5e+2m1\text{s} + 5\text{e} + 2\text{m} Not used for V3 GEMMs (sacrifices a mantissa bit for wider exponent range)

Conventional mixed-precision FP8 recipes (often called "hybrid FP8") use E4M3 for forward activations and weights (where precision matters most) and switch to E5M2 for backward gradients (assuming gradients have wider dynamic range). DeepSeek-V3 instead uses E4M3 uniformly across all FP8 tensors—forward activations, weights, and backward gradients alike. What makes uniform E4M3 possible without gradient overflow or underflow is V3's fine-grained tile and block scaling.

Why per-tensor scaling fails on activation outliers

To map a high-precision group of numbers XX into E4M3 (whose maximum finite value on Hopper is 448448), we scale the group so its largest absolute value max⁡∣X∣\max |X| maps to the top of the E4M3 range:

q=round⁡E4M3(Xs),X^=s⋅q,s=max⁡∣X∣448.q = \operatorname{round}_{\mathrm{E4M3}}\left(\frac{X}{s}\right), \qquad \widehat{X} = s \cdot q, \qquad s = \frac{\max |X|}{448}.

(In the released checkpoint weights, this factor ss is stored as weight_scale_inv, so dequantization simply multiplies the E4M3 integer/float value qq by weight_scale_inv.)

In large Transformer models, hidden states and activation gradients routinely develop outlier channels: a few dimensions spike to magnitudes 100×100\times or 1,000×1{,}000\times larger than the typical values in the tensor. If you compute a single global scale factor ss across an entire activation tensor, that single outlier forces ss to be huge, crushing all normal values in the tensor toward zero (underflow) and destroying their 3-bit mantissa resolution.

Fine-grained quantization: 1×1281 \times 128 tiles and 128×128128 \times 128 blocks

To isolate outliers so a spike in one token or channel never degrades the rest of the tensor, DeepSeek-V3 computes independent online scale factors on small local sub-tensors (§3.3.2):

  1. Tile-wise 1×1281 \times 128 grouping for activations (and activation gradients): Each token row is partitioned into contiguous 128-channel slices. Every 1×1281 \times 128 slice gets its own online scale factor sAs^A. Thus, an outlier in token 5 only affects the 127 neighboring channels within that single 128-element slice of token 5, leaving every other token and channel untouched.
  2. Block-wise 128×128128 \times 128 grouping for weights: Each weight matrix is partitioned into 2D blocks of 128 input channels×128 output channels128 \text{ input channels} \times 128 \text{ output channels} (16,38416{,}384 weights per block), with one shared scale factor sBs^B per block.

Why does the inner dimension of 128128 match across both schemes? Look at a matrix multiplication Cmn=∑k=1KAmkBknC_{mn} = \sum_{k=1}^K A_{mk} B_{kn} broken into chunks of size NC=128N_C = 128 along the shared inner reduction dimension KK:

C^mn=∑g=1K/128sm,gAsg,nB∑k∈gqmkAqknB.\widehat C_{mn}=\sum_{g=1}^{K/128} s^A_{m,g}s^B_{g,n} \sum_{k\in g}q^A_{mk}q^B_{kn}.

Within each 128-element chunk gg along the inner dimension KK, the activation scale sm,gAs^A_{m,g} and the weight scale sg,nBs^B_{g,n} are constant! That means the GPU's Tensor Cores can multiply the raw E4M3 values qmkAqknBq^A_{mk} q^B_{kn} over 128128 inner steps first, and then multiply the resulting 128-element partial sum by the scalar product sm,gAsg,nBs^A_{m,g} s^B_{g,n} once per chunk.

Note also how little memory overhead these scales add: storing one 4-byte FP32 scale per 128 activation bytes adds just 4/128=3.125%4 / 128 = \mathbf{3.125\%} metadata overhead, and storing one 4-byte scale per 128×128=16,384128 \times 128 = 16{,}384 weight bytes adds just 4/16,384=0.0244%4 / 16{,}384 = \mathbf{0.0244\%} overhead.

Fixing Hopper Tensor Core accumulation error via FP32 promotion

Fine-grained scaling solves dynamic range, but a second hardware quirk lurks inside the NVIDIA H800 Tensor Cores (WGMMA instructions). When accumulating products of FP8 numbers over a long inner dimension (such as K=4096K = 4096 or K=7168K = 7168), the Hopper FP8 Tensor Core accumulator does not maintain full 23-bit FP32 mantissa precision; internally, its adder aligns mantissas to only 14 fraction bits (13 bits after the leading bit) before truncating low bits.

In the authors' diagnostic benchmark on random matrices of inner dimension K=4096K = 4096, standard Hopper FP8 WGMMA accumulation produced a maximum relative error of nearly 2% compared to exact FP32 accumulation (content/fp8.tex). Over 61 layers and 14.8T tokens, a 2% drift in forward and gradient dot products noticeably degrades training loss.

DeepSeek-V3 eliminates this accumulation drift by periodically promoting partial sums from the Tensor Core accumulator out to full FP32 registers on the standard CUDA cores every NC=128N_C = 128 inner-dimension elements (equivalent to 4 WGMMA instructions of width 32):

Fine-grained activation and weight scale groups alongside periodic promotion of Tensor Core partial sums to FP32 CUDA-core registers.

Fine-grained quantization groups (1×1281 \times 128 activation tiles and 128×128128 \times 128 weight blocks, left) paired with periodic promotion of every NC=128N_C = 128 Tensor Core partial sum to FP32 CUDA registers (right), from Report §3.3.2.

Notice how cleanly the two fixes dovetail:

  1. The Tensor Cores run 4 consecutive FP8 WGMMA instructions (4×32=1284 \times 32 = 128 inner elements), keeping the partial sum short enough that 14-bit internal alignment loses virtually no precision.
  2. The partial sum is copied to CUDA-core FP32 registers, where it is simultaneously dequantized by multiplying by sm,gAsg,nBs^A_{m,g} s^B_{g,n} and accumulated into a true 32-bit floating-point running total.
  3. Because Hopper supports asynchronous warpgroup execution, one warpgroup performs the CUDA-core FP32 scale-and-add while another warpgroup keeps the Tensor Cores busy on the next WGMMA tile.

Online quantization vs. delayed scaling

Many earlier FP8 frameworks used delayed scaling, choosing the current step's quantization scale based on the maximum absolute value observed over several previous training steps. Delayed scaling avoids reading the current tensor twice, but if an activation magnitude suddenly jumps on step tt, the stale scale overflows; if it drops, the stale scale underflows.

Because DeepSeek-V3 already tiles activations into small 1×1281 \times 128 vectors (and weights into 128×128128 \times 128 blocks) that fit comfortably inside on-chip SRAM/registers during the preceding operation, V3 computes the exact max⁡∣x∣\max |x| of each group online on the fly. In ablation runs on 16B and 230B MoE models (Appendix B), combining E4M3 online tile/block scaling with NC=128N_C = 128 FP32 promotion matched baseline BF16 training loss to within 0.25%0.25\% relative error.


Sources: Report §3.3 (content/fp8.tex) for E4M3 format, 1×1281\times 128 / 128×128128\times 128 scaling, Hopper 14-bit accumulator analysis, and NC=128N_C=128 promotion; §3.5.2 (main.tex, lines 660–687) for FP8 hardware design recommendations; Appendix B (main.tex, lines 1458–1486) for BF16 vs. FP8 loss comparisons. Continue to Chapter 17: The Actual Mixed-precision Pipeline.

17. The Actual Mixed-precision Pipeline

Chapter 16 established how a single matrix multiplication runs in E4M3 with 1×1281 \times 128 and 128×128128 \times 128 scales and NC=128N_C = 128 FP32 promotion. Now we trace how an entire training step fits together: which GEMMs and cached activations use FP8, how transposed backward GEMMs handle tile orientation, which sensitive operators stay in BF16 or FP32, and how low-precision storage cuts memory and network traffic.

The three GEMMs of a linear layer: Fprop, Dgrad, and Wgrad

Consider a linear layer Y=XWY = XW where input activations X∈RT×dinX \in \mathbb{R}^{T \times d_{\mathrm{in}}} multiply weights W∈Rdin×doutW \in \mathbb{R}^{d_{\mathrm{in}} \times d_{\mathrm{out}}} to produce Y∈RT×doutY \in \mathbb{R}^{T \times d_{\mathrm{out}}}. During a training step, this layer executes three GEMMs:

  1. Forward pass (Fprop): Y=XWY = XW (contracting along dind_{\mathrm{in}}).
  2. Backward input-gradient (Dgrad): ∇X=∇YWT\nabla_X = \nabla_Y W^T (contracting along doutd_{\mathrm{out}}).
  3. Backward weight-gradient (Wgrad): ∇W=XT∇Y\nabla_W = X^T \nabla_Y (contracting along the token dimension TT).

DeepSeek-V3 executes all three GEMMs in FP8, taking E4M3 inputs, accumulating in FP32 via NC=128N_C = 128 promotion, and outputting BF16 (for Fprop and Dgrad) or FP32 (for Wgrad).

Mixed-precision linear-layer flow with FP8 matrix inputs, FP32 sums and master weights, BF16 outputs and optimizer states, and forward/input-gradient/weight-gradient paths.

DeepSeek-V3 mixed-precision training framework for a linear operator, from Report §3.3.1 (content/fp8.tex). Master weights and weight gradients are maintained in FP32, AdamW moments and cached master weights are stored in BF16, and all three GEMMs (Fprop, Dgrad, Wgrad) consume FP8 inputs.

How tile orientations work across Fprop, Dgrad, and Wgrad

Remember from Chapter 16 that hardware-efficient FP8 promotion requires the quantization scale to be constant along the 128-element chunks of the inner contraction dimension of the GEMM:

Why didn't the authors simplify Dgrad and Wgrad by quantizing ∇Y\nabla_Y into symmetric 128×128128 \times 128 2D blocks so it wouldn't need different orientations for Dgrad (1×1281 \times 128) and Wgrad (128×1128 \times 1)? They tested that exact shortcut in Appendix B (main.tex, lines 1476–1486) on a 16B MoE model—and after roughly 300B tokens of training, block-wise quantized ∇Y\nabla_Y triggered a catastrophic loss divergence. Because activation gradients have strong token-specific outliers, pooling 128 tokens by 128 channels into a single scale wiped out small gradient signals across tokens. Preserving 1-token-wide (1×1281 \times 128) granularity on ∇Y\nabla_Y during Dgrad is mandatory for training stability.

Precision inventory across every component of the model

Not every operation in DeepSeek-V3 belongs in FP8. Operators that are either numerically delicate or memory-bandwidth-light stay in BF16 or FP32 (content/fp8.tex):

Component / Tensor Precision format Engineering rationale
Linear GEMMs (Fprop, Dgrad, Wgrad) FP8 (E4M3) inputs →\to BF16/FP32 out Dominates total FLOPs; 2×2\times tensor-core speed over BF16
Embedding table & Output head BF16 (higher precision) Directly faces 129,280-way token lookups and vocabulary logits
MoE gating / Router BF16 / FP32 (higher precision) Tiny compute cost; small rounding perturbations can flip top-8 discrete routing
RMSNorm & Attention core BF16 / FP32 (higher precision) Squares, reciprocal square roots, and exponentials are sensitive to precision
SwiGLU cached input FP8 (recomputed in backward) Halves activation memory for the 58 MoE layers; SwiGLU output recomputed on the fly
Linear input after Attention Custom E5M6 (12-bit) + 2n2^n scales Shared by both Wgrad of WOW^O and sensitive backward pass of Attention
MoE Dispatch (All-to-All) FP8 Halves inter-node InfiniBand and intra-node NVLink activation traffic
MoE Combine (All-to-All) BF16 Preserves accuracy when summing 8 weighted expert outputs + shared expert
Master weights & Grad accumulators FP32 Prevents small parameter updates from underflowing across micro-batches
AdamW 1st & 2nd moments (mt,vtm_t, v_t) BF16 (sharded via ZeRO-1) Cuts optimizer state memory in half compared to FP32 moments without loss degradation

Two clever activation-caching optimizations: SwiGLU and E5M6

To shrink the activation memory kept alive across DualPipe stages for the backward pass, Section 3.3.3 introduces two targeted storage formats:

  1. Caching SwiGLU inputs in FP8: Inside each MoE expert, the gate and up projections (Wgu,WuuW_g u, W_u u) produce intermediate vectors that feed the elementwise SwiGLU activation, whose output then feeds the down-projection WdW_d. Instead of storing both the pre-SwiGLU tensors in BF16 and the post-SwiGLU tensor for WdW_d's Wgrad, V3 caches the SwiGLU inputs in FP8 and recomputes the cheap elementwise SwiGLU product on the fly during the backward pass.
  2. Custom E5M6 format for the post-attention linear input: Consider the concatenated attention output ot∈R16384o_t \in \mathbb{R}^{16384} entering the output projection WOW^O. During the backward pass, this exact tensor is needed in two places: by the Wgrad of WOW^O, and by the backward pass of the core Attention operator itself. Because the Attention backward pass is too sensitive for 8-bit E4M3, while storing full BF16 (16 bits) is bulky, V3 stores this specific activation in a customized 12-bit E5M6 format (1 sign, 5 exponent, 6 mantissa bits) using integral power-of-two quantization scales. Why integral power-of-two scales? Because multiplying or dividing a floating-point number by 2k2^k only shifts its exponent bits without touching its 6 mantissa bits, allowing the tensor to be transposed and regrouped from 1×1281 \times 128 (forward) to 128×1128 \times 1 (Wgrad backward) with zero additional mantissa rounding error.

FP8 Dispatch vs. BF16 Combine

In every MoE layer, quantizing activations into FP8 before the All-to-All Dispatch step delivers a double payoff: the remote experts need FP8 inputs for their Fprop GEMMs anyway, and shipping FP8 over InfiniBand and NVLink cuts dispatch network volume in half compared to BF16 (likewise for backward activation gradients entering Dgrad).

On the return trip (All-to-All Combine), however, the relay and originating GPUs must sum the outputs of 8 routed experts (and backward input gradients from 8 experts). Quantizing each expert's output to 8 bits before summing 8 terms would compound rounding errors across the reduction, so Combine stays in BF16 in both forward and backward passes.

Why the released checkpoint ships in FP8

Because DeepSeek-V3 is trained natively with 128×128128 \times 128 block-scaled E4M3 weights in every major linear layer, the official Hugging Face release ships the native FP8 weights (E4M3 tensors alongside weight_scale_inv FP32 128×128128 \times 128 scale tensors) rather than performing post-training quantization on a BF16 model. Inference engines on Hopper/Ada GPUs can run those FP8 blocks directly, or multiply each 128×128128 \times 128 block by weight_scale_inv to dequantize to BF16 on hardware that lacks native FP8 support.


Sources: Report §3.3.1–3.3.3 (content/fp8.tex) for the three-GEMM FP8 framework, high-precision exceptions, E5M6 post-attention caching, SwiGLU input caching, BF16 AdamW moments, and FP8 dispatch / BF16 combine; Appendix B (main.tex, lines 1476–1486) for the block-wise Dgrad divergence experiment; reference/_README_WEIGHTS.md for released FP8 weight dequantization. Continue to Chapter 18: Memory Management and Reliability.

18. Memory Management and Reliability

In Chapter 13, we saw that DeepSeek-V3 trains across 2,048 H800 GPUs with zero Tensor Parallelism (TP=1TP = 1), keeping every layer's MLA projections and shared expert unsharded on a single GPU so that tensor-parallel AllReduce collectives never contend with MoE All-to-All traffic over NVLink. Achieving TP=1TP = 1 on an 80 GB H800 GPU while running 17 concurrent micro-batches in flight inside DualPipe requires an aggressive, coordinated attack on every category of training memory (§3.2.3, §3.3.3).

Decomposing the training memory footprint

At peak occupancy during a training step, a GPU's High-Bandwidth Memory (HBM) must hold five distinct classes of state:

Mtrain=Mweights+Mgradients+Moptimizer+Mactivations+Mbuffers.M_{\mathrm{train}} = M_{\mathrm{weights}} + M_{\mathrm{gradients}} + M_{\mathrm{optimizer}} + M_{\mathrm{activations}} + M_{\mathrm{buffers}}.

To appreciate how quickly these terms balloon without sharding and low precision, consider the raw global state of a 671B-parameter model:

Once static weight and optimizer memory is sharded via PP16, EP64, and ZeRO-1, the dominant consumer of HBM is saved forward activations (MactivationsM_{\mathrm{activations}}), which must stay resident in memory from the moment a micro-batch executes its forward pass (FF) until its corresponding backward weight-gradient pass (WW) completes up to PP+1=17PP + 1 = 17 micro-batch slots later.

Targeted activation recomputation: RMSNorm, MLA up-projections, and SwiGLU

Storing every intermediate tensor across 17 in-flight micro-batches would easily overflow 80 GB of HBM. On the other hand, full layer checkpointing (discarding all intermediate tensors inside a Transformer block and re-running the entire MLA and MoE forward pass during backpropagation) would add roughly 33% extra compute FLOPs and double All-to-All network traffic.

Instead, DeepSeek-V3 selectively recomputes only those operators whose output tensors are huge in memory but cheap in FLOPs (§3.2.3, §3.3.3):

Operator recomputed in backward What is cached from forward What is discarded & recomputed Why the trade is heavily lopsided
1. All RMSNorm layers Input vector ht∈R7168h_t \in \mathbb{R}^{7168} Normalized output RMSNorm⁡(ht)\operatorname{RMSNorm}(h_t) RMSNorm is a fast elementwise vector op, but its output is a full 7,168-wide tensor at every sub-block entrance
2. MLA Query & KV up-projections Compressed latents ctQ∈R1536c_t^Q \in \mathbb{R}^{1536} and ctKV∈R512c_t^{KV} \in \mathbb{R}^{512} (plus ktR∈R64k_t^R \in \mathbb{R}^{64}) Expanded 128-head qC,qR,kC,vCq^C, q^R, k^C, v^C (57,34457{,}344 scalars/token total!) Caching 1,536+576=2,1121{,}536 + 576 = 2{,}112 latent scalars instead of 57,34457{,}344 expanded head scalars cuts MLA activation memory by 27.2×27.2\times!
3. SwiGLU activation in MoE Pre-SwiGLU gate/up outputs in FP8 (2×20482 \times 2048 bytes/expert) Post-SwiGLU intermediate tensor Recomputing SiLU⁡(a)⊙b\operatorname{SiLU}(a) \odot b is a trivial elementwise op; caching inputs in FP8 saves an entire BF16 intermediate buffer

Look closely at row 2: in a standard 128-head Transformer, keeping queries, keys, and values alive for the backward pass of FlashAttention requires caching 128×(192+192+128)=65,536128 \times (192 + 192 + 128) = 65{,}536 scalars per token per layer. Because MLA factors all 128 heads through the tiny latents ctQc_t^Q (1,5361{,}536) and ctKVc_t^{KV} (512512), DeepSeek-V3 simply discards the expanded 128-head tensors after the forward pass and regenerates them on the fly from ctQc_t^Q and ctKVc_t^{KV} during the backward pass. Thus, MLA compresses training activation memory just as dramatically as it compresses inference KV cache memory.

Offloading Exponential Moving Average (EMA) weights to CPU

During pre-training, maintaining an Exponential Moving Average (EMA) of the model weights:

θˉt=ρθˉt−1+(1−ρ)θt\bar\theta_t = \rho \bar\theta_{t-1} + (1 - \rho)\theta_t

allows researchers to evaluate how the checkpoint will perform after learning-rate decay without waiting for the cooldown phase. Keeping an extra copy of 671B EMA weights in GPU HBM would waste precious accelerator memory. Instead, DeepSeek-V3 stores the EMA parameter copy in host CPU RAM and updates it asynchronously over PCIe after each optimizer step, adding zero GPU memory footprint and zero wall-clock stall to the training loop (§3.2.3).

Physical weight and gradient sharing for the MTP module

As noted in Chapters 9 and 14, the Multi-Token Prediction (MTP) module shares the 129,280-row token embedding table (Emb⁡\operatorname{Emb}) and output projection head (OutHead⁡\operatorname{OutHead}) with the main 61-layer model. Because DualPipe's mirrored bidirectional layout places Pipeline Stage 0 (containing the main model's Emb⁡\operatorname{Emb} and initial layers) and Pipeline Stage 15 (containing the main model's final layers, OutHead⁡\operatorname{OutHead}, and the MTP module) on the exact same physical GPUs, the main model and the MTP module read from the same physical weight buffer and accumulate into the same gradient buffer in local HBM, eliminating duplicate 1.85B-parameter tables and cross-stage gradient synchronization.

Summary of the memory-saving stack

Combining these six techniques explains how DeepSeek-V3 fits a 671B-parameter model and 17 in-flight DualPipe micro-batches onto 80 GB H800 GPUs without Tensor Parallelism:

  1. EP64 + PP16 + ZeRO-1 shard expert weights, layer depth, and optimizer states across the cluster.
  2. BF16 AdamW moments and cached master weights halve optimizer storage compared to FP32.
  3. MLA latent caching + up-projection recomputation shrinks attention backward-pass activations by over 27×27\times.
  4. RMSNorm and SwiGLU recomputation (with FP8 SwiGLU input caching and E5M6 post-attention caching) eliminates bulky intermediate buffers.
  5. DualPipe co-location shares the embedding and output head physically between Stage 0 and Stage 15 + MTP.
  6. Asynchronous CPU offloading moves EMA tracking weights off the GPUs entirely.

Sources: Report §3.2.3 (main.tex, lines 560–577) for RMSNorm/MLA recomputation, CPU EMA, and physical MTP sharing; §3.3.3 (content/fp8.tex) for E5M6 post-attention caching, FP8 SwiGLU caching, and BF16 optimizer states. Continue to Chapter 19: Instruction Tuning and Reasoning Distillation.

19. Instruction Tuning and Reasoning Distillation

Pre-training and context extension yield DeepSeek-V3-Base, a model that predicts document continuations across 128K tokens. Turning that base checkpoint into DeepSeek-V3—an assistant capable of both concise everyday conversation and deep multi-step mathematical and algorithmic reasoning—requires two post-training stages: Supervised Fine-Tuning (SFT) on 1.5 million curated instruction examples (§5.1) followed by Reinforcement Learning (RL) (§5.2).

The centerpiece of V3's SFT pipeline is reasoning distillation from DeepSeek-R1: rather than training V3 directly on raw, verbose R1 chain-of-thought traces, the authors train intermediate domain-specific teacher models that fuse R1's self-verification and reflection habits into clean, well-formatted solutions.

Why not distill raw DeepSeek-R1 outputs directly?

Internal DeepSeek-R1 models (trained via large-scale reinforcement learning to think through long chains of thought) achieve high accuracy on competition math, logic, and coding tasks. However, raw R1 traces suffer from three drawbacks for a general-purpose daily assistant (§5.1.1):

  1. Overthinking and extreme length: R1 frequently spends thousands of tokens exploring dead ends and second-guessing simple steps, inflating inference latency and token bills.
  2. Poor formatting: Raw RL-trained reasoning traces often interleave unstructured stream-of-consciousness scratchpads that are hard for a human user to read.
  3. Domain specialization: A single prompting setup does not simultaneously optimize competition math, competitive programming, and general logical puzzles.

Building the domain-specific teacher models

To capture R1's verification skills while enforcing clean formatting and concise length, the authors build specialized domain teacher models (referred to as "expert models" in §5.1.1—distinct from the SwiGLU MoE experts inside a Transformer layer) for specific reasoning domains: mathematics, code competitions, and logic puzzles.

Each domain teacher is trained from a pretrained base checkpoint via a two-stage bootstrap pipeline:

  1. Dual-format SFT: For every problem in the domain, the pipeline constructs two SFT training instances:
    • <problem, original_response>: paired with a standard, cleanly formatted human or baseline solution.
    • <system_prompt, problem, R1_response>: paired with an R1-generated solution, prefixed by an explicit system prompt instructing the model to generate step-by-step reflection and self-verification mechanisms.
  2. High-temperature RL synthesis and rejection sampling: The SFT-trained domain teacher then undergoes reinforcement learning using high-temperature sampling (τ>1\tau > 1). Sampling at high temperature forces the model to blend token transitions from both training regimes—integrating R1's reflection and verification steps directly into the clean structure of <problem, original_response> even when the explicit R1 system prompt is omitted. After hundreds of RL steps, the specialized teacher generates candidate solutions for the SFT prompt pool, and rejection sampling filters for correct, well-formatted, concise responses to include in DeepSeek-V3's final SFT dataset.

Non-reasoning SFT data

For non-reasoning domains—such as creative writing, role-play, multi-turn dialogue, translation, and straightforward factual QA—long chain-of-thought reflection is unnecessary. For these categories, DeepSeek-V3 generates candidate responses using DeepSeek-V2.5 and passes them through human annotators who verify factual accuracy, helpfulness, and stylistic quality (§5.1.1).

Combining the R1-distilled reasoning examples and the human-verified V2.5 non-reasoning examples yields the final 1.5 million SFT dataset.

SFT training protocol and sample-masked packing

Starting from the 128K-extended DeepSeek-V3-Base checkpoint, Supervised Fine-Tuning minimizes standard autoregressive cross-entropy loss on the target response tokens yy given prompt qq:

LSFT=−∑tlog⁡πθ(yt∣q,y<t).\mathcal L_{\mathrm{SFT}} = -\sum_{t} \log \pi_\theta(y_t \mid q, y_{<t}).

The SFT stage runs for 2 epochs over the 1.5M instances using a cosine learning-rate decay from 5×10−65 \times 10^{-6} down to 1×10−61 \times 10^{-6} (§5.1.2).

To maximize GPU utilization on variable-length instruction turns, multiple prompt-response examples are packed into a single training sequence. However, unlike pre-training (which omitted cross-sample attention masking), SFT applies strict sample masking (block-diagonal causal attention masks) so tokens in one SFT example can never attend to tokens from a preceding example packed into the same sequence.

Empirical impact of R1 reasoning distillation

How much of V3's jump on math and coding benchmarks comes from this R1 distillation pipeline, and what is the cost in output token length? In Section 5.4.1 (main.tex, lines 1148–1179), the authors run a controlled ablation on DeepSeek-V2.5, comparing a baseline trained without R1-distilled data against one trained with R1-distilled reasoning data:

Benchmark Baseline V2.5 Accuracy + R1 Distillation Accuracy Baseline Avg. Length (tokens) + R1 Distillation Avg. Length (tokens)
MATH-500 (Pass@1) 74.6%74.6\% 83.2%83.2\% (+8.6%+8.6\%) 769769 tokens 1,5101{,}510 tokens (1.96×1.96\times)
LiveCodeBench-CoT (Pass@1) 31.1%31.1\% 37.4%37.4\% (+6.3%+6.3\%) 718718 tokens 783783 tokens (1.09×1.09\times)

The ablation reveals both the power and the fundamental tradeoff of reasoning distillation:

By filtering teacher outputs through domain-specialized models rather than copying raw R1 traces (which often run 4,000–10,000+ tokens per problem), DeepSeek-V3 captures the bulk of R1's accuracy boost while keeping response lengths practical for an interactive chat model. The next chapter examines how the final Reinforcement Learning stage aligns and sharpens the SFT checkpoint further.


Sources: Report §5.1 (main.tex, lines 947–973) for the 1.5M SFT dataset, domain teacher pipeline, and 2-epoch SFT hyperparameters; §5.4.1 (main.tex, lines 1148–1179) for the R1 distillation ablation on DeepSeek-V2.5. Continue to Chapter 20: Rewards, GRPO, and Self-feedback.

20. Rewards, GRPO, and Self-feedback

After Supervised Fine-Tuning (Chapter 19), DeepSeek-V3 undergoes a Reinforcement Learning (RL) phase to align outputs with human preferences and further sharpen math and coding performance (§5.2). Instead of Proximal Policy Optimization (PPO)—which requires storing and training a separate value/critic network of comparable size to the 671B policy—DeepSeek-V3 uses Group Relative Policy Optimization (GRPO), estimating baselines directly from groups of sampled outputs for the same prompt.

Rule-based vs. model-based rewards

To score candidate responses across both verifiable technical tasks and open-ended conversation, the RL pipeline combines two distinct reward sources (§5.2.1):

  1. Rule-based rewards (for deterministic math and code tasks):
    • For mathematics problems with deterministic answers, the model is instructed to place its final answer inside a standard box format (e.g., \boxed{...}), allowing a deterministic parser to verify exact equivalence against the ground truth.
    • For competitive programming problems, candidate code is compiled and executed against a suite of unit test cases to compute pass/fail rewards directly.
    • Using hard compilers and exact-match rules avoids the classic failure mode of learned reward models on reasoning tasks: reward hacking, where the policy learns superficial stylistic tricks or lengthy boilerplate that fools a neural judge without actually solving the problem.
  2. Model-based rewards (for free-form and creative tasks):
    • For tasks without a rigid compiler check—such as creative writing, open-ended QA, or role-play—the pipeline uses a Reward Model (RM) initialized from the DeepSeek-V3 SFT checkpoint.
    • For questions that have a free-form reference answer, the RM judges whether the candidate response matches the reference; for purely unconstrained prompts, the RM scores overall helpfulness and quality from <prompt, response>.
    • To make the RM itself more reliable and less susceptible to reward hacking, the authors train it on preference pairs annotated with chain-of-thought reasoning traces that explain step-by-step why one response is better before emitting the reward score.

Group Relative Policy Optimization (GRPO)

In standard PPO, computing the advantage AtA_t of a token requires a learned value model Vϕ(st)V_\phi(s_t) to predict the expected return from state sts_t. For a 671B-parameter MoE model, maintaining an extra 671B value network in GPU memory during RL rollouts and updates is prohibitively expensive.

GRPO eliminates the critic network altogether (§5.2.2). For each prompt qq, GRPO samples a group of GG candidate outputs {o1,o2,…,oG}\{o_1, o_2, \ldots, o_G\} from the current frozen behavior policy πθold\pi_{\theta_{\mathrm{old}}}, scores each output to obtain scalar rewards {r1,r2,…,rG}\{r_1, r_2, \ldots, r_G\}, and computes the advantage AiA_i of output oio_i by normalizing its reward against the mean and standard deviation of its own prompt group:

Ai=ri−mean⁡(r1,r2,⋯ ,rG)std⁡(r1,r2,⋯ ,rG).A_i = \frac{r_i - \operatorname{mean}(r_1, r_2, \cdots, r_G)}{\operatorname{std}(r_1, r_2, \cdots, r_G)}.

For example, if G=4G = 4 candidate solutions to a coding problem receive binary pass/fail rewards r=[1,1,0,0]r = [1, 1, 0, 0], the group mean is 0.50.5, the standard deviation is 0.50.5, and the normalized advantages are A=[+1,+1,−1,−1]A = [+1, +1, -1, -1]. The two passing solutions are reinforced equally and the two failing solutions are penalized equally, automatically calibrating for the intrinsic difficulty of prompt qq without any learned value baseline.

The clipped GRPO surrogate and reverse-KL penalty

Given the group-normalized advantages AiA_i, GRPO updates the policy πθ\pi_\theta by maximizing the PPO-style clipped surrogate objective with an explicit KL-divergence penalty against a frozen reference policy πref\pi_{\mathrm{ref}} (the SFT checkpoint):

JGRPO(θ)=E[q∼P(Q),{oi}i=1G∼πθold(O∣q)]1G∑i=1G(min⁡(ρiAi,  clip⁡(ρi,1−ϵ,1+ϵ)Ai)−β DKL(πθ ∥ πref)),\mathcal{J}_{\mathrm{GRPO}}(\theta) = \mathbb{E}\left[q \sim P(Q), \{o_i\}_{i=1}^G \sim \pi_{\theta_{\mathrm{old}}}(O \mid q)\right] \frac{1}{G}\sum_{i=1}^G \left( \min\left( \rho_i A_i,\; \operatorname{clip}(\rho_i, 1-\epsilon, 1+\epsilon) A_i \right) - \beta\,\mathbb{D}_{\mathrm{KL}}\left(\pi_\theta \,\|\, \pi_{\mathrm{ref}}\right) \right),

where the importance-sampling probability ratio is:

ρi=πθ(oi∣q)πθold(oi∣q),\rho_i = \frac{\pi_\theta(o_i \mid q)}{\pi_{\theta_{\mathrm{old}}}(o_i \mid q)},

and the per-sample unbiased nonnegative KL estimator (Schulman's k3 estimator) is:

DKL(πθ ∥ πref)=πref(oi∣q)πθ(oi∣q)−log⁡πref(oi∣q)πθ(oi∣q)−1.\mathbb{D}_{\mathrm{KL}}\left(\pi_\theta \,\|\, \pi_{\mathrm{ref}}\right) = \frac{\pi_{\mathrm{ref}}(o_i \mid q)}{\pi_\theta(o_i \mid q)} - \log\frac{\pi_{\mathrm{ref}}(o_i \mid q)}{\pi_\theta(o_i \mid q)} - 1.

Look at the two components of this update:

  1. The clipped ratio clip⁡(ρi,1−ϵ,1+ϵ)Ai\operatorname{clip}(\rho_i, 1 - \epsilon, 1 + \epsilon) A_i: When Ai>0A_i > 0, increasing πθ(oi∣q)\pi_\theta(o_i \mid q) improves the objective only until ρi\rho_i hits 1+ϵ1 + \epsilon, preventing a single high-advantage sample from pushing the policy too far in one step. When Ai<0A_i < 0, decreasing πθ(oi∣q)\pi_\theta(o_i \mid q) is similarly capped once ρi\rho_i drops below 1−ϵ1 - \epsilon.
  2. The nonnegative KL penalty r−log⁡r−1r - \log r - 1 (with r=πref/πθr = \pi_{\mathrm{ref}} / \pi_\theta): Because r−1≥log⁡rr - 1 \ge \log r for all r>0r > 0 (with equality if and only if πθ=πref\pi_\theta = \pi_{\mathrm{ref}}), this estimator is strictly nonnegative for every single sample oio_i and keeps πθ\pi_\theta anchored near the well-formatted SFT policy πref\pi_{\mathrm{ref}}.

During RL training, the authors feed prompts spanning coding, math, logical reasoning, creative writing, role-play, and question answering, using diverse system prompts to ensure the aligned assistant responds naturally whether or not a user supplies a custom system prompt.

Generative reward judging and self-feedback

To evaluate how well generative chain-of-thought reward judging works—and whether the model can act as its own judge—the authors benchmark DeepSeek-V3 on RewardBench (§5.3.2, §5.4.2):

Reward model / Judge method Chat Chat-Hard Safety Reasoning RewardBench Average
GPT-4o-0513 (generative judge) 96.6 70.4 86.7 84.9 84.7
Claude-3.5-Sonnet-1022 (generative judge) 96.4 74.0 81.6 84.7 84.2
DeepSeek-V3 (single generative judgment) 96.9 79.8 87.0 84.3 87.0
DeepSeek-V3 (voting @ 6 judgments) 96.9 82.6 89.2 89.7 89.6

Notice the jump from 87.0 to 89.6 when aggregating 6 sampled chain-of-thought judgments via majority voting—with Reasoning jumping from 84.384.3 to 89.789.7 and Chat-Hard from 79.879.8 to 82.682.6. Because open-ended preference judgment benefits from test-time scaling just like math problem solving, the authors use multi-sample voting over DeepSeek-V3's own generative judgments (guided by constitutional principles) as a self-feedback signal to iteratively align the model on general subjective tasks (§5.4.2).


Sources: Report §5.2 (main.tex, lines 975–1016) for rule-based/model-based rewards and GRPO equations; §5.3.2 (main.tex, lines 1117–1143) for RewardBench evaluations; §5.4.2 (main.tex, lines 1181–1191) for self-rewarding and constitutional voting. Continue to Chapter 21: Serving Prefill and Decode.

21. Serving Prefill and Decode

Serving a 671B-parameter MoE model in production presents two workloads with diametrically opposed hardware profiles:

If a single GPU pool tries to run both phases simultaneously, heavy prefill batches stall decode inter-token latency, while small decode batches underutilize prefill compute. To optimize both regimes simultaneously, DeepSeek-V3 disaggregates prefill and decode onto separate GPU deployment units with tailored parallelism degrees, communication kernels, and redundant expert placement (§3.4).

Side-by-side comparison: Prefill vs. Decode deployment units

Table 1 summarizes the production H800 deployment configurations reported in Sections 3.4.1 and 3.4.2:

Parameter / Subsystem Prefill Deployment Unit (§3.4.1) Decode Deployment Unit (§3.4.2)
Cluster size 4 nodes (32 H800 GPUs) 40 nodes (320 H800 GPUs)
Attention & Dense MLP parallelism TP4 + SP (Sequence Parallelism) ×\times DP8 (dense MLPs use TP1, DP32) TP4 + SP ×\times DP80
MoE Expert Parallelism EP32 across all 32 GPUs EP320 across all 320 GPUs
Experts hosted per GPU per MoE layer 9 routed experts/GPU (8 original + 1 redundant hot copy) + shared expert 1 expert/GPU (256 GPUs host 1 routed expert each; 64 GPUs host redundant routed + shared experts)
All-to-All communication path Hierarchical IB →\to NVLink forwarding (same as training) Direct point-to-point IB via IBGDA (GPU-initiated async RDMA)
Micro-batch overlap strategy Dual micro-batch overlap (Compute of batch A ↔\leftrightarrow All-to-All of batch B) Exploring dual micro-batch overlap (Attention of batch A ↔\leftrightarrow Dispatch+MoE+Combine of batch B)

Let's unpack why each of these architectural choices looks the way it does.

Inside the 32-GPU Prefill unit

In the 32-GPU (4-node) prefill unit:

  1. Attention uses TP4 + SP paired with DP8 (4×8=324 \times 8 = 32 GPUs): Splitting 128 attention heads 4 ways (32 heads per GPU) keeps tensor-parallel communication strictly inside a 4-GPU NVLink subgroup while reducing per-GPU KV cache and activation footprints during long-prompt prefill. Meanwhile, the first three dense SwiGLU layers use TP1 (DP32) to avoid any tensor-parallel AllReduce overhead.
  2. MoE uses EP32 with 1 redundant expert per GPU: Partitioning 256 routed experts across 32 GPUs places 256/32=8256 / 32 = 8 original routed experts on each GPU. To prevent hot experts from creating straggler GPUs when live user prompts cluster around specific domains, each GPU allocates 1 additional expert slot (32 redundant slots across the cluster) to host a replicated copy of a high-load expert, bringing each GPU's inventory to 9 routed experts per layer (plus the shared expert).
  3. Dual micro-batch ping-pong overlap: Just like DualPipe in training, the prefill engine splits incoming prompt traffic into two balanced micro-batches (AA and BB). While micro-batch AA executes its Attention and MoE GEMMs on the tensor cores, micro-batch BB executes its All-to-All Dispatch and Combine over IB and NVLink, hiding cross-node communication behind prefill compute.

Inside the 320-GPU Decode unit

During autoregressive decoding, latency requires reading as few expert weight matrices per GPU as possible on each step. Scaling Expert Parallelism out to 320 GPUs (40 nodes) transforms the per-GPU memory-bandwidth bottleneck:

  1. One expert per GPU (EP320): Across the 320 GPUs in a decode unit, 256 GPUs each host exactly 1 of the 256 routed experts per layer. What do the remaining 320−256=64 GPUs320 - 256 = \mathbf{64\text{ GPUs}} host? They hold redundant copies of hot routed experts alongside replicated copies of the always-active shared expert!
  2. Treating the shared expert as a 9th routed destination: In prefill (and training), every GPU holds a local copy of the shared expert and evaluates it locally. In decode's EP320 layout, however, storing and reading both a routed expert and a shared expert on every GPU would double per-GPU HBM weight reads. Instead, the shared expert is replicated across a subset of the 64 extra GPUs and treated by the All-to-All dispatcher as a 9th routed destination that every token automatically selects alongside its 8 learned routed experts. That way, every single GPU in the 320-GPU pool reads at most 1 expert's weights (44.04M44.04\text{M} parameters ≈44 MB\approx 44\text{ MB} in FP8) per layer!
  3. Point-to-point IBGDA networking: With 320 GPUs spread across 40 nodes, decode All-to-All messages are small and latency-critical. Rather than bouncing tokens through a two-stage IB →\to NVLink relay, decode kernels use IBGDA (InfiniBand GPUDirect Async) so GPU threads directly issue low-latency point-to-point RDMA writes across InfiniBand. Because IBGDA requires very few SMs to drive network transfers, almost all 132 SMs stay available for MLA attention and expert GEMMs.

Online redundant expert rearrangement

Even though auxiliary-loss-free balancing keeps all 256 experts evenly loaded across the global pre-training corpus, live production traffic shifts constantly by time of day and application domain (for example, a surge in Python coding queries).

Because each MoE layer's 256 experts are mathematically independent transformation functions, duplicating expert ii's weight matrices onto a redundant GPU slot and splitting incoming token traffic across the two physical copies produces the exact same mathematical output as running all tokens on a single copy.

In production, the serving system continuously tracks per-expert token load statistics in real time and recalculates and rearranges the redundant hot-expert replicas periodically (e.g., every 10 minutes) (§3.4.1), rebalancing GPU queues dynamically without altering the model's learned routing weights. The authors also note ongoing exploration of dynamic redundancy, where each GPU holds a larger pool of expert weights in HBM (e.g., 16 experts) and a fast global routing solver picks which 9 physical slots to activate on each step before launching the All-to-All transfer.

Production SLO units vs. minimum hardware to run the weights

Note the distinction between the minimum hardware required to load the checkpoint and the 32-GPU / 320-GPU units used in DeepSeek's high-throughput cloud service:


Sources: Report §3.4.1–3.4.2 (main.tex, lines 583–629) for prefill/decode deployment units, TP4+SP/DP/EP degrees, redundant expert placement, IBGDA, and micro-batch overlap; §6 (main.tex, lines 1208–1214) for deployment unit scale considerations. Continue to Chapter 22: Speculative Decoding with MTP.

22. Speculative Decoding with MTP

In standard autoregressive decoding, generating NN output tokens requires NN sequential forward passes through all 61 layers of the main DeepSeek-V3 backbone. Because each decode step only processes 1 token per request, the GPUs spend most of their time streaming expert and attention weights out of HBM rather than saturating their tensor cores.

Although the Multi-Token Prediction (MTP) module is primarily introduced to densify supervision during pre-training (Chapter 9), it can also be kept at inference time as a built-in speculative decoding draft head (§2.2, §5.4.3). In Section 5.4.3, the authors report that the MTP module's second-token prediction achieves an 85% to 90% acceptance rate across diverse generation domains, boosting end-to-end decoding throughput by 1.8×1.8\times tokens per second (TPS).

How MTP drafts a second token and the main model verifies it

Recall how the depth-1 MTP module operates at position ii:

  1. After the 61-layer main model processes the prefix ending at token xix_i, it produces final hidden state hi0h_i^0 and samples (or greedily selects) the immediate next token x^i+1\hat{x}_{i+1} from pi+10=OutHead⁡(hi0)p_{i+1}^0 = \operatorname{OutHead}(h_i^0).
  2. Whereas pre-training fed the ground-truth embedding Emb⁡(xi+1)\operatorname{Emb}(x_{i+1}) into the MTP projection M1M_1, inference feeds the newly generated token's embedding Emb⁡(x^i+1)\operatorname{Emb}(\hat{x}_{i+1}) alongside hi0h_i^0: hi′1=M1[RMSNorm⁡(hi0);  RMSNorm⁡(Emb⁡(x^i+1))].h_i^{\prime 1} = M_1\left[\operatorname{RMSNorm}(h_i^0);\;\operatorname{RMSNorm}(\operatorname{Emb}(\hat{x}_{i+1}))\right].
  3. Running the single MTP Transformer layer TRM⁡1\operatorname{TRM}_1 and shared output head on hi′1h_i^{\prime 1} yields a draft probability distribution q(⋅)=pi+21q(\cdot) = p_{i+2}^1 for the second future token, from which the system draws a speculative candidate x~i+2\tilde{x}_{i+2}.

Now, on the next forward pass of the 61-layer main model, instead of feeding only the single verified token [x^i+1][\hat{x}_{i+1}], the serving engine feeds the two-token pair [x^i+1,x~i+2][\hat{x}_{i+1}, \tilde{x}_{i+2}] in parallel:

Why does evaluating 2 tokens in parallel through the 61-layer main model take nearly the same wall-clock time as evaluating 1 token? Because during memory-bandwidth-bound decoding, the GPU already has to load the weight matrices from HBM into SRAM; multiplying those loaded weights against 2 token vectors per sequence instead of 1 reuses the exact same weight reads at virtually zero extra memory-bandwidth cost.

Exactness of speculative decoding: Greedy and stochastic verification

Crucially, speculative decoding is lossless: it produces the exact same output probability distribution as running the 61-layer main model one token at a time, never degrading output quality to gain speed.

1. Greedy decoding (τ=0\tau = 0)

Under greedy decoding, the target model's decision at position i+2i+2 is simply x∗=arg⁡max⁡xp(x)x^* = \arg\max_x p(x).

2. Stochastic sampling (τ>0\tau > 0)

When sampling from p(x)p(x) at nonzero temperature, simply accepting x~∼q(x)\tilde{x} \sim q(x) unconditionally would bias the output toward the draft model qq. Standard lossless speculative sampling (Leviathan et al., 2023; Chen et al., 2023) preserves the exact target distribution p(x)p(x) via a two-step accept/reject rule:

  1. Acceptance step: Given proposed token x~∼q(⋅)\tilde{x} \sim q(\cdot), accept x~\tilde{x} with probability: α(x~)=min⁡(1,  p(x~)q(x~)).\alpha(\tilde{x}) = \min\left(1,\; \frac{p(\tilde{x})}{q(\tilde{x})}\right).
  2. Residual correction step (on rejection): If x~\tilde{x} is rejected, discard it and sample a replacement token xi+2x_{i+2} from the normalized positive residual distribution: pres(x)=max⁡(p(x)−q(x),  0)∑ymax⁡(p(y)−q(y),  0).p_{\mathrm{res}}(x) = \frac{\max\left(p(x) - q(x),\; 0\right)}{\sum_{y} \max\left(p(y) - q(y),\; 0\right)}.

To verify that this rule recovers p(x)p(x) exactly, sum the probability of emitting any token xx via direct acceptance plus rejection-and-resampling:

For a concrete two-token check: suppose p=[0.6,0.4]p = [0.6, 0.4] and the MTP draft predicts q=[0.8,0.2]q = [0.8, 0.2] on tokens {A,B}\{A, B\}. Token AA is drafted 80%80\% of the time and accepted with probability 0.6/0.8=0.750.6 / 0.8 = 0.75, contributing 0.8×0.75=0.600.8 \times 0.75 = 0.60 to AA. Token BB is drafted 20%20\% of the time and accepted with probability min⁡(1,0.4/0.2)=1.0\min(1, 0.4/0.2) = 1.0, contributing 0.200.20 to BB. The remaining 20%20\% rejected mass goes entirely to pres=[0,1]p_{\mathrm{res}} = [0, 1] (token BB), bringing BB's total probability to 0.20+0.20=0.400.20 + 0.20 = 0.40—matching p=[0.6,0.4]p = [0.6, 0.4] down to the last decimal.

Notice also that under this exact rule, the expected acceptance probability across the vocabulary is:

Ex~∼q[α(x~)]=∑xmin⁡(p(x),q(x))=1−TV⁡(p,q),\mathbb{E}_{\tilde{x} \sim q}[\alpha(\tilde{x})] = \sum_x \min(p(x), q(x)) = 1 - \operatorname{TV}(p, q),

where TV⁡(p,q)=12∑x∣p(x)−q(x)∣\operatorname{TV}(p, q) = \frac{1}{2}\sum_x |p(x) - q(x)| is the total variation distance between the main model and the MTP head. An 85%–90% acceptance rate means the single-layer MTP head's next-token distribution sits within 0.10–0.150.10\text{–}0.15 total variation distance of the full 61-layer backbone!

Connecting 85%–90% acceptance to the 1.8×1.8\times TPS speedup

Why does an 85%–90% acceptance rate translate to roughly a 1.8×1.8\times decoding speedup?

In each verification cycle, the main model always produces at least 11 valid token (either the bonus token following an accepted draft, or the corrected token replacing a rejected draft), plus the drafted token itself whenever accepted (with probability a∈[0.85,0.90]a \in [0.85, 0.90]). Thus, each cycle yields an expected 1+a=1.85 to 1.901 + a = 1.85\text{ to }1.90 tokens.

If the wall-clock time tcyclet_{\mathrm{cycle}} of running the 2-token verification pass plus the 1-layer MTP draft head is only a few percent higher than a standard 1-token forward pass t0t_0 (since the MTP module is just 1 Transformer layer compared to 61 in the main model, and the 2-token verification pass is memory-bandwidth bound on the same weight loads), the net throughput multiplier is:

Speedup=(1+a) t0tcycle≈1.85 to 1.901.03 to 1.05≈1.8×.\text{Speedup} = \frac{(1 + a)\,t_0}{t_{\mathrm{cycle}}} \approx \frac{1.85\text{ to }1.90}{1.03\text{ to }1.05} \approx \mathbf{1.8\times}.

When a draft token is rejected on step ii, the serving engine simply rewinds the KV cache pointer by 1 slot to overwrite the rejected draft entry (ci+2KV,ki+2Rc_{i+2}^{KV}, k_{i+2}^R) on the next step, ensuring the MLA cache remains strictly consistent with the verified token stream.


Sources: Report §2.2 (main.tex, lines 453–455) and §5.4.3 (main.tex, lines 1193–1199) for MTP speculative decoding, the 85%–90% acceptance rate, and the 1.8×1.8\times TPS speedup. Continue to Chapter 23: Base-model Evidence and Ablations.

23. Base-model Evidence and Ablations

Before examining the post-trained chat assistant in Chapter 24, this chapter evaluates the raw pretrained checkpoint (DeepSeek-V3-Base) alongside the controlled architectural ablations reported in Section 4.4, Section 4.5, and Appendix B. Separating base-model evaluations from post-training evaluations lets us distinguish what the 671B MoE architecture and 14.8T-token pre-training run learned directly from what was later distilled from DeepSeek-R1 during SFT and RL.

Evaluation methodology: perplexity, generation, and Bits-Per-Byte (BPB)

In Section 4.4 (tables/base_evaluation.tex), the authors benchmark DeepSeek-V3-Base against three open-weight baselines using the exact same internal evaluation harness: DeepSeek-V2-Base (236B total / 21B active, 8.1T tokens), Qwen2.5-72B-Base (72B dense, 18T tokens), and LLaMA-3.1-405B-Base (405B dense, 15.6T tokens).

The benchmark suite uses three distinct measurement protocols:

  1. Perplexity-based (likelihood) evaluation: For standard multiple-choice benchmarks (such as MMLU, MMLU-Pro, C-Eval, CMMLU, PIQA, HellaSwag, and RACE), the harness scores the log-likelihood of each candidate continuation given a few-shot prompt rather than parsing free-form text.
  2. Generation-based evaluation: For math, coding, and reading comprehension (GSM8K, MATH, HumanEval, MBPP, LiveCodeBench-Base, DROP, NaturalQuestions), the model generates a multi-token completion that is checked by an exact-match parser, F1 scorer, or code unit-test runner.
  3. Bits-Per-Byte (BPB) on Pile-test: Because DeepSeek-V3-Base, Qwen2.5, and LLaMA-3.1 use different BPE tokenizers with different compression ratios, raw per-token perplexity cannot be compared across models. Normalizing total negative log-likelihood (in base-2 bits) by the number of raw UTF-8 bytes in the text gives a tokenizer-agnostic compression metric: BPB⁡=−log⁡2p(text)number of UTF-8 bytes in text.\operatorname{BPB} = \frac{-\log_2 p(\text{text})}{\text{number of UTF-8 bytes in text}}.

Comprehensive DeepSeek-V3-Base benchmark comparison

Table 1 summarizes key benchmarks from tables/base_evaluation.tex across English general knowledge, code, math, Chinese/multilingual tasks, and language modeling compression:

Benchmark (Metric, Shots) DeepSeek-V2 Base Qwen2.5 72B Base LLaMA-3.1 405B Base DeepSeek-V3 Base
Architecture (Active / Total) 21B / 236B MoE 72B Dense 405B Dense 37B / 671B MoE
MMLU (Acc, 5-shot) 78.4 85.0 84.4 87.1
MMLU-Pro (Acc, 5-shot) 51.4 58.3 52.8 64.4
BBH (EM, 3-shot) 78.8 79.8 82.9 87.5
DROP (F1, 3-shot) 80.4 80.6 86.0 89.0
NaturalQuestions (EM, 5-shot) 38.6 33.2 41.5 40.0
RACE-High (Acc, 5-shot) 50.3 55.5 56.8 51.3
HumanEval (Pass@1, 0-shot) 43.3 53.0 54.9 65.2
MBPP (Pass@1, 3-shot) 65.0 72.6 68.4 75.4
LiveCodeBench-Base (Pass@1, 3-shot) 11.6 12.9 15.5 19.4
CRUXEval-O (Acc, 1-shot) 50.3 59.5 58.5 69.8
GSM8K (EM, 8-shot) 81.6 88.3 83.5 89.3
MATH (EM, 4-shot) 43.4 54.4 49.0 61.6
MGSM (EM, 8-shot) 63.6 76.2 69.9 79.8
C-Eval (Acc, 5-shot) 81.4 89.2 72.5 90.1
CMMLU (Acc, 5-shot) 84.0 89.5 73.7 88.8
MMMLU-non-English (Acc, 5-shot) 64.0 74.8 73.8 79.4
Pile-test (BPB, lower is better) 0.606 0.638 0.542 0.548

Look closely at the pattern across categories:

Controlled ablation 1: Multi-Token Prediction (§4.5.1)

Because the main table compares models with different corpora and sizes, Section 4.5 runs controlled ablations isolating V3's new components on two smaller MoE scales: a Small MoE (15.7B total / 2.4B active, trained on 1.33T tokens) and a Large MoE (228.7B total / 20.9B active, trained on 540B–578B tokens).

In the MTP ablation (main.tex, lines 825–866), adding a 1-depth MTP module during training and discarding it at evaluation time yields consistent gains across both scales:

Model Scale Configuration Pile BPB (↓\downarrow) MMLU BBH DROP HumanEval MBPP GSM8K MATH
15.7B MoE (1.33T tok) Baseline 0.656 50.0 39.0 55.5 20.7 42.2 25.4 10.7
15.7B MoE (1.33T tok) + MTP (D=1D=1) 0.655 50.0 41.4 58.5 26.8 43.4 31.4 12.6
228.7B MoE (540B tok) Baseline 0.583 67.5 66.2 68.5 44.5 61.6 72.3 38.6
228.7B MoE (540B tok) + MTP (D=1D=1) 0.579 66.6 69.9 70.9 53.7 66.2 74.0 39.8

Notice that MTP delivers its sharpest gains on multi-step generative tasks—boosting HumanEval by +6.1+6.1 and +9.2+9.2 points and BBH by +2.4+2.4 and +3.7+3.7 points—even when the MTP head is completely removed at test time.

Controlled ablation 2: Auxiliary-Loss-Free Balancing (§4.5.2–4.5.3)

Next, the authors compare traditional sequence-wise auxiliary-loss balancing against V3's auxiliary-loss-free bias controller ( holding sigmoid gating and top-kk affinity normalization identical in both runs):

Model Scale Balancing Method Pile BPB (↓\downarrow) MMLU BBH DROP HumanEval MBPP GSM8K MATH
15.7B MoE (1.33T tok) Aux-Loss-Based 0.656 50.0 39.0 55.5 20.7 42.2 25.4 10.7
15.7B MoE (1.33T tok) Aux-Loss-Free 0.655 51.4 40.2 59.0 22.6 45.8 27.1 13.0
228.7B MoE (578B tok) Aux-Loss-Based 0.579 68.3 66.7 67.6 40.2 59.2 70.7 37.2
228.7B MoE (578B tok) Aux-Loss-Free 0.576 67.2 67.3 67.9 46.3 62.2 74.5 39.6

As discussed in Chapter 8, Section 4.5.3 further demonstrates on 1B and 3B MoE models that switching a standard auxiliary loss from sequence-level to batch-level achieves the exact same validation loss improvement as the bias controller (2.258→2.2532.258 \to 2.253 at 1B; 2.085→2.0802.085 \to 2.080 at 3B), confirming that freeing individual sequences from uniform-routing constraints is the underlying mechanism behind the gain.

Controlled ablation 3: FP8 vs. BF16 training loss (Appendix B)

Finally, Figure 1 (figures/fp8-v.s.-bf16.png from Appendix B) tracks the training loss trajectories of the 16B and 230B MoE models trained in V3's fine-grained FP8 recipe versus pure BF16:

FP8 and BF16 loss curves for approximately 16B and 230B MoE experiments, with inset relative-loss differences and broadly overlapping trajectories.

Training loss curves (EMA-smoothed with coefficient 0.9) and relative loss error between BF16 and DeepSeek-V3's FP8 recipe on ~16B MoE (left, 1.33T tokens) and ~230B MoE (right, ~0.9T tokens), from Report Appendix B. Relative loss error stays well below 0.25%0.25\% across the entire run.

Together, these three sets of controlled experiments confirm that each of V3's core training changes—MTP supervision, batch-level bias balancing, and tile/block FP8 quantization—pull their weight independently before scaling up to the full 671B run.


Sources: Report §4.4 (main.tex, lines 767–823) and tables/base_evaluation.tex for V3-Base benchmarks; §4.5.1–4.5.3 (main.tex, lines 825–932) for MTP and load-balancing ablations; Appendix B (main.tex, lines 1458–1486) for FP8 vs. BF16 loss curves. Continue to Chapter 24: What the Chat Evaluations Establish.

24. What the Chat Evaluations Establish

In Section 5.3 (tables/chat_evaluation.tex), the authors evaluate the fully post-trained DeepSeek-V3 chat checkpoint—incorporating 128K context extension, 1.5M SFT examples with DeepSeek-R1 reasoning distillation, and GRPO reinforcement learning—against leading open-weight and proprietary models of its era: DeepSeek-V2.5-0905, Qwen2.5-72B-Instruct, LLaMA-3.1-405B-Instruct, Claude-3.5-Sonnet-1022, and GPT-4o-0513.

Every benchmark in the main chat suite is evaluated with a maximum generation cap of 8,192 output tokens, and small competition datasets (such as AIME 2024 and CNMO 2024) are averaged across 16 sampling runs at temperature τ=0.7\tau = 0.7 to reduce single-sample variance.

English knowledge, reasoning, and instruction following

Table 1 compares the models on general academic knowledge, graduate-level STEM reasoning, reading comprehension, and strict formatting compliance:

Benchmark (Metric) DeepSeek V2.5-0905 Qwen2.5 72B-Inst LLaMA-3.1 405B-Inst Claude-3.5 Sonnet-1022 GPT-4o 0513 DeepSeek-V3
MMLU (EM, 5-shot) 80.6 85.3 88.6 88.3 87.2 88.5
MMLU-Redux (EM, 0-shot) 80.3 85.6 86.2 88.9 88.0 89.1
MMLU-Pro (EM, 0-shot CoT) 66.2 71.6 73.3 78.0 72.6 75.9
GPQA-Diamond (Pass@1, 0-shot) 41.3 49.0 51.1 65.0 49.9 59.1
DROP (F1, 3-shot) 87.8 76.7 88.7 88.3 83.7 91.6
IFEval (Prompt Strict Acc) 80.6 84.1 86.0 86.5 84.3 86.1

Across broad academic benchmarks, DeepSeek-V3 matches or edges out LLaMA-3.1-405B-Instruct and GPT-4o-0513 on MMLU (88.588.5) and MMLU-Redux (89.189.1), while trailing Claude-3.5-Sonnet-1022 on MMLU-Pro (75.975.9 vs. 78.078.0) and GPQA-Diamond (59.159.1 vs. 65.065.0, where V3 still leads all other open-weight models and GPT-4o by +8 to +10+8\text{ to }+10 points).

Factuality: English SimpleQA vs. Chinese C-SimpleQA

When we move from multiple-choice knowledge (MMLU) to short-form, open-ended factual recall without multiple-choice hints, a sharp language split appears:

Factuality Benchmark DeepSeek V2.5-0905 Qwen2.5 72B-Inst LLaMA-3.1 405B-Inst Claude-3.5 Sonnet-1022 GPT-4o 0513 DeepSeek-V3
SimpleQA (English, Correct %) 10.2 9.1 28.1 28.4 38.2 24.9
C-SimpleQA (Chinese, Correct %) 54.1 48.4 50.4 51.3 59.3 64.8
C-Eval (Chinese knowledge, 5-shot) 79.5 86.1 77.2 76.7 76.0 86.5

On Chinese SimpleQA, DeepSeek-V3 leads every model in the table at 64.8%64.8\% (+5.5+5.5 points ahead of GPT-4o-0513). On English SimpleQA, however, V3 scores 24.9%24.9\%, behind GPT-4o-0513 (38.2%38.2\%), Claude-3.5-Sonnet (28.4%28.4\%), and LLaMA-3.1-405B (28.1%28.1\%). This contrast reflects the domain and language allocation of the training corpus and shows why multiple-choice MMLU scores do not automatically predict open-ended tail-fact recall.

Code generation, competitive programming, and software engineering

Coding benchmarks in Table 2 fall into two distinct workflows: algorithmic generation / competitive programming (HumanEval-Mul, LiveCodeBench, Codeforces) and repository-level editing / issue resolution (SWE-bench Verified, Aider):

Coding Benchmark DeepSeek V2.5-0905 Qwen2.5 72B-Inst LLaMA-3.1 405B-Inst Claude-3.5 Sonnet-1022 GPT-4o 0513 DeepSeek-V3
HumanEval-Mul (8 langs, Pass@1) 77.4 77.3 77.2 81.7 80.5 82.6
LiveCodeBench (Aug–Nov 2024, CoT) 29.2 31.1 28.4 36.3 33.4 40.5
LiveCodeBench (Aug–Nov 2024, non-CoT) 26.2 28.7 30.1 32.8 34.2 37.6
Codeforces (Percentile) 35.6 24.8 25.3 20.3 23.6 51.6
SWE-bench Verified (Agentless, Resolved %) 22.6 23.8 24.5 50.8 38.8 42.0
Aider-Edit (Diff format, Acc %) 71.6 65.4 63.9 84.2 72.9 79.7
Aider-Polyglot (Acc %) 17.8 7.6 5.8 45.3 16.0 49.6

Notice how clearly the strengths separate by task type:

Competition mathematics: where R1 distillation shines brightest

The largest margin in the entire report appears on mathematical reasoning benchmarks (tables/chat_evaluation.tex):

Math Benchmark DeepSeek V2.5-0905 Qwen2.5 72B-Inst LLaMA-3.1 405B-Inst Claude-3.5 Sonnet-1022 GPT-4o 0513 DeepSeek-V3
AIME 2024 (Avg Pass@1 over 16 runs) 16.7 23.3 23.3 16.0 9.3 39.2
MATH-500 (Greedy EM) 74.7 80.0 73.8 78.3 74.6 90.2
CNMO 2024 (Avg Pass@1 over 16 runs) 10.8 15.9 6.8 13.1 10.8 43.2

On MATH-500, DeepSeek-V3 hits 90.2%90.2\% (+10.2+10.2 points above Qwen2.5-72B and +11.9+11.9 points above Claude-3.5-Sonnet). On olympiad-level AIME 2024 and CNMO 2024, V3 scores 39.2%39.2\% and 43.2%43.2\%—more than doubling or tripling every non-reasoning model in the table. As the ablation in Chapter 19 demonstrated, this leap is driven by combining V3-Base's strong pre-training math foundation with R1-distilled self-verification traces and rule-based GRPO reinforcement learning.

Open-ended chat preference benchmarks

Finally, Section 5.3.1 evaluates open-ended conversational preference on Arena-Hard and AlpacaEval 2.0 (using GPT-4-Turbo-1106 as the judge and reporting length-controlled win rate on AlpacaEval 2.0):

Model Arena-Hard (Win Rate vs. baseline) AlpacaEval 2.0 (Length-Controlled Win Rate)
DeepSeek-V2.5-0905 76.2 50.5
Qwen2.5-72B-Instruct 81.2 49.1
LLaMA-3.1-405B-Instruct 69.3 40.5
GPT-4o-0513 80.4 51.1
Claude-3.5-Sonnet-1022 85.2 52.0
DeepSeek-V3 85.5 70.0

(Note a minor textual discrepancy in the paper: Table 6 in main.tex lists V3's Arena-Hard score as 85.585.5, whereas the accompanying prose in §5.3.1 refers to it as "over 86%"; we follow the explicit table figure of 85.585.5.) On both preference benchmarks, V3 places first, jumping +19.5+19.5 percentage points over V2.5 on length-controlled AlpacaEval 2.0 (50.5→70.050.5 \to 70.0).


Sources: Report §5.3 (main.tex, lines 1018–1143) and tables/chat_evaluation.tex. Continue to Chapter 25: Costs, Limitations, and Practical Use.

25. Costs, Limitations, and Practical Use

DeepSeek-V3's reported training cost of $5.576M (2.788 million H800 GPU hours) sparked intense discussion across the machine learning and systems communities. To use that figure accurately—and to plan real-world deployments of the 671B-parameter checkpoint—we can trace the exact throughput and FLOP math implied by the paper's numbers, clearly separate what the $5.576M budget includes from what it excludes, and evaluate the hardware footprint required to serve the model.

Reconstructing the GPU-hour, wall-clock, and throughput math

Table 1 in Report §1 breaks the official training compute bill into three stages, priced at a benchmark rental rate of $2.00 per H800 GPU hour:

Training Stage H800 GPU Hours Implied Full-Cluster Days (2,048 GPUs) Cost at $2/GPU-hour
Pre-training (14.8T tokens) 2,664,000 (2,664K2{,}664\text{K}) 54.20 days54.20\text{ days} $5,328,000 ($5.328M)
Context extension (32K & 128K) 119,000 (119K119\text{K}) 2.42 days2.42\text{ days} $238,000 ($0.238M)
Post-training (SFT & GRPO RL) 5,000 (5K5\text{K}) 0.10 days0.10\text{ days} (≈2.44 hours\approx 2.44\text{ hours}) $10,000 ($0.010M)
Total 2,788,000 (2,788K2{,}788\text{K}) 56.72 days56.72\text{ days} $5,576,000 ($5.576M)

From the pre-training figures (14.8T14.8\text{T} tokens in 2,664,0002{,}664{,}000 H800 GPU hours, or 180,000180{,}000 GPU hours per trillion tokens), several concrete cluster metrics follow directly:

  1. Elapsed wall-clock time: On a continuously occupied 2,048-GPU cluster (2,048×24=49,1522{,}048 \times 24 = 49{,}152 GPU hours per calendar day), 1.0T1.0\text{T} tokens takes 180,000/49,152≈3.66 days180{,}000 / 49{,}152 \approx \mathbf{3.66\text{ days}}, and the full 14.8T14.8\text{T}-token pre-training run takes 2,664,000/49,152≈54.20 days2{,}664{,}000 / 49{,}152 \approx \mathbf{54.20\text{ days}}.
  2. Sustained token throughput per GPU: 14.8×1012 tokens2,664,000 GPU-hours≈5,555,556 tokens/GPU-hour≈1,543 tokens/GPU-second.\frac{14.8 \times 10^{12}\text{ tokens}}{2{,}664{,}000\text{ GPU-hours}} \approx 5{,}555{,}556\text{ tokens/GPU-hour} \approx \mathbf{1{,}543\text{ tokens/GPU-second}}. Across all 2,048 GPUs simultaneously, the cluster processes an average of 2,048×1,543.2≈3.16 million tokens/second2{,}048 \times 1{,}543.2 \approx \mathbf{3.16\text{ million tokens/second}}.
  3. Effective FLOP rate: Using the standard dense-equivalent training approximation C≈6NactiveDC \approx 6 N_{\mathrm{active}} D with Nactive≈37×109N_{\mathrm{active}} \approx 37 \times 10^9 parameters and D=14.8×1012D = 14.8 \times 10^{12} tokens yields: C≈6×(37×109)×(14.8×1012)≈3.29×1024 FLOPs.C \approx 6 \times (37 \times 10^9) \times (14.8 \times 10^{12}) \approx \mathbf{3.29 \times 10^{24}\text{ FLOPs}}. Dividing 3.29×10243.29 \times 10^{24} FLOPs by 2,664,000×3,600=9.5904×1092{,}664{,}000 \times 3{,}600 = 9.5904 \times 10^9 GPU-seconds gives roughly 343 TFLOP/s per H800 GPU343\text{ TFLOP/s per H800 GPU} in dense-equivalent model FLOPs (and even higher in actual hardware tensor-core FLOPs once quadratic attention, MTP overhead, and activation recomputation are included). Sustaining >343 TFLOP/s>343\text{ TFLOP/s} per GPU across 64-way cross-node MoE parallelism is a direct testament to DualPipe communication overlap and FP8 tensor-core execution.

What the $5.576M figure includes—and what it excludes

As the authors state explicitly in Footnote 1 of Report §1 (main.tex, lines 202–208), the $5.576M figure is the marginal compute cost of the official final training run. It does not include:

Keep that boundary clear when comparing training budgets: $5.576M is an impressively low marginal compute bill for a frontier-class 14.8T-token run, not the total cost of operating a frontier AI lab.

Practical deployment planning and hardware trade-offs

In Section 6 (main.tex, lines 1201–1228), the authors candidly discuss the operational trade-offs of deploying DeepSeek-V3:

  1. Minimum weight memory vs. production deployment scale:
    • Raw checkpoint size: In native 8-bit E4M3 (plus 128×128128 \times 128 FP32 block scales), the 671B main model occupies roughly 671 GB671\text{ GB} (or ∼685 GB\sim 685\text{ GB} with the 14B MTP module). Dequantized to 16-bit BF16, the weights double to ∼1.34 TB\sim 1.34\text{ TB}.
    • Small-scale self-hosting (16 GPUs): Because two 8-GPU H800/H100 nodes provide 16×80 GB=1,280 GB16 \times 80\text{ GB} = 1{,}280\text{ GB} of HBM, a team can load and run the native FP8 checkpoint on 2 nodes (16 GPUs) with ample room for MLA KV caches—or quantize the weights further (e.g., to INT4/FP4 at ∼340 GB\sim 340\text{ GB}) to fit on a single 8-GPU node.
    • High-throughput cloud serving (32-GPU prefill + 320-GPU decode): On 16 GPUs, each GPU must stream 16 routed experts plus the shared expert out of HBM on every decode step, limiting single-stream token generation speed. DeepSeek's production cloud service scales out to 320 GPUs for decode so each GPU holds just 1 expert per layer—achieving more than 2×2\times the end-to-end generation speed of DeepSeek-V2 while serving massive concurrent user traffic.
  2. Choosing how to run V3 in practice:
    • For teams with low-to-moderate request concurrency, calling a hosted API (which amortizes the 320-GPU decode pool across thousands of customers) is far cheaper and lower-latency than running a dedicated cluster.
    • For teams requiring on-premise data privacy, 2 nodes of 8×\timesH100/H200 (FP8) or 1 node of 8×\timesH200 (1,128 GB HBM in FP8) can host the full unquantized FP8 checkpoint, using MLA's compact 70.3 KB/token70.3\text{ KB/token} cache to support long contexts and enabling the MTP head for a ∼1.8×\sim 1.8\times speculative decoding boost at low batch sizes.

Sources: Report §1 (main.tex, lines 186–208) for the GPU-hour and cost breakdown; §3.4 for prefill/decode cluster architecture; §6 (main.tex, lines 1201–1228) for deployment limitations and future directions. Continue to Chapter 26: One Request and One Training Step.

26. One Request and One Training Step

To see how all the mechanisms in this book interlock at runtime, this chapter traces two concrete workflows from start to finish: first, an 8,000-token user request flowing through DeepSeek-V3's disaggregated prefill and decode serving stack; second, a 62.9M-token global training batch flowing through one optimizer step of the 2,048-GPU DualPipe + FP8 pre-training engine.


Trace A: One 8,000-token user request at inference time

Suppose a developer sends a prompt containing a technical specification and a Python module—which tokenizes into S=8,000S = 8{,}000 tokens—and asks DeepSeek-V3 to diagnose a bug and write a patch.

1. Tokenization and embedding lookup (Prefill cluster: 32 GPUs)

The request lands on a 32-GPU (4-node) prefill unit configured with TP4 + SP and DP8 for attention, and EP32 for MoE layers (Chapter 21). The byte-level BPE tokenizer maps the string into 8,0008{,}000 integer IDs in {0,…,129,279}\{0, \ldots, 129{,}279\}. On the assigned data-parallel attention group, the embedding table maps each ID to a vector ht(0)∈R7168h_t^{(0)} \in \mathbb{R}^{7168}, yielding an initial activation tensor of shape 8,000×7,1688{,}000 \times 7{,}168.

2. Multi-head Latent Attention across 8,000 prompt tokens

At Layer 1 (and every subsequent layer ℓ∈{1,…,61}\ell \in \{1, \ldots, 61\}), RMSNorm normalizes hth_t, and the MLA down-projections compress each token into:

Because prefill has 8,0008{,}000 tokens available in parallel, the 4 tensor-parallel attention GPUs (32 heads per GPU) expand qC,qR,kC,vCq^C, q^R, k^C, v^C across their 32 local heads, run FlashAttention over the 8,000×8,0008{,}000 \times 8{,}000 lower-triangular causal mask, and project the concatenated head outputs back to R7168\mathbb{R}^{7168} via WOW^O. Only the compact 576-element state [ctKV;ktR][c_t^{KV}; k_t^R] is written to the persistent KV cache.

3. Layers 1–3: Dense SwiGLU FFNs

In the first three layers, there is no router or All-to-All communication. Each GPU runs the dense SwiGLU FFN (d=7168→f=18,432→d=7168d = 7168 \to f = 18{,}432 \to d = 7168, using TP1 / DP32) directly on its local slice of prompt tokens and adds the result to the residual stream.

4. Layers 4–61: DeepSeekMoE with ping-pong micro-batch overlap

Starting at Layer 4, each token enters the DeepSeekMoE block:

  1. Routing: The router computes 256 sigmoid affinities si,t=sigmoid⁡(utTei)s_{i,t} = \operatorname{sigmoid}(u_t^T e_i), adds the frozen pre-training load-balancing biases bib_i, applies the top-4 node filter, selects the winning 8 routed experts StS_t, and computes the unbiased mixture weights gi,t=2.5⋅si,t/∑j∈Stsj,tg_{i,t} = 2.5 \cdot s_{i,t} / \sum_{j \in S_t} s_{j,t}.
  2. Overlapped All-to-All Dispatch: The prefill unit splits active work into two micro-batches (AA and BB). While micro-batch BB runs its compute kernels, micro-batch AA quantizes its token vectors to FP8 (1×1281 \times 128 tiles) and dispatches them across the 32 GPUs (using hierarchical IB →\to NVLink forwarding). Each GPU hosts 8 original routed experts plus 1 redundant replica of a hot expert (updated every 10 minutes from live traffic telemetry).
  3. Expert GEMMs and BF16 Combine: Each GPU runs grouped FP8 SwiGLU GEMMs for its 9 local routed expert slots alongside the shared expert, and combines the weighted BF16 outputs back to the originating token positions.

5. First output token and KV cache transfer to the Decode pool

After Layer 61 and the final RMSNorm, the output head projects position 8,0008{,}000's hidden state to 129,280129{,}280 logits, emitting the first response token x^8001\hat{x}_{8001}.

To hand the request off to the 320-GPU (40-node) decode unit, only the compact MLA cache has to move. Across all 61 layers, 8,0008{,}000 tokens in BF16 occupy:

8,000×61×576×2 bytes=562,176,000 bytes≈562.2 MB (decimal)≈536.1 MiB8{,}000 \times 61 \times 576 \times 2\text{ bytes} = \mathbf{562{,}176{,}000\text{ bytes}} \approx 562.2\text{ MB (decimal)} \approx 536.1\text{ MiB}

(instead of 32.0 GB32.0\text{ GB} under standard 128-head MHA!).

6. Autoregressive Decode with EP320 and MTP Speculative Decoding

On the 320-GPU decode cluster (TP4 + SP, DP80 for attention; EP320 with 1 expert per GPU for MoE), generation proceeds in speculative 2-token cycles (Chapter 22):


Trace B: One 62.9M-token optimizer step in pre-training

Now consider one steady-state optimizer step (say, around the 5T-token mark) on the 2,048-GPU H800 training cluster, configured with PP16 (DualPipe), EP64 (across 8 nodes), TP1, and ZeRO-1 (DP128 for dense weights, DP2 for expert weights).

1. Packing the 62.9M-token global batch

The data loader assembles 15,36015{,}360 sequences of length S=4,096S = 4{,}096 (62,914,56062{,}914{,}560 tokens total). Prior to packing, 10% of documents undergo Prefix-Suffix-Middle (PSM) Fill-in-the-Middle formatting (<|fim_begin|>...), and combined punctuation/newline tokens are randomly split to prevent token-boundary bias. Multiple documents are packed into each 4,096-token row without cross-sample attention masking.

2. DualPipe bidirectional micro-batch streaming

Across the 128 data-parallel chains (2,048/16=1282{,}048 / 16 = 128 GPUs per pipeline stage), each global step is sliced into micro-batches that enter the 16-stage pipeline from both ends simultaneously (Stream 1 flowing Rank 0→150 \to 15; Stream 2 flowing Rank 15→015 \to 0). Each GPU holds two mirrored layer chunks (e.g., Rank 0 holds Stage 0 and Stage 15 + MTP).

3. Inside an overlapped F&BF\&B chunk: 112 Compute SMs + 20 Comm SMs

In steady state, each GPU executes a paired Forward chunk (FF, from one micro-batch) and Backward chunk (BB, from another micro-batch):

4. Loss computation at Stage 15 (and physically co-located Stage 0)

When a micro-batch reaches the final layer (Stage 15, co-located on Rank 0 with Stage 0):

  1. The main output head computes next-token cross-entropy loss LMain\mathcal{L}_{\mathrm{Main}}.
  2. The depth-1 MTP module reads the shared embedding table Emb⁡(xi+1)\operatorname{Emb}(x_{i+1}) and shared output head OutHead⁡\operatorname{OutHead} directly from Rank 0's local HBM (zero cross-stage network transfer), computing LMTP=λLMTP1\mathcal{L}_{\mathrm{MTP}} = \lambda \mathcal{L}_{\mathrm{MTP}}^1 with λ=0.3\lambda = 0.3.
  3. The tiny sequence-level balance term LBal\mathcal{L}_{\mathrm{Bal}} (α=0.0001\alpha = 0.0001) is added, and backpropagation begins.

5. End-of-step ZeRO-1 update, bias feedback, and CPU EMA

Once all micro-batches finish their backward weight-gradient (WW) passes into the FP32 gradient accumulators:

  1. Gradient synchronization and clipping: Each DP group (DP128 for dense layers, DP2 for routed experts) runs ReduceScatter over InfiniBand to average gradients onto each rank's ZeRO-1 shard, clips the global gradient norm at 1.01.0, updates its shard of the FP32 master weights using BF16 AdamW moments (mt,vtm_t, v_t, with η=2.2×10−4\eta = 2.2 \times 10^{-4}), and broadcasts updated weights back via AllGather (quantizing updated master weights into 128×128128 \times 128 E4M3 blocks for the next step).
  2. Routing bias update: Across the 62.9M tokens (∼503.3M\sim 503.3\text{M} routed assignments), each MoE layer compares observed expert load ℓi\ell_i against uniform target load ℓtarget\ell_{\mathrm{target}} and updates bi←bi+γsign⁡(ℓtarget−ℓi)b_i \leftarrow b_i + \gamma \operatorname{sign}(\ell_{\mathrm{target}} - \ell_i) with γ=0.001\gamma = 0.001.
  3. Asynchronous CPU EMA: Over PCIe, the updated weights are blended asynchronously into the host CPU RAM copy of the Exponential Moving Average (θˉt\bar{\theta}_t) without stalling the next training step.

Sources: Integrated synthesis of Report §2 (MLA, DeepSeekMoE, MTP), §3 (DualPipe, IB/NVLink kernels, FP8 pipeline, recomputation, prefill/decode serving), and §4 (FIM, packing, AdamW schedules). Continue to Chapter 27: Reference, Questions, and Source Map.

27. Reference, Questions, and Source Map

This closing chapter consolidates the source provenance, paper-versus-release configuration differences, mathematical notation, chapter-to-TeX line mappings, glossary definitions, and worked review exercises for the entire book.

Source provenance

The primary reference throughout this book is the DeepSeek-V3 Technical Report (arXiv:2412.19437v2), revised February 18, 2025. The official TeX source archive (2412.19437v2-source.tar.gz) is preserved under src/content/docs/papers/dsv3/ with SHA-256 checksum:

7b9051eb58724bbbf2480d734593eaac2e0e165f14d45e23255c29b0e0bebcc8

Extracted TeX files include main.tex, commands.tex, deepseek.cls, content/fp8.tex, tables/base_evaluation.tex, tables/chat_evaluation.tex, and the original figures in figures/.

Supplementary implementation references come from the official DeepSeek-V3 GitHub repository pinned to commit:

9b4e9788e4a3a731f7567338ed15d3ec549ce03b

(August 28, 2025), preserved locally as reference/inference-model.py, reference/_README_WEIGHTS.md, and reference/_official-README.md, alongside reference/release-config.json retrieved from the official Hugging Face model repository. Full retrieval metadata and file hashes are recorded in source-manifest.json.

Paper vs. release configuration summary

Parameter / Detail Technical Report (2412.19437v2) Released Repo / config.json Technical explanation
Vocabulary size (VV) Stated as 128K (§4.1) vocab_size: 129280 128K is a rounded label; 129,280 is the padded matrix dimension (2020×642020 \times 64)
Context length Extended & tested to 128K (§4.3) max_position_embeddings: 163840 Config allocates a 160K RoPE ceiling; 128K (131,072131{,}072) is the trained/evaluated window
Weight init std (σ\sigma) σ=0.006\sigma = 0.006 (§4.2) initializer_range: 0.02 Report states actual training init; 0.02 is an unused default in the inference script
Routed scaling factor Omitted in schematic Eq. 12–16 routed_scaling_factor: 2.5 Inherited DeepSeekMoE multiplier applied to normalized top-8 affinities in Gate
Active parameters Rounded 37B (§1) Weight note: 36.7B; matrix sum: ~37.45B Depends on whether embedding lookup rows (0.93B) are counted in active parameters
Total checkpoint size 671B main model (§1) Repo headline: 685B (671B + 14B MTP) Weight note lists ~11.5B unique MTP weights + shared embedding/output head (~1.85B)
Arena-Hard win rate Table 6: 85.5 Section 5.3.1 prose: "over 86%" Minor editorial discrepancy between table and prose in the paper

Chapter-to-source map

Line numbers below refer to the extracted main.tex and content/fp8.tex files from 2412.19437v2-source.tar.gz:

Chapters Report Sections Local TeX / Reference Files
1, 25 §1 (Intro, Cost Table 1), §6 (Limitations) main.tex lines 151–267, 1201–1228
2–6 §2.1.1 (MLA), §4.2 (Hyperparameters) main.tex lines 270–332, 714–727; reference/inference-model.py (MLA)
7–8 §2.1.2 (DeepSeekMoE, Bias, Node cap), §4.5.2–4.5.3 main.tex lines 334–397, 737–744, 868–932; reference/inference-model.py (Gate, MoE)
9, 22 §2.2 (MTP), §4.5.1 (MTP ablation), §5.4.3 (Speculative decoding) main.tex lines 410–455, 825–866, 1193–1199
10–11 §4.1 (Corpus, BPE, Packing, FIM), §4.2 (Schedules) main.tex lines 692–744
12 §4.3 (YaRN 32K/128K extension, NIAH) main.tex lines 746–765
13–15 §3.1 (Cluster), §3.2.1 (DualPipe), §3.2.2 (IB/NVLink kernels), §3.5.1 main.tex lines 457–558, 632–658
16–17 §3.3.1–3.3.3 (FP8 framework, tiles/blocks, NC=128N_C=128), §3.5.2, App. B content/fp8.tex; main.tex lines 660–687, 1458–1486
18 §3.2.3 (Recomputation, CPU EMA, MTP co-location), §3.3.3 main.tex lines 560–577; content/fp8.tex
19 §5.1 (SFT & R1 distillation), §5.4.1 (Distillation ablation) main.tex lines 947–973, 1148–1179
20 §5.2 (Rewards & GRPO), §5.3.2 (RewardBench), §5.4.2 (Self-feedback) main.tex lines 975–1016, 1117–1143, 1181–1191
21 §3.4.1 (Prefill unit), §3.4.2 (Decode unit) main.tex lines 583–629
23 §4.4 (Base evaluations), §4.5 (Ablations), Appendix B tables/base_evaluation.tex; main.tex lines 767–944, 1458–1486
24 §5.3 (Chat evaluations, Arena-Hard, AlpacaEval 2.0) tables/chat_evaluation.tex; main.tex lines 1018–1143
26 End-to-end synthesis Integrated trace across §§2–5

Notation reference

Symbol Value in V3 Definition
LL 6161 Number of main Transformer layers (33 dense + 5858 MoE)
dd 7,1687{,}168 Hidden dimension of the residual stream
nhn_h 128128 Number of attention heads per layer
dhC,dhVd_h^C, d_h^V 128128 Per-head content query/key width and value width
dhRd_h^R 6464 Per-head rotary position (RoPE) query/key width
dcd_c 512512 KV latent compression dimension (ctKV∈R512c_t^{KV} \in \mathbb{R}^{512})
dc′d'_c 1,5361{,}536 Query latent compression dimension (ctQ∈R1536c_t^Q \in \mathbb{R}^{1536})
ctKV,ktRc_t^{KV}, k_t^R 512,64512, 64 The two vectors cached per token per layer in MLA (576576 scalars total)
Ns,NrN_s, N_r 1,2561, 256 Shared experts (11) and routed experts (256256) per MoE layer
KrK_r 88 Number of routed experts activated per token
ff 2,0482{,}048 Intermediate SwiGLU width of each expert (18,43218{,}432 in dense layers 1–3)
MM 44 Maximum number of nodes a token's routed experts may span in training
si,ts_{i,t} ∈(0,1)\in (0, 1) Unbiased sigmoid router affinity sigmoid⁡(utTei)\operatorname{sigmoid}(u_t^T e_i)
bib_i ∈R\in \mathbb{R} Per-expert load-balancing bias (used only in top-KrK_r selection)
gi,tg_{i,t} ∈R≥0\in \mathbb{R}_{\ge 0} Normalized gating weight derived from unbiased affinities si,ts_{i,t}
γ\gamma 0.001→00.001 \to 0 Bias update step size (0.0010.001 for first 14.3T tokens, 00 for final 500B)
α\alpha 0.00010.0001 (MoE) / 11 (YaRN) Complementary sequence balance coefficient (§2.1.2) or YaRN threshold (§4.3)
DD 11 Multi-Token Prediction depth (11 extra future token in V3)
λ\lambda 0.3→0.10.3 \to 0.1 MTP loss weight (0.30.3 for first 10T tokens, 0.10.1 for final 4.8T)
NCN_C 128128 Inner-dimension interval for promoting FP8 Tensor Core sums to FP32 registers
PP,EP,DP,TPPP, EP, DP, TP 16,64,varies,116, 64, \text{varies}, 1 Pipeline, Expert, Data, and Tensor Parallelism degrees in training
F,B,W,F&BF, B, W, F\&B — Forward, full Backward, Weight-grad, and overlapped Fwd-Bwd chunk times in DualPipe
G,Ai,ϵ,βG, A_i, \epsilon, \beta — Group size, normalized advantage, clipping ratio, and KL penalty weight in GRPO

Glossary of key terms

Worked review exercises

  1. Expert parameter and FLOP accounting: A single SwiGLU expert has d=7168d = 7168 and f=2048f = 2048. How many parameters does it contain, and how many multiply-add FLOPs are executed across the 9 active experts (1 shared + 8 routed) for one token in one MoE layer?
    • Solution: Each expert has 3df=3×7168×2048=44,040,1923df = 3 \times 7168 \times 2048 = 44{,}040{,}192 parameters (≈44.04M\approx 44.04\text{M}). At 2 FLOPs per multiply-add (6df≈88.08M6df \approx 88.08\text{M} FLOPs/expert), evaluating 9 experts costs 9×88,080,384=792,723,456 FLOPs≈792.72M9 \times 88{,}080{,}384 = 792{,}723{,}456\text{ FLOPs} \approx 792.72\text{M} FLOPs per token per layer.
  2. MLA KV cache sizing: How many raw bytes of BF16 MLA cache are required to store a 10,000-token conversation across all 61 layers?
    • Solution: Each token stores dc+dhR=512+64=576d_c + d_h^R = 512 + 64 = 576 BF16 scalars (1,1521{,}152 bytes) per layer. Across 61 layers and 10,000 tokens, 10,000×61×1,152=702,720,000 bytes≈702.72 MB10{,}000 \times 61 \times 1{,}152 = 702{,}720{,}000\text{ bytes} \approx 702.72\text{ MB} (0.654 GiB0.654\text{ GiB}).
  3. Bias selection vs. unbiased weighting: Suppose a top-2 router over 3 experts produces raw sigmoid affinities s=[0.7,0.6,0.5]s = [0.7, 0.6, 0.5] and current load-balancing biases are b=[0.0,−0.2,+0.2]b = [0.0, -0.2, +0.2]. Which two experts are selected, and what are their normalized weights gi′g'_i?
    • Solution: Adding biases gives selection scores s+b=[0.7,0.4,0.7]s + b = [0.7, 0.4, 0.7], so Experts 1 and 3 are selected. Their mixture weights use the unbiased affinities 0.70.7 and 0.50.5, yielding g1′=0.7/(0.7+0.5)≈0.583g'_1 = 0.7 / (0.7 + 0.5) \approx 0.583 and g3′=0.5/1.2≈0.417g'_3 = 0.5 / 1.2 \approx 0.417 (before multiplying by routed_scaling_factor = 2.5).
  4. Context extension attention scaling: Why do Stage 1 (1,920×32,7681{,}920 \times 32{,}768) and Stage 2 (480×131,072480 \times 131{,}072) of YaRN context extension process the exact same number of tokens per step (62,914,56062{,}914{,}560) yet require 4×4\times more causal attention pair evaluations in Stage 2?
    • Solution: Total causal pairs per step scale as B⋅S22=(BS)⋅S2B \cdot \frac{S^2}{2} = \frac{(BS) \cdot S}{2}. Holding total tokens BS=62.91MBS = 62.91\text{M} fixed while quadrupling SS from 32K to 128K quadruples the number of pairwise query-key dot products per step.
  5. Speculative decoding throughput: If the depth-1 MTP draft head achieves an acceptance rate of a=0.88a = 0.88 and a 2-token verification + draft cycle takes tcycle=1.04 t0t_{\mathrm{cycle}} = 1.04\,t_0 relative to a standard 1-token step t0t_0, what is the net tokens-per-second speedup?
    • Solution: Each cycle emits an expected 1+a=1.881 + a = 1.88 verified tokens in time 1.04 t01.04\,t_0, giving a net speedup of 1.88/1.04≈1.81×1.88 / 1.04 \approx \mathbf{1.81\times}.

Return to the Book Table of Contents or revisit Chapter 26: One Request and One Training Step.