Transformer Block
DeepSeek-V3
Hard · 🔒 Plus required
MLA + MoE combined block
Independent study note. Written from the public paper and official code. This is not TensorTonic Plus and does not reproduce their exercises, starter code, or tests. For the official version, subscribe on TensorTonic.
Overview
A DeepSeek-V3 block is a standard pre-norm Transformer residual pair whose two sublayers are not the usual multi-head attention plus dense MLP. Attention is always Multi-head Latent Attention (MLA). The feed-forward half is a dense SwiGLU MLP on a short prefix of layers and DeepSeekMoE on the rest. The paper keeps this skeleton so the model can cache a few hundred latent numbers per token instead of a full key/value tensor, while most of the parameter count lives in routed experts that a given token never touches. Production V3 has 61 such blocks; the first three use the dense MLP, the remaining 58 use MoE. The residual topology itself is ordinary: normalize, mix, add; normalize, mix, add.
How it works
Let (\mathbf{x}\in\mathbb{R}^{B\times T\times d}) be the residual stream at one layer, with (d=7168) in the 671B config. Both norms are RMSNorm with learnable gain and (\varepsilon=10^{-6}):
\mathbf{x}'=\mathbf{x}+\mathrm{MLA}(\mathrm{RMSNorm}(\mathbf{x})),\qquad \mathbf{x}''=\mathbf{x}'+\mathrm{FFN}(\mathrm{RMSNorm}(\mathbf{x}')).
MLA takes the normalized stream, compresses queries and the joint key/value state, applies decoupled RoPE on a 64-dimensional side channel, and writes an output of shape ((B,T,d)) through (W^{O}). The FFN branch is chosen from the layer index (\ell\in{0,\ldots,L-1}):
\mathrm{FFN}_{\ell}=\begin{cases} \mathrm{MLP}_{d\to d_{\mathrm{ff}}\to d} & \ell < N_{\mathrm{dense}},\\ \mathrm{MoE} & \ell \ge N_{\mathrm{dense}}. \end{cases}
The paper sets (L=61) and (N_{\mathrm{dense}}=3). Both MLP and every expert (shared or routed) are SwiGLU:
\mathrm{SwiGLU}(\mathbf{u})=W_{2}\bigl(\mathrm{SiLU}(W_{1}\mathbf{u})\odot W_{3}\mathbf{u}\bigr).
Dense layers use (d_{\mathrm{ff}}=18432). MoE layers use a much thinner inner width (d_{\mathrm{moe}}=2048), one always-on shared expert, and 256 routed experts of which (K_{r}=8) fire per token. The MoE residual in the paper already includes the incoming FFN input (\mathbf{u}_{t}) inside equation (12); the official Block instead adds that residual outside MoE.forward, so the module itself returns only shared-plus-routed expert outputs.
MLA and MoE do not share weights across layers. What they share is the residual width (d): MLA’s output projection and the FFN’s down-projection both land back in (\mathbb{R}^{d}), which is why the two halves compose without a reshape.
Official code
The block is Block in inference/model.py. Construction is:
self.attn = MLA(args)
self.ffn = MLP(dim, inter_dim) if layer_id < n_dense_layers else MoE(args)
self.attn_norm = RMSNorm(dim)
self.ffn_norm = RMSNorm(dim)
forward is two residual adds. Production numbers live in inference/configs/config_671B.json (n_layers=61, n_dense_layers=3, dim=7168). The ModelArgs defaults in the same file are a smaller demo (27 layers, one dense layer) used by the __main__ smoke test, not the 671B checkpoint.
Watch-outs
- Applying MoE on layer 0, or a dense MLP after layer 2, disagrees with both the paper and
config_671B.json. The switch is a strict prefix: (\ell < N_{\mathrm{dense}}), not a periodic pattern. - Do not add (\mathbf{u}_{t}) inside the MoE module if you already add it in the block. Double-counting the residual is a silent shape-correct bug.
- MLA’s softmax scale is (1/\sqrt{d_{h}+d_{h}^{R}}=1/\sqrt{192}), not (1/\sqrt{128}). Using the content-only head width under-scales the scores.
- Dense and MoE inner widths differ (
inter_dimvsmoe_inter_dim). Reusing 18432 for experts, or 2048 for the prefix MLP, changes both FLOPs and the loaded checkpoint layout.
Sources
- Paper: DeepSeek-V3 Technical Report, arXiv:2412.19437 (Sec. 2.1, Sec. 4.2)
- Code: deepseek-ai/DeepSeek-V3 (
inference/model.py,inference/configs/config_671B.json)