Sam Babichenko

Reading notes / Running RL at scale

The training-inference mismatch and FP16

Qi et al., 2025

Policies and responses
x;x; y;y; yt;y_t; ∣y∣|y|prompt; response; its tt-th token; its length in tokens
sts_tprefix (x,y1,…,yt−1)(x,y_1,\dots,y_{t-1})
θ;\theta; θ′\theta'weights being updated; weights that sampled the batch
μθ;\mu_\theta; πθ\pi_\thetasampler's (inference engine's) policy; trainer's (training engine's) policy, both at weights θ\theta
R(x,y);R(x,y); A^\hat Areward; advantage (reward minus the mean of the other responses' rewards)
J(θ)J(\theta)expected reward under the trainer's policy
Mismatch and weights
δt\delta_tper-token gap log⁡πθ′(yt∣st)−log⁡μθ′(yt∣st)\log\pi_{\theta'}(y_t\mid s_t)-\log\mu_{\theta'}(y_t\mid s_t), in nats
wt;w_t; w(y)w(y)correction weight eδte^{\delta_t}; its product over the response
rt′r'_tGRPO's ratio πθ(yt∣st)/πθ′(yt∣st)\pi_\theta(y_t\mid s_t)/\pi_{\theta'}(y_t\mid s_t)
πθ(y∣x)/μθ′(y∣x)\pi_\theta(y\mid x)/\mu_{\theta'}(y\mid x)sequence weight of PG-Seq-IS
Constants
CCcap on importance weights in truncation and masking (3 in the tests)
SSloss-scaling factor of FP16 training, adjusted automatically

Context. Reinforcement-learning (RL) fine-tuning of a language model runs two programs on the same weights. An software built for fast generation, such as vLLM or SGLang, that samples the responses used for training; this note calls it the sampler generates the responses, and a software that computes losses and gradients, such as PyTorch FSDP, DeepSpeed or Megatron; this note calls it the trainer recomputes their token probabilities and takes the gradient. In exact arithmetic the two compute the same policy. In practice they use different kernels, operation orders and parallel layouts, so they round at different places and give the same token different probabilities. This the difference between the token probabilities that the sampler and the trainer assign to the same response under the same weights makes nominally on-policy training slightly off-policy, and it has been linked to sudden collapses of RL runs. Earlier fixes reweight the gradient by reweighting samples drawn from one distribution by the ratio of a target distribution's probability to the sampling distribution's, so that averages estimate expectations under the target ratios between the two engines, per token (Yao et al., 2025) or per response (Liu et al., 2025), both blog posts, or align the two implementations by hand. Qi et al. (2025) trace most of the mismatch to the number format: bfloat16, a 16-bit floating-point format with 8 exponent bits and 7 mantissa bits: the range of 32-bit floats with coarse precision; the default for modern training, the 16-bit format that nearly all large-model training now uses.

BF16 has only 7 the bits of a floating-point number that store its significant digits; with mm of them, rounding to nearest changes a number by at most 2−(m+1)2^{-(m+1)} of its size, so each rounding can change a value by up to 2−8≈0.4%2^{-8}\approx0.4\%, and two engines that round at different places end up with visibly different log-probabilities. The differences add up along a response: in BF16 the trainer's log-probability of a sampled response is lower than the sampler's by about one nat per thousand tokens on average (the slope of a line the paper fits across responses). IEEE half precision: 5 exponent bits and 10 mantissa bits, so rounding is 8 times finer than in BF16, but the largest number is about 65,504 and the smallest normal one about 6×10−56\times10^{-5} rounds eight times more finely. Its narrow range matters little in fine-tuning, where pretraining has already set the scale of weights and activations, and multiplying the loss by a large factor SS before backpropagation and dividing the gradients by SS before the update, so that small gradients do not round to zero in FP16; dynamic versions adjust SS when overflows occur keeps small gradients representable. With both engines in FP16 the estimated KL divergence between their response distributions is 24 times smaller, and the plain importance-weighted policy gradient trains stably to near-perfect accuracy on a problem set the model can learn to solve, where every BF16 method in the comparison either collapses or levels off lower. The change is a configuration setting, and it also shrinks the the loss from tuning the weights to maximize reward under the trainer's probabilities when answers at evaluation and deployment are generated with the sampler's probabilities, which reweighting cannot remove.

Setting. A prompt xx gets a response y=(y1,…,y∣y∣)y=(y_1,\dots,y_{|y|}) with reward R(x,y)R(x,y), and the prefix (x,y1,…,yt−1)(x,y_1,\dots,y_{t-1}) before token tt is the prefix before token tt. Write the sampler's policy at weights θ\theta: μθ(yt∣st)\mu_\theta(y_t\mid s_t) is the probability the inference engine gives token yty_t after sts_t and the trainer's policy at weights θ\theta: the probabilities the training engine computes and differentiates for the sampler's and the trainer's policies at weights θ\theta, the weights that generated the current batch; θ\theta are the weights being updated, equal to θ′\theta' before the first update on that batch for the weights that sampled the current batch, and the per-token gap log⁡πθ′(yt∣st)−log⁡μθ′(yt∣st)\log\pi_{\theta'}(y_t\mid s_t)-\log\mu_{\theta'}(y_t\mid s_t) between trainer and sampler at the same weights, in nats for the per-token gap between them, which would be 0 in exact arithmetic. Training maximizes J(θ)=ExJ(x)J(\theta)=\mathbb E_x J(x), with J(x)=Ey∼πθ[R(x,y)]J(x)=\mathbb E_{y\sim\pi_\theta}[R(x,y)] for one prompt, but the responses are drawn from μθ′\mu_{\theta'}, so the unbiased gradient weights each response by its sequence ratio,∇θJ(x)=Ey∼μθ′[πθ(y∣x)μθ′(y∣x)⏟sequence weight×∇θlog⁡πθ(y∣x) A^],\begin{aligned}&\nabla_\theta J(x)=\mathbb E_{y\sim\mu_{\theta'}}\Big[\underbrace{\frac{\pi_\theta(y\mid x)}{\mu_{\theta'}(y\mid x)}}_{\text{sequence weight}}\\&\qquad\times\nabla_\theta\log\pi_\theta(y\mid x)\,\hat A\Big],\end{aligned}where the advantage: the reward R(x,y)R(x,y) minus a baseline that does not depend on yy, such as the mean reward of the other responses sampled for xx is the advantage; the paper calls this estimator PG-Seq-IS. Leaving the weight out biases the gradient whenever μ≠π\mu\ne\pi. The weight is a product of one ratio per token, so its variance grows with length; truncation caps it at a constant the cap on importance weights in the truncated and masked corrections; C=3C=3 in the paper's tests, and masking drops responses whose weight exceeds CC. The other methods start from group relative policy optimization: a clipped per-token policy-gradient objective in which each response's advantage is computed from the rewards of the other responses sampled for the same prompt in its the form of GRPO with no division by the group's reward standard deviation and with each response's summed token losses divided by a constant form, whose per-token ratio rt′=πθ(yt∣st)/πθ′(yt∣st)r'_t=\pi_\theta(y_t\mid s_t)/\pi_{\theta'}(y_t\mid s_t) divides by the trainer's own probability at θ′\theta'. GRPO-Token-TIS multiplies token tt's term by min⁡(wt,C)\min(w_t,C), with the per-token correction weight πθ′(yt∣st)/μθ′(yt∣st)=eδt\pi_{\theta'}(y_t\mid s_t)/\mu_{\theta'}(y_t\mid s_t)=e^{\delta_t}; its product over the response is w(y)w(y) the correction weight (Yao et al.), and GRPO-Seq-MIS multiplies every term of the response by w(y) 1{w(y)≤C}w(y)\,\mathbf 1\{w(y)\le C\} (Liu et al.). Both need an extra trainer forward pass at θ′\theta', about 25% of the training cost by the authors' count, which PG-Seq-IS avoids: the sampler records μθ′\mu_{\theta'}, and πθ\pi_\theta comes from the training forward pass. group sequence policy optimization: a GRPO variant that clips a length-normalized ratio of whole-response probabilities instead of per-token ratios; it does not use the sampler's probabilities is also tested.

Main findings (all empirical). (a) Offline, with DeepSeek-R1-Distill-Qwen-1.5B, FP16 in both engines cuts the estimated KL divergence between their response distributions from 7.64 to 0.32 nats, while the sampler's own accuracy is the same in BF16, FP16 and 32-bit (FP32) arithmetic to within about 2.5 points. (b) On a RL on the 1,460 MATH problems that the starting model solves in 20% to 80% of 40 samples; a sound algorithm should drive training accuracy to nearly 100%, and passing means converging above about 95% with that model, no BF16 method matches FP16: GRPO and GRPO-Token-TIS collapse, and GRPO-Seq-MIS stays stable but reaches only 95% training accuracy and 34% on AIME 2024, against 99% and 39% for PG-Seq-IS in FP16. (c) In FP16 all five algorithms perform almost the same. (d) With a BF16 trainer, raising only the sampler's precision helps, and a 32-bit sampler is fully stable but generates about three times more slowly; FP16 in both engines is stable at full speed. (e) FP16 is also more stable or learns faster for a 30B a model in which each token is processed by a few expert sub-networks chosen by a learned router (top-kk selection) out of many model, for low-rank adaptation: fine-tuning only a low-rank update BABA added to each weight matrix, with the original weights frozen training, for a 14B dense model trained with DAPO's recipe, and for OctoThinker-3B, a model from the Llama family.

Consequences. When RL fine-tuning is unstable, switch the sampler and the trainer to FP16, with the dynamic loss scaling that PyTorch, DeepSpeed and Megatron already provide, before adding importance-sampling corrections. With a small mismatch the plain unbiased estimator works, the extra forward pass of the GRPO-based corrections can be dropped, and the choice among corrections matters little. The mismatch on sampled tokens, such as the mean and extremes of πθ′−μθ′\pi_{\theta'}-\mu_{\theta'}, is worth tracking, since in these runs it grew before every collapse. Reweighting can remove the bias of the gradient but leaves the weights tuned for the trainer's probabilities; only making the engines agree helps the model that is deployed. FP16 shrinks the mismatch without removing it, and later work went further: a sampler that matches the trainer bit for bit, which showed that the mismatch alone can collapse training (Zhong et al., 2026), and a trust region measured in total variation from the sampler's probabilities (Qi et al., 2026).

Step 1

BF16 rounding accounts for most of the mismatch, and the mismatch grows with response length. FP16 spends 5 of its 16 bits on the exponent and 10 on the mantissa, so its largest number is about 6.6×1046.6\times10^4 and the next number above 1 is 1+2−101+2^{-10}; BF16 spends 8 and 7, reaching about 3.4×10383.4\times10^{38} with next number 1+2−71+2^{-7}. The engines differ in kernels, in how the model is split across GPUs, in processing a response token by token when generating and all at once when training, and, for mixture-of-experts models, in a top-kk expert choice that a small numerical difference can change; each difference moves where rounding happens. The authors sample 32 responses per AMC and AIME question from R1-Distill-Qwen-1.5B at temperature 1 with no top-p truncation, so that the sampler's probabilities are the model's unmodified ones, and rescore every token in the DeepSpeed training engine with the same weights. In FP16 the two engines' token probabilities lie much closer to the diagonal, and the sequence log-ratio ∑tδt=log⁡(πθ′(y∣x)/μθ′(y∣x))\sum_t\delta_t=\log\big(\pi_{\theta'}(y\mid x)/\mu_{\theta'}(y\mid x)\big) has a fitted slope of −1.01-1.01 nats per thousand tokens in BF16 against −0.07-0.07 in FP16. The sampler's accuracy does not depend on its precision: AMC 2023 and AIME 2024 scores agree across BF16, FP16 and FP32 to within about 2.5 points, in no consistent order. My reading, not in the paper: if the gap is proportional to the rounding step, 8-fold finer rounding makes per-token gaps about 8 times smaller and the KL divergence, quadratic in small gaps, up to 64 times smaller; the measured factor of 24 lies between the two.

Step 2

In BF16 the corrections trade bias against variance, and none reaches FP16's accuracy. The sanity test leaves out problems the model always solves, which waste compute, and problems it never solves, which leave a low score unexplained. Each iteration samples 64 questions with 8 responses each, with an 8,000-token context, and takes 4 gradient steps on that batch, and the comparison is repeated in two frameworks, VeRL and Oat. In BF16 plain GRPO collapses first (training accuracy peaks at 73% and 84% in the two frameworks), GRPO-Token-TIS a little later (82% and 88%), and GSPO, which ignores μ\mu, lasts longer still before its gradient norm becomes NaN in VeRL. Only GRPO-Seq-MIS does not collapse, but it learns slowly, reaching 95% training accuracy and 34% on AIME 2024. The authors read this as a tradeoff: per-token corrections and GSPO keep variance low but leave bias, so they learn fast and then collapse, while sequence-level weights remove the bias at the cost of the variance of a product of thousands of per-token weights. They attribute Seq-MIS's lower AIME score, against 39% for PG-Seq-IS in FP16, to the deployment gap.

Step 3

In FP16 the plain importance-weighted gradient works, and the choice among algorithms stops mattering. With both engines in FP16 the sequence weight πθ(y∣x)/μθ′(y∣x)\pi_\theta(y\mid x)/\mu_{\theta'}(y\mid x) is concentrated near 1 instead of spread over orders of magnitude, so PG-Seq-IS, with no truncation, trains faster and to higher reward than every BF16 correction in both frameworks, reaching 99% training accuracy. Run in FP16, GRPO, GRPO-Token-TIS, GRPO-Seq-MIS, GSPO and PG-Seq-IS give nearly indistinguishable curves (plain GRPO scores slightly lower on AIME 2024 and slightly higher on AIME 2025): with a small mismatch, training is nearly on-policy and the corrections have little to correct. The runs also show what comes before a collapse. In every run that collapses the mismatch grows first, and the extreme values of πθ′(yt∣st)−μθ′(yt∣st)\pi_{\theta'}(\htmlData{gr=gn1}{y_t}\mid s_t)-\mu_{\theta'}(y_t\mid s_t) over a batch approach ±1\pm1: with identical weights, one engine gives a sampled token probability near 1 and the other near 0. Stable runs keep the mismatch bounded. The authors suspect a bias in the optimization drives this growth and leave it untested.

Step 4

Raising only the sampler's precision helps, and FP16 in both engines is the only stable choice at full speed. In VeRL, with vLLM as the sampler and PyTorch FSDP as the trainer, the authors run four combinations: both in BF16; an FP16 sampler with a BF16 trainer; an FP32 sampler with a BF16 trainer; and both in FP16. With the BF16 trainer, each increase in the sampler's precision delays the collapse and raises reward, and the FP32 sampler gives a fully stable run, but its generation is nearly three times slower than in FP16 or BF16, which rules it out at scale. Both engines in FP16 give the lowest mismatch and the most stable run, reaching nearly 100% training accuracy with no loss of speed.

Step 5

The gain holds for a mixture-of-experts model, LoRA, a larger dense model and another model family. Mixture-of-experts models are the hardest case, since the engines split them across GPUs differently and route each token by a top-kk choice. On Qwen3-30B-A3B-Base trained on DAPO-Math-17k (16 responses per prompt, up to 20,480 tokens), FP16 gives higher training accuracy and higher AIME 2024 scores for all three algorithms tried. With LoRA of rank 32 on all layers, Qwen2.5-Math-1.5B trained on MATH with GRPO-Token-TIS collapses after about 600 steps in BF16 and trains stably in FP16. A 14B dense base model trained with DAPO's recipe on 54.4k math problems gains reward much faster in FP16 and reaches higher AIME 2024 accuracy. OctoThinker-3B, a Llama-3.2-3B model further trained on reasoning data, becomes unstable after about 150 steps of GRPO in BF16 and trains smoothly in FP16.

Limits. The evidence is training curves, one run per configuration with no repeated seeds reported, and the most detailed comparisons use a 1.5B model on a problem set filtered so that full accuracy is reachable. The largest models are a 30B mixture-of-experts model and a 14B dense one; the authors expect FP16's range to need care with overflow in much larger models, and the move toward 8-bit training for speed goes the other way. The link from rounding to collapse is shown by changing the precision; the paper does not trace which operations contribute most to the gap. How small the remaining FP16 mismatch must be to be harmless, and whether it stays harmless over much longer runs, is not measured.

Terms

Training-inference mismatch
sampler and trainer give the same token different probabilities under the same weights, because they round differently
BF16
8 exponent bits, 7 mantissa bits: FP32's range, next number above 1 is 1+2−71+2^{-7}
FP16
5 exponent bits, 10 mantissa bits: range up to about 65,504, next number above 1 is 1+2−101+2^{-10}
Loss scaling
multiply the loss by SS, divide the gradients by SS, so small FP16 gradients do not underflow
Sequence log-ratio
∑tδt\sum_t\delta_t: fitted slope −1.01-1.01 nats per 1,000 tokens in BF16, −0.07-0.07 in FP16
PG-Seq-IS
policy gradient weighted by πθ(y∣x)/μθ′(y∣x)\pi_\theta(y\mid x)/\mu_{\theta'}(y\mid x); unbiased, no extra forward pass
Token TIS / Seq MIS
multiply GRPO's terms by min⁡(wt,C)\min(w_t,C), or by w(y) 1{w(y)≤C}w(y)\,\mathbf 1\{w(y)\le C\}
Deployment gap
weights tuned for the trainer's probabilities, answers generated with the sampler's
Sanity test
1,460 MATH problems solved 20% to 80% of the time at the start; a sound method nears 100%
Precision ablation
FP32 sampler with BF16 trainer is stable but about 3 times slower; FP16 in both is stable at full speed

Quiz

  1. FP16 overflows above about 65,504, which is why pretraining moved to BF16. Why is its range not a problem in RL fine-tuning, according to the paper?
  2. Why can importance-sampling corrections remove the bias of the gradient but not the deployment gap?
  3. Why does PG-Seq-IS avoid the extra cost, about 25% of training by the authors' count, that GRPO-Token-TIS and GRPO-Seq-MIS incur?
  4. During a BF16 run, the mismatch between the engines on sampled tokens, the batch mean of ∣πθ′(yt∣st)−μθ′(yt∣st)∣|\pi_{\theta'}(y_t\mid s_t)-\mu_{\theta'}(y_t\mid s_t)|, starts to grow. What do these experiments suggest?

Sources