Memory: Kimi K3
on 512 GB200s
FP32 where training keeps its history. BF16 where the model computes. The hard part is understanding what is live at the same time.
Default case: full Kimi K3, PP8 / CP1 / TP1 / DP-shard64 / EP64, DistMuon plus AdamW, one 4K row per microbatch, and 64 microbatches in one 1F1B schedule. This is a training memory study, not an inference KV-cache calculator.
FP32 training does not mean FP32 GEMMs
In this recipe, the sharded resident parameter is the master weight. FSDP makes a BF16 compute view for forward and backward; the optimizer updates the FP32 resident shard. Do not count a separate, full-model BF16 master copy on every GPU.
| Object | Dtype | Lifetime / ownership |
|---|---|---|
| Resident / master parameter | FP32 | Storage shard; persists across updates |
| Forward/backward parameter view | BF16 | Unsharded over FSDP, but still local to PP and EP |
| Gradient reduction / accumulation policy | FP32 | Unreduced PP gradients can outlive one microbatch |
Optimizer-visible param.grad |
FP32 | Matches the FP32 resident parameter in this recipe |
| Muon momentum | FP32 | One tensor with the storage gradient's layout |
| AdamW first and second moments | FP32 | Two tensors for the small AdamW remainder |
| Model GEMMs / main activations | BF16 | Exceptions for selected pointwise arithmetic and statistics |
Muon needs one momentum, not two Adam moments
The first study counted 2,779,931,738,208 parameters. In this optimizer assignment, 2,777,072,664,576 use DistMuon and 2,859,073,632 use AdamW: about 99.897% versus 0.103%. Routed expert matrices alone are 97.94% of the model. Selecting 16 of 896 experts reduces compute per token, not the number of trainable weights or optimizer states we must store.
FP32 master + FP32 gradient + FP32 momentum
FP32 master + gradient + two FP32 moments
Update-state tally = 12 P_muon + 16 P_adam
= 33,370,617,153,024 bytes
= 30.35 TiB across the logical model
Ideal 512-way average = 60.70 GiB / GPU
This tally assumes all trainable parameters have gradients and optimizer state. It is not a measured peak or an assertion that every gradient exists throughout forward. It excludes BF16 compute views, unsharded accumulation, activations, padding, communication, and optimizer workspaces. The familiar “16 or 17 bytes per parameter” shortcut is not a universal memory law.
Twice the GPUs halves evenly distributed resident state. It does not automatically halve a gathered compute unit, microbatch activations, or NCCL workspace.
A memory lab, with its assumptions exposed
Pick a pipeline rank. The state ledger uses the actual 93-layer structure, including the first dense FFN, last MLA layer, embeddings, vision pathway, and output head. The backward budget adds explicitly modeled working sets. It is a planning model, not a substitute for measuring an implementation.
Full deferred gradients replace reduced shards in this phase; they are not added on top of an entire second gradient copy. Actual reduction can briefly overlap both and needs additional buffers.
| Allocation category | Modeled size | What the number means |
|---|
PP, EP, and FSDP divide different things
Own a model slice
Ranks 0–6 own 12 layers each; rank 7 owns the remaining nine. Embeddings and vision sit at the front, the output head at the back. Pipeline stages are not perfectly balanced, so a model-wide average hides the worst rank.
Own 14 experts per MoE layer
896 / 64 = 14. The 64 ranks exchange tokens, rather than all 512 ranks participating in one EP group. Dense attention and shared-expert weights are not divided by EP.
Shard the resident history
512 / PP8 = 64 ranks per pipeline stage. Dense master/gradient/state shards span those 64 ranks. EP already divides the expert bank by 64, leaving expert FSDP = 64 / 64 = 1: no further expert-storage division.
On one pipeline stage, let D = non-routed parameters and E = routed parameters. Resident parameters / GPU = D / dense_FSDP + E / (EP * expert_FSDP) BF16 gathered stage view = 2 * (D + E / EP) bytes At PP8 / EP64 / FSDP64: expert_FSDP = 1
Increasing EP at fixed PP and GPU count can shrink the expert compute slice while reducing the expert FSDP degree. It does not create additional aggregate HBM. And the 512 GPUs do not form one pooled allocation space: every rank must stay within its own device capacity.
64 microbatches do not mean 64 saved forwards
In ordinary 1F1B, a rank fills its local pipeline, then alternates forward and backward. Backward releases that microbatch's saved activations. With eight physical stages and enough microbatches, rank 0 can hold eight unfinished forwards; rank 7 needs only one. This is a logical schedule bound, excluding implementation-specific send/receive buffers and keepalives.
Peak unfinished forwards on rank r = min(microbatches, PP - r)
At the default shape, local packed tokens T = rows × context = 4096. One BF16 [T, 7168] stream is 56 MiB. Twelve
checkpointed layer inputs across five unfinished forwards on rank 3 give a boundary-input floor of 3.28 GiB. The growing AttnRes
bank and kernel workspaces are additional, not hidden inside that number.
Global tokens per update are DP × microbatches × rows × context: 64 × 64 × 1 × 4096 = 16,777,216. Increasing
microbatches beyond the 1F1B live-forward bound mostly extends the schedule; increasing rows or context increases each microbatch's
activation and routing footprint. Two 2K rows and one 4K row have the same flattened token count, but different document attention
boundaries.
KDA's fixed-size inference state does not make its training activations constant-size: token and chunk intermediates still need storage or recomputation. Varlen FlashAttention avoids materializing the full attention-probability matrix for MLA, but still needs Q/K/V, outputs, and backward statistics. Neither attention path has a zero activation-memory bill.
From a 30-TiB state bill to a local budget
Each step changes one ownership or activation assumption. The same FP32-master / FP32-state / BF16-compute policy is kept throughout. Component lengths below use a logarithmic axis; add the numeric values, not bar lengths.
A measured run is the capacity proof
The reference completed 12 updates with FP32 resident state, BF16 compute, PP8 / FSDP64 / EP64, full layer checkpointing, varlen attention, compiled pointwise regions, no CUDA graphs, and forced-balanced HybridEP routing. It demonstrates short-run feasibility of this specific configuration; it is not a general capacity guarantee or a convergence result. The fixed reference stays fixed when you change calculator controls.
The calculator deliberately does not label the gap between its subtotal and 146.18 GiB as “activation memory.” That would invent a decomposition. Some important reasons implementations exceed a state-only estimate:
Deferred PP gradients
Gradient accumulation can retain unreduced stage gradients until the schedule finishes. A reduced FP32 shard and an unreduced FP32 dense gradient differ by the FSDP factor. Repeated backward calls do not create 64 independent parameter-gradient histories.
Gather / reduction buffers
A casted input shard, all-gather output, compute view, and reduce-scatter input may briefly overlap. Retaining every in-flight buffer defeats an otherwise good memory budget. Resharding and bounded buffer lifetimes matter as much as dtype.
SiTU-GLU temporaries
Gate/up products cover routed assignments, not just original tokens. Eager FP32 pointwise intermediates occupy HBM. Compiling the pointwise region can fuse intermediates and shorten their lifetimes; it does not compress the FP32 master weights.
Muon working layouts
DistMuon redistributes shards into logical matrices before its update. The storage layout, compute layout, communication buffers, BF16 iteration copy, and Gram matrices have different lifetimes. Transient buffers avoid paying optimizer-only storage during model compute.
Memory outside PyTorch
NCCL can allocate workspace outside PyTorch's caching allocator. Unused cached blocks are not necessarily available to NCCL. Communicator initialization order and runtime connection policy can therefore change whether an otherwise identical run starts.
Graphs and precision shortcuts
CUDA graphs can retain private pools and captured buffers. BF16 reduction alone does not shrink FP32 master, optimizer-visible gradient, or momentum shards. Neither graph capture nor lower reduction precision is a free state-memory reduction.
Tensor allocation, allocator reservation, and total device usage are different measurements. The reported 38.13-GiB difference ignores external allocations and fragmentation. Check every PP rank and the first optimizer update, not only the first forward. Also check later iterations, when momentum and caches are populated.
Sources and accounting notes
- Kimi K3 technical report and released configuration: architecture and logical dimensions.
- TorchTitan Kimi K3 and DistMuon: parameter shapes, momentum storage, and Newton–Schulz computation. Optimizer assignments and lifecycle settings refer to the recipe analyzed here, not every upstream recipe.
- PyTorch FSDP and pipeline parallelism: mixed precision, sharded storage, and schedule concepts.
- Presentation inspired by Edward Yang's Hopper memory study. This page uses Kimi K3, GB200, Muon, and the stated FSDP/PP policy; it does not transplant DeepSeek's AdamW or DualPipe assumptions.
GiB = 230 bytes; TiB = 240 bytes. Structural totals match study 01. Shards are modeled by ideal division, ignoring per-tensor padding. Non-default PP splits are contiguous illustrative partitions, not validated launch recipes. The selected-activation model omits kernel-specific state and may include candidates an implementation aliases or recomputes. No internal run links, data paths, or cluster identifiers are included.