Off-Policy RL for LLMs, Explained Visually

Importance sampling and score centering for policy gradient

Oct 25, 2026

Part 1 derived the policy gradient for language models.An animation of a trainer p, as a point in a two-dimensional slice of parameter space, moving toward a high-reward region marked with a star. On-policy, the sampler is the trainer, so every step is pure signal. The trainer walks straight to the star, and a plot of its average reward below climbs to 1 and stays there. A cartoon of on-policy training. The sampler is the trainer, so training heads straight for high reward. It ended by describing the on-policy assumption, which says that the model generating the completions is the exact one we differentiate during training. That assumption rarely holds in practice. This post covers what happens when training goes off-policy and the two main ways to correct for it, importance sampling and score centering.

Recap

Part 1 ended by looking at the policy gradient one token at a time. At a given position in the completion, each possible next token vv has a probability pvp_v and a score sv=∇θlog⁡pvs_v = \nabla_\theta \log p_v. The sampled token yty_t contributes R sytR \, s_{y_t} to the policy gradient, where RR is the completion’s reward.

The key fact from part 1 is that the score has zero mean when the token is sampled from pp:

Eyt∼p[syt]=∑vpv ∇θlog⁡pv=∇θ∑vpv=0 \mathbb{E}_{y_t \sim p}[s_{y_t}] = \sum_v p_v \, \nabla_\theta \log p_v = \nabla_\theta \sum_v p_v = 0

The same fact is why subtracting a baseline bb from the reward doesn’t change the expected gradient, since b sytb \, s_{y_t} averages to zero as well. Off-policy, the score no longer averages to zero, so both properties break.

The examples in this post reuse the prompt from part 1, “What is 17 × 24?”.The prompt "What is 17 × 24? Show your work, then give a final answer." and a completion in progress, "17 × 24 = 17 × 20 + 17 × 4 = 340 +", followed by an empty slot. Below it, the model's probabilities for the next token: 68 at 0.82, the slip 58 at 0.07, and small amounts for other tokens. One token is sampled, appended, and the process repeats. The running example from part 1. After “17 × 24 = 17 × 20 + 17 × 4 = 340 +”, the model gives the correct next token, 68, a probability of 0.82, and the slip 58 a probability of 0.07. Choosing 68 leads to the right answer (408) and reward 1, while the slip 58 leads to a wrong answer and reward 0.

Where off-policy data comes from

Training is off-policy whenever the completions come from a distribution qq other than the policy pθp_\theta being updated. In LLM RL, an inference engine generates the rollouts and a training framework updates the weights, so we’ll call qq the sampler and pθp_\theta the trainer. Any gap between the two is called the training-inference mismatch. It is famously hard to get rid of, and it can quietly degrade training or collapse the reward entirely.Supervised fine-tuning, by contrast, happily trains on text generated by an entirely different model or written by a person, with no correction at all.

There are three common causes of unwanted mismatch. Two come from timing, because the sampler generated the rollouts using older weights than the trainer’s current ones. The third comes from computation, because the two engines compute slightly different probabilities even from the same weights.

The RL loop. The sampler q, an inference engine such as vLLM or SGLang, generates rollouts, which go to the trainer p, a training framework, with their rewards. The trainer recomputes log-probabilities, takes a gradient step, and syncs the new weights back to the sampler. In theory q equals p; in practice they differ.

Multiple updates per batch

Generating rollouts is often the most expensive part of RL for LLMs, so trainers usually split each batch of rollouts into minibatches and take one gradient step on each. DAPO, for example, splits each batch into 16 steps. Only the first step is on-policy. After that first step, θ\theta has moved, and every later minibatch comes from a slightly older policy.Classic PPO goes further and makes several passes, or epochs, over the same batch. Recent LLM recipes mostly avoid this for stability. TRL’s GRPO trainer, for example, defaults to a single pass. This staleness is a deliberate tradeoff for sample efficiency, and proximal policy optimization (PPO) introduced ratio clipping specifically to handle it.

One batch of rollouts, all sampled by θ₀, is split into four minibatches. Each takes one gradient step, so the policy moves from θ₀ to θ₁, θ₂, and θ₃. The first minibatch is trained at the same θ₀ that sampled it and is on-policy; the second, third, and fourth are one, two, and three steps stale.

Stale weights

To keep GPUs busy, large-scale RL runs inference and training asynchronously and serves rollouts with continuous batching. While the sampler is still generating a slow rollout, the trainer keeps updating the weights on faster ones that already finished. By the time that rollout completes, the trainer has moved on to a newer checkpoint, and if new weights sync mid-generation, a single rollout can even span several checkpoints. This staleness is worst in long agentic tasks, where some episodes finish in minutes and others take hours or days.

Asynchronous training. The trainer takes steps at θ₀, θ₁, θ₂, and θ₃ while the sampler keeps generating, receiving new weights at each sync. A short rollout is generated entirely by θ₀. A long rollout starts under θ₀, continues under θ₁ after the first sync, and finishes under θ₂, so a single completion contains tokens from three different policies, all older than the θ₃ it is trained at.

Numerical differences

Even with fresh weights and a single gradient step, the sampler and trainer rarely compute the exact same probabilities. They are usually different programs: after the sampler generates a rollout, the trainer runs its own forward pass over those tokens to compute log-probabilities for the policy gradient loss. Even on identical weights, the two forward passes can disagree for two reasons:

  • Different precisions and codebases. The two engines may run at different precisions, such as an fp8 or int8 sampler paired with a bf16 trainer, or a quantized KV cache.A floating-point format can store only a fixed number of values between consecutive powers of two, and every weight and activation is rounded to the nearest one. bf16 has 128 values between 1 and 2, spaced 1/1281/128 apart, while fp8’s e4m3 format has only 8, spaced 1/81/8 apart. So the same weight, 1.3, is stored as 1.296875 in bf16 but 1.25 in fp8. A number line from 1.25 to 1.375. In bf16, the representable values are 1/128 apart, and 1.3 rounds to the nearby 1.296875. In fp8 e4m3, the only representable values in this range are 1.25 and 1.375, and 1.3 rounds to 1.25. They may also come from independent codebases, each with its own hard-to-detect bugs.
  • Same kernels, different shapes. Even with identical, correct kernels, the sampler decodes one token at a time while the trainer scores the whole completion in one forward pass. Different input shapes can change the order of floating-point reductions, and floating-point addition isn’t associative.Addition is associative when (a+b)+c(a + b) + c always equals a+(b+c)a + (b + c). Floating-point addition isn’t, because each intermediate sum is rounded to the nearest representable number, and representable numbers get sparser as they grow. In bf16, they are 1 apart just below 256 but 2 apart above it, so 257 has no exact representation and rounds back to 256. In bf16, representable numbers are 1 apart below 256 and 2 apart above it, so 257 rounds to 256. So (1+1)+256=258(1 + 1) + 256 = 258, but 1+(1+256)1 + (1 + 256) rounds to 256256 at each step. When different kernels add a long sum of logits or attention scores in a different order, the final result can differ slightly for the same reason. Batch-invariant kernels remove the dependence on shape, but they take real engineering effort and cost GPU utilization. Running both engines in fp16 instead of bf16 greatly reduces the mismatch, but doesn’t eliminate it.

At the “340 +” slot from part 1, for example, the two engines can disagree slightly about the next token, even with identical weights:

The same prefix and weights, scored by two engines. The sampler, running in fp8 and decoding one token at a time, gives 68 a probability of 0.83 and 58 a probability of 0.06. The trainer, running in bf16 and scoring the whole completion at once, gives 0.82 and 0.07.

Here the trainer gives the slip 58 a probability of 0.07, while the sampler used 0.06. Small discrepancies like this show up at every token of every rollout.

Small as they are, these differences can build up over training and grow larger in long responses, where the reward signal is already thin (a fixed number of bits of feedback spread across more tokens) and asynchronous execution adds staleness on top.

All three sources of mismatch come from deliberate throughput tradeoffs. Multiple updates per batch, asynchronous rollouts, and fast inference kernels make RL practical at scale, and giving them up would make training much slower. So the practical question is how to train well on off-policy data.

Sampling from a better model

In all three cases above, the sampler is meant to be a copy of the trainer, so any gap between them is error. Other times, the data comes from a different source on purpose, because it can show the trainer something it wouldn’t produce on its own:

  • A stronger model. Rollouts from a larger or better model can show the trainer solutions it would rarely find on its own. LUFFY, for example, mixes reasoning traces from a stronger model into on-policy RL.
  • A teacher with extra context. Even the same model can act as a teacher if its prompt includes the reference solution or other privileged information; the student then learns from those completions without seeing the hint. STaR’s rationalization step works this way, giving the correct answer as a hint. Instead of generating completions, the teacher can also score the student’s rollouts.
  • People. Hand-written demonstrations are the oldest kind of off-policy data, and SFT trains on them with no correction at all.

Here the gap between sampler and trainer carries useful signal rather than error, and the question is how much of it the trainer should absorb. The gap can also be large, which weakens corrections that assume a small mismatch. The rest of this post focuses on unwanted mismatch.

Why off-policy updates go wrong

The policy gradient is an expectation over completions from the policy being trained. With off-policy data, the REINFORCE estimator averages the same quantity over the sampler’s completions instead. The trainer computes the same formula on each completion, R(y) ∇θlog⁡pθ(y)R(y) \, \nabla_\theta \log p_\theta(y), but averaging it over qq instead of pθp_\theta changes the expectation:

Ey∼q[R(y) ∇θlog⁡pθ(y)]≠Ey∼pθ[R(y) ∇θlog⁡pθ(y)]=∇θJ(θ) \begin{aligned} &\mathbb{E}_{y \sim q}\big[R(y) \, \nabla_\theta \log p_\theta(y)\big] \\ &\quad \neq \mathbb{E}_{y \sim p_\theta}\big[R(y) \, \nabla_\theta \log p_\theta(y)\big] = \nabla_\theta J(\theta) \end{aligned}

To see what goes wrong, look at a single token position under a constant reward.

A thought experiment: constant reward

Suppose every completion earns the same reward, R=1R = 1, no matter what it says.An animation of a trainer p, as a point in a two-dimensional slice of parameter space, with a sampler q off to one side. Every completion earns the same reward, so there is no signal, and every step is pure drift. The trainer walks in a straight line to the sampler and stops there. There is nothing to learn, and on-policy the expected update is exactly zero. At each position, the sampled token’s score averages to Ep[syt]=0\mathbb{E}_p[s_{y_t}] = 0, so Ep[R syt]=R⋅0\mathbb{E}_p[R \, s_{y_t}] = R \cdot 0.

Off-policy, the sampler qq draws the token, while the trainer pp still computes its score. The average score is then

sˉ=Eyt∼q[syt]=∑vqv ∇θlog⁡pv, \bar{s} = \mathbb{E}_{y_t \sim q}[s_{y_t}] = \sum_v q_v \, \nabla_\theta \log p_v ,

and the zero-mean identity no longer applies, because the weights qvq_v are not the probabilities pvp_v inside the score. In general sˉ≠0\bar{s} \neq 0, so the expected update Eq[R syt]=R sˉ\mathbb{E}_q[R \, s_{y_t}] = R \, \bar{s} isn’t zero either. The model moves even though the reward carries no information.

That update points along sˉ\bar{s}, which is the negative gradient of the cross-entropy loss −∑vqvlog⁡pv-\sum_v q_v \log p_v between qq and pp. Minimizing that loss trains pp to imitate qq, so with a constant reward, off-policy policy gradient is supervised distillation of the trainer toward the sampler. It pulls pp toward whatever qq does, including every quirk of its numerics or staleness.

Drift and signal

When the reward varies across completions, the covariance identity E[AB]=E[A] E[B]+Cov(A,B)\mathbb{E}[AB] = \mathbb{E}[A]\,\mathbb{E}[B] + \mathrm{Cov}(A, B) splits the update into a part from the mismatch and a part from the reward. As before, fix the prompt and the prefix before position tt. Averaging over the next token yt∼qy_t \sim q and the rest of the completion (which determines RR) gives:

Eq[R syt]⏟policy gradient update=Eq[R]  sˉ⏟drift+Covq(R,  syt)⏟signal \underbrace{\mathbb{E}_q[R \, s_{y_t}]}_{\text{policy gradient update}} = \underbrace{\mathbb{E}_q[R] \; \bar{s}}_{\text{drift}} + \underbrace{\mathrm{Cov}_q(R, \; s_{y_t})}_{\text{signal}}

  • The signal term is the only one that depends on which tokens led to which rewards. It is large when tokens that tend to produce high reward have scores pointing in a consistent direction. This is the part of the update we actually want.
  • The drift term depends on the rewards only through their average. Its direction is sˉ\bar{s}, the distillation direction from the thought experiment, scaled by how much reward the prefix typically earns.

On-policy, q=pq = p, so sˉ=0\bar{s} = 0 and the drift term vanishes. It exists only because of the mismatch.

Why drift compounds

Distilling toward a sampler that never changes is benign.The same cartoon with a frozen sampler, never updated, sitting off to one side of the trainer's path. Each step adds a drift toward the sampler to the signal, which is measured at the sampler, and the trainer settles where the two pulls balance, short of the star. Its average reward climbs and then plateaus below the on-policy level. The reward of the sampler's rollouts stays flat, since the sampler never changes. A frozen sampler: training settles short of the peak. Its target stays put, so pp simply converges toward qq and stops. But in RL for language models, the sampler doesn’t stay fixed. Every weight sync refreshes it from the trainer’s latest weights, and it then adds its own numerical bias on top. So the sampler is a slightly biased copy of the trainer that moves whenever the trainer does.

That closes a feedback loop.The same cartoon with a synced sampler. After every three steps, the sampler copies the trainer's weights, and its fixed bias pushes it away again, so it keeps landing to one side of the trainer. The trainer approaches the star, then gets dragged past it along the bias and keeps going. Its average reward, and the reward of the sampler's rollouts, peak early and then fall steadily for the rest of training. A synced sampler: the reward peaks, then falls. Each step pulls the trainer toward the biased sampler, and the next sync copies those new weights back into the sampler, which applies its bias again. If that bias points the same way from one step to the next, each pull adds to the last and the error keeps growing. A quantized sampler could produce this kind of persistent bias: its rounding error is a deterministic function of the weights, and the weights change only a little per step (though nothing guarantees that successive pulls line up).We don’t yet know whether real numerical bias persists across steps. The trainer–sampler gap has been seen to grow during training, but kernel errors also look like symmetric noise, which would partly cancel. That may explain why off-policy runs often look fine for a while and then suddenly collapse.

At scale, Modal saw this pattern training a 35B model on agentic coding. In every run that collapsed, the sampler–trainer KL had first grown threefold or more. Samplers matched to the trainer’s hardware and precision started with about a quarter of the mismatch, but GRPO still collapsed on them, just later. With the corrections below, runs stayed stable at nearly five times the mismatch. So the mismatch’s growth predicted collapse, and its starting size didn’t.

Evidence: frozen vs synced samplers

This feedback loop makes a testable prediction. With a frozen sampler, training with +1/0+1/0 rewards is ordinary SFT on the correct completions, which is stable even on text from a completely different model. With a synced sampler, the same rewards should become unstable, because the sampler is a biased copy of the trainer that keeps getting refreshed.

Marek and Ryabinin test this by training Qwen3-1.7B on the Countdown arithmetic game, with the sampler’s weights slightly perturbed to create a controlled mismatch. They compare three reward schemes, +1/0+1/0, +1/−1+1/{-}1, and group-centered, with the sampler either frozen (never updated) or synced from the trainer after every step.Redrawn from Marek and Ryabinin (2026), Figure 2. Each curve is the mean of three seeds.

Two plots of held-out accuracy over 600 training steps, starting from about 45%. With a frozen sampler, never updated: +1/0 rewards climb slowly to about 53% and stay there, while +1/−1 and group-centered rewards collapse to 0% within 20 steps. With a mismatched sampler synced every step: group-centered rewards climb to about 78% and stay there; +1/−1 reaches about 69%, then declines from step 140 and falls to about 35%; +1/0 peaks at about 61% after 20 steps, then collapses to about 5% by step 340.

  • With a frozen sampler, only +1/0+1/0 is stable, since it reduces to SFT on the correct completions. The two schemes with negative rewards collapse within 20 steps for a different reason: pushing down the probability of fixed bad completions has no floor, as log⁡p\log p can fall to −∞-\infty.
  • With a synced sampler, the ordering flips. +1/0+1/0, the SFT-like setting, collapses first, +1/−1+1/{-}1 lasts longer, and group-centered rewards stay stable.

The drift term explains the ordering with a synced sampler. Its size is set by the average reward E[R]\mathbb{E}[R], and at the same accuracy, the three schemes give very different averages:

  • With +1/0+1/0 rewards, E[R]\mathbb{E}[R] equals the accuracy, about 0.5 to 0.6 in these runs, so the drift is large from the first step. This run collapses first.
  • With +1/−1+1/{-}1 rewards, E[R]=2⋅accuracy−1\mathbb{E}[R] = 2 \cdot \text{accuracy} - 1. At the starting accuracy of about 45%, that’s close to zero, and it reaches only about 0.4 once the model improves. The drift is smaller, and this run lasts longer before collapsing.
  • With group-centered rewards, E[R]\mathbb{E}[R] is zero at the prompt by construction, whatever the accuracy.This holds when every completion counts equally, as in the original GRPO loss, which averages over each completion’s tokens. Variants like DAPO and Dr. GRPO weight every token equally instead, so longer completions count more. The drift shared by every token then scales with a length-weighted average advantage, ∑iAiLi/∑iLi\sum_i A_i L_i / \sum_i L_i for completions of length LiL_i, which is zero only if right and wrong completions are equally long. This run stays stable.

Even when E[R]\mathbb{E}[R] is zero across whole completions, though, it rarely stays zero at individual prefixes.

Drift survives group centering

Group centering, as in GRPO, works at the sequence level. It subtracts the group’s average reward from each completion’s reward, and every token in the completion shares that same advantage. Because those advantages average to zero across the group, you might expect the drift to vanish. At any token position, though, drift scales with the expected advantage at that prefix. That token-level average can be far from zero even when the whole group averages to zero.

A prefix that has already made the “340 + 58” slip is headed for a wrong answer, so its expected advantage is negative. A prefix that is on track, like “340 + 68”, has a positive one. These prefix-level averages are largest in magnitude where the outcome is already mostly decided. There the later tokens barely affect the reward, so the signal is near zero and the update is almost pure drift.

The expected reward at three prefixes of the 17 × 24 prompt, which sets the scale of the drift there, under three reward schemes. At the prompt, where P(correct) is about 0.5: +0.50 with +1/0 rewards, and 0 with +1/−1 and group-centered rewards. After the on-track prefix "340 + 68", where P(correct) is about 0.95: +0.95, +0.90, and +0.45. After the slip "340 + 58", where P(correct) is about 0.02: +0.02, −0.96, and −0.48. Values above zero pull the trainer toward the sampler, and values below zero push it away. Group centering makes the value zero at the prompt, but not at the later prefixes.

Group centering shrinks the drift, which explains why it is the most stable of the three schemes above, but it doesn’t eliminate it. Promising prefixes still pull the trainer toward the sampler, and mistakes push it away, even at tokens that don’t affect the reward.

Importance sampling

The classical fix for training on samples from the wrong distribution is importance sampling, a general Monte Carlo technique for estimating an expectation under one distribution using samples drawn from another.Here we use only the reweighting step, which some authors call importance weighting. Classic importance sampling also chooses the distribution to sample from, often to reduce variance. In RL the samples come from whatever sampler produced them, so there is no such choice to make. The RL literature still calls it importance sampling, and method names like TIS and MIS follow that usage.

Reweighting the samples

For any function ff,The synced-sampler cartoon again, with each rollout weighted by its importance ratio p/q. The sampler still copies the trainer every three steps and is pushed to one side by its bias, but the weights cancel the drift, so every step is signal only. The signal is measured at the trainer. The trainer takes the same path as on-policy training, straight to the star, and its average reward climbs to 1 and stays there. The reward of the sampler's rollouts levels off a little lower, since the sampler sits one bias away from the star. Weighted by the exact importance ratios, the sampler’s bias no longer matters. The trainer follows the on-policy path.

Ey∼p[f(y)]=∑yp(y) f(y)=∑yq(y) p(y)q(y) f(y)=Ey∼q[p(y)q(y) f(y)] \begin{aligned} \mathbb{E}_{y \sim p}[f(y)] &= \sum_y p(y) \, f(y) \\ &= \sum_y q(y) \, \frac{p(y)}{q(y)} \, f(y) \\ &= \mathbb{E}_{y \sim q}\Big[\frac{p(y)}{q(y)} \, f(y)\Big] \end{aligned}

Each sample is weighted by its importance ratio p(y)/q(y)p(y)/q(y). If the sampler generates a completion more often than the trainer would, the completion gets down-weighted, and if it generates one less often, that one gets up-weighted. On average, the samples then count as if they had been drawn from pp. The only requirement is that the sampler can generate everything the trainer can: q(y)>0q(y) > 0 wherever p(y)>0p(y) > 0.Top-p and top-k sampling break this, because tokens outside the nucleus have q=0q = 0 but p>0p > 0. The usual fix, used by MAI-Thinking-1 and DeepSeek, is to apply the sampler’s mask in the trainer too, so pp has the same support as qq.

Applied to the policy gradient, with f(y)=R(y) ∇θlog⁡pθ(y)f(y) = R(y) \, \nabla_\theta \log p_\theta(y), this gives an unbiased estimate from the sampler’s rollouts:

∇θJ(θ)=Ey∼q[pθ(y)q(y)⏟importance ratioR(y)∇θlog⁡pθ(y)] \nabla_\theta J(\theta) = \mathbb{E}_{y \sim q}\big[\underbrace{\tfrac{p_\theta(y)}{q(y)}}_{\text{importance ratio}} R(y)\nabla_\theta \log p_\theta(y)\big]

Reweighting is also cheap. The trainer already computes pθ(y)p_\theta(y) in its forward pass, and inference engines can return the log-probabilities of the tokens they sample at almost no extra cost.

Why sequence-level ratios explode

A completion’s probability is the product of its token probabilities, so its importance ratio is a product of per-token ratios:

pθ(y)q(y)=∏t=1Tpθ(yt∣y<t)q(yt∣y<t)⏟rt \frac{p_\theta(y)}{q(y)} = \prod_{t=1}^{T} \underbrace{\frac{p_\theta(y_t \mid y_{<t})}{q(y_t \mid y_{<t})}}_{r_t}

Each factor is usually close to 1,In the worked example from earlier, at “340 +” in 17 × 24, the trainer gives the slip 58 a probability of 0.07 and the sampler 0.06, so its factor is 0.07/0.06≈1.170.07 / 0.06 \approx 1.17. The factor for 68 is 0.82/0.83≈0.990.82 / 0.83 \approx 0.99. but a completion has hundreds or thousands of them, and small factors compound. A per-token ratio of 1.01, repeated over 1,000 tokens, compounds to 1.011000≈21,0001.01^{1000} \approx 21{,}000, and 0.99 shrinks to 0.991000≈0.000040.99^{1000} \approx 0.00004.

Real per-token ratios aren’t constant. They wander above and below 1, but under the sampler each one averages to exactly 1, Eq[pv/qv]=∑vpv=1\mathbb{E}_q[p_v / q_v] = \sum_v p_v = 1, which is what keeps importance sampling unbiased. The log of the sequence ratio is a sum of these small random terms, so it behaves like a random walk whose spread grows with the square root of the length. A simulation with small random per-token ratios shows how quickly the rollouts’ weights spread apart:Each token’s log-ratio is drawn from a normal distribution with mean −0.05²/2 and standard deviation 0.05, so a typical ratio is within about 5% of 1, and the ratios average exactly 1. The y-axis uses a log scale, where each path is a random walk that drifts downward, so most rollouts end well below 1. The few that end above it hold the mean at 1. Each rollout’s gradient is multiplied by its weight, so the ×8.5 rollout counts about 300 times as much as the ×0.03 one, but nothing about it is more informative. Its tokens’ small disagreements just happened to line up. The histogram shows where 5,000 rollouts end. The shares in the text use 20,000, and the effective sample sizes split those into batches of 512.

Simulated rollouts, each 1,000 tokens long, with the running product of per-token ratios on a log scale from 0.01 to 10. All start at 1. Most drift downward, well below 1, while a few climb toward 10. By the end, one highlighted rollout has a weight of 8.5 while another has 0.03. A sideways histogram on the right shows where 5,000 rollouts end, piled up near zero with a median of about 0.28, below the dashed line at 1, which is still the mean, held up by the few large weights.

The weights still average to 1, so the estimate stays unbiased, but that average is shared very unevenly. In this simulation, most rollouts get a weight below 1Each token’s ratio averages to exactly 1 under the sampler, Eq[r]=∑vqv pv/qv=1\mathbb{E}_q[r] = \sum_v q_v \, p_v / q_v = 1, but its log does not average to 0. Because log is concave, Eq[log⁡r]≤log⁡Eq[r]=0\mathbb{E}_q[\log r] \le \log \mathbb{E}_q[r] = 0, and the gap is exactly KL(q ∥ p)\mathrm{KL}(q \,\|\, p). So the log of the sequence weight is a random walk that drifts downward, by about KL\mathrm{KL} per token, while its spread grows only with the square root of the length. Over many tokens, most weights sink below 1, and a few large ones make up the difference. In this simulation, 78% end up below 1, and the share approaches 100% as completions get longer. and barely move the gradient, while a few get large weights and dominate it. As completions get longer, an even larger share falls below 1. At 1,000 tokens, a batch of 512 rollouts weighted this way has an effective sample size of only about 70:This is the effective sample size, (∑iwi)2/∑iwi2(\sum_i w_i)^2 / \sum_i w_i^2 for weights wiw_i. It equals the batch size when all weights are equal and approaches 1 when a single weight dominates. It measures how concentrated the weights are. Because the gradient’s noise also depends on the rewards and scores, ESS does not measure that noise directly. The values here are medians over simulated batches of 512. you pay to generate 512 rollouts, but the batch behaves like 70. At 2,000 tokens, it drops to about 20.

Token-level ratios

Sequence-level importance sampling weights every token’s score in a completion by the same number, the product of all its per-token ratios. In practice, almost every method uses token-level ratios instead, weighting each token’s score by its own ratio rtr_t:

∑trt R syt,rt=pθ(yt∣y<t)q(yt∣y<t) \sum_t r_t \, R \, s_{y_t}, \qquad r_t = \frac{p_\theta(y_t \mid y_{<t})}{q(y_t \mid y_{<t})}

Compared with the exact sequence ratio, this keeps one factor of the product and sets all the others to 1. Every token gets its own correction, but each term reweights only the choice of that token itself. It leaves the prefix before the token and the continuation after it (which decides the reward) uncorrected:

One completion split at the token 68: the prefix "17 × 24 = … = 340 +", the token 68, and the rest of the completion, "= 408. Answer: 408". Exact importance sampling would weight the token's score by the ratios of all the prefix tokens, times its own ratio r_t, times the ratios of all the later tokens. Token-level importance sampling keeps only r_t and sets the other factors to 1. So the token itself is corrected, but the prefix, which decides where the token is sampled, and the rest of the completion, which decides the reward, are still distributed according to the sampler q. Dropping them trades the product's exploding variance for a bias, which is small when p ≈ q.

The token itself is corrected exactly. With its prefix held fixed, weighting the sampled token by rtr_t turns an average over the sampler’s next-token distribution into an average over the trainer’s. In particular, it restores the zero-mean identity from the recap:

Eyt∼q[rt syt]=∑vqv pvqv sv=∑vpv sv=0 \mathbb{E}_{y_t \sim q}[r_t \, s_{y_t}] = \sum_v q_v \, \frac{p_v}{q_v} \, s_v = \sum_v p_v \, s_v = 0

So the drift term vanishes at every prefix, and only the signal is left.

The prefix and continuation in that term are not corrected. Both still come from the sampler, which decides what prefixes the token is trained on (like “340 +”) and how the completion finishes from there to earn its reward. Correcting for those would require multiplying in the ratios of every other token, which is the product that explodes. So token-level importance sampling is an approximation. It works well when the sampler and trainer are close, since they then reach similar prefixes and finish them in similar ways.

Token ratios are much better behaved than their product, but they are still unbounded. The largest ones come from tokens that the trainer finds much more likely than the sampler did. A token with q=0.001q = 0.001 and p=0.01p = 0.01 gets a weight of 10. Any one such token is rare, but a batch has millions of tokens, so some appear in every batch. A handful of heavily weighted tokens can then dominate the gradient. The weight never divides by zero, since the sampler produced each token and so gave it q>0q > 0, but it has no ceiling.

A gradient dominated by a few tokens causes three problems. It points wherever their scores point, so it swings from batch to batch depending on which rare tokens happened to be drawn. The two engines also disagree most on those tokens, often because of numerical error, so the gradient leans hardest on its least reliable parts. And a single huge weight inflates the gradient’s norm. If gradients are clipped by norm, as they usually are, the whole update shrinks, and every other token’s contribution with it.

Bounding the ratio: TIS, MIS, and PPO

So practical methods bound the ratio. They differ in what they do with a token whose ratio falls outside the bounds:

  • Truncated importance sampling (TIS) caps the weight at wt=min⁡(rt,C)w_t = \min(r_t, C), with C=2C = 2 a common default. Tokens with large ratios still count, just by no more than CC. CISPO caps the weight the same way.
  • Masked importance sampling (MIS), introduced as IcePop, keeps rtr_t inside a band such as [0.5,5][0.5, 5] and drops the token outside it. The idea is that when the two engines disagree that much, the token’s gradient is too unreliable to use.
  • Proximal policy optimization (PPO) clips the objective with min⁡(rtAt, clip(rt,1−ϵ,1+ϵ) At)\min\big(r_t A_t, \ \mathrm{clip}(r_t, 1 - \epsilon, 1 + \epsilon) \, A_t\big), typically with ϵ=0.2\epsilon = 0.2. Taking the minimum of the clipped and unclipped terms makes the objective pessimistic: clipping can only lower it, never raise it. For the gradient, that acts as a one-sided mask. The clip binds only after the advantage has pushed the ratio past the band, above 1+ϵ1 + \epsilon for a positive advantage or below 1−ϵ1 - \epsilon for a negative one, where the objective flattens and the token’s gradient becomes zero. On the other side of the band, the unclipped term is smaller and the token keeps its full weight rtr_t. For a negative advantage, that leaves every ratio above 1+ϵ1 + \epsilon unclipped, so the weight is still unbounded there. DAPO raises the upper edge to 1.28.PPO was designed for multiple updates per batch, where the ratio measures how far the policy has moved since the rollouts were generated. Many implementations compute the denominator by running the old policy in the trainer rather than using the sampler’s logged probabilities, so the ratio never sees the numerical mismatch. IcePop uses both: MIS between sampler and trainer, and PPO clipping between policy versions.
  • Group sequence policy optimization (GSPO) stays at the sequence level but replaces the product with the geometric mean of the token ratios, (pθ(y)/q(y))1/T(p_\theta(y) / q(y))^{1/T}, and clips that to a very narrow band. Averaging the log-ratios instead of summing them keeps the weight from growing or shrinking exponentially with length.
Four plots of the weight each token's score gets as a function of its ratio r = p / q, on a log scale from 0.1 to 10, over a faint histogram showing that most ratios are close to 1. Importance sampling: w = r, which grows without bound. TIS and CISPO: w = min(r, 2), so weights above 2 are capped. MIS and IcePop: w = r between 0.5 and 5, and zero outside that band, so those tokens are dropped. PPO: w = r inside the band from 0.8 to 1.2; for a positive advantage, tokens above 1.2 are dropped, and for a negative advantage, tokens below 0.8 are dropped.

What bounding the ratio costs

Every bound trades variance for bias.With a fixed cap, like TIS’s 2, this bias doesn’t shrink with more samples. It would if the cap grew like n\sqrt{n} in the number of samples nn (Ionides, 2008). The ratio was there to remove the drift, and bounding brings some of it back. The zero-mean calculation above shows where it comes from. For weights that depend only on the token, such as TIS’s cap and MIS’s mask, replace rvr_v with the bounded weight wvw_v.PPO’s clip doesn’t fit this form, because the active side of the band depends on the sign of the advantage (how the whole completion turned out) rather than on the token alone. It still leaves drift behind, just with a messier formula. The expected weighted score at a prefix is then

Eq[wyt syt]=∑vqv wv sv=∑vqv wv sv−∑vpv sv⏟= 0=−∑v(pv−qv wv) sv=−∑v∈B(pv−qv rv)⏟= 0 sv−∑v∉B(pv−qv wv) sv=−∑v∉B(pv−qv wv) sv, \begin{aligned} \mathbb{E}_q[w_{y_t} \, s_{y_t}] &= \sum_v q_v \, w_v \, s_v \\ &= \sum_v q_v \, w_v \, s_v - \underbrace{\sum_v p_v \, s_v}_{=\,0} \\ &= -\sum_v \big(p_v - q_v \, w_v\big) \, s_v \\ &= -\sum_{v \in \mathcal{B}} \underbrace{\big(p_v - q_v \, r_v\big)}_{=\,0} \, s_v - \sum_{v \notin \mathcal{B}} \big(p_v - q_v \, w_v\big) \, s_v \\ &= -\sum_{v \notin \mathcal{B}} \big(p_v - q_v \, w_v\big) \, s_v , \end{aligned}

where B\mathcal{B} is the set of tokens whose ratio falls inside the bounds.The synced-sampler cartoon with truncated importance sampling. In this cartoon, the capped weights cancel part of the drift and move the point where the signal is measured partway from the sampler toward the trainer, so each step is that signal plus a smaller drift toward the sampler. The trainer gets close to the star, and settles just to the side of it, where the leftover drift balances the signal. Its average reward levels off near 0.95, while the reward of the sampler's rollouts, one bias further away, levels off near 0.77. TIS: some drift survives, so training settles just off the peak. Those keep wv=rvw_v = r_v, so qv wv=pvq_v \, w_v = p_v and they drop out. Drift comes back only through the tokens outside B\mathcal{B}: when MIS drops a token, it leaves −pv sv-p_v \, s_v (as if the sampler could never have produced it), and when TIS caps a token at 2, it leaves −(pv−2 qv) sv-(p_v - 2 \, q_v) \, s_v.

Bounding caps or drops only tokens whose ratio is far from 1, so it removes drift where the two engines roughly agree and leaves it where they disagree most. A more severe mismatch pushes more tokens outside the bounds and can leave more drift behind.

Score centering

Importance sampling removes drift by reweighting samples, but its practical, bounded versions let some of the drift back in.The synced-sampler cartoon with score centering. Each step's signal is measured at the sampler's position and applied to the trainer, and there is no drift. The trainer moves so that the sampler, which sits one bias away from it, climbs toward the star. Within a few syncs, the sampler lands on the star and the trainer stops one bias away from it. The reward of the sampler's rollouts climbs to 1, while the trainer's own reward levels off just below. Score centering: no drift, so the sampler climbs to the peak and the trainer stops one bias away. Score centering removes drift directly, by subtracting the sampler’s expected score at every prefix.

Subtracting the expected score

A token’s score syt=∇θlog⁡pyts_{y_t} = \nabla_\theta \log p_{y_t} points in the direction in parameter space that makes that token more likely, and each sampled token contributes R sytR \, s_{y_t} to the update. Off-policy, these scores no longer average to zero. Their average under the sampler, sˉ\bar{s}, is the single cause of the drift, and score centering subtracts it from the score of every sampled token:

s~yt=syt−sˉ \tilde{s}_{y_t} = s_{y_t} - \bar{s}

The centered score averages to zero under the sampler, Eq[s~yt]=sˉ−sˉ=0\mathbb{E}_q[\tilde{s}_{y_t}] = \bar{s} - \bar{s} = 0, so when the update is split into drift and signal, the drift term vanishes and only the signal is left:

Eq[R s~yt]=Eq[R]Eq[s~yt]⏟= 0+Covq(R,s~yt)=Covq(R,  syt−sˉ⏟constant)=Covq(R,syt) \begin{aligned} \mathbb{E}_q[R \, \tilde{s}_{y_t}] &= \mathbb{E}_q[R] \underbrace{\mathbb{E}_q[\tilde{s}_{y_t}]}_{=\,0} + \mathrm{Cov}_q(R, \tilde{s}_{y_t}) \\ &= \mathrm{Cov}_q\big(R, \; s_{y_t} - \underbrace{\bar{s}}_{\text{constant}}\big) \\ &= \mathrm{Cov}_q(R, s_{y_t}) \end{aligned}

Compare the centered update with the policy gradient ∇θJ\nabla_\theta J, the direction that most increases the trainer’s expected reward. On-policy, each prefix contributes Ep[R syt]\mathbb{E}_p[R \, s_{y_t}], and since the score already averages to zero there, the same decomposition leaves just Covp(R,syt)\mathrm{Cov}_p(R, s_{y_t}). So at each prefix, score centering turns the off-policy update back into the on-policy one, except that the covariance is measured over the sampler’s draws. Across a whole rollout, the sampler still determines which prefixes are visited, just as in token-level importance sampling.At the logits, the entry of Covp\mathrm{Cov}_p for token aa is pa Ap(a)p_a \, A_p(a): the token’s probability times its advantage (how much choosing it raises the expected reward). Covq\mathrm{Cov}_q uses qaq_a instead, and computes the advantage over the sampler’s continuations. At “340 +”, if only 68 leads to a correct answer, Covp\mathrm{Cov}_p pushes 68 up by 0.148 and Covq\mathrm{Cov}_q by 0.141.

In practice, the change is one extra term in the usual policy gradient loss. Subtract the trainer’s log-probabilities, averaged under the sampler, from the sampled token’s log-probability, with a stop-gradient on the sampler’s probabilities:

L=−R (log⁡pyt⏟sampled token−∑vsg⁡[qv]log⁡pv⏟average under the sampler) L = -R \, \Big( \underbrace{\log p_{y_t}}_{\text{sampled token}} - \underbrace{\sum_v \operatorname{sg}[q_v] \log p_v}_{\text{average under the sampler}} \Big)

The first term alone gives plain REINFORCE, whose negative gradient is R sytR \, s_{y_t}. The second term’s gradient is sˉ=∑vqv∇θlog⁡pv\bar{s} = \sum_v q_v \nabla_\theta \log p_v, so the full loss has negative gradient R s~ytR \, \tilde{s}_{y_t}. The average runs over the whole vocabulary, which takes some care to compute.

A few properties follow directly from the centered score:

  • The correction depends only on the prefix. Each position gets its own sˉ\bar{s}, computed from the sampler’s next-token distribution there. But at a given position it doesn’t depend on which token was sampled.
  • It does nothing on-policy. When q=pq = p, sˉ=0\bar{s} = 0.Reward baselines and score-function control variates also subtract something with zero mean from the policy gradient, relying on the same identity Ep[s]=0\mathbb{E}_p[s] = 0. But those reduce variance, changing the variance of an on-policy update and leaving its mean alone. Score centering corrects bias, changing the mean of an off-policy update.
  • It has no thresholds to tune. Unlike TIS, MIS, or PPO, there are no bounds or bands to choose.

There’s another way to read the correction.Juliette Decugis @DecugisJulietteCool paper! We can view score centering as:
REINFORCE+R*KL(q||p) since grad_p KL = -E_q
so RL went from KL reg -> no KL -> KL bonus!

Funny enough I tried w/ @TacoCohen to revive KL reg by smoothing pi_ref. Realized now we don’t know where to push p, only what to avoid: q’s bias.
Sep 25, 2026 ↗
With qq held fixed, the expected score is the gradient of a KL divergence. Only the cross-entropy part of KL(q ∥ p)\mathrm{KL}(q \,\|\, p) depends on θ\theta, so

∇θKL(q ∥ p)=−∇θ∑vqvlog⁡pv=−∑vqv ∇θlog⁡pv=−sˉ. \begin{aligned} \nabla_\theta \mathrm{KL}(q \,\|\, p) &= -\nabla_\theta \sum_v q_v \log p_v \\ &= -\sum_v q_v \, \nabla_\theta \log p_v = -\bar{s} . \end{aligned}

If we write KL\mathrm{KL} for KL(q ∥ p)\mathrm{KL}(q \,\|\, p) and substitute, vanilla policy gradient’s drift term becomes a KL gradient weighted by the prefix’s expected reward. The centered score, syt−sˉ=syt+∇θKLs_{y_t} - \bar{s} = s_{y_t} + \nabla_\theta \mathrm{KL}, adds the same KL gradient to each sample, weighted by that sample’s reward:

Eq[Rsyt]⏟REINFORCE=−Eq[R]∇θKL⏟drift+Covq(R,syt)⏟signalEq[R(syt+∇θKL)]⏟score centering=Covq(R,syt) \begin{aligned} \underbrace{\mathbb{E}_q[R s_{y_t}]}_{\text{REINFORCE}} &= \underbrace{-\mathbb{E}_q[R] \nabla_\theta \mathrm{KL}}_{\text{drift}} + \underbrace{\mathrm{Cov}_q(R, s_{y_t})}_{\text{signal}} \\[6pt] \underbrace{\mathbb{E}_q\big[R (s_{y_t} + \nabla_\theta \mathrm{KL})\big]}_{\text{score centering}} &= \mathrm{Cov}_q(R, s_{y_t}) \end{aligned}

So vanilla policy gradient’s drift is an accidental KL term. It pulls the trainer toward the sampler when the prefix’s expected reward is positive, and pushes it away when that reward is negative. Score centering’s added term cancels it on average, so neither pull remains.

At the logits

The correction is easiest to see at the logits, as in part 1. There, sampling token aa gives the logit gradient ga=1a−pg_a = \mathbf{1}_a - p, where 1a\mathbf{1}_a is the one-hot vector for aa. It pushes aa up and every token down in proportion to the trainer’s probability. The score is this vector carried back to the parameters through the logits zuz_u, sa=∑uga,u ∇θzus_a = \sum_u g_{a,u} \, \nabla_\theta z_u, and that map is linear, so averaging and subtracting commute with it. The expected score sˉ\bar{s} therefore corresponds to the average logit gradient gˉ\bar{g} over the sampler’s draws:

gˉ=∑bqb (1b−p)=∑bqb 1b⏟= q−(∑bqb)⏟= 1 p=q−p \begin{aligned} \bar{g} &= \sum_b q_b \, (\mathbf{1}_b - p) \\ &= \underbrace{\sum_b q_b \, \mathbf{1}_b}_{=\,q} - \underbrace{\Big(\sum_b q_b\Big)}_{=\,1} \, p \\ &= q - p \end{aligned}

That’s the drift at the level of logits. Even with a constant reward, the logits move by q−pq - p on average, toward the sampler’s distribution. Score centering subtracts this same vector from every draw. In the centered logit gradient g~a\tilde{g}_a, the logit-level counterpart of s~a\tilde{s}_a, the trainer’s probabilities cancel:

g~a=(1a−p)−(q−p)=1a−q \tilde{g}_a = (\mathbf{1}_a - p) - (q - p) = \mathbf{1}_a - q

The push-down is now in proportion to the sampler’s probabilities.Some figures from here on exaggerate the mismatch at “340 +” so that it’s visible, with a trainer at p=(0.6,0.3,0.1)p = (0.6, 0.3, 0.1) and a sampler at q=(0.8,0.1,0.1)q = (0.8, 0.1, 0.1) over 68, 58, and everything else. The earlier example used a more realistic gap, 0.82 against 0.83 for 68. The sampler drew the token, so the push averages to zero over its draws: ∑aqa(1a−q)=q−q=0\sum_a q_a (\mathbf{1}_a - q) = q - q = 0.

Logit gradients at the 340 + prefix, over the tokens 68, 58, and everything else, with trainer probabilities 0.6, 0.3, and 0.1 and sampler probabilities 0.8, 0.1, and 0.1. Top row, vanilla off-policy, 1ₐ − p: drawing 68 gives (+0.4, −0.3, −0.1), drawing 58 gives (−0.6, +0.7, −0.1), and drawing other gives (−0.6, −0.3, +0.9). Averaged with the sampler's probabilities 0.8, 0.1, and 0.1, these give q − p = (+0.2, −0.2, 0), a drift toward q. Subtracting the same q − p from every draw gives 1ₐ − q. Bottom row, score centering: drawing 68 gives (+0.2, −0.1, −0.1), drawing 58 gives (−0.8, +0.9, −0.1), and drawing other gives (−0.8, −0.1, +0.9), which average to zero, so there is no drift. A last column assumes only 68 leads to a correct answer, with reward 1 for 68 and 0 otherwise, and averages the reward times each draw's gradient. Vanilla gives (+0.32, −0.24, −0.08), signal plus drift. Score centering gives (+0.16, −0.08, −0.08), signal only, which still pushes 68 up.

Written in terms of the logits, with zytz_{y_t} the sampled token’s logit, the loss from above simplifies further. The softmax normalizer cancels, because the weights qvq_v sum to one:

L=−R (zyt−∑vsg⁡[qv] zv) L = -R \, \Big( z_{y_t} - \sum_v \operatorname{sg}[q_v] \, z_v \Big)

The loss is linear in the logits, and its negative logit gradient, R (1yt−q)R \, (\mathbf{1}_{y_t} - q), doesn’t depend on the trainer’s probabilities at all. On-policy, the push on a token fades as the trainer learns it, since 1a−p\mathbf{1}_a - p shrinks as pap_a approaches 1. With centering, only the sampler sets the push.

Score centering vs importance sampling

Computed exactly, both methods cancel drift, but they get there differently. Importance sampling multiplies each sampled token’s score by its own weight, which depends on which token was drawn and can be huge for rare ones; practical versions bound that weight, and bounding lets drift back in. Score centering instead subtracts one fixed shift per prefix, the same for every token sampled there. Because it uses no ratio, rare tokens never get large weights, and there is nothing to clip. The two can also be used together.

At the 340 + prefix, three tokens the sampler might draw: 68 (trainer 0.82, sampler 0.83), 58 (0.07 and 0.06), and a rare token 86 (0.01 and 0.001). Importance sampling multiplies each token's score by its own ratio: 0.99 for 68, 1.17 for 58, and 10 for 86, which TIS caps at 2. Score centering subtracts the same vector s̄ from the score of every token at this prefix, so there is nothing to clip.

What it optimizes

After centering, the expected update is just the signal, Covq(R,syt)\mathrm{Cov}_q(R, s_{y_t}). There are two useful ways to see what it optimizes: as credit for each token relative to its own prefix, and as the policy gradient of the sampler’s reward.

Credit relative to the prefix

Hold the prefix fixed, and write Qq(a)=Eq[R∣a]Q_q(a) = \mathbb{E}_q[R \mid a] for the expected reward of completions that choose token aa next, and Vq=∑aqa Qq(a)V_q = \sum_a q_a \, Q_q(a) for the expected reward of the prefix as a whole. Both average over how the sampler finishes the completion. The difference is the token’s advantage,

Aq(a)=Qq(a)−Vq, A_q(a) = Q_q(a) - V_q ,

how much choosing aa raises or lowers the expected reward from here. By construction, advantages average to zero: ∑aqa Aq(a)=Vq−Vq=0\sum_a q_a \, A_q(a) = V_q - V_q = 0.This is not GRPO’s advantage. Group centering gives each completion one number, Ri−RˉR_i - \bar{R}, shared by all its tokens. Aq(a)A_q(a) is per token, measured against the expected reward of that token’s own prefix, and it’s never computed. It only appears when the update is averaged over the sampler’s draws.

Now expand the centered update. Averaging over the rest of the completion first replaces RR with Qq(a)Q_q(a), since the centered score depends only on the token aa:

Eq[R s~yt]=∑aqa Qq(a) s~a=∑aqa Aq(a) s~a+Vq∑aqa s~a⏟= 0=∑aqa Aq(a) sa−sˉ∑aqa Aq(a)⏟= 0=Eq[Aq(yt) syt] \begin{aligned} \mathbb{E}_q[R \, \tilde{s}_{y_t}] &= \sum_a q_a \, Q_q(a) \, \tilde{s}_a \\ &= \sum_a q_a \, A_q(a) \, \tilde{s}_a + V_q \underbrace{\sum_a q_a \, \tilde{s}_a}_{=\,0} \\ &= \sum_a q_a \, A_q(a) \, s_a - \bar{s} \underbrace{\sum_a q_a \, A_q(a)}_{=\,0} \\ &= \mathbb{E}_q\big[A_q(y_t) \, s_{y_t}\big] \end{aligned}

Each token is credited only by how much it changes the expected reward of its own prefix. Vanilla policy gradient’s drift partly clones the sampler. Score centering instead compares tokens against each other. It moves the trainer toward tokens that do better than the sampler’s other choices at the same prefix, and away from ones that do worse.

Group centering cannot do this because it works at the sequence level: it subtracts the group’s average reward from every token of a completion, leaving a nonzero expected advantage at a prefix like “340 + 58”. Score centering works at the token level, behaving in expectation as if each token’s baseline were the expected reward of its own prefix. After the slip, nearly every continuation ends in a wrong answer, so AqA_q is about zero for every later token, and they get no push in either direction.An exact value-function baseline, replacing RR with R−VqR - V_q at every prefix, would give the same expected update. Score centering gets it without training a critic, but only in expectation, and without the critic’s variance reduction.

The gradient of the sampler’s reward

Suppose the mismatch is a fixed bias on the logits. At each prefix, the sampler computes the trainer’s logits zz and adds an offset δ\delta that doesn’t depend on θ\theta, so q=softmax⁡(z+δ)q = \operatorname{softmax}(z + \delta). The offset can differ from one prefix to the next; it just doesn’t move when the weights do.

Differentiating the sampler’s log-probability through its logits z+δz + \delta, with δ\delta held fixed, gives 1a−q\mathbf{1}_a - q, the usual softmax gradient evaluated at the sampler’s probabilities.Nan Jiang @nanjiang_cs@YouJiacheng consider linear softmax policy. the proposed correction does nothing and simply calculate the gradient under the sampling distribution.Sep 19, 2026 ↗ That matches the centered logit gradient g~a\tilde{g}_a from above.You Jiacheng @YouJiachengActually this argument is not limited to linear policy.
Consider the gradient w.r.t. logits.
s = ∇_z log p(a) = e_a - p
\bar{s} = E_{a~q}[e_a - p] = (q - p)
centered score s - \bar{s} = e_a - q
Thus, score centering is a STE: z_p + sg(z_q - z_p).
Sep 20, 2026 ↗
Because both reach the weights through the same logits, the centered score is the sampler’s own score:

∇θlog⁡qa=s~a \nabla_\theta \log q_a = \tilde{s}_a

Under a fixed logit bias, then, score centering is the exact on-policy gradient for the sampler. It maximizes the expected reward of the model that actually generates the rollouts. The feedback loop that makes drift compound is gone, because nothing is being distilled. A fixed bias is also the persistent kind that compounds under vanilla policy gradient, so score centering is exact in the case where drift does the most damage.

Score centering acts as a straight-through estimator. Write the sampler’s logits as the trainer’s plus a gap treated as a constant, z~=z+sg⁡[zq−z]\tilde{z} = z + \operatorname{sg}[z_q - z], where zq=z+δz_q = z + \delta. Its value is the sampler’s logits, so softmax⁡(z~)=q\operatorname{softmax}(\tilde{z}) = q, but its gradient flows to the trainer’s logits unchanged. Score centering is REINFORCE computed on the sampler’s logits, with the gradient passed straight through to the trainer’s.Quantization-aware training uses the same straight-through trick. It treats the gap between the model being trained and the model that runs as a constant, and improves the one that runs. Like score centering, it is exact only when that gap doesn’t move with the weights. The difference is where the shortcut sits, at the weights in quantization-aware training and at the logits in score centering. Two chains of blocks with a forward pass left to right and a dashed backward pass right to left. Quantization-aware training: weights, round, network, loss. The gradient goes from the loss to the network, then skips the rounding block, treated as the identity, to reach the weights. The shortcut is at the weights. Score centering: weights, network, plus gap, loss. The gradient skips the plus-gap block, treated as the identity, to reach the network, then goes back to the weights. The shortcut is at the logits.

Vanilla policy gradient and score centering side by side, at the 340 + prefix with 68 drawn, trainer p = (0.6, 0.3, 0.1) and sampler q = (0.8, 0.1, 0.1). Solid arrows are the forward pass and dashed arrows the backward pass, which runs back through every box. Both start from the trainer network and the trainer's logits. Vanilla takes a softmax to get p and the loss minus R log p of 68; backpropagating through that softmax gives the trainer's logits the gradient 1 for 68 minus p = (+0.4, −0.3, −0.1). Score centering adds the gap between the engines, a logged constant, to the trainer's logits to get the sampler's logits, then takes a softmax to get q and the loss minus R log q of 68. Backpropagating through that softmax gives 1 for 68 minus q = (+0.2, −0.1, −0.1) at the sampler's logits. The + sits on the forward path, but the backward path goes straight through, around the +, treating it as the identity, so the same gradient reaches the trainer's logits unchanged. The constant gap gets no gradient.

When score centering is exact

The sampler-gradient reading assumed a fixed bias. In general, the centered score is the exact derivative of a related distribution, the sampler tilted by the trainer’s change, νδ∝q pθ+δ/pθ\nu_\delta \propto q \, p_{\theta + \delta} / p_\theta, at δ=0\delta = 0.Yingru Li @RichardYRLiConsider a trainer-tangent family whose base point is the sampler: i.e., apply the trainer’s probability change under a small update, then renormalize:νδ(a∣h)∝q(a∣h) pθ+δ(a∣h)pθ(a∣h)\displaystyle \nu_\delta(a \mid h) \propto q(a \mid h) \, \frac{p_{\theta+\delta}(a \mid h)}{p_\theta(a \mid h)}ν0=q\displaystyle \nu_0 = qDifferentiating this trainer-tangent family with respect to small update δ here at the base point directly yields the centering argument.Sep 21, 2026 ↗ Under a fixed bias, that tilted distribution is the sampler itself. If instead the offset depends on the weights, δ(θ)\delta(\theta), differentiating through z+δz + \delta also picks up the offset’s own gradient:

∇θlog⁡qv⏟sampler’s score=s~v⏟centered score+∇θδv−Eq[∇θδ]⏟offset’s gradient, centered \underbrace{\nabla_\theta \log q_v}_{\text{sampler's score}} = \underbrace{\tilde{s}_v}_{\text{centered score}} + \underbrace{\nabla_\theta \delta_v - \mathbb{E}_q[\nabla_\theta \delta]}_{\text{offset's gradient, centered}}

The two extra terms cancel whenever the offset’s gradient is the same for every token, and in particular whenever the offset doesn’t move with the weights at all. Exactness depends on how the offset changes with the weights rather than on its size, and the three common kinds of mismatch fall into different cases:

  • Sampling masks are exact. Top-kk, top-pp, and grammar constraints set the logits of disallowed tokens to −∞-\infty and leave the rest alone. A small change to the weights doesn’t change which tokens are allowed, so the offset stays fixed and centering is exact. If the mask is the only difference between the engines, score centering gives the same update as applying the sampler’s mask in the trainer, because the masked trainer’s distribution is already qq.
  • Quantization is approximate. A quantized sampler rounds the weights, so the offset is the rounding error in the logits, and it changes whenever the weights do. The quantized sampler’s exact gradient wouldn’t help anyway, since rounding is flat almost everywhere. Score centering treats the offset as fixed, the straight-through approximation from above, so here it approximates the sampler’s gradient rather than matching it.
  • Staleness isn’t covered. A stale sampler runs older weights, so its offset, δ=z(θold)−z(θ)\delta = z(\theta_{\text{old}}) - z(\theta), moves exactly opposite to the trainer’s logits and cancels any change to the current weights. The stale sampler doesn’t respond to the current weights at all, so it has no gradient for centering to match, and the sampler-gradient reading doesn’t apply.

Computing the expected score

For a language model, sˉ\bar{s} is a sum over the vocabulary, just like the softmax. With continuous or combinatorial actions it usually has no closed form, which is one reason off-policy methods there rely on importance sampling instead.

Even for a language model, though, sˉ\bar{s} needs the sampler’s full next-token distribution at every position, while inference engines normally return only the sampled token’s probability. Logging the whole distribution is expensive. With a 152K-token vocabulary, one position takes about 600 KB in fp32, so a batch of 1,024 rollouts of 32K tokens each would need about 20 TB!

One practical approximation logs only the sampler’s top kk probabilities (the head HH) and fills in the rest of the vocabulary (the tail TT) with the trainer’s probabilities, rescaled to sum to one:Another option is a Monte Carlo estimate. At each position, have the sampler draw a few extra tokens (without continuing or grading them) and subtract their average score. That needs no tail model and is exact on average, but it adds noise, and a single estimate isn’t exactly zero even on-policy. Thinking Machines’ StableReinforce loss appears to do exactly this with 8 tokens per position, as Martin Marek found by recovering its gradients.

q^v={qvv∈Hρ pvv∈Tρ=1−∑v∈Hqv1−∑v∈Hpv \hat{q}_v = \begin{cases} q_v & v \in H \\ \rho \, p_v & v \in T \end{cases} \qquad \rho = \frac{1 - \sum_{v \in H} q_v}{1 - \sum_{v \in H} p_v}

A sorted next-token distribution at 340 +, with k = 4. The head, the top four tokens 68, 58, 78, and 6, uses the sampler's logged probabilities, 0.83, 0.06, 0.03, and 0.02, for a head mass of 0.94. The tail is not logged. It is filled in with the trainer's probabilities, which have tail mass 0.08, scaled by ρ = 0.06 / 0.08 = 0.75 so that the tail holds the sampler's remaining mass of 0.06.

The tail never has to be summed. Because the trainer’s expected score is zero, the tail’s part of it is minus the head’s part, and the correction reduces to a sum over the kk head tokens:

Eq^[s]=∑v∈Hqv sv+ρ∑v∈Tpv sv=∑v∈Hqv sv+ρ (∑vpv sv⏟= 0−∑v∈Hpv sv)=∑v∈H(qv−ρ pv) sv \begin{aligned} \mathbb{E}_{\hat{q}}[s] &= \sum_{v \in H} q_v \, s_v + \rho \sum_{v \in T} p_v \, s_v \\ &= \sum_{v \in H} q_v \, s_v + \rho \, \Big( \underbrace{\sum_{v} p_v \, s_v}_{=\,0} - \sum_{v \in H} p_v \, s_v \Big) \\ &= \sum_{v \in H} \big( q_v - \rho \, p_v \big) \, s_v \end{aligned}

This is exact on the head and biased only through the tail model. Next-token distributions are concentrated enough that the tail barely matters.With k=128k = 128, the head held more than 99.9% of the sampler’s probability on average, in all but the most aggressively quantized of Marek and Ryabinin’s settings. k=32k = 32 already matched full score centering in every setting they tested, and runs with k=128k = 128 finished within 1% of the baseline’s wall-clock time on their own JAX sampler. They did not measure the overhead in vLLM or SGLang.

As Modal points out, top-p sampling makes this exact. The sampler’s probabilities are zero outside its candidate set, so logging each candidate’s ID and probability (about 8 bytes each) gives sˉ\bar{s} with no tail to estimate, as long as the trainer applies the same mask to its own probabilities. The same log serves as the mask. It’s usually about the size of a top-kk log, but it has no fixed size, since the candidate set grows wherever the sampler is uncertain.

In PyTorch, the whole loss is a few lines on top of the usual policy gradient loss. It needs the sampler’s top-kk log-probabilities and token ids, which vLLM and SGLang can return alongside each sampled token:These must be the sampler’s final sampling probabilities, after temperature, top-p, and any other processing, and the trainer’s pp should use the same temperature. Inference engines don’t always return that by default. vLLM, for example, returns raw log-probabilities unless logprobs_mode is set to a processed mode, and returns at most 20 per token unless max_logprobs is raised.

import torch

def score_centering_loss(train_logp, samp_topk_logp, topk_ids, sampled_ids, advantages, eps=1e-6):
    """
    train_logp:     [N, V] trainer log-probs (in fp32) at each of N positions
    samp_topk_logp: [N, k] sampler's top-k log-probs, logged during generation
    topk_ids:       [N, k] token ids of the sampler's top-k
    sampled_ids:    [N]    the token the sampler chose at each position
    advantages:     [N]    each completion's advantage, broadcast to its tokens
    """
    train_head_logp = train_logp.gather(-1, topk_ids)
    with torch.no_grad():  # no gradient through q or the tail's use of p
        q_head, p_head = samp_topk_logp.exp(), train_head_logp.exp()
        rho = (1 - q_head.sum(-1)).clamp_min(eps) / (1 - p_head.sum(-1)).clamp_min(eps)
        coef = q_head - rho[:, None] * p_head  # q_v - rho * p_v on the head
    sampled_logp = train_logp.gather(-1, sampled_ids[:, None]).squeeze(-1)
    centering = (coef * train_head_logp).sum(-1)
    return -(advantages * (sampled_logp - centering)).sum()  # normalize as your trainer does

Without the centering term, this is the ordinary policy gradient loss. The reference implementation, in JAX and PyTorch, also supports composing with TIS and MIS.

When it helps

The previous sections make two predictions. If the mismatch acts like a fixed bias, as a quantized sampler’s might, most of the damage is drift, so removing it should be enough. If the sampler is stale, centering still leaves a gap between Covq\mathrm{Cov}_q and Covp\mathrm{Cov}_p, so it may need importance weights alongside it. Two sets of experiments bear out both. Marek and Ryabinin test each kind of mismatch on its own and make it severe on purpose, so that the methods separate within a few hundred steps. Modal trains a larger model on a realistic mix of both.

Three plots of training accuracy. Qwen3-30B-A3B on math with FP8 weights and an FP4 KV cache: vanilla policy gradient rises to about 45%, then collapses to 0% by step 180, while score centering reaches 52% and TIS 51%; the other importance-sampling methods mostly collapse. With INT8 weights and an INT4 KV cache: score centering climbs from 4% to about 30%, TIS reaches 12% late in training, and vanilla policy gradient and the rest end near 0%. Qwen3-0.6B on Countdown with the sampler synced every 64 steps: TIS combined with score centering reaches about 72%, PPO and DAPO about 58%, score centering alone oscillates between 5% and 35%, and TIS alone collapses to about 5%.
Redrawn from Marek and Ryabinin (2026), Figures 1 and 4. Each correction is applied on its own to the same REINFORCE objective with group-centered rewards. The plots show training accuracy. The 30B runs use one to five seeds per method and rollouts of up to 1,024 tokens; the 0.6B runs use three seeds and rollouts of up to 512 tokens.

In Marek and Ryabinin’s experiments:

  • Quantized sampler.Quantizing the sampler is attractive in the first place because generating rollouts is usually the most expensive part of RL for LLMs. Lower-precision weights and KV cache make each decoding step faster and let the same GPUs hold more rollouts at once. On Qwen3-30B-A3B, vanilla policy gradient collapses once the KV cache is quantized, while score centering stays stable. At the most aggressive setting, with INT8 weights and an INT4 KV cache, score centering is the only method that trains well. TIS improves slowly and ends far behind, and everything else makes no progress, including PPO and DAPO, whose clip was designed for policy movement rather than numerical error.
  • Stale sampler. When the sampler syncs only every 64 steps, neither correction works alone. TIS collapses, and score centering oscillates. Combined, they do best, ahead of PPO and DAPO, which were built for exactly this kind of staleness.

Modal’s run points the same way. They trained Qwen3.6-35B-A3B on agentic coding, fully asynchronously, with samplers on six kinds of accelerators at NVFP4, FP8, and BF16, so the mismatch mixed numerical error with staleness. Score centering alone and MIS alone each delayed the collapse but didn’t prevent it, and score centering’s run collapsed after its sampler–trainer KL had grown about threefold. Only the two combined trained stably to the end, centering the masked weights the way the next section centers capped ones.

It isn’t settled why score centering alone oscillates with a stale sampler, but its logit gradient suggests a mechanism.The cartoon with a stale sampler that has no bias, synced from the trainer every six steps, and score centering alone. Between syncs, every step's signal is measured at the stale sampler, so the trainer keeps moving in the same direction. It overshoots the star, and after the next sync it is pushed back past it the other way. It bounces across the star for the rest of training, and both reward lines rise and then oscillate. A stale sampler with score centering alone: the trainer overshoots the peak and bounces across it. Centering’s push on each logit is set entirely by the sampler, and a stale sampler doesn’t know the trainer has moved. At “340 +”, if only 68 leads to a correct answer, a trainer that has already reached p68=0.95p_{68} = 0.95 would get an on-policy push of p68(1−p68)≈0.05p_{68}(1 - p_{68}) \approx 0.05 on its logit. A sampler still at q68=0.80q_{68} = 0.80 makes centering push by q68(1−q68)=0.16q_{68}(1 - q_{68}) = 0.16, more than three times as hard. Between syncs, the trainer takes 64 steps computed for where it used to be, which acts much like one step 64 times as large. A step that large may overshoot the optimum, and the next sync may swing the trainer back past it, though as far as we know that hasn’t been tested.

Centering also removes vanilla policy gradient’s accidental KL term, which pulls the trainer toward the sampler on prefixes with positive expected reward and pushes it away on prefixes with negative expected reward. With a biased sampler, that pull is toward the bias. With a stale sampler, it is toward the trainer’s own recent weights, acting like PPO’s KL trust region. StableReinforce keeps centering but puts a small pull back on purpose, a KL term toward the sampler with a fixed weight of 0.01, in place of vanilla’s VqV_q. When the sampler is a stronger model or a teacher, that pull is how the trainer imitates it, so centering removes the imitation along with the drift and learns only from the rewards.

Centered importance sampling

Score centering and importance sampling fix different parts of the update, so they can be used together. Recall the split into drift and signal:

  • Importance weights change the signal. They change how much each draw counts. With exact weights, the next token is weighted by the trainer’s probabilities instead of the sampler’s, although the prefix and the rest of the completion still come from the sampler. Bounding the weights spoils this slightly, and also lets some drift back in.
  • Centering changes only the drift. It subtracts one fixed vector per prefix, the same for every draw. That makes the weighted score average to zero at every prefix, and leaves the signal untouched, since subtracting a constant doesn’t change a covariance.

So stacking them keeps the importance-weighted signal and gets centering’s zero drift.The synced-sampler cartoon with centered truncated importance sampling. Centering the capped-weight score removes the drift that truncated importance sampling leaves behind, so each step is signal only. The capped weights move the point where the signal is measured part of the way from the sampler back toward the trainer. The trainer and sampler both settle close to the star, one on each side of it. The reward of the sampler's rollouts and the trainer's own reward both level off near 1. Centering removes the drift that TIS leaves behind. In this cartoon, the capped weights still move where the signal is measured, partway from the sampler back toward the trainer, so both end up close to the peak.

Centering the weighted score

Centering works the same way here: take whatever multiplies RR in the update and subtract its average over the sampler’s draws. In plain policy gradient that’s the score ss, whose average is sˉ\bar{s}. With TIS or MIS, it’s the weighted score w sw \, s, so the combined update subtracts the average of the weighted score instead:

R (wyt syt−Eq[w s]),Eq[w s]=∑vqv wv sv R \, \big( w_{y_t} \, s_{y_t} - \mathbb{E}_q[w \, s] \big), \quad \mathbb{E}_q[w \, s] = \sum_v q_v \, w_v \, s_v

Subtracting the plain sˉ\bar{s} here would overcorrect, since the weights have already removed most of the drift. Bounding leaves some drift behind, and this term subtracts exactly that. Computing it needs the bounded weight wvw_v, such as min⁡(pv/qv,2)\min(p_v / q_v, 2), for every token in the vocabulary, not just the sampled one.The top-kk approximation still works. On the modeled tail, every token’s ratio is pv/q^v=1/ρp_v / \hat{q}_v = 1/\rho, so they all get the same weight f(1/ρ)f(1/\rho), and the average weighted score is again a sum over the head: Eq^[w s]=∑v∈H(qv wv−ρ f(1/ρ) pv) sv\mathbb{E}_{\hat{q}}[w \, s] = \sum_{v \in H} \big( q_v \, w_v - \rho \, f(1/\rho) \, p_v \big) \, s_v. With w=1w = 1, this is the plain correction above.

In the figure below, TIS alone leaves a small nonzero average (the leftover drift). Subtracting that same vector from every draw moves the average to zero while keeping the differences between draws, which carry the signal, unchanged.

Weighted logit gradients at the 340 + prefix, with trainer probabilities 0.6, 0.3, and 0.1 and sampler probabilities 0.8, 0.1, and 0.1 for the tokens 68, 58, and everything else. The importance ratios are 0.75, 3, and 1, and TIS caps the 3 at 2. Top row, TIS alone, w times (1_a − p): drawing 68 gives (+0.30, −0.22, −0.07), drawing 58 gives (−1.20, +1.40, −0.20), and drawing other gives (−0.60, −0.30, +0.90). Averaged over the sampler's draws, these leave a drift of (+0.06, −0.07, +0.01): less than plain policy gradient's q − p = (+0.2, −0.2, 0), but not zero. Subtracting that same leftover from every draw gives the bottom row, TIS plus score centering, whose average is zero.

Two special cases confirm the formula. With w=1w = 1, this is plain score centering. With exact token-level weights, w=p/qw = p / q, the subtracted term is ∑vpv sv=0\sum_v p_v \, s_v = 0, and there’s nothing left to center.

The same holds for whole rollouts. With exact, unclipped sequence-level importance weights, the update already equals the trainer’s gradient in expectation, because the weights correct the prefixes and the rest of the completion as well as each token. Score centering would add nothing there.Han and Hu frame both corrections as estimates of Cov(R,w s)\mathrm{Cov}(R, w\,s). Unlike the policy gradient under capped or masked weights, the covariance ignores a constant added to the reward. A group baseline estimates it by centering the reward, and score centering by centering the weighted score. With sequence-level weights the baseline is enough, but with token-level weights it generally leaves a bias that centering removes. But those weights’ variance explodes with length, so every practical method truncates or bounds them, and the bounding brings back drift for centering to remove.

Fixing a stale sampler

In the stale-sampler experiment, centering alone oscillated, while combining it with TIS did best.The same stale sampler with centered truncated importance sampling. The capped weights move where the signal is measured partway back toward the trainer, so the push shrinks as the trainer nears the star. The trainer settles at the star, and both reward lines rise to about 1 and stay there. With importance weights, the push depends on where the trainer is again, so it slows down near the peak and settles. Centering alone pushes each logit by R (1yt−q)R \, (\mathbf{1}_{y_t} - q), which is set entirely by the stale sampler. Importance weights put the trainer’s probabilities back into the update. For tokens whose ratio stays below the cap, the weight pa/qap_a / q_a undoes how often the sampler picks them, turning centering’s expected logit gradient ∑aqa Qq(a) (1a−q)\sum_a q_a \, Q_q(a) \, (\mathbf{1}_a - q) into the on-policy form ∑apa Qq(a) (1a−p)\sum_a p_a \, Q_q(a) \, (\mathbf{1}_a - p). It isn’t the full on-policy gradient, since the rest of each completion still comes from the stale sampler. But like the on-policy push, it fades as the trainer learns a token, even while the sampler stays where it was at the last sync. That may be why the combination is stable where centering alone is not.

We don’t yet know whether these gains hold for long agentic rollouts under the milder mismatch of a well-engineered system.

Wrapping up

Everything in this post follows from one fact in part 1: the score averages to zero only when the model being trained draws the tokens. Off-policy, it averages to sˉ\bar{s}, and the policy gradient picks up a pull toward the sampler. Importance sampling removes that pull by reweighting each draw as if the trainer had made it, and score centering removes it by subtracting sˉ\bar{s} directly. Score centering alone works well when the gap behaves like a fixed bias. When the sampler is stale, though, its signal is out of date, and adding importance weights on top of centering helps by reweighting the signal toward the current trainer.

The table below collects the comparisons made along the way, at a single next-token position.

Method Drift Signal as if drawn from Variance from the ratio Knobs Logged
Uncorrected full sampler none none nothing
Sequence IS none trainer explodes with length none sampled log-prob
Token IS none trainer, next token only heavy-tailed none sampled log-prob
TIS from capped tokens trainer, capped limited by the cap cap sampled log-prob
MIS from dropped tokens trainer, in band limited by the band band sampled log-prob
PPO clip from clipped tokens trainer, clipped unbounded when A<0A < 0 ϵ\epsilon sampled log-prob
Score centering none sampler none none top-kk log-probs
Centered TIS none trainer, capped limited by the cap cap top-kk log-probs

Further reading

References

Bai, J. (2026). Score Centering under Policy Mismatch. https://biechi.github.io/blog/score-centering/
Bengio, Y., Léonard, N., & Courville, A. (2013). Estimating or Propagating Gradients Through Stochastic Neurons for Conditional Computation. https://arxiv.org/abs/1308.3432
Decugis, J. (2026). Score centering as REINFORCE plus a reward-weighted KL bonus. Post on X. https://x.com/DecugisJuliette/status/2103450635827875955
DeepSeek-AI. (2025). DeepSeek-V3.2: Pushing the Frontier of Open Large Language Models. https://arxiv.org/abs/2512.02556
Dong, Y., Fu, K., Li, H., Zhu, X., Liu, Y., Shao, L., Ye, J., & Wang, Z. (2026). Probing RLVR Training Instability through the Lens of Objective-Level Hacking. Forty-Third International Conference on Machine Learning. https://arxiv.org/abs/2602.01103
Fu, W., Gao, J., Shen, X., Zhu, C., Mei, Z., He, C., Xu, S., Wei, G., Mei, J., Wang, J., Yang, T., Yuan, B., & Wu, Y. (2025). AReaL: A Large-Scale Asynchronous Reinforcement Learning System for Language Reasoning. https://arxiv.org/abs/2505.24298
Han, S., & Hu, Z. (2026). Baselines and Score Centering in Policy Gradient Estimation. https://arxiv.org/abs/2610.22263
He, H., & Thinking Machines Lab. (2025). Defeating Nondeterminism in LLM Inference. https://thinkingmachines.ai/blog/defeating-nondeterminism-in-llm-inference/
Hou, Z., Li, Y., Tang, J., & Dong, Y. (2026). Single-Rollout Asynchronous Optimization for Agentic Reinforcement Learning. https://arxiv.org/abs/2607.07508
Ionides, E. L. (2008). Truncated Importance Sampling. Journal of Computational and Graphical Statistics, 17(2), 295–311. https://doi.org/10.1198/106186008X320456
Jacob, B., Kligys, S., Chen, B., Zhu, M., Tang, M., Howard, A., Adam, H., & Kalenichenko, D. (2018). Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference. Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. https://arxiv.org/abs/1712.05877
Jiang, N. (2026a). Score centering for a linear softmax policy. Post on X. https://x.com/nanjiang_cs/status/2101413762351710451
Jiang, N. (2026b). Toward RL on mixed-precision, mixed-accelerator samplers. Modal Blog. https://modal.com/blog/toward-rl-on-mixed-precision-mixed-accelerator-samplers
Khatri, D., Madaan, L., Tiwari, R., Bansal, R., Duvvuri, S. S., Zaheer, M., Dhillon, I. S., Brandfonbrener, D., & Agarwal, R. (2026). The Art of Scaling Reinforcement Learning Compute for LLMs. The Fourteenth International Conference on Learning Representations. https://openreview.net/forum?id=FMjeC9Msws
Li, Y. (2026). Score centering as the derivative of a trainer-tangent family. Post on X. https://x.com/RichardYRLi/status/2101941461935870074
Ling Team. (2025). Every Step Evolves: Scaling Reinforcement Learning for Trillion-Scale Thinking Model. https://arxiv.org/abs/2510.18855
Liu, J., Li, Y., Fu, Y., Wang, J., Liu, Q., & Jiang, Z. (2025). When Speed Kills Stability: Demystifying RL Collapse from the Training-Inference Mismatch. https://richardli.xyz/rl-collapse
Liu, L., Yao, F., Zhang, D., Dong, C., Shang, J., & Gao, J. (2025). FlashRL: 8Bit Rollouts, Full Power RL. https://fengyao.notion.site/flash-rl
Liu, Z., Chen, C., Li, W., Qi, P., Pang, T., Du, C., Lee, W. S., & Lin, M. (2025). Understanding R1-Zero-Like Training: A Critical Perspective. https://arxiv.org/abs/2503.20783
Lu, K., & Thinking Machines Lab. (2025). On-Policy Distillation. https://thinkingmachines.ai/blog/on-policy-distillation/
Marek, M. (2026). Recovering the StableReinforce loss from its gradients. Post on X. https://x.com/mrtnm/status/2114145574987702525
Marek, M., & Ryabinin, M. (2026). Score Centering Stabilizes Off-policy Reinforcement Learning. https://arxiv.org/abs/2609.20807
Microsoft AI Team. (2026). MAI-Thinking-1: Building a Hill-Climbing Machine. https://microsoft.ai/pdf/mai-thinking-1.pdf
MiniMax. (2025). MiniMax-M1: Scaling Test-Time Compute Efficiently with Lightning Attention. https://arxiv.org/abs/2506.13585
Mohamed, S., Rosca, M., Figurnov, M., & Mnih, A. (2020). Monte Carlo Gradient Estimation in Machine Learning. Journal of Machine Learning Research, 21(132), 1–62. https://jmlr.org/papers/v21/19-346.html
Owen, A. B. (2013). Monte Carlo Theory, Methods and Examples. https://artowen.su.domains/mc/
Piché, A., Kamalloo, E., Pardinas, R., Chen, X., & Bahdanau, D. (2025). PipelineRL: Faster On-Policy Reinforcement Learning for Long Sequence Generation. https://arxiv.org/abs/2509.19128
Qi, P., Liu, Z., Zhou, X., Pang, T., Du, C., Lee, W. S., & Lin, M. (2025). Defeating the Training-Inference Mismatch via FP16. https://arxiv.org/abs/2510.26788
Schulman, J., Wolski, F., Dhariwal, P., Radford, A., & Klimov, O. (2017). Proximal Policy Optimization Algorithms. https://arxiv.org/abs/1707.06347
Shao, Z., Wang, P., Zhu, Q., Xu, R., Song, J., Bi, X., Zhang, H., Zhang, M., Li, Y. K., Wu, Y., & Guo, D. (2024). DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models. https://arxiv.org/abs/2402.03300
Sutton, R. S., & Barto, A. G. (2018). Reinforcement Learning: An Introduction (2nd ed.). MIT Press. http://incompleteideas.net/book/the-book-2nd.html
Tian, K., Liu, S., Jiang, T., Dong, S., Li, Y., Ding, T., Guo, Y., Li, S., Hou, H., Wang, C., & Wang, Y. (2026). What Should a Self-Teacher See? Privileged Context Design for On-Policy Self-Distillation. https://arxiv.org/abs/2609.25623
Wang, Y. (2026). Score centering as optimizing the sampler’s reward. Post on X. https://x.com/yifeiwang77/status/2102049177203323316
Yan, J., Li, Y., Hu, Z., Wang, Z., Cui, G., Qu, X., Cheng, Y., & Zhang, Y. (2025). Learning to Reason under Off-Policy Guidance. https://arxiv.org/abs/2504.14945
Yang, A., & Qwen Team. (2025). Qwen3 Technical Report. https://arxiv.org/abs/2505.09388
Yao, F., Liu, L., Zhang, D., Dong, C., Shang, J., & Gao, J. (2025). Your Efficient RL Framework Secretly Brings You Off-Policy RL Training. https://fengyao.notion.site/off-policy-rl
You, J. (2026a). Score centering at the logits. Post on X. https://x.com/YouJiacheng/status/2101580038546362759
You, J. (2026b). Score Centering is “secretly” a STE. Post on X. https://x.com/YouJiacheng/status/2101580523558887564
Yu, Q., Zhang, Z., Zhu, R., Yuan, Y., Zuo, X., Yue, Y., Dai, W., Fan, T., Liu, G., Liu, L., Liu, X., Lin, H., Lin, Z., Ma, B., Sheng, G., Tong, Y., Zhang, C., Zhang, M., Zhang, W., … Wang, M. (2025). DAPO: An Open-Source LLM Reinforcement Learning System at Scale. https://arxiv.org/abs/2503.14476
Zelikman, E., Wu, Y., Mu, J., & Goodman, N. D. (2022). STaR: Bootstrapping Reasoning With Reasoning. Advances in Neural Information Processing Systems. https://arxiv.org/abs/2203.14465
Zheng, C., Liu, S., Li, M., Chen, X.-H., Yu, B., Gao, C., Dang, K., Liu, Y., Men, R., Yang, A., Zhou, J., & Lin, J. (2025). Group Sequence Policy Optimization. https://arxiv.org/abs/2507.18071
Zhong, T., Ling, N., Pi, Y., Wei, Z., Yu, T., Fox, G., Wu, P., & Yu, X. (2026). Diagnosing Training Inference Mismatch in LLM Reinforcement Learning. https://arxiv.org/abs/2605.14220