Notes on what the 2025–26 open-weight model reports say happens between the main pretraining run and fine-tuning: learning-rate decay and annealing, late data mixes, code and agent data, long-context extension, architecture retrofits, added vision and audio, mid-run changes to the optimizer and precision, and how labs check the result. Each chapter explains the method, works a real example, and gives the reasons the labs themselves stated.
Disclaimer: This blog is compiled and edited with help from LLMs. Every number links to the public document it came from, so please check the source before citing it.
This is Part 2 of Reading Open-Weight Recipes, a series where I review what open-weight model releases have written down about their training recipes between December 2024 and October 2026. The atlas indexes the disclosures lab by lab; these notes go through what happens between the main pretraining run and fine-tuning, one phase at a time, with the mechanism, a worked example using numbers from a released model, and the reasons the labs themselves gave.
The same caveats as the rest of the series apply. Everything here comes from the public reports of open-weight releases (plus Microsoft AI's reports, whose models are mostly closed-weight), so it describes what those labs chose to disclose. It is not a description of how frontier closed models are trained, and where a report is silent I don't fill the gap. These are personal notes, not written for, reviewed by, or endorsed by any lab covered here.
After a base model has read trillions of tokens, what do labs still change before fine-tuning begins, and why has that late stretch of training become a stage of its own?
Between the main pretraining run and supervised fine-tuning sits a stage that labs call mid-training, annealing, cooldown, context extension or continued pre-training. In 2024 it was mostly a short patch to stretch the context window: DeepSeek-V3 spent under 1% of its tokens on it. By 2026, in the reports reviewed here, it had grown into the place where labs reshape a base model for what comes next:
For DeepSeek V4.1-Flash, these notes count more than a third of all training tokens as midtraining.
These notes follow the same format as the pretraining notes and the posttraining notes. Each chapter opens with the question it answers, explains the method with a diagram, equations and short pseudocode, works a real example, quotes the labs' own reasons, and ends with trade-offs, three takeaways and two check-yourself questions. Underlined numbers link to their source; hover them for the exact quote.
The notes assume you know how a transformer is trained with next-token prediction and what a learning-rate schedule is. Rotary position embeddings, mixture-of-experts layers, sparse attention, vision encoders and the Muon optimizer are introduced in the pretraining notes; these notes link back to it and go further only where midtraining changes something. The core models and labs are those of the pretraining notes, whose roster lists each model's size and release date. Qwen, MiniMax, StepFun, Ant's Ling, NVIDIA's Nemotron and Mistral, which the atlas added later, come in where their reports change or sharpen a point.
Labs draw the line differently, so these notes use one rule for every release; chapter 00 explains it and sorts real phases with it. In short:
When a lab's own label differs from this rule, the chapters say both.
The chapters follow a few model families through several releases. Sizes are total / active parameters per token.
| Family | Releases | How they relate |
|---|---|---|
| DeepSeek | V3 (Dec 2024, 671B / 37B); V3.1 and V3.1-Terminus (Aug–Sep 2025); V3.2-Exp and V3.2 (Sep–Dec 2025); V4-Pro and V4-Flash (Apr 2026, 1.6T / 49B and 284B / 13B); V4.1-Flash (Sep 2026, 552B plus 196B of lookup memory, 16B active) | V3.1 continues V3 with longer context; V3.2 retrofits sparse attention onto V3.1-Terminus; V4 and V4.1-Flash are new models trained from scratch |
| Kimi (Moonshot) | K2 (Jul 2025, 1.04T / 32B); K2.5 (Jan 2026); K3 (Jul 2026, 2.8T / 104B); K3.1 Pro (Oct 2026) | K2.5 continues a near-final K2 checkpoint with vision; K3.1 Pro shares K3's training stages |
| GLM (Z.ai) | GLM-4.5 (Jul 2025, 355B / 32B); GLM-5 (Feb 2026, 744B / 40B); GLM-5.2 (Jun 2026) | GLM-5.2 keeps GLM-5's dimensions |
| MiMo (Xiaomi) | MiMo-7B (Apr 2025, dense); MiMo-V2-Flash (Dec 2025, 309B / 15B); V2.5 and V2.5-Pro (Apr 2026, 310B / 15B and 1.02T / 42B); V2.6-Flash and V2.6-Pro (Sep 2026, same sizes as V2.5) | V2.5 adds vision and audio; V2.6 adds an omni stage and agent-centric midtraining (whether its text backbone is a new run is not stated) |
| MAI (Microsoft AI) | MAI-Thinking-1 (Jun 2026), built on the base model MAI-Base-1 (962B / 34.7B) | the report covers pretraining, midtraining and posttraining of one model |
| Symbol | Meaning | Symbol | Meaning |
|---|---|---|---|
| η, ηmax, ηmin | learning rate; its peak and final values | D | training tokens |
| L, L′ | trained context length; target length | s = L′/L | context scale factor |
| b | RoPE base | dh, dr | head dimension; rotated dimensions per head (dr = dh when the whole head rotates) |
| θi = b−2i/dr | rotary frequency of dimension pair i | λi = 2π/θi | its wavelength: tokens per full turn |
| wk | mixture weight of data source k | B | batch size, in tokens unless stated |
Token counts use B for billion and T for trillion. Other symbols are local to the chapter that defines them. In stage figures, neutral grey marks pretraining and peach marks midtraining.
Chapters 00 and 01 give the map: what midtraining is, how it grew, and why the low-learning-rate phase at the end of training matters so much. Chapters 02 and 03 cover what data goes in late: the mix, and the code and agent data that 2025-26 models added. Chapters 04 and 05 cover long context; the playground after chapter 04 shows what each RoPE scaling method does to every rotary dimension. Chapters 06 to 08 cover changes to the model itself: new attention, added vision and audio, and switching the optimizer or precision partway through. Chapter 09 covers how labs check a midtrained base and what they leave out, and chapter 10 follows three labs end to end. For which lab adopted what and when, see the midtraining section of the atlas.
What happens between the main pretraining run and fine-tuning, and why did it grow from a 126B-token context patch in DeepSeek-V3 (0.8% of its tokens) to 17T in DeepSeek V4.1-Flash (38%) and about half of Kimi K2.5's training?
A language model is built in three stages. Pretraining starts from random weights and trains next-token prediction on a large general corpus of web text, code, books and papers. Posttraining comes last: supervised fine-tuning (SFT, training on example responses) and reinforcement learning (RL, training on rewards for the model's own outputs) teach the model how to answer, reason and use tools. Midtraining sits between them. The loss is still next-token prediction on documents, but the recipe changes: smaller, targeted data, longer sequences, a low learning rate η (the factor that scales each weight update), and sometimes new modules such as a vision encoder.
The report on GLM-4.5, Z.ai's 355B-parameter mixture-of-experts (MoE) model, states the idea plainly: after pre-training it adds stages that use "medium-size domain-specific datasets, including instruction data", and it names them mid-training.
Labs use different words for these phases: mid-training (GLM, MAI, Meta, MiMo, DeepSeek V4), annealing (Kimi K2), cooldown (Moonlight, Kimi K3), learning-rate decay stage (DeepSeek V4.1-Flash), context extension (DeepSeek-V3) and continued pre-training (DeepSeek V3.2-Exp). To compare releases, these notes apply one rule to every lab. The idea behind it: midtraining is a deliberate change of recipe after the main run, not just the tail of a learning-rate schedule. A phase shows that intent in one of three ways: the lab names it as a phase, it changes the data or the context after the main decay, or it continues training a model that was already trained. In full:
Figure 0.1 lays the rule out with an example under each entry.
The rule sometimes overrides the lab's own label. Four cases show how it sorts real phases:
Why not count every learning-rate decay? A literal "any decay" rule would add about 4.8T to DeepSeek-V3 and 5.5T to Kimi K2, but nothing to labs that run one cosine from the first step (GLM, MAI). The count would then measure the shape of a schedule rather than a deliberate change of recipe.
MID_NAMES = {"mid-training", "annealing", "cooldown", "learning-rate decay stage",
"context extension", "continued pre-training"}
def stage(phase, main_decay_end):
if phase.kind in ("SFT", "RL"):
return "posttrain"
if phase.lab_name in MID_NAMES: # clause (1)
return "midtrain"
if phase.start >= main_decay_end and (phase.new_mix or phase.new_context):
return "midtrain" # clause (2), e.g. MiMo-7B stages 2 and 3
if phase.continues_earlier_base: # clause (3): released model or earlier checkpoint
return "midtrain"
return "pretrain" # incl. in-schedule decay, unnamed length growth
def midtrain_share(phases, main_decay_end):
lm = [p for p in phases if not p.encoder_only] # tokens must pass through the LM
pre = sum(p.tokens for p in lm if stage(p, main_decay_end) == "pretrain")
own = sum(p.tokens for p in lm
if stage(p, main_decay_end) == "midtrain" and not p.inherited)
return own / (pre + own) # inherited pretraining counts in pre; inherited midtraining does not
What do labs do in these phases? Labeling each phase by its main purpose gives seven kinds. A phase that does two things is counted once, under its main purpose: GLM-4.5's 128K stage with synthetic agent trajectories is a long-context phase. The counts come from a cross-lab grid that codes 68 releases from the labs these notes started with (the "coded releases"). Of them, 27 describe a midtraining recipe of their own; the rest are refreshes that reuse a parent's phases, releases that describe none, and a few where the question does not apply (the table in the disclosure section below lists them). Among the 27, the number of releases with each kind:
The six labs the atlas added later are not in these counts. Their reports mostly add cases to the same kinds, among them more retrofits (Qwen's sparse attention and Ling's hybrid linear attention, ch06) and more agentic stages (StepFun, NVIDIA, ch03). One kind is new: training an existing base on a larger model's logits, as NVIDIA does for both Nemotron 3.5 models; Mistral distills its Ministral 3 models from Mistral Small 3.1 the same way after pruning them from it (ch06).
To compare releases of different sizes, these notes measure midtraining as a share of the tokens a release was trained on:
A release that pretrains on 9T tokens and then midtrains on 1T has a share of 1 / (9 + 1) = 10%. Two details matter for real releases. Dpre includes pretraining inherited from a parent model, while Dmid counts only the release's own midtraining tokens. And only tokens that pass through the language model count, so a vision encoder trained on its own is left out. Figure 0.2 applies the measure to nine releases, in release order and to scale.
In tokens, the growth runs from billions to trillions:
Part of this rise is labeling. The rule follows what a lab names as a phase, and three DeepSeek generations land on different sides of that line:
Growth is not monotone. MiMo-7B already put a quarter of its tokens into stages 2 and 3 in April 2025, while GLM-5, Z.ai's 744B MoE, spent 5.5% in February 2026.
DeepSeek V4.1-Flash. One run of 45T tokens: pretraining at a constant η to 28T, the named learning-rate decay stage from 28T to 34T, then the 1M extension from 34T to 45T.
Dpre = 28T; Dmid = (34 − 28) + (45 − 34) = 6 + 11 = 17T; share = 17 / (28 + 17) = 17 / 45 = 37.8%.
MAI-Thinking-1. Main pretraining 30T; mid-training phase 1 3.4T at 65,536 context; phase 2 150B at 262,144.
Dmid = 3,400 + 150 = 3,550B; share = 3,550 / (30,000 + 3,550) = 3,550 / 33,550 = 10.6%.
The labeling effect. DeepSeek-V3's two context phases total about 125.8B tokens (ch05 derives the count), so its share is 125.8 / (14,800 + 125.8) = 0.84%. V3 also decayed η over 4.3T tokens and held it low for 500B more, but inside its main schedule and without naming a stage. Counted the way V4.1-Flash's named stage is, those 4.8T would give (4,800 + 125.8) / 14,925.8 = 33%.
Why did so much work move into this late stretch, rather than into pretraining or a new run? The reports and papers give four reasons.
The last data have an outsized effect. When η decays, the loss falls fastest: MiniCPM saw it drop sharply as soon as the decay began. Putting data there also beats saving it for SFT: mixing high-quality and SFT data into a 2.4B model's decay raised MMLU from 44.6 to 50.9 after identical SFT. Chapter 01 shows why.
It costs a fraction of a new run. A change made late needs only the late tokens. DeepSeek gave a V3.1-Terminus checkpoint sparse attention (creating V3.2-Exp) with 945.8B tokens of continued training instead of a new 14.8T run.
Long sequences are cheapest at the end. A token in a long sequence costs more than one in a short sequence, because standard attention compares it with every earlier token: DeepSeek-V3's context extension used several times more GPU-hours per token than its pretraining (ch05 works out the numbers). Llama 3's report gives this as the reason to train on them only at the end: "the compute in self-attention layers grows quadratically in the sequence length". Kimi says of K3's context curriculum, which reaches 256K and 1M only in its cooldown, that "concentrating the costly long-sequence computation within a small fraction of the overall training budget keeps the curriculum economical".
It prepares the base for RL. MiMo V2.6 switched its optimizer from AdamW to Muown, a Muon variant, during mid-training "to prepare the model for subsequent large-batch RL", and started quantization-aware training there, training with the forward pass in the low-precision number format the model will later run in, so it adapts to it (ch08).
"In mid-training we further emphasize STEM, math, and coding abilities to build a strong foundation for reasoning RL climbs."
"We further introduce an agent-centric mid-training phase that expands the exploration space for agentic tasks, enabling the model to discover more effective task-solving trajectories during post-training."
Meta gives similar reasons: the first phase of Muse Glimmer, Meta's 30B on-device model, adds synthetic and domain data "to improve the starting point for post-training", and Llama 4's mid-training aimed "to improve core capabilities", including long context. Some labs state what they did without saying why. Kimi K2's report says only that "towards the end of pre-training, we conducted an annealing phase", with no reason and no description of its data.
The 68 coded releases fall into four groups:
| Group | Count | Releases |
|---|---|---|
| Own midtraining recipe | 27 | DeepSeek-V3, Prover-V2 (its 7B model's 4K → 32K extension), V3.1, V3.2-Exp, V4, V4-Flash-Vision-Exp, V4.1-Flash; Moonlight, Kimi-VL, Kimi K2, Kimi Linear, K2.5, K3; GLM-4.1V-Thinking, GLM-4.5, GLM-4.5V, GLM-4.6V, GLM-5, GLM-5.2; MiMo-7B, MiMo-VL-7B, MiMo-V2-Flash, V2.5, V2.6; MAI-Thinking-1; Llama 4, Muse Glimmer |
| Refresh that reuses a parent's phases | 13 | DeepSeek R1, V3-0324, R1-0528 (V3's phases); V3.1-Terminus (V3.1); Math-V2, V3.2 (V3.2-Exp); V4-DSpark, V4-Flash-0731, V4-Pro-0813 (V4); V4.1-Flash-1017 (V4.1-Flash); Kimi K3.1 Pro (K3); GLM-5.3 (GLM-5.2); MiMo V2.6-MOPD (V2.6) |
| Describe no midtraining | 25 | Kimi K2-0905, K2 Thinking, K2.6, K2.7 Code; GLM-4-0414, GLM-Z1-0414, GLM-4.6, GLM-4.7, GLM-4.7-Flash, GLM-5.1, GLM-5.3-Flash; MiMo V2.5-Pro; Gemma 3 (its 32K → 128K step is pretraining under the rule), Gemma 3n, Gemma 3 270M, Gemma 4, Gemma 4 12B; MAI-1-preview, MAI-Base-2; Inkling, Inkling-Small; gpt-oss, gpt-oss-safeguard; Llama 4 Behemoth, Muse Spark Open |
| Not applicable | 3 | MAI-DS-R1 (posttrains DeepSeek-R1), the Gemma 4 assistant drafters, MiMo V2.6-Distill-Qwen-9B (a distilled student) |
So 40 releases describe some midtraining (27 recipes plus 13 refreshes), 25 describe none and 3 have none of their own to describe. Among the 25 are recent major releases such as Gemma 4, Inkling, MAI-Base-2, gpt-oss and Muse Spark Open. All six labs added to the atlas later describe some midtraining, so 11 of the atlas's 13 labs do; Gemma and Thinking Machines are the two that do not.
What is described is often thin:
No. It is the decay inside K2's main learning-rate schedule, and Kimi itself calls it pre-training. Only the named 400B annealing phase and the 60B long-context phase that follow count as midtraining.
Dmid = 500 + 500 + 100 = 1,100B; share = 1,100 / (22,000 + 1,100) = 1,100 / 23,100 ≈ 4.8%, the value in Figure 0.2.
Why do labs put their best data in the final, low-learning-rate stretch of training, and how do short anneals tell them which data deserves to be there?
The decay phase is the end of a learning-rate schedule, where the learning rate η falls from its peak ηmax toward a floor ηmin. Labs also call it annealing or cooldown, and often change the data at the same time. The pretraining notes cover warmup, cosine and warmup-stable-decay (WSD) schedules in more detail (pretraining notes, ch 09).
Every schedule warms up briefly to ηmax and ends low; what differs is when the fall happens (Figure 1.1):
Two observations seem to clash. Each optimizer step moves the weights by an amount that scales with η: MiniCPM measured the largest element-wise weight change between checkpoints of a 2.4B model and found that "the updates exhibit a robust correlation with the learning rate's magnitude". Yet the loss barely moves while the steps are large and drops fast once they shrink. MiniCPM saw large updates with little loss reduction before the decay, and an accelerated decrease during it; Hägele et al. found the drop "aligns closely with the decay in LR".
Wen et al. explain this with a river valley picture of the loss surface: a few steep directions (the valley walls) and a flat direction along the valley floor (the river). At high η the weights "undergo large oscillations" across the walls while moving quickly along the river, so the loss stays high even as the weights make progress. Decay calms the oscillation, "revealing true optimization progress".
The river valley explains why the loss drops during the decay, not which data the final weights remember. A simple picture does: each step pulls the weights part of the way toward what its batch prefers, and every later step pulls again, partly erasing the earlier pulls. A batch's say in the final weights therefore depends on two things:
With easy numbers: if every step pulls 5% of the way, then 100 steps later 0.95100 ≈ 0.6% of a batch's pull is left; at 0.2% per step, 0.998100 ≈ 82% is left. Big pulls are forgotten quickly, small ones remembered for long.
A one-parameter toy model makes this precise. Take one weight p and a quadratic loss per batch, ℓt(p) = ½ h (p − mt)², where mt is the value batch t prefers and h is the curvature: a large h is a steep valley wall, a small h the flat floor. After N gradient steps, p is a weighted average of the batches' preferred values, and batch t gets the weight
A gradient step on ℓt gives
so SGD here is a moving average of the batches' preferred values with rate αt. Unrolling it over N steps:
The approximation uses 1 − α ≈ e−α for small α, so a product of (1 − αu) becomes e to the minus their sum; Figure 1.2 and the code use the exact product. The weights ct sum, with the leftover on p0, to 1.
In a steep direction (large h) only the last stretch survives, and after a decay that stretch is the decay data. In a flat direction the average spans the whole run. Figure 1.2 runs it on a WSD schedule with the same two pull sizes at peak η: the decay supplies 99.4% of the final value in the steep direction and 18% in the flat one.
def final_weights(etas, h):
"""Weight c[t] of batch t's preferred value in the final parameter (toy SGD)."""
c, keep = [0.0] * len(etas), 1.0
for t in reversed(range(len(etas))):
a = etas[t] * h
c[t] = a * keep # its pull, shrunk by every later step
keep *= 1 - a
return c, keep # sum(c) + keep == 1; keep stays on p_0
etas = [1.0] * 800 + [1 - k / 200 for k in range(200)] # WSD, peak 1
for h in (0.05, 0.002):
c, keep = final_weights(etas, h)
print(h, round(sum(c[800:]), 3)) # 0.994, 0.182
The model is illustrative: it assumes a fixed quadratic loss and plain SGD. Adam rescales each coordinate's step, but MiniCPM trained with Adam, and its step sizes still tracked η.
Experiments show the same effect. MiniCPM mixed high-quality and SFT data into a 2.4B model's decay; after the same SFT, MMLU rose from 44.6 to 50.9 and GSM8K from 27.7 to 42.3, and the authors recommend that capability work "should start from the decay phase". OLMo 2 calls its final stage mid-training, at 5–10% of training FLOPs; for the 7B it raised the benchmark average from 53.0 to 62.9 and GSM8K from 24.1 to 67.5, though its mid-training mix includes the GSM8K training split.
A decay has a shape and a length. For the shape, let x run from 0 at the start of the decay to 1 at its end; over a decay of Nd steps ending at step N:
A quarter of the way through (x = 0.25), linear decay is at 0.75 ηmax and 1−sqrt already at 0.5 ηmax; halfway, they are at 0.5 and 0.29. So 1−sqrt drops η quickly at first and spends longer near zero (Figure 1.1). A linear decay to zero is common in short anneals (Llama 3, OLMo 2, Moonlight's cooldown). Hägele et al. found that the 1−sqrt shape "consistently performs better than linear decay".
On length, MiniCPM found 10% of tokens enough and 2.5% short; Hägele et al. saw gains plateau at around 20%, and a 5% (1−sqrt) decay nearly matched cosine on a 20B-token run.
Because the decay phase reacts strongly to its data, a short anneal on a candidate dataset is a cheap way to judge it. The procedure:
Llama 3 took a 50%-trained 8B model, annealed η linearly to 0 over 40B tokens, and gave the new dataset 30% of the mix, which it found "more efficient than performing scaling law experiments for every small dataset". The gains can shrink with scale: annealing on GSM8k and MATH training data raised Llama 3 8B's validation scores by 24.0% and 6.4%, but the 405B gain was negligible.
def anneal_test(ckpt, candidate, default_mix, tokens=40e9, share=0.3):
"""Llama 3 recipe: 50%-trained 8B checkpoint, linear decay to 0 over 40B tokens."""
mix = {candidate: share, default_mix: 1 - share}
model, eta0 = copy(ckpt), ckpt.lr
steps = int(tokens / ckpt.batch_tokens)
for k in range(steps):
model.lr = eta0 * (1 - k / steps) # linear anneal to 0
model.step(sample(mix))
return evaluate(model) # compare with the same anneal on default_mix alone
OLMo 2 made this cheaper still with microanneals: short anneals of one candidate source mixed with general web text, with η driven to zero as in a full anneal. Its default takes equal amounts of candidate and web data (50/50), and it also varied the ratio (ch02 gives that result). 19 of them cost 130B tokens, less than three full 50B anneals. MAI tuned MAI-Thinking-1's mid-training weights "according to single-source microanneals".
Figure 1.3 draws six published schedules to scale. They show three ways to place midtraining around the decay; a fourth, re-warming, restarts from a decayed model.
Decay inside pretraining, then midtraining at a low η. DeepSeek-V3 ended pretraining at 7.3×10−6 and ran its two context phases at that rate, "matching the final learning rate from the pre-training stage". MiMo-7B held 3×10−5 through stage 2 and most of stage 3, then decayed to 1×10−5. Kimi K2's 5.5T cosine stays in pretraining under the rule; its annealing and long-context phases (400B + 60B) took η from 2×10−5 to 7×10−6, and the report describes neither the data nor a reason.
One cosine through midtraining. GLM-4.5 decays from 2.5×10−4 to 2.5×10−5 until the end of mid-training. MAI-Thinking-1's main cosine ends at 2×10−5; its mid-training phase 1 continues from 2×10−5 to 1×10−5 without warmup, and phase 2 runs at 1×10−6.
A named decay stage. DeepSeek V4.1-Flash holds η at 2.6×10−4 to 28T tokens. Its named learning-rate decay stage covers 28T to 34T; η keeps falling during the 1M extension (34T to 45T) until it reaches 2.6×10−5 at 40T and is then held. When the decay starts at 28T, the vision encoder is unfrozen. MiniMax named such a stage much earlier: MiniMax-Text-01 (Jan 2025) closed its main run with a 1T-token "fast decay phase" that took η exponentially to 3×10−5, and MiniMax M2 (Oct 2025) spent its last 9.3T tokens in a decay phase that also grew the context from 8K to 192K.
Re-warming a decayed model. Moonlight, after a full cosine, raised η to 1×10−4 in 100 steps, then decayed linearly to 0 over 500B tokens of "the highest quality data, focusing on math, code, and reasoning". Moonlight is not in the figure, and neither is Muse Glimmer, which runs both mid-training phases below the pretraining peak and gives no values.
Averaging is another way to calm the oscillation: at a constant high η, nearby checkpoints scatter around the valley floor and their average lands closer to it, since "averaging reduces noise". The uniform average of the last K checkpoints, spaced Δ steps apart and ending at step N, is
With K = 4 and Δ = 600, that is steps N, N − 600, N − 1,200 and N − 1,800. Hägele et al. found weight averaging narrows the gap to a cooldown without closing it, and ByteDance found averages of constant-η checkpoints a "low-cost simulator for the annealed performance". Labs use averaging for four different jobs:
The toy model says a phase can rewrite a direction only if its learning-rate area is large next to 1/h. Area is steps × mean η (warmup ignored), and the mean of a cosine from ηa to ηb is (ηa + ηb)/2. All phases use a batch of 134M tokens.
Main pretraining: cosine 2×10−4 to 2×10−5 over 30T tokens, mean 1.1×10−4: 30×1012 / 134×106 = 223,881 steps × 1.1×10−4 = 24.6.
Phase 1: mean 1.5×10−5; 3.4T tokens = 25,373 steps × 1.5×10−5 = 0.381. Phase 2: 150B tokens = 1,119 steps × 1×10−6 = 0.0011.
Total 25.0. Midtraining is 3.55 / 33.55 = 10.6% of tokens but (0.381 + 0.0011) / 25.0 = 1.5% of the learning-rate area. In the toy model, phase 1 rewrites only directions with h × 0.381 well above 1, that is h ≫ 2.6; flatter directions keep what pretraining put there.
"decays along a cosine schedule from a peak of 2×10−4 to a minimum of 2×10−5—a final-to-peak ratio of 0.1× rather than the more common 0.01× as we found that decaying the LR less improved post-RL results."
"Our early experiments showed that models trained with the WSD schedule perform worse on general benchmarks (SimpleQA, MMLU), indicating underfitting in the stable stage."
"The learning rate we use for this phase is lower than the peak pre-training learning rate, so as to to balance gains on synthetic-data objectives against acceptable regression on organic perplexity benchmarks."
Its weight is about ηt h · exp(−h At). After an early batch, the learning-rate area At still to come is large, so for large h the exponential is near zero: later steps overwrite it. Batches in the decay face a small At and survive.
Its mean η is far lower: 1.5×10−5 in phase 1 and 1×10−6 in phase 2, against 1.1×10−4 for the 30T-token main cosine. Area is steps × mean η, so 0.38 of a total 25.0.
When a lab starts a midtraining phase with a fixed token budget, which data does it raise in the mix, by how much, and how does it keep the model from losing what pretraining taught it?
A midtraining phase has a fixed token budget, so every token given to one source is taken from another. Raising the share of math or code is the point of the phase, but it pulls against two costs:
The sections below work out the arithmetic of repetition, show what labs raise and by how much, and then turn to replay and to how the weights are chosen.
A corpus is split into sources such as web text, code, math and books. The mixture weight wk is the fraction of a phase's tokens drawn from source k (∑k wk = 1). For a phase of Dphase tokens and a source with Uk unique tokens, three numbers follow from it:
Upweighting a source means raising wk above its pretraining value, so uk > 1. With easy numbers: a 1T-token phase that gives math 20% takes 200B math tokens; if the math source holds 100B unique tokens, that is 2 epochs, and if pretraining gave math 5%, math is upweighted 0.20 / 0.05 = 4 times. Good sources are small, so a large wk often means ek > 1: repetition.
Repetition has a limit. In runs up to 9B parameters, Muennighoff et al. found that up to 4 epochs of repeated data changed loss negligibly compared with unique data, while with more repetition the value of extra compute eventually decays to zero. MAI caps every dataset at 8 repetitions in its pretraining mix search, and its ~300B tokens of high-quality math were already seen 5.28 times on average before midtraining. Xiaomi reports one exception: in its preliminary experiments, synthetic reasoning data could be trained for an extremely high number of epochs without overfitting.
The simplest recipe is a cooldown: decay the learning rate (chapter 01) on the best data. Moonlight, Kimi's 16B-total, 3B-active mixture-of-experts (MoE) model, re-warmed its learning rate and decayed it to zero over a 500B-token cooldown on "the highest quality data, focusing on math, code, and reasoning", without percentages.
Xiaomi's MiMo-7B, a 7B dense reasoning model, gave numbers. Xiaomi calls its stages 2 and 3 pre-training; these notes count them as midtraining because they follow the main learning-rate decay and change the mix. Stage 2 (4T tokens) raised math and code to about 70%. Stage 3 (about 2T) added about 10% synthetic reasoning responses. MiMo-V2-Flash, Xiaomi's 309B-total, 15B-active MoE, upsampled code-centric data in its 4T-token "Mid-training" stage and added about 5% synthetic reasoning data; the code share is not given.
Microsoft AI's MAI-Thinking-1 gives the fullest numbers. Its base model, MAI-Base-1, is a 962B-total, 34.7B-active MoE. MAI-Thinking-1's first midtraining phase, 3.4T tokens at 65,536 context, sets STEM and math to 35%, keeps code at 55% and leaves 10% for background sources, all drawn from the pretraining corpus: "no new or synthetic sources are introduced". Meta's Muse Glimmer, a ~29.6B dense model built for on-device agents, adds synthetic reasoning traces and structured problem-solving demonstrations to organic data in its midtraining Phase 1, without shares.
Moonlight, GLM-4.5, Kimi K2.5, DeepSeek V4, MiMo V2.6 and Muse Glimmer say what they upweighted but not by how much. Figure 2.1 collects the phases that state percentages. Among the labs added to the atlas later, MiniMax states a share close to MiMo-7B's: M1's 7.5T-token continued pretraining of MiniMax-Text-01 raised STEM, code, book and reasoning data to 70% (not drawn in the figure).
Read the top two rows together. Taking the categories as roughly comparable, MAI-Thinking-1's first phase raises STEM and math from 21.2% of MAI-Base-1's pretraining mix to 35% and holds code near 55%, so the extra share comes out of the rest, which falls from 24.3% to 10%. That is the forgetting side of the trade-off, and the replay section below asks how much general data is enough.
A reasoning trace is the step-by-step text a model writes before its answer (a chain of thought). A synthetic trace is written by another model, usually a strong reasoning model, for a question the lab collected. GLM-4.5, Z.ai's 355B-total, 32B-active MoE, gathered math, science and coding-competition questions from web pages and books and had a reasoning model write the reasoning, in a 500B-token stage. MiMo-VL-7B, Xiaomi's vision-language model, regenerated answers with long chains of thought and kept them only after rejection sampling (drawing several answers and keeping those that pass a quality check).
The reports give reasons, measured effects and some abstentions:
A network trained on a new distribution tends to lose what it learned on the old one: the same weights serve both, and nothing in the new batches pulls them back. This is catastrophic forgetting. In Ibrahim et al.'s continued pretraining of a 405M model, validation loss on the original Pile data rose from 2.17 to 3.56 after 200B tokens of German. The standard fix is replay, keeping a share of the old distribution in the new phase. With 25% replay the Pile loss ended at 2.33, while German loss moved only from 1.11 to 1.16. The authors find that even the lowest replay they tested, 1%, significantly reduces forgetting, while 50% slows learning of the new data.
Labs' replay shares vary widely with the stage:
Muse Glimmer works through the learning rate instead: Phase 1 runs below the pretraining peak to balance synthetic-data gains "against acceptable regression on organic perplexity benchmarks".
A quality classifier is a small model that scores each document, for example for educational value or reasoning depth, so a lab can keep, drop or upweight it. Most labs describe such classifiers only for pretraining data. For midtraining, MAI is the most explicit: it keeps documents, mainly from its PDF corpus, that the Essential-Web taxonomy labels technically correct, at least intermediate in reasoning depth and at Bloom level "Analyze" or above (the fourth of six levels from Remember to Create). A fine-tuned 0.5B-parameter model produces those labels.
Weights come from small experiments. MAI tunes weights within each category with single-source microanneals, the short test anneals described in chapter 01. One OLMo 2 microanneal result bears on "how much": a 10/90 math-to-web mix lifted its GSM8K-subset score from 28.5 to 61, near the 63.5 of a 35/65 mix, so presence mattered more than share. MAI also caps each source's epochs in midtraining, more strictly for sources the model already seems to have memorized (chapter 09).
Put together, planning a phase is a loop over sources: turn each weight into tokens and epochs, and check the epochs against the source's cap.
# Plan one midtraining phase: tokens and epochs per source, with epoch caps.
def plan_phase(D_phase, w, U, seen, cap):
# w[k]: mixture weight (sums to 1); U[k]: unique tokens in source k
# seen[k]: epochs already used in pretraining; cap[k]: max total epochs
assert abs(sum(w.values()) - 1.0) < 1e-6
plan = {}
for k in w:
D_k = w[k] * D_phase # tokens drawn from source k
e_k = D_k / U[k] # passes over source k in this phase
if seen[k] + e_k > cap[k]:
raise ValueError(f"{k}: {seen[k] + e_k:.2f} epochs exceeds cap {cap[k]}")
plan[k] = (D_k, e_k)
return plan
def next_document(sources, w, rng):
# each document is drawn from source k with probability w[k], then packed
names = list(w)
k = rng.choice(names, p=[w[n] for n in names])
return sources[k].next_document()
DeepSeek-Coder-V2 states both the mix and the source sizes: Dphase = 6,000B with w = 0.60 code, 0.10 math, 0.30 natural language. The code corpus holds 1,170B tokens and the math corpus 221B.
Code: 0.60 × 6,000B = 3,600B, so e = 3,600 / 1,170 = 3.08 epochs. Math: 0.10 × 6,000B = 600B, so e = 600 / 221 = 2.71 epochs. Natural language: 0.30 × 6,000B = 1,800B of replay. Both specialized sources stay under Muennighoff's 4 epochs.
MAI-Thinking-1, midtraining phase 1: Dphase = 3,400B gives STEM/math 0.35 × 3,400B = 1,190B, code 0.55 × 3,400B = 1,870B and background 0.10 × 3,400B = 340B. Against the pretraining shares in MAI's Table 5 (code 54.6%, STEM 15.8% + math 5.4% = 21.2%, the rest 24.3%): u = 35 / 21.2 = 1.65 for STEM/math, 55 / 54.6 = 1.01 for code and 10 / 24.3 = 0.41 for the rest.
The 1,190B STEM/math share cannot be turned into epochs: it draws on math (300B unique), STEM (2.2T) and Bloom-filtered PDFs, and MAI does not give the size of the filtered pool. The math numbers give a rough bound: if the pretraining cap of 8 repetitions also applied to the math family's average in midtraining, math could supply at most (8 − 5.28) × 300B ≈ 816B, so at least 1,190B − 816B ≈ 374B of the share would come from the other STEM sources. Illustrative only: a 0.6T filtered STEM/math pool would be passed 1,190 / 600 ≈ 2.0 times in phase 1 alone.
"Overall, we further bias the mixture towards STEM, math, and code to build a strong foundation for reasoning RL climbs"
"This approach is expected to enhance specialized skills without compromising general language abilities"
0.70 × 4T = 2.8T tokens, and 2.8 / 1.4 = 2 epochs: under the 4 epochs Muennighoff et al. found nearly as good as unique data, before adding pretraining passes.
Pile loss ended at 2.33 instead of 3.56, avoiding most of the forgetting. The cost: German loss 1.16 instead of 1.11, and a quarter of the budget spent on old data.
Why did 2025-26 midtraining start feeding models whole repositories, GitHub issue-and-fix histories and agent trajectories, and what does one such training sample look like?
This chapter asks two questions: what the data looks like, and why labs add it in midtraining rather than in pretraining or post-training. The data comes in three sample formats, each closer to the work a coding agent does:
Code corpora used to treat each source file as its own document, yet a function is often called in one file and defined in another, so the model rarely saw a definition next to its use. DeepSeek-Coder (2024) introduced repository-level samples, built in four steps:
import in Python, using in C# and include in C;The format matters: training DeepSeek-Coder on file-level code only lowered cross-file completion in Java, TypeScript and C#.
import re
# Simplified from DeepSeek-Coder's Algorithm 1 (Python imports only; one sample
# per repository, where the original makes one per connected group of files).
IMPORT = re.compile(r"^\s*(?:from|import)\s+([\w.]+)", re.M)
def repo_sample(files): # files: {path: source text}
module = {p[:-3].replace("/", "."): p for p in files if p.endswith(".py")}
deps = {p: {module[m] for m in IMPORT.findall(src)
if m in module and module[m] != p}
for p, src in files.items()} # files that p imports
indeg = {p: len(deps[p]) for p in files} # imported files not yet placed
order, left = [], set(files)
while left:
p = min(left, key=lambda q: (indeg[q], q)) # minimal in-degree: cycles still finish
order.append(p)
left.remove(p)
for q in left:
if p in deps[q]:
indeg[q] -= 1
return "".join(f"# {p}\n{files[p]}\n" for p in order) # path comment, then file
GLM-4.5, Z.ai's 355B-total, 32B-active mixture-of-experts (MoE) model, made this a named midtraining stage: 500B tokens of concatenated files from the same repository "to learn cross-file dependency". Kimi K2.5 (Moonshot's 1.04T-total, 32B-active MoE) has a joint vision-text stage, which Moonshot calls pre-training and these notes count as midtraining; it also upweighted repository-level code. MAI-Thinking-1 adds file-level documents alongside its repository format, treating the two as complementary tasks.
On GitHub an issue is a bug report or feature request, a pull request (PR) is the proposed change that resolves it, and a commit is one recorded change, shown as a diff of removed and added lines. SWE-bench (2023) turned that pairing into a benchmark: given a codebase and an issue, the model writes a patch that is evaluated against real tests. It has 2,294 problems from 12 Python repositories. An issue-PR pair is a worked instance of exactly that task.
GLM-4.5 put model-filtered issues, PRs and commits into its repository stage, with related ones concatenated into one context and commits in diff form. GLM-5 (744B total, 40B active) relaxed the repository filters, tightened filtering of individual issues and retrieved more relevant files per pair, reaching about 10 million issue-PR pairs and about 160B unique tokens. Kimi K2.5 upweighted issues, code reviews and commit histories to improve "agentic coding subtasks such as patch generation and unit test writing".
Figure 3.1 compares the three code formats on one made-up repository.
An agent trajectory is the record of a model working on a task with tools. GLM-5's report writes one as (q, r1, a1, o1, …, rn, an, on): the question, then for each round the model's reasoning ri, its action ai (a tool call such as a shell command or a file edit) and the observation oi that the environment returns. ReAct (2022) introduced this interleaving of reasoning and actions. Written out with role markers, a trajectory is ordinary text and can be trained with next-token loss.
These labs describe such data in midtraining:
Which tokens carry loss? A trajectory mixes text the model wrote with text the tools returned, so there are two conventions:
Most labs here do not say which they use in midtraining. NVIDIA does: the agent traces are the only SFT-style data in its blend, and their tool responses are masked from the loss. Meta's synthetic pipeline, which feeds Muse Glimmer's midtraining Phase 2 and SFT alike, disables training on trajectory parts judged undesirable, such as bad tool calls. Figure 3.2 writes out one short coding trajectory and marks which rows each convention trains on.
The first reason is length. Repository and issue-PR samples are long, and GLM-4.5 and GLM-5 pretrain at 4K tokens. GLM-4.5 raised the sequence length from 4K to 32K to fit large repositories and used best-fit packing (placing whole documents into sequences instead of cutting them; chapter 05) to avoid truncating repo-level code. In GLM-5 an average issue-PR pair is about 16,000 tokens, four times the pretraining window, and every midtraining stage runs at 32K or longer (worked example below). In both releases midtraining is the first stage where such a sample fits whole.
The second reason is the reinforcement learning (RL) that comes later. RL samples several attempts at a task and raises the probability of those that did better than the rest. If the model never solves a task, every attempt gets the same zero reward and nothing stands out.
GRPO, the group method GLM-5 says its RL builds on, makes this exact. It scores attempt i within a group of attempts at the same task by the advantage (ri − mean r) / std r, where ri is that attempt's reward. In a group of four where one attempt succeeds (rewards 1, 0, 0, 0), the mean is 0.25 and the standard deviation over the four is 0.43, so the success gets advantage +1.73 and each failure −0.58, and the update moves toward the success. When all rewards are equal, the numerator is zero for every attempt and std r is zero as well; the DAPO authors treat such a group's advantage as zero, giving zero policy gradient, and their method filters out groups whose accuracy is 0 or 1. Either way, RL learns from a task only once the model sometimes solves it.
pass@k measures "sometimes": the probability that at least one of k samples is correct. Small rates matter. With per-attempt success p and a group of 16 independent attempts (illustrative numbers), the chance of at least one success is 1 − (1 − p)16: 1 − 0.99916 = 1.6% at p = 0.001 and 1 − 0.9816 = 27.6% at p = 0.02. Only groups with mixed outcomes give GRPO a gradient, so raising p in midtraining multiplies the tasks RL can learn from.
Chen et al. draw n ≥ k samples per task, c of them correct, and average over tasks:
where C(a, b) counts ways to choose b items from a. The fraction is the probability that k samples drawn without replacement from the n are all wrong, so one minus it is the chance that at least one is right. Chen et al. use this instead of 1 − (1 − p̂)k with p̂ = c/n, which they show is biased.
Three papers support the argument. Yue et al. compared RL-trained models with their bases on math, code and visual reasoning. RL won at k = 1, but the base models scored higher at large k, and the RL models' reasoning paths were already in the base models' sampling distribution. Gandhi et al. traced what the base needs to habits such as checking work and backtracking: under identical RL on the Countdown arithmetic game, Qwen-2.5-3B reached about 60% and Llama-3.2-3B about 30%, and continued pretraining on OpenWebMath filtered for those habits let Llama match Qwen's improvement. OctoThinker reached a similar result with midtraining on math data.
The labs give shorter reasons:
Midtraining used to mean more documents, and supervised fine-tuning (SFT) meant prompt-response pairs. The line is fading. GLM-4.5 already describes its midtraining data as medium-size, domain-specific and partly instruction data (chapter 00). Muse Glimmer feeds demonstrations from the same synthetic pipeline into midtraining Phase 2 and into SFT. MiMo-VL-7B, Xiaomi's vision-language model, lists "long-context Supervised Fine-Tuning (SFT)" as the fourth stage of its pre-training phase. What mostly separates the two is scale, since midtraining stages run hundreds of billions of tokens (500B in each of GLM-4.5's first two stages), yet MiMo-VL's "SFT" stage is 550B tokens, so even that line is blurring.
GLM-5 reports about 10 million issue-PR pairs and 160B unique tokens. Average sample: 160 × 109 / 107 = 16,000 tokens per pair, including its files and diffs.
Fit: GLM-5's first midtraining stage trains at 32K (32,768 tokens), so an average pair fills 16,000 / 32,768 = 0.49 of a sequence. GLM-5's own 4K pretraining window would hold only 4,096 / 16,000 = 26% of an average pair, which is why repository data arrives together with longer context.
Share: GLM-5's three midtraining stages total 1,000B + 500B + 50B = 1,550B tokens (1,572.8B with the two sparse-attention retrofit stages counted in ch00). One pass over the issue-PR data would be 160 / 1,550 = 10.3% of the three stages (160 / 1,572.8 = 10.2% of all midtraining), or 160 / 1,000 = 16% of the 32K stage. GLM-5 gives neither the epochs nor the stage that holds this data, so these shares are illustrative.
"an agent-centric mid-training phase that expands the exploration space for agentic tasks, enabling the model to discover more effective task-solving trajectories during post-training."
"we further enhance the coding capabilities of DeepSeek-V4 series by incorporating agentic data during the mid-training phase."
All attempts get the same reward, so the numerator ri − mean r is zero for every attempt; the advantage is taken as zero (or DAPO drops the group) and no gradient flows. pass@k at large k measures whether at least one of k samples succeeds, which is the pool RL can draw on.
No. The average pair is 16,000 tokens; a 4,096-token window holds about a quarter of it. All of GLM-5's midtraining stages run at 32K or longer, so whichever stage holds this data fits an average pair whole (GLM-4.5 made the same move, extending to 32K for repository code).
A RoPE model trained on 4K-token sequences fails on a 128K-token input: which rotary dimensions break, and how do interpolation, a larger base, YaRN and position-free global layers each repair them?
Rotary position embedding (RoPE; pretraining chapter 04 defines it) splits each query and key into pairs of numbers, treats each pair as an arrow in a plane, and turns pair i of the token at position m by the angle m·θi. In the dot product of a query at m and a key at n, position enters only through the difference (m − n)·θi, so attention sees how far apart the tokens are.
Each pair turns at its own speed θi, in radians per token; its wavelength λi counts the tokens per full turn. Fast pairs tell neighbouring tokens apart; slow pairs barely move over thousands of tokens. The speeds fall geometrically from a base b, counted over the dr rotated dimensions of a head's dh (many models rotate only part of the head; dr = dh when the whole head rotates):
A toy head with dr = 4 and b = 10,000 has two pairs: pair 0 turns 1 radian (57°) per token, a full turn every 6.3 tokens, and pair 1 turns 10,000−1/2 = 0.01 radian, a full turn every 628 tokens. A model trained at length L must later work at L′ = s·L. This chapter covers the position side; chapter 05 covers the data, stages and systems.
Train the toy head at L = 500. Pair 0 makes about 80 turns, so training shows it every angle; pair 1 reaches at most 5 radians (286°) and never completes a turn. At 2,000 tokens pair 1 reaches 20 radians, passing through angles from 286° to 360° that training never produced.
A real head splits the same way: fast pairs (λi ≪ L) have seen every angle, while slow pairs (λi > L) never finish a turn, so the network can read absolute position from them (the YaRN authors' argument) and past L they produce angles it never saw. LLaMA 7B, trained at 2,048 tokens, reached perplexity above 103 at 4,096 (Chen et al.), and fine-tuning at the new length alone grew its effective window only from 2,048 to 2,560 tokens in more than 10,000 batches.
So every fix must keep the slow pairs within the trained angles without blurring the fast ones. On the toy head stretched to 2,000 tokens (s = 4):
| method | pair 0 (80 turns within L) | pair 1 (0.8 turn within L) |
|---|---|---|
| position interpolation | 0.25 rad per token: neighbours 4× closer | 0.0025 rad per token, reaches 5 rad |
| base 10,000 → 160,000 | 1 rad per token, unchanged | 0.0025 rad per token, reaches 5 rad |
| YaRN (α = 1, β = 32) | over 32 turns: unchanged | under 1 turn: ÷ 4, reaches 5 rad |
| no position encoding | no angles, so nothing leaves the trained range | |
Position interpolation (PI; Chen et al., 2023) divides every position by s:
Chen et al. extended the context of LLaMA models from 7B to 65B parameters within 1,000 steps, the 7B and 13B to 32,768 tokens. The cost falls on the fast pairs: neighbouring tokens are now only θi/s apart on every pair, which removes RoPE's high-frequency detail, and the YaRN authors report that PI fine-tunes degraded beyond roughly s = 8 (Chen et al. themselves report usable 7B and 13B models at s = 16). Gemma 3 still uses PI, from 32K to 128K with a factor of 8, twice the length ratio.
A larger base b′ leaves pair 0 alone (θ0 = 1 for any base) and stretches each pair more the slower it is:
Meta's Llama 2 Long work (Xiong et al., 2023) called this adjusted base frequency (ABF). It raised b from 10,000 to 500,000 for 400B tokens of continued pretraining. Without it the model could not attend beyond 4,000 to 6,000 tokens; with it, ABF alone held up across a 32,768-token retrieval probe.
The "NTK-aware" rule, written up in the YaRN paper, picks b′ so that the slowest pair (i = dr/2 − 1) stretches exactly s times, as under PI:
For the toy head that is 10,000 × 42 = 160,000; for dr = 128 and s = 32, b′ ≈ 338,000. Pair i is then stretched by λ′i/λi = s2i/(dr−2), less than s for every pair but the slowest. Middle pairs whose wavelength is a little above L can therefore still meet new angles: the rule leaves some dimensions "slightly extrapolated", so s must be set above the length ratio.
Take dr = dh = 128 (64 pairs; the whole head rotates), as in LLaMA 7B (4096/32 = 128). At any base λ0 = 2π ≈ 6.28 tokens. The slowest pair has λ63 = 2π·b126/128: 2π × 8,660 ≈ 54,400 at b = 10,000 and 2π × 805,800 ≈ 5,063,000 at b = 1,000,000. Pair i finishes less than one turn within L when λi > L, that is when i > (dr/2)·ln(L/2π)/ln b:
| base b | λ0 | λ63 | pairs with λi > 4,096 | pairs with λi > 131,072 |
|---|---|---|---|---|
| 10,000 | 6.28 | 54,410 | 18 (i ≥ 46; 64 × 6.48/9.21 = 45.0) | 0 (64 × 9.95/9.21 = 69.1 > 63) |
| 1,000,000 | 6.28 | 5,063,256 | 33 (i ≥ 31; 64 × 6.48/13.82 = 30.0) | 17 (i ≥ 47; 64 × 9.95/13.82 = 46.1) |
The 131,072 column counts pairs that still never finish a turn even when training at 128K. The setting is illustrative; GLM-4.5 made this base switch when moving from 4K to 32K.
YaRN (Peng et al., 2023) decides per pair, by the number of turns ri = L/λi that pair i makes within L. Pairs that turn many times keep their frequency, so nearby tokens stay distinct; pairs that never finish a turn are interpolated as in PI; a ramp γ mixes the two in between:
For LLaMA, α = 1 and β = 32 worked well. YaRN also divides the logits by a temperature t, which the authors link to attention entropy rising with length. For one head's query qm ∈ ℝdh at position m and key kn ∈ ℝdh at n:
The rule was fitted for lowest perplexity on LLaMA 7B to 65B. It multiplies every logit by (0.1 ln s + 1)2, 1.30 at s = 4. Scaling q and k by √(1/t) inside the rotary embedding applies it without touching attention code.
def yarn_frequencies(d_r, b, L, s, alpha=1.0, beta=32.0):
i = arange(d_r // 2) # pair index, fast first
theta = b ** (-2 * i / d_r) # [d_r/2] frequencies
r = L * theta / (2 * pi) # r_i = L / lambda_i
gamma = clip((r - alpha) / (beta - alpha), 0, 1) # paper's ramp
theta_new = (1 - gamma) * theta / s + gamma * theta
scale = 0.1 * log(s) + 1 # sqrt(1/t)
return theta_new, scale
def rope_yarn(x, pos, theta_new, scale):
# x: [n, d_r] rotated part of queries or keys; pos: [n] positions m
ang = pos[:, None] * theta_new[None, :] # [n, d_r/2]
x1, x2 = x[:, 0::2], x[:, 1::2]
out = empty_like(x)
out[:, 0::2] = x1 * cos(ang) - x2 * sin(ang)
out[:, 1::2] = x1 * sin(ang) + x2 * cos(ang)
return scale * out # q.k gains scale**2 = 1/t
DeepSeek-V3 applies YaRN only to its 64-dimension decoupled rotary key (MLA, pretraining chapter 03), as DeepSeek-V2 did, during two 1,000-step stages at 32K and 128K. Of its 32 pairs, 11 are unchanged, 12 sit on the ramp and 9 are stretched 40× (Figure 4.1). The released code multiplies every logit by (0.1 ln 40 + 1)2 ≈ 1.874, YaRN's 1/t. s = 40 over 4,096 positions covers 163,840, a margin over 128K.
Labs pick b′ by hand and none says how; the table's last column gives the NTK-aware rule for comparison. Their choices range from about the rule (Kimi-VL, MiMo-V2-Flash) to 16 times above it (MiMo-7B).
| Model | dr | Length | Method and setting | NTK-aware b′ (computed) |
|---|---|---|---|---|
| Gemma 3 (4B, 12B, 27B) | not used by PI | 32K → 128K | PI: factor 8; global-layer base 1M, local 10k | n/a |
| GLM-4.5 | 64 of 128 | 4K → 32K → 128K | base raise at the 32K step: 10,000 → 1,000,000 | 85,500 at the 32K step; 358,000 at 128K (chosen: 2.8×) |
| MiMo-7B | 128 (all) | 8,192 → 32,768 | base raise in stage 3: 10,000 → 640,000 | 40,900 (chosen: 16×) |
| Kimi-VL | 64 | 8K → 32K → 128K | base raise: 50,000 → 800,000 | 875,000 (chosen: 0.9×) |
| MiMo-V2-Flash | 64 of 192 | 32,768 → 262,144 | base raise, global layers only: 640,000 → 5,000,000; window layers keep 10,000 | 5,475,000 (chosen: 0.9×) |
| GLM-5.2 | 64 | 200K → 1M | base raise (from configs; procedure not described): 1,000,000 (GLM-5) → 8,000,000 | n/a |
| DeepSeek-V3 | 64 (decoupled key) | 4K → 32K → 128K | YaRN on the decoupled key: s = 40, α = 1, β = 32, b = 10,000 | n/a |
| gpt-oss | 64 (all) | 4,096 → 131,072 | YaRN on the dense layers: factor 32, b = 150,000 | n/a |
| Kimi K2.5 | 64 | 32,768 → 262,144 | YaRN: factor 64 from 4,096, b = 50,000 | n/a |
MiMo-7B and Kimi-VL call these stages the end of pretraining. These notes count them as midtraining (chapter 00): each is a distinct stage after the main decay that changes the context length (clause 2 of the rule), and Kimi-VL's also continues training an earlier base, an intermediate Moonlight checkpoint (clause 3). Gemma 3 also extends its context at the end of pre-training, but its report names no separate phase and gives no learning-rate schedule, so the rule counts the extension as pretraining, like DeepSeek V4's growth inside its run.
Each fix above retunes RoPE whenever the context grows. Several 2025-26 models avoid that: they drop position encoding (NoPE) from global layers and keep RoPE, if at all, where offsets stay short. A window layer never sees an offset beyond its window, and a NoPE layer has no angles at all. Two designs appear:
Llama 4 also adds temperature scaling at inference, its counterpart to YaRN's temperature. With its attn_temperature_tuning flag on (off by default), Meta's reference code scales a NoPE layer's query at position m:
The factor is 1 while m + 1 < 8,192 and 1 + 0.1·ln 129 ≈ 1.49 at m + 1 = 1,048,576. The constants are the code's defaults, and the code cites Scalable-Softmax, which argues that softmax attention flattens as the number of keys grows. Llama 4's RoPE layers are still rescaled in one model: the code notes "Only Llama-4-Scout uses scaled rope", which divides the frequency of every pair with a wavelength above 8,192 tokens by 16.
"When extending the sequence length to 32K, we also adjusted RoPE’s base frequency from 10,000 to 1,000,000 for better long-context modeling ability."
"Second, it simplifies long-context training, as it obviates the need for RoPE parameter adjustments, such as frequency base tuning or methods like YaRN"
"Rotary position embeddings (RoPE) with θ [the base b] = 500,000 are applied exclusively to the local attention layers; the global layers rely on the accumulated positional signal from surrounding local layers, making the model extendable."
It rotates by m/s, so for m < L′ the angle mθi/s stays below Lθi. The cost: neighbouring tokens differ by only θi/s on every pair, including the fast pairs that carry local order.
The first turns r = 4,096/100 ≈ 41 times within L, more than β, so γ = 1: unchanged. The second turns r ≈ 0.41 times, fewer than α, so γ = 0: its frequency is divided by 40 and its wavelength becomes 400,000 tokens.
When a model trained at length L is stretched to L′, which rotary dimensions see angles they never saw in training, and what does each method do about it?
This demo goes with chapter 04. RoPE rotates each pair of query and key dimensions at its own frequency θi = b−2i/dr (dr: rotated dimensions per head), so pair i makes one full turn every λi = 2π/θi tokens. Each dot is one pair, placed at its wavelength after the method is applied; the dashed curve is the original wavelength, and the two horizontal lines mark L and L′. A pair whose wavelength is longer than L never completed a full turn in training, so at longer contexts it can reach angles the model has not seen. Pick a real model's settings or change them yourself. Three things to try:
Why do labs reach 128K to 1M tokens of context in a few stages instead of training long from the start, and what data and parallelism does each long stage need?
Chapter 04 fixed the positions. Here a stage is a stretch of training at one sequence length L. A long stage raises three separate questions, taken in turn below: when and in how many steps the length grows (staging), what fills a sequence of 128K tokens or more (data), and how to train a sequence that outgrows one GPU (systems).
Three pressures push long sequences late, and a fourth argues for small steps:
A late stage costs little quality. In Xiong et al.'s 7B runs, switching from 4K to 32K at 80% of training used 2.27 × 1022 FLOPs against 3.78 × 1022 for 32K throughout. The long-document QA scores were mixed: NarrativeQA unchanged at 18.5 and QuALITY 38.3 against 37.9, but Qasper 25.0 against 28.6 and QMSum 11.0 against 11.5; the authors summarize it as "almost no loss on performance". In MAI's ablations, 1T tokens at 32K then about 100B at 256K matched the code loss at 128K of a full 1T-token run at 128K, and most of the gain came within the first 1–10% of the extension.
| stage | L | sequences per batch | tokens per step | tokens |
|---|---|---|---|---|
| pretraining | 4,096 | 15,360 | 4,096 × 15,360 = 62,914,560 | 14.8T |
| extension 1 | 32,768 | 1,920 | 32,768 × 1,920 = 62,914,560 | 1,000 steps: 62.9B |
| extension 2 | 131,072 | 480 | 131,072 × 480 = 62,914,560 | 1,000 steps: 62.9B |
From the table and the model's config:
DeepSeek reports 180K GPU hours per trillion pretraining tokens and 119K for the roughly 126B extension tokens: 5.3× per token, above the FLOP estimate of 3.3×. DeepSeek gives no breakdown; lower utilization at long lengths would explain the gap.
Attention scores and the weighted sum of values cost 2·L2·(dqk + dv) FLOPs per head per sequence (forward, full matrix). With 128 heads, dqk = 192 and dv = 128, one layer costs 128 × 2 × 320·L2 = 81,920·L2. The causal mask keeps half the matrix, so per token one layer adds 40,960·L and 61 layers about 2.5 × 106·L.
The reports show three patterns (Figure 5.1 draws eight schedules to scale):
The reports give three answers to what a long sequence should hold:
Both GLM releases also add agent trajectories at long lengths (chapter 03).
Concatenating documents and cutting every L tokens splits any document that straddles a cut. Best-fit packing (Ding et al., 2024) avoids most cuts with the Best-Fit-Decreasing heuristic:
Take L = 10 and documents of 6, 5, 4 and 3 tokens. Concatenate-and-cut gives [6 + 4 tokens of the 5] and [its last token + 4 + 3], splitting one document. Best-fit puts 6 and 5 in two sequences, then 4 into the first (the tightest fit) and 3 into the second: [6 + 4] and [5 + 3 + 2 padding], nothing cut.
def best_fit_pack(doc_lengths, L):
chunks = [] # 1. cut only docs longer than L
for n in doc_lengths:
while n > L:
chunks.append(L); n -= L
if n > 0:
chunks.append(n)
chunks.sort(reverse=True) # 2. longest chunk first
space, seqs = [], [] # free tokens per sequence
for c in chunks:
fits = [j for j, r in enumerate(space) if r >= c]
if fits: # tightest sequence that fits
j = min(fits, key=lambda j: space[j])
else: # open a new sequence
space.append(L); seqs.append([])
j = len(space) - 1
space[j] -= c
seqs[j].append(c)
return seqs # leftover space is padding
# Ding et al. find the tightest fit with a segment tree
GLM-4.5 skipped it in pretraining, where "random truncation is a good data-augmentation strategy", and used it in midtraining; DeepSeek V4.1-Flash reports a padding rate of at most 10−4. Packed documents can attend to each other unless the mask blocks it; DeepSeek-V3 packs but does "not incorporate cross-sample attention masking", and the other sources here do not say.
At 256K to 1M tokens one sequence's activations outgrow a GPU, so context parallelism (CP) splits the sequence itself over P GPUs. Most of a layer treats each token alone and runs on each GPU's own tokens; attention is the exception, since every query needs keys and values held on other GPUs. Two designs move that data (Figure 5.2):
MAI-Thinking-1 used Ulysses-style CP only for long-context midtraining, adding ZeRO-3 (FSDP: parameters sharded and gathered just in time) for its 256K phase on 4,096 GB200 GPUs. Kimi K3 notes that softmax attention "requires ranks to exchange key–value blocks whose size grows with the sequence length", while its KDA layers (Kimi Delta Attention, linear attention with a fixed-size state; chapter 04) pass that state with one all-gather.
"Rather than training at the full 256K context length throughout pre-training or mid-training—which would be impractical due to the low MFU at long sequence lengths—we adopt a staged approach"
"Length alone, however, does not confer long-range capability."
"For datasets in mid-training, we applied best-fit packing to avoid truncating the reasoning process or repo-level code."
By 32×. Per sequence, attention grows with L2, 322 = 1,024×, but a fixed token budget holds 32× fewer sequences (15,360 → 480), so per step the growth is 1,024/32 = 32×, the length ratio.
Concatenation cuts wherever a sequence boundary falls, splitting any document that straddles it. Best-fit packing cuts only documents longer than L, into pieces of at most L, and places whole pieces into the sequence with the least space that fits them; the small leftover gaps become padding.
How did DeepSeek and Z.ai give a trained dense-attention model sparse attention with at most 6.4% of its original pretraining tokens, and why did both train the new part alone first?
Architecture ideas often arrive after a base model is finished, and retraining to adopt one repeats the whole run: 14.8T tokens for DeepSeek-V3, DeepSeek's 671B-total mixture-of-experts (MoE) model. A retrofit loads the trained weights, adds or changes a component, and keeps training until the network adapts. The labs call this continued pre-training; these notes count continued training that adds a new attention to an earlier base as midtraining (Chapter 00).
The sparse-attention retrofits in this chapter follow one sequence:
The main case is dense to sparse attention. Dense attention compares each query with every earlier token, so a sequence's attention cost grows with the square of its length. DeepSeek Sparse Attention (DSA), introduced in pretraining notes Chapter 03, lets each query read only a few thousand earlier tokens. The next sections walk DSA through the four steps; later ones show how other labs varied them.
DSA leaves the trained attention weights in place and adds two things to every attention layer:
With k = 2,048, a query at position 131,072, the end of a 128K sequence, has main attention read 2,048 latents instead of 131,072, one in 64; the indexer still scores all 131,072, at a much lower cost per pair. Up to position 2,048, top-2048 keeps every token, so selection only matters deeper into a sequence.
The indexer's score for query position t and earlier key position j sums over HI indexer heads g. Each head matches a query vector computed from the query's hidden state xt against a key vector computed from xj, and a weight, also computed from xt, scales the match:
DeepSeek-V3.2-Exp uses HI = 64, dI = 128 and k = 2048; GLM-5 uses 32 heads of 128. Per query–key pair the V3.2-Exp indexer does 64 × 128 = 8,192 multiply-adds in FP8, a ninth of the 73,728 that MLA spends scoring the same pair.
DSA runs MLA in its weight-absorbed form, which DeepSeek calls the MQA mode: the key up-projection is folded into the query, so each of the 128 heads compares its query with the shared latent plus the rotary key, 512 + 64 = 576 dimensions, 128 × 576 = 73,728 multiply-adds before reading values. V3.1-Terminus trained in the expanded form, with 192-dimensional query–key heads (128 + 64) and 128-dimensional values; that is the form Chapter 05 counts. Both compute the same attention.
One fact shapes the rest of the recipe: top-k is a discrete choice. The language-modeling (LM) loss flows through attention over the selected tokens, but no gradient flows back through which tokens were selected. The indexer needs a loss of its own. Figure 6.1 shows the layer before and after the swap, and what trains in each of the two stages that follow.
A trained dense model already knows which tokens matter: its attention weights. For query t, DeepSeek sums the main attention weights at,h,j over heads h and normalizes over j. Each head's weights sum to 1, so the sum is H, the number of main heads, and the target is the head average. A Kullback–Leibler (KL) divergence pulls the softmax of the index scores toward it:
The loss is zero when the indexer's distribution matches the dense attention. Since top-k keeps the highest scores, an indexer trained this way keeps the tokens dense attention weighted most.
The gradient is the usual softmax cross-entropy result, since p does not depend on the indexer: a score rises where dense attention puts more mass than the indexer does and falls where it puts less.
The first stage keeps dense attention and freezes every parameter except the indexers, so the model's outputs do not change while the indexers learn ℒI from attention the model already computes. DeepSeek started from the DeepSeek-V3.1-Terminus base, already extended to 128K, and trained the indexers at learning rate 10−3 for 1,000 steps of 16 sequences of 128K tokens, 2.1B tokens.
DeepSeek gives the stage's purpose only as "to initialize the lightning indexer". Arithmetic shows what skipping it would mean. A new indexer ranks tokens almost at random, and if k of t earlier tokens are picked at random, each is kept with probability k/t, so the expected attention mass kept is k/t whatever the attention pattern: 2,048 / 131,072 = 1.6% at the end of a 128K sequence. The LM loss would then have to adapt the whole network to near-random selections.
Z.ai measured how far a warm-up alone gets. GLM-4.7-Flash, a 30B-total MLA model, scores 79.21 on RULER at 128K with dense attention. Switching to sparse attention after only a 1,000-step indexer warm-up gives 71.35, with shorter contexts "virtually unaffected", and 150B tokens of joint training recover 78.86. That recovery is the next stage's job.
Then selection turns on and every parameter trains, with two losses on disjoint parameters:
This stage takes nearly all the tokens. DeepSeek used learning rate 7.3 × 10−6 and 15,000 steps of 480 sequences of 128K tokens, 943.7B tokens, on the data distribution of V3.1-Terminus's 128K extension. That learning rate is the one DeepSeek-V3 ended pretraining with (Chapter 08).
Compared with its parent after identical post-training, V3.2-Exp matched V3.1-Terminus on MMLU-Pro (85.0), scored 67.8 vs 68.4 on SWE-bench Verified, and scored four points higher on the independent AA-LCR long-context test in reasoning mode.
def indexer_kl(attn, scores):
# attn: [H, L, n] main attention weights over n candidates (n = L dense, k sparse)
# scores: [L, n] index scores I for the same candidates (masked entries = -inf)
p = attn.mean(0) # [L, n] head average = normalized head sum
q = softmax(scores, dim=-1) # [L, n] indexer distribution
return (xlogy(p, p) - xlogy(p, q)).sum() # sum over t of KL(p_t || q_t)
# Stage 1, dense warm-up (V3.2-Exp: 1,000 steps x 16 sequences x 128K, LR 1e-3)
freeze(all_params_except_indexers)
for batch in data_128k:
out = model(batch, sparse=False) # dense attention: outputs unchanged
loss = sum(indexer_kl(l.attn.detach(), l.scores) for l in out.layers)
loss.backward(); opt.step()
# Stage 2, sparse training (15,000 steps x 480 sequences x 128K, LR 7.3e-6)
unfreeze(all_params)
for batch in data_128k:
out = model(batch, sparse=True, k=2048) # per layer: idx = topk(scores, k)
loss_lm = cross_entropy(out.logits, batch.targets) # reaches main model only
loss_i = sum(indexer_kl(l.attn.detach(), l.scores.gather(-1, l.idx))
for l in out.layers) # reaches indexers only (input detached)
(loss_lm + loss_i).backward(); opt.step()GLM-5, Z.ai's 744B-total MoE, pretrained with MLA on 27T tokens and mid-trained up to 200K context. Its DSA training "begins from the base model at the end of mid-training":
GLM-5's sparse stage is 47 times smaller than DeepSeek's, and neither lab explains the difference. Qwen ran the same two stages for Qwen3.8-Flash-Next (Aug 2026), a Gated DeltaNet hybrid with one full-attention layer in every four, to replace that full attention with Qwen Sparse Attention (QSA) during continued pretraining at 256K:
The indexer still scores every earlier token, so its own cost grows with the context. For GLM-5.2's 1M context, Z.ai shares it: "every 4 transformer layers share a lightweight indexer", which sits in the first of the four, and the next three reuse its top-k indices. The released config gives 21 of 78 layers their own indexer, not 78 / 4 ≈ 20: the first two layers keep their own, and the other 76 form 19 groups of four, each led by one indexer, so 2 + 19 = 21. GLM-5.2 "is trained with IndexShare from mid-training with 128K sequence length"; the blog gives no token count, does not name the pretrained base, and does not say how the shared indexers were initialized.
The model card links Z.ai's IndexCache paper for IndexShare. Its training-aware variant trains each shared indexer to pick tokens that suit every layer reusing its choice: it distills the indexer of layer ℓ against itself and the m layers ℓ+1 … ℓ+m that reuse its indices, ℒ = (1/(m+1)) ∑ℓ′=ℓ…ℓ+m ∑t DKL(p(ℓ′)t ‖ q(ℓ)t), which has the same gradient as one KL toward the average of their attention distributions. The blog does not say whether GLM-5.2 used this loss.
The same steps recur when labs swap other parts:
Later models made the switch earlier. DeepSeek moved it into pretraining: DeepSeek-V4-Flash used dense attention for its first 1T tokens, then warmed up the indexer and went sparse, and DeepSeek-V4.1-Flash trained sparse attention from scratch. Figure 6.2 puts the three DSA retrofits on one token axis, to scale.
Figure 6.2 draws these budgets. DeepSeek-V3.2-Exp: warm-up 1,000 × 16 × 131,072 = 2.10B; sparse stage 15,000 × 480 × 131,072 = 943.7B; total 945.8B. Against V3's 14.8T pretraining tokens: 945.8 / 14,800 = 6.4%. Against the 630B + 209B = 839B of V3.1's context extension that the base inherits: 945.8 / 839 = 1.13.
GLM-5: warm-up 1,000 × 14 × 202,752 = 2.84B; sparse stage 20B; total 22.84B. Against 27T: 22.84 / 27,000 = 0.085%.
Per step, DeepSeek's warm-up used 16 × 131,072 = 2.1M tokens and its sparse stage 480 × 131,072 = 62.9M, a 30× larger batch. The sparse stages differ by 943.7 / 20 = 47×.
Token shares understate compute: DeepSeek's retrofit tokens and GLM-5's warm-up tokens run at 131,072 or 202,752 context, where the indexer and dense attention cost more per token than at the 4K both models started pretraining with.
"What makes DSA particularly interesting from a researcher’s perspective is how it was introduced via Continued Pre-Training from a dense base model. This avoided the “astronomical” cost of training from scratch."
"For the consideration of continued training from DeepSeek-V3.1-Terminus, we instantiate DSA based on MLA (DeepSeek-AI, 2024) for DeepSeek-V3.2-Exp."
"For this phase we have used a cross-entropy loss, as the distributional shift introduced by long-context and agentic data makes teacher logits less reliable at this stage."
"training a trillion-parameter replacement from scratch discards the 20T-token investment in Ling-2.0-1T."
The indexer's scores affect the output only through which tokens top-k selects, a discrete choice that passes no gradient. The indexer instead trains on its own KL loss toward the main attention over the selected set, with its input detached so that loss does not reach the main model.
Each token is kept with probability 2,048 / 65,536, so about 3.1% of the mass. The dense warm-up first trains the indexer, with everything else frozen, to match the head-averaged dense attention, so selection keeps the high-mass tokens from the first sparse step.
When a lab adds images and audio to a text model it has already trained, which parts does it train in which order, how many tokens does each stage take, and how does it check that the text skills survive?
A vision-language model joins three parts:
Patches and token counts are in pretraining notes, ch 07; this chapter covers the stages that join the parts to an existing LM. Those stages all train on next-token loss over the text, so what tells them apart is which parts receive gradients and which stay frozen.
The risk sits in the projector. A new projector emits vectors the LM has never seen, and if the LM trains then, the updates land on weights that took trillions of tokens to learn. LLaVA (2023) set the order that avoids this: stage 1 trains only the projection on 595K image-caption pairs with encoder and LM frozen, "a compatible visual tokenizer for the frozen LLM"; stage 2 also updates the LM. Later labs grew this into a procedure of up to five stages:
With encoder weights ψ, projector weights φ and LM weights W:
Xv is the image, Np its patch count, N the soft tokens the LM reads (Np/4 after a 2×2 merge such as Kimi-VL's pixel shuffle), dv the encoder width. J is next-token loss on text positions. A stage is defined by which weights are in S: {φ} in stage 1, {ψ, φ} in stage 2, all three in stages 3 and 4.
Labs skip or merge stages. Figure 7.1 shows which part trains in each stage and which releases report it.
Kimi, DeepSeek and Xiaomi first train the encoder beside a small stand-in LM. Kimi-VL turned SigLIP-SO-400M (a contrastively trained image encoder) into its 400M MoonViT over 2T tokens; K2.5 trained MoonViT-3D for about 1T tokens against Moonlight-16B-A3B "with very few training FLOPs". DeepSeek's ViT saw about 47B image-text pairs, then 236B tokens through a 4B mixture-of-experts (MoE) LM that is then discarded. MiMo-ViT trained on more than 4T image tokens beside a small LM. These tokens never reach the production LM, so midtraining token counts leave them out.
MiMo-VL-7B (Xiaomi, on MiMo-7B-Base) runs both steps in full:
Other labs shorten or drop these steps:
Then all parts train together, and text-only data stays in the mix. Three releases show the earlier size of this stage, 1.4T to 2T tokens:
These stages have grown to pretraining size. K2.5 continues "from a near-end Kimi K2 checkpoint over additional 15T vision-text tokens at 4K sequence length". MiMo-V2.6 (September 2026, a 310B Flash and a 1.02T Pro; whether Flash reuses V2.5's base is not stated) trains its backbone on text, then attaches its ViT and audio encoder and trains "the full model on omni-modal data": 3T tokens for Pro, 22T for Flash. Both labs call this pre-training; the rule of chapter 00 counts continued training of an earlier base as midtraining. DeepSeek's V4-Flash-Vision-Exp card says only that visual modules were added to V4-Flash before continued training.
The last stage extends the context with all parts training:
STAGES = [ # MiMo-VL-7B, Table 1: (name, trainable parts, tokens, seq_len, lr)
("S1 projector warm-up", {"projector"}, 300e9, 8192, 1e-3),
("S2 ViT + projector", {"vit", "projector"}, 167e9, 8192, 1e-4), # table: "1e-4, 1e-5"
("S3 all parameters", {"vit", "projector", "llm"}, 1.4e12, 8192, 1e-5),
("S4 long context", {"vit", "projector", "llm"}, 550e9, 32768, 2.5e-5),
]
def run(model, data):
for name, trainable, tokens, seq_len, lr in STAGES:
for part in ("vit", "projector", "llm"):
getattr(model, part).requires_grad_(part in trainable) # frozen: no gradient
opt = make_optimizer([p for p in model.parameters() if p.requires_grad], lr)
seen = 0
while seen < tokens:
batch = data.sample(stage=name, seq_len=seq_len) # mix changes per stage
h_img = model.projector(model.vit(batch.images)) # (N, d) soft tokens
loss = model.llm.next_token_loss(batch.text, h_img) # loss on text positions
loss.backward(); opt.step(); opt.zero_grad()
seen += batch.num_tokensFor K2.5, Kimi tested timing at a fixed vision-text budget: vision from 0% of training at 10:90 vision:text, from 50% at 20:80, or from 80% at 50:50. Early fusion scored best on text knowledge (45.5 against 43.9 and 43.1); with later injection, text scores dipped when vision arrived, then recovered (table in pretraining notes, ch 07). Starting from a near-end K2 checkpoint ruled out vision from 0%, so K2.5 took the other half of the lesson: a constant, moderate ratio (not given) from the start of its joint stage, rather than "aggressive vision-heavy training concentrated at the end". That stage begins after about 15T text-only tokens, so over K2 plus K2.5 vision arrives about halfway.
DeepSeek V4.1-Flash, a 552B-backbone MoE, has images in its data from the first of 45T tokens, at a 7:1 text-only to multimodal ratio. The encoder stays frozen (its final norm layer and the projector train) until the learning-rate decay stage at 28T, then trains with the LM "with a smaller learning rate". The stage rule counts that decay stage as midtraining. DeepSeek gives no reason for the timing.
Figure 7.2 puts these schedules on one axis: the tokens that pass through the LM before and during the multimodal stages.
Most labs report this in words. MiMo-VL says its models "maintain decent performance on text-only benchmarks" against MiMo-7B but prints no MiMo-7B column; GLM-V trains on pure text "to preserve its language capabilities" and shows no comparison. Two releases give numbers: K2.5's ablation, and the V4-Flash-Vision-Exp card, which beats V4-Flash-0731 on 6 of 7 text-agent benchmarks and trails on Cybergym, 75.3 to 76.7. Both models are post-trained, so this does not isolate the vision stage.
Tokens: Flash trains 26T text and 22T omni tokens, Pro 27T and 3T.
Both leave out the unsized agent-centric stage that follows; adding it to top and bottom raises a fraction below 1, so as midtraining shares these are lower bounds (Pro ≥ 10%, as in Figure 0.2 of chapter 00).
Parameters (Table 1; encoders include input embeddings, exclude projectors): MiMo-ViT 681M + audio tokenizer encoder 308M + audio patch encoder 127M = 1,116M.
The encoders are tiny next to a large MoE; the stage's size comes from its tokens.
"This ensures the projector learns to map visual concepts to the language model's representation space effectively, providing informative gradient signals for subsequent training stages rather than noisy updates from a poorly aligned projector."
"To preserve text abilities, all stages that update the language model are joint training stages."
Only the randomly initialized projector; ViT and LM are frozen. It first learns to map visual features into the LM's space, so later stages get informative gradients, not noisy updates.
No: the encoders total about 1.12B parameters, 0.36% of Flash's 310B; the stage is large because of its 22T tokens, 45.8% of 48T.
When a lab switches optimizer, turns on 4-bit training or changes a loss weight partway through a run, what state has to carry over, and what goes wrong if it restarts from zero?
A checkpoint holds more than the weights the model runs with. Labs change three kinds of state at stage boundaries, and each is risky to change mid-run for its own reason:
The sections below take the three in that order. Only the changes made for what follows midtraining (RL, serving in 4 bits, a hardware number format) come with stated reasons. Of the schedule changes, one keeps each step the same size when the context grows; the rest turn settings down as the run settles, at schedule boundaries. Some changes fall at token counts these notes count as main pretraining (in-schedule decay, Chapter 00); each is labeled. Figure 8.1 places several on a token axis.
AdamW, Adam with decoupled weight decay (pretraining notes Chapter 08), does not step by the raw gradient g. It keeps two running averages per weight, of g and of g2, corrects them for starting at zero, and steps by their ratio:
The ratio is what makes warm Adam gentle: averaging noisy batches shrinks m̂ more than √v̂. For a weight whose gradient flips sign from batch to batch, m̂ nearly cancels while √v̂ does not, so the weight barely moves. Kimi's Moonlight report measured AdamW update RMS "usually around 0.2 to 0.4" (in units of η).
Restart m and v at zero and the averaging is gone. The first step has m̂1 = g1 and v̂1 = g12, so every weight moves by η · sign(g1) and the update's root-mean-square (RMS) is η. A cold restart at an unchanged learning rate therefore takes first steps 2.5 to 5 times their usual size until the averages refill, over roughly 1/(1−β2) = 20 steps for β2 = 0.95.
Muon sets its step size by construction instead. It keeps one momentum matrix per weight matrix and replaces it with the nearest semi-orthogonal matrix, whose singular values are all 1 (computed by Newton–Schulz iteration, NS):
The step size comes from the orthogonalization, not from the state: a cold buffer (M0 = 0) gives O1 = NS(G1), a normal-size step in a noisier single-batch direction, until momentum μ = 0.95 has averaged about 20 steps. Muon has no counterpart to Adam's v; its M plays the role of Adam's m.
MiMo-V2.6-Pro, Xiaomi's 1.02T-total omni-modal MoE, was pretrained with AdamW on 27T text tokens and then 3T omni-modal tokens; the lab calls both pre-training, and these notes count the omni stage as midtraining. Its agent-centric mid-training, at 256K and then 1M context, switched the hidden weight matrices to Muown, a Muon variant, while embeddings, the LM head and the MoE router stayed on AdamW. The reason is the RL stage that follows: AdamW showed "diminishing optimization efficiency as the batch size increased in mixed-task RL", while Muon "retains stronger data efficiency beyond the critical-batch-size regime". The critical batch size is the point past which larger batches give diminishing returns (McCandlish et al.).
The switch is risky in two ways. The new optimizer's state starts cold, as above, and the new optimizer may not suit weights shaped by the old one: Qu et al. report that "naively switching to Muon for fine-tuning leads to degraded performance due to an optimizer mismatch", with damage that grows with update strength, and Moonlight found Muon SFT of an AdamW-pretrained Qwen2.5-7B only "on par" with AdamW. MiMo cites the risk and reports "no loss spike throughout the training process".
Muown targets a drift that Muon leaves unchecked. Its authors split a weight matrix's spectral norm (its largest singular value) into a row-magnitude factor and a row-coherence factor, and found that under Muon without weight decay the largest row norm grows and pulls the spectral norm up with it. Muown therefore gives the row magnitudes their own parameter, which MiMo describes as "explicit row-norm control, mitigating spectral-norm drift and reducing sensitivity to weight decay":
Here ρ holds the row magnitudes and ‖R‖row the row lengths of the direction matrix R. What a switch carries over follows from the Muown paper's initialization; MiMo does not say how it initialized Muown or what learning rate mid-training used.
The paper scales the R step "to match the RMS norm of a typical Adam update", so one learning rate serves both parts. A switch can therefore start from AdamW-trained weights; the sketch below follows the paper's rule.
def switch_to_muown(ckpt, hidden): # illustrative, per the Muown paper
state = {}
for name, W in ckpt.master_weights.items(): # FP32 weights W, unchanged
if name in hidden: # attention, MLP and expert matrices
rho = W.norm(dim=1) # ρ: [d_out] row magnitudes of W
state[name] = dict(
rho=rho, # ρ, updated by Adam
R_rownorm=rho.clone(), # cached ‖R‖_row (R = W here)
M=zeros_like(W), # Muon momentum for R, starts cold
m_rho=zeros_like(rho), # Adam first moment for ρ, starts cold
v_rho=zeros_like(rho)) # Adam second moment for ρ, starts cold
# each step rebuilds R = diag(R_rownorm / rho) W, so R = W at the switch;
# AdamW's m and v for W are dropped: nothing in Muown uses them
else: # embeddings, LM head, MoE router
state[name] = ckpt.adamw_state[name] # stays on AdamW (carry-over assumed)
return stateAt the start of RL, MiMo carries over "the FP32 master weights and Muown's row state from the SFT checkpoint", to "stabilize MXFP4 training" (MXFP4 is the 4-bit format of the next section).
A model served in 4 bits computes with rounded weights, which is not quite the function it was trained as. Quantization-aware training (QAT) lets training see the rounding. It runs the forward pass on quantized weights while gradients update an FP32 master copy, passing through the rounding as if it were the identity (the straight-through estimator):
In MXFP4, blocks of 32 four-bit values share one power-of-two scale (pretraining notes Chapter 11). Each value is 0, ±0.5, ±1, ±1.5, ±2, ±3, ±4 or ±6 times the scale, so the grid is coarse: with δ = 0.25, a weight of 0.37 is 1.48δ and rounds to 1.5δ = 0.375, while 0.90 is 3.6δ and rounds to 4δ = 1.0, 11% too large. Turning QAT on changes every forward pass at once, and labs turn it on at different points:
No lab compares start points. Starting earlier gives the model more tokens to adapt; every later stage must then keep the quantization in its training kernels.
Low-precision formats store each block of numbers with a shared scale, so changing the scale format changes how every block is rounded, and the change has to reach every layer. DeepSeek-V3 trained in FP8 with one scale per 1×128 activation tile and per 128×128 weight block, and rounded only some scales to powers of 2. DeepSeek-V3.1 "is trained using the UE8M0 FP8 scale data format on both model weights and activations to ensure compatibility with microscaling data formats". UE8M0 is an unsigned, exponent-only 8-bit scale, the E8M0 scale format of the Microscaling (MX) standard, so every scale is a power of two. The card does not say which stage used it. V3.1's only training before SFT is its 839B-token context extension, so these notes count it as midtraining, an inference. One layer missed the change: the V3.1-Terminus card says the self_attn.o_proj parameters "do not conform to the UE8M0 FP8 scale data format".
NVIDIA tested a precision switch before the anneal, inside main pretraining under these notes' rule. Nemotron 3 Super trains most linear layers in 4-bit NVFP4 for all 25T pretraining tokens; promoting every tensor to MXFP8 1T tokens before the anneal improved the loss curve but not downstream accuracy, so NVIDIA kept NVFP4 to the end.
A longer sequence holds more tokens, so a batch of a fixed number of sequences grows in tokens, and each step averages its gradient over more of them. DeepSeek-V3 and MiMo-V2-Flash both cut the batch, counted in sequences, by the factor the context grew, which keeps tokens per step fixed: 62.9M for DeepSeek-V3 at 4K, 32K and 128K (Chapter 05 works through these numbers and their GPU-hour cost) and 67.1M for MiMo-V2-Flash at 32K and 256K (worked example below). DeepSeek-V3 also kept its learning rate at the value pretraining ended on instead of restarting the schedule (quoted below), while MiMo-V2-Flash kept decaying it. Neither report gives the batch unit or a reason. MiMo-VL went the other way at its 32K stage and raised the learning rate because packing grew its effective batch (Chapter 07).
Multi-token prediction (MTP) adds a head that predicts one further token, with its loss scaled by a weight (pretraining notes Chapter 06). Every report below lowers that weight from 0.3 to 0.1 late in the run:
Auxiliary-loss-free balancing keeps experts evenly loaded with a per-expert routing bias ce (for expert e) that is added to routing scores only when choosing experts. After each step, an overloaded expert's bias falls and an underloaded one's rises, by a fixed rate γ:
Setting γ = 0 freezes the biases at their learned values. The loss-free balancing paper found that a high fixed rate "deteriorates load balance in the later stage" of training, and the reports slow or stop balancing late:
A frozen part can join training mid-run. DeepSeek-V4.1-Flash kept its vision encoder frozen until its learning-rate decay stage (midtraining in these notes) began at 28T of 45T tokens, then trained it jointly "with a smaller learning rate" (Chapter 07).
No lab gives a reason for these changes. What they share is timing: each sits on a schedule boundary, either the start of the learning-rate decay (DeepSeek-V3's and DeepSeek-V4's MTP weight, V4.1-Flash's vision encoder), the final low-learning-rate tail (DeepSeek-V3's bias rate), or a named stage (GLM-4.5 at 15T, Moonlight's cooldown, MiMo-V2-Flash's Stages 2 and 3).
At 26T of its 27T tokens, MiMo-V2-Flash moves from Stage 2 to Stage 3, its context extension, and changes several settings at once. The report gives the batch without a unit; reading it as sequences:
before: 2,048 × 32,768 = 67,108,864 tokens per step
after: 256 × 262,144 = 67,108,864
The context grows by s = 262,144 / 32,768 = 8 and the batch shrinks 8×, so tokens per step stay at 67.1M. Stage 3's 1T tokens are then 1012 / 67,108,864 ≈ 14,900 steps.
The learning rate continues its cosine decay from 3 × 10−5 to 1 × 10−5: from 3 / 32 = 9.4% to 1 / 32 = 3.1% of the 3.2 × 10−4 peak.
The bias update rate drops 100×, from γ = 0.001 to 1 × 10−5. Each step moves a bias by exactly ±γ, so over the whole stage one expert's bias can move by at most 14,900 × 10−5 ≈ 0.15.
The RoPE base of the global-attention layers rises from 640,000 to 5,000,000 (Chapter 04), and the MTP weight has been 0.1 since 22T. The report gives no reason for any of these values.
"We therefore switch to a variant of Muon optimizer, Muown, for the hidden weight matrices during mid-training to prepare the model for subsequent large-batch RL."
"We perform quantization-aware training (QAT) [50] throughout the entire post-training stage, covering both SFT and RL, so that the model adapts to quantization-induced precision loss."
"The learning rate for both phases is set to 7.3× 10−6, matching the final learning rate from the pre-training stage."
With m̂1 = g1 and v̂1 = g12, each weight moves by η · sign(g1), an update RMS of η. Warm AdamW updates have RMS around 0.2 to 0.4 η, so the first cold steps are 2.5 to 5 times larger until the averages refill.
Each step moves a bias by exactly ±γ, so at γ = 0.001 it could move up to 14,900 × 0.001 ≈ 14.9; at the actual 1 × 10−5, at most about 0.15, 100 times less. With γ = 0, as in Moonlight's cooldown, it cannot move at all.
How do labs tell whether midtraining made the base model better, and which data do they deliberately keep out of it?
The chapter takes the two halves of that question in turn:
A base model, the checkpoint before supervised fine-tuning, does not follow instructions, so labs prompt it with a few solved examples and a new question to continue. DeepSeek compares V4.1-Flash-Base with its two V4 bases on 20 benchmarks in one setting (16 scored for all three; the 4 multimodal ones only for V4.1-Flash), each with a fixed number of examples (5 for MMLU-Pro, 0 for HumanEval). The answer is then scored in one of two ways:
Small gaps are noise: DeepSeek treats scores within 0.3 "at the same level", and K2 averages GPQA-Diamond over eight runs "to mitigate the high variance".
The MAI-Thinking-1 report (Microsoft AI; base model MAI-Base-1) argues against accuracy for pretraining work. It tracks nearly 40 benchmarks scored by negative log-likelihood (NLL): the model reads held-out text, such as vendor-written worked solutions or private code, and the score is its mean loss. NLL needs no sampling or judge, and teacher forcing (conditioning on the true prefix) keeps one formatting slip from compounding. Multiple-choice skill, MAI notes, "typically emerges only at surprisingly large scale". Five category scores are weighted into one target, with code at 0.5. NLL per token compares models only when they share a tokenizer, as MAI's ablations do.
Tokenizers cut the same text into different numbers of tokens, so per-token losses measure differently sized pieces. Bits per byte (BPB) fixes the denominator. The Pile paper defines it from the mean loss ℓ in nats per token:
NT is the number of tokens and NB the number of UTF-8 bytes in the evaluation text (LT, LB in the paper); all are scalars. NT·ℓ is the total loss in nats, dividing by ln 2 turns nats into bits, and dividing by NB spreads the bits over bytes. Same text, same bytes: BPB puts models with different tokenizers on one scale.
DeepSeek-V3 reported BPB on the Pile test set. V4.1-Flash-Base "achieves lowest BPB on all tasks" against V4-Flash-Base and V4-Pro-Base on held-out internal documentation, code and academic material. MAI compares MAI-Base-1 with DeepSeek, Kimi and Gemma bases on four held-out tasks: lower BPB than models of similar active size, with DeepSeek V4 Pro best. Both note that APIs do not return log-likelihoods, so only open-weight models qualify.
Figure 9.1 shows why the denominator matters on one toy string: the tokenizer with the lower loss per token is not the better model of the text.
The Pile paper measured the GPT-2 tokenizer at NT/NB = 0.29335 tokens per byte across the Pile. Take an illustrative loss ℓ = 2.0 nats per token.
Chapter 03 defines pass@k, the chance that at least one of k sampled answers is correct, and its unbiased estimator. Because reinforcement learning (RL) learns only from answers the model sometimes produces, labs use pass@k on the base as a ceiling for RL. Yue et al. (2025) found that RL-trained models beat their bases at small k while the bases win at large k, and they treat the base as an upper bound on what current RL elicits. MiMo-7B adopts the metric from Yue et al.; its base's lead over other bases, a 32B one included, widens as k grows. The GLM-V report plots pass@k on the non-multiple-choice part of MathVista and says base performance "arguably sets the upper bound for the final results after reinforcement learning".
To judge one phase, labs score checkpoints before and after it on the same held-out set, checking what the phase targets and what it should leave alone. MAI's small-scale ablations of context extension do this with code NLL: the last 16K tokens of a repository chunk are scored after 16K to 256K tokens of context. After extension the loss falls steadily as context grows, while models mid-trained at shorter lengths get worse beyond twice their training length. At 16K and 32K all five configurations reach about the same NLL: no short-context cost (chapter 05; OLMo 2's few-shot before/after is in chapter 01).
Decontamination removes test items from training data. The labs here mostly match n-grams, runs of n consecutive words, between benchmarks and training text; they differ in n and in what they do with a hit:
import re
def grams(text, g): # GPT-3: lowercase words, punctuation stripped
words = re.sub(r"[^\w\s]", "", text.lower()).split()
return {tuple(words[i:i + g]) for i in range(len(words) - g + 1)}
def build_index(benchmarks, g=10): # DeepSeek: 10-grams of questions and solutions
index = set()
for item in benchmarks:
index |= grams(item.question, g) | grams(item.solution, g)
return index
def is_clean(doc, index, g=10): # sketch: drop the whole document on one hit
return not (grams(doc, g) & index)
index = build_index(benchmarks)
corpus = [d for d in corpus if is_clean(d, index)]MAI also limits how often midtraining repeats a source. Between two pretraining checkpoints, it measures what fraction of a source's validation-loss improvement comes from tokens predicted with near certainty (NLL below 0.01). The intuition: a token the model already predicts almost perfectly has little left to teach, so if most of a source's loss gain comes from such tokens, the model is learning to recite that source rather than to generalize. MAI reads a high fraction as "memorization or highly repeated structure" and gives such sources stricter epoch caps. In the notation here (the report gives it in words; I assume near-certainty at the later checkpoint):
Here Vj is the validation tokens of source j and ℓt(1), ℓt(2) the losses of token t at the earlier and later checkpoint. For example (illustrative numbers), if a source's validation loss falls by 100 nats in total and 70 of them come from tokens now below 0.01, mj = 0.7 and the source is capped harder than one at 0.1. The report gives no cap values.
Kimi K3.1 Pro, Moonshot's 3T-class open-weight model, removed data for safety. As post-training scaled, its vulnerability-research scores rose; Kimi traced this to cyber content in the general midtraining corpus and cyber tasks in the RL mix. For the open-weight release it removed both and kept general coding tasks. On its xdev-bench-hard exploit tasks, a checkpoint without the removal solves 90.5% at pass@3 and the released model 81.0%. Kimi does not say how the data was found. The blog calls K3.1 Pro "a post-trained version of Kimi K3" yet edits its midtraining corpus, so these notes count it as having midtraining. MAI leaves out synthetic data: in its midtraining "no new or synthetic sources are introduced".
Chapter 00 counts which releases describe midtraining at all and finds 27 distinct recipes. Of those 27, 12 state their token count, 5 allow only an estimate and 10 give no total size. Four give a mix share as a number, and only MAI gives its whole mix by domain: 35% STEM and math, 55% code, 10% other. Outside the grid, NVIDIA gives the whole mix of Nemotron 3.5 Super's agentic stage (chapter 03), and Ant gives Ling-2.6-1T's final mid-training phase at 256K as 43% general, 42% reasoning and 15% agentic data.
"use Bits-Per-Byte (BPB) as the metric to guarantee fair comparison among models using different tokenizers."
"we cap data source exposure during mid-training to avoid overfitting sources that appear highly memorized by the end of pre-training."
"For the open-weight release of K3.1 Pro, we identified and removed cyber-related data from both training stages, while retaining the general-purpose coding tasks needed for model usefulness."
The models use different tokenizers, so their tokens cover different numbers of bytes. Total bits over the shared byte count puts every model on one scale.
Without the removal a checkpoint solved 90.5% of xdev-bench-hard at pass@3; the released model solves 81.0%.
When a lab rebuilds its midtraining from one release to the next, what changes, and how much of the run does it take?
Chapters 00 to 09 took one midtraining decision at a time. This chapter follows three labs across releases and reads each release the same way: which phases followed the main run, in what order, how many tokens they took, and what changed besides the data.
Figure 10.1 draws each release's midtraining tokens on one scale, colored by what each phase was for.
That is the largest share of any DeepSeek release (Kimi K2.5's 51% in chapter 00 is larger). Part of the jump is labeling: DeepSeek-V3 also held its learning rate constant for most of its run and decayed it over the last 4.8T, but inside its main schedule, so the rule counts that as pretraining (chapter 00 puts V3 at 33% if it were counted). The long-context work did grow: 11T at 1M against V3's 126B.
| Choice | V3 · Dec 2024 | V3.2-Exp · Sep 2025 | V4 · Apr 2026 | V4.1-Flash · Sep 2026 |
|---|---|---|---|---|
| Phases after the main run | two YaRN context phases | sparse-attention retrofit: indexer warm-up, then sparse training | none named besides an agentic mid-training phase of unstated size and place; length grows inside the run | a learning-rate decay stage, then context extension, inside one 45T run |
| Tokens | 126B (0.8%) | 2.1B + 943.7B | agentic phase size not given | 6T + 11T (38%) |
| Context | 4K → 32K → 128K | 128K, unchanged | 4K → 16K → 64K → 1M during pretraining | 64K → 1M |
| Other changes | learning rate held at its final pretraining value | DeepSeek Sparse Attention added | agentic data for coding | vision encoder unfrozen at the start of the decay, at a smaller learning rate |
| Choice | GLM-4.5 · Jul 2025 | GLM-5 · Feb 2026 | GLM-5.2 · Jun 2026 |
|---|---|---|---|
| Phases | repo-level code (500B, 32K) → synthetic reasoning (500B, 32K) → long context and agent data (100B, 128K) | 32K (1T) → 128K (500B) → 200K (50B), then a sparse-attention retrofit (2.84B warm-up + 20B) | 128K midtraining with a shared sparse-attention indexer from the start; 1M coding-agent training (stage not stated) |
| Tokens | 1.1T (4.8% of 23T) | 1.55T + 23B retrofit (5.5% of about 28.6T) | not given |
| Context and RoPE | 4K → 32K → 128K; base 10,000 → 1,000,000 at 32K | 4K → 32K → 128K → 200K | 1M; config base 8M (GLM-5's config: 1M) |
| Data focus | repo-level code with issues, PRs and commits; synthetic reasoning; long documents; synthetic agent trajectories; some instruction data | repo-level software-engineering data, long documents and synthetic agent trajectories upsampled; a small share of MRCR-like data at 200K | 1M-context coding-agent data |
On GLM-5's retrofit, Z.ai reported that this was enough:
"Although the training budget is much smaller than that of DeepSeek-V3.2 (943.7B tokens), we find that it is enough to adapt the DSA model to match the performance of the original MLA model."
| Choice | MiMo-7B · Apr 2025 | V2-Flash · Dec 2025 | V2.6 · Sep 2026 |
|---|---|---|---|
| Phases | stage 2: math and code raised to about 70% (4T, 8K); stage 3: about 10% synthetic reasoning responses, 32K (2T) | "Mid-training": code-centric data and about 5% synthetic reasoning (4T, 32K); "Context Extension" (1T, 256K) | omni stage adding vision and audio; agent-centric midtraining at 256K; a final 1M stage |
| Tokens | 6T (about 25%) | 5T (19% of 27T) | omni stage 3T (Pro), 22T (Flash); agent stage not given |
| Context and RoPE | 8K → 32K; base 10,000 → 640,000 | 32K → 256K; global-layer base 640,000 → 5,000,000 | 32K → 256K during pretraining, then 1M at the end of midtraining |
| Setup changes | batch 2,560 → 640; learning rate held, then decayed to 1e-5 | learning rate 1e-4 → 3e-5 → 1e-5 | AdamW → Muown for hidden matrices; MXFP4 quantization-aware training |
MiMo-7B's two late stages already followed the pattern GLM and DeepSeek reached later: shift the mix toward math and code, then add synthetic reasoning and longer context at a low learning rate. V2.6 widened the purpose of the stage from data to the whole training setup:
"Mid-training bridges this general foundation and subsequent large-scale RL by further developing the model's agentic abilities, extending long-context support, and adapting the optimization setup for large-batch training."
The optimizer switch is the clearest example. Xiaomi pretrained V2.6 with AdamW, found that its efficiency fell as RL batches grew, and switched to a Muon variant in midtraining so that the model would already be adapted when RL began (chapter 08).
Across the three labs, the choices of chapters 01 to 09 sort into five purposes (Figure 10.2).
Using the tables above, compute for each release the share of all its training tokens that were trained at a context of 128K or longer: DeepSeek-V3 (its 128K phase was 62.9B tokens), GLM-4.5, GLM-5, MiMo-V2-Flash and DeepSeek V4.1-Flash. What changed between late 2024 and late 2026?
DeepSeek-V3: 62.9B of 14,926B ≈ 0.42%. GLM-4.5: its 100B long-context phase of 23.1T ≈ 0.43%. GLM-5: 500B at 128K plus 50B at 200K, 550B of about 28.6T ≈ 1.9%. MiMo-V2-Flash: 1T at 256K of 27T ≈ 3.7%. DeepSeek V4.1-Flash: 11T at 1M of 45T ≈ 24%, and the other 34T were already trained at 64K. Long-context training went from under half a percent of the run to about a quarter. Two changes made that affordable: attention whose cost grows slowly with length (DeepSeek says its hybrid of compressed sparse attention and heavily compressed attention makes one-million-token context "feasible in practice"; see the pretraining notes' chapter 03), and growing length inside the main run instead of in a short stage at the end (chapter 05).
Not necessarily. V4 grows context and decays its learning rate inside its single pretraining run without naming those phases, so the rule counts them as pretraining. V4.1-Flash names a learning-rate decay stage and a context extension, so the rule counts them as midtraining. Part of the difference is how the reports describe the run, which is why these notes always state the rule and the denominator alongside a share.
Xiaomi found that AdamW's efficiency fell as RL batch sizes grew, and switched its hidden matrices to a Muon variant during midtraining "to prepare the model for subsequent large-batch RL". Xiaomi does not say why it switched in midtraining rather than when RL began. Chapter 08 shows what a switch disturbs, the optimizer state, which suggests a reason to do it on ordinary training data first, but that reasoning is ours, not Xiaomi's.
Short definitions of the terms used in these notes, with the chapter that explains each one.
To give credit if you find this work useful, please cite:
@misc{ma2026openrecipesmidtrain,
title={Reading Open-Weight Recipes, Part 2: What 2025--26 Model Reports Disclose About Midtraining},
author={Ma, Ziqiao},
howpublished={\url{https://mars-tin.github.io/blogs/posts/open_recipes_midtraining}},
note={Blog post},
year={2026}
}