
























在强化学习(包括 RLHF、PPO、GRPO 等)用于大语言模型(LLM)微调时,会存在一个核心问题:模型在训练阶段与推理阶段使用的策略概率分布不完全一致。
训练过程中通常包含两个不同的计算环节:
Rollout (推理 / 采样阶段)
生成文本样本(sequence)用于估算奖励(reward)。这个阶段往往使用高度优化的推理引擎和特定的浮点精度设置(例如 BF16、FP8 等),追求快速生成与高 throughput。
训练 / 更新阶段
使用采样生成的数据计算梯度、更新策略权重。这个阶段通常使用另一个训练引擎,关注数值稳定性与精确梯度计算,并可能采用不同的浮点精度和算子实现。
即使两个阶段用的是相同的模型参数,由于精度、算子、并行策略(TP/DP 分布式)、浮点累积误差等差异,它们分别计算出的策略分布在数学上并不完全匹配,这种差异称作“训-推误差”。(BAAI Hub)
结果是,即便算法逻辑相同,不同精度数值运算会因为舍入误差、累积误差、不同的 reduction 顺序等导致训练策略 (π_train) 与推理策略 (π_inference) 在概率分布上有微小偏差。(BAAI Hub)
这种微小差异在监督学习里可能不会显著,但在 RL 中会被放大,因为强化学习依赖概率比率来估计梯度(如在 PPO/GRPO 中的 importance weights)。
这两者底层优化(内存布局、并行策略、 kernel 实现、float reduction 顺序)不同,会导致相同参数下的 log-prob 输出不一致,进一步造成策略分布差异。(vLLM Blog)
强化学习优化通常依赖策略梯度估计,例如在 PPO/GRPO 等方法里:
\( \nabla_\theta J(\theta) = E_{\tau\sim π_\theta} [ \nabla_\theta \log π_\theta(\tau) A(\tau) ] \)
其中采样 trajectory (τ) 使用的是 rollout 策略 (π_inference),但实际 gradient 计算和更新依据训练策略 (π_train)。如果两个分布不一致:
梯度估计偏差(biased gradient)
训练过程中计算的梯度不再是对真实目标的无偏估计,而是受 mismatch 影响的近似值,随着训练推进,梯度噪声和偏差会放大,导致训练震荡甚至崩溃。(arXiv)
部署-训练性能差距(deployment gap)
即使训练稳定收敛,得到的策略更适合训练引擎上的分布,而在推理引擎上的表现仍旧不佳。(mlpod.com)
动态累积效应
随着生成序列长度与模型规模增大,这些差异在低概率 token(tail tokens)上尤其显著,并在序列级别累积,导致 log-prob 差异不断增大,训练过程对噪声更敏感。(arXiv)
Mismatch 会使策略更新方向不再是严格梯度方向,而是带有噪声和偏差的近似,导致:
随着训练进程,这些噪声可能随着更新步数累积,使训练优化路径更加不稳定。(arXiv)
低概率 token 在策略梯度中占较大权重,其数值误差更剧烈,导致贡献的 gradient variance 特别高,从而难以收敛。(arXiv)
可以把方法大致分成四类:
统一训练和推理的浮点精度,减少底层算子差异:
对 rollout 采样概率与训练策略概率做 re-weight,使 gradient estimator 更接近无偏:
最新工作指出 mismatch 不是静态数值误差,而是随训练演化的动态问题。提出根据训练变化动态调整学习率等优化策略以抑制 mismatch 引发的梯度噪声。(arXiv)
从底层并行策略、算子实现、batch reduction 一致性等角度确保 trainer 与 sampler 使用完全一致的核函数和实现(例如 TP-大小一致的 deterministic kernels)。(arXiv)
| 层级 | 问题核心 | 典型表现 |
|---|---|---|
| 训练-推理 mismatch | 数值/架构/实现差异 | 策略分布不一致 |
| 梯度估计偏差 | 超出了 RL 算法的原假设 | 不稳收敛、震荡 |
| 动态累积问题 | mismatch 与梯度噪声随训练推进耦合 | 崩溃或 early exit |
可以看出,训-推误差并不是表面上的“训练与推理区别”,而是被强化学习放大的一类 概率分布与优化动态之间的根本冲突。解决这类问题需从底层精度、引擎一致性和训练动态角度综合考虑,而不仅仅是算法层面的机械修正。(BAAI Hub)
用当前训练策略的“整句概率”,去纠正这条样本其实是由“另一个策略”采出来的事实。
在 LLM RL 中:
Sequence-level IS 就是:
不关心 token 细节,只在“整条序列”这一层把分布对齐。
下面这个流程几乎等价于你在 PPO / GRPO 系统里真实会看到的实现。
对 prompt ( x ):
\( \tau = (a_1,\dots,a_T) \sim \pi_{\text{rollout}}(\cdot \mid x) \)
同时 必须保存:
\(
\log \pi_{\text{rollout}}(\tau)= \sum_{t=1}^T\log \pi_{\text{rollout}}(a_t \mid s_t)
\)
⚠️ 这一步用的是推理引擎算出来的 log-prob
⚠️ 不是训练引擎的结果
计算 reward(来自 RM / rule / verifier):
\( R(\tau) \)
然后构造 advantage(最简单版本):
\( A(\tau) = R(\tau) - b \)
其中 ( b ) 可以是:
用 当前训练模型参数 ( \theta ),重新 forward 这条序列:
\(\log \pi_{\text{train}}(\tau)= \sum_{t=1}^T\log \pi_\theta(a_t \mid s_t)\)
此时你已经有了两套值:
\( w(\tau)= \frac{\pi_{\text{train}}(\tau)}{\pi_{\text{rollout}}(\tau)}= \exp\Big(\log \pi_{\text{train}}(\tau)\log \pi_{\text{rollout}}(\tau)\Big) \)
🔥 这里是 数值风险最高的一步
- 长序列
- log-prob 差值
- 指数放大
实际系统中几乎一定会:
\( \tilde w(\tau)= \text{clip}(w(\tau), w_{\min}, w_{\max}) \)
否则训练会立刻不稳定。
Sequence-level IS 的策略梯度写成:
\( \nabla_\theta J=\mathbb{E}*{\tau \sim \pi*{\text{rollout}}}\Big[\tilde w(\tau)\cdot A(\tau)\cdot\nabla_\theta \log \pi_\theta(\tau)\Big] \)
展开即:
\( \tilde w(\tau)\cdot A(\tau)\cdot\sum_{t=1}^T\nabla_\theta\log \pi_\theta(a_t \mid s_t) \)
注意:
权重是 sequence-level 的,但梯度仍然是 token-level 累加
你实际上在算:
\( \mathbb{E}*{\tau \sim \pi*{\text{rollout}}} \big[ \nabla_\theta \log \pi_\theta(\tau) A(\tau) \big] \)
但你真正想要的是:
\( \mathbb{E}*{\tau \sim \pi*{\text{train}}} \big[ \nabla_\theta \log \pi_\theta(\tau) A(\tau) \big] \)
利用重要性采样恒等式:
\( \mathbb{E}*{\tau \sim \pi*{\text{train}}}[f(\tau)]=\mathbb{E}*{\tau \sim \pi*{\text{rollout}}}\left[\frac{\pi_{\text{train}}(\tau)}{\pi_{\text{rollout}}(\tau)}f(\tau)\right] \)
Sequence-level IS 就是在用这个等式。
\( \log \pi(\tau) = \sum_{t=1}^T \log \pi(a_t) \)
👉 单条样本就能主宰整个 batch
PPO 里已经有:
\( r_t = \frac{\pi_\theta}{\pi_{\text{old}}} \)
再叠一层 sequence-level IS:
你在工业 / 开源系统里看到的通常是:
sequence-level IS
+ weight clipping
+ reward normalization
+ small LR
+ frequent policy refresh
本质是:
用一堆工程手段,压住它天然的高方差。
Sequence-level IS 是“在理论上正确、在实践中危险、但在工程上不得不用的工具”。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。