Hugging Face Blog

vLLM 从 V0 到 V1:在强化学习中正确性优先于修正

8.7内容质量
vLLM 从 V0 到 V1:在强化学习中正确性优先于修正

TL;DR · AI 摘要

vLLM从V0到V1的升级聚焦推理后端正确性,修复了logprob语义、运行时默认值和飞行中权重更新等关键问题,确保强化学习训练中的结果可靠。

核心要点

  • vLLM V1优先解决推理后端的正确性问题,而非直接优化性能。
  • 关键修复包括logprob计算、运行时默认参数和飞行中权重更新的一致性。
  • fp32精度的lm_head仍是残余差距,影响最终输出精确性。
#vLLM#强化学习#推理引擎#Hugging Face#模型部署
打开原文

标题:vLLM V0 到 V1:强化学习中的正确性优先于修正

来源链接:http://huggingface.co/blog/ServiceNow-AI/correctness-before-corrections

发布时间:2026-05-06T19:06:55.743Z

PipelineRL 使用 vLLM 作为 rollout 生成的推理引擎。该推理引擎采样 token 并返回 token 的 logprob;训练器使用这些 logprob 来计算策略比率、KL 散度、裁剪率、熵和奖励。任何在 logprob 计算方式上的差异都可能改变训练动态。这正是我们在从 vLLM V0 迁移到 V1 期间需要消除的训练-推理不匹配问题。

简而言之:在我们修复了四个问题之后,vLLM V1 成功匹配了我们的 vLLM V0 基准:处理后的 rollout logprob、V1 特定的运行时默认设置、飞行中的权重更新路径,以及用于最终投影的 fp32 lm_head。我们在修改 RL 目标之前,首先修复了后端行为。

基准运行使用的是 vLLM 0.8.5;V1 运行使用的是 vLLM 0.18.1。图1展示了最终结果。红色曲线是初始的 V1 尝试,绿色曲线是应用下述修复后的最终 V1 运行结果。

图3
图3

图1. vLLM V0 基准(蓝色)、初始 vLLM V1 尝试(红色)和最终 vLLM V1 运行(绿色,包含 fp32 lm_head)的训练器侧指标。最终的 V1 运行在裁剪率、KL 散度、熵和奖励方面均接近 V0 的轨迹。

迁移目标

vLLM V1 是对 V0 引擎的一次重大重写。因此我们的迁移目标被有意限定得很窄:

  1. 验证 V1 是否以训练器期望的形式返回 rollout logprob
  2. 使用相同的负载重新运行与 V0 基准的对比
  3. 只有在恢复后端一致性之后,才评估目标层面的变化

最早出现的明显症状体现在以下指标中:

  • clamp_log_ratio_new_old_indicator
  • kl_new_old
  • entropy
  • reward

这些指标来自一次 GSPO 训练运行,即本实验所使用的优化目标。类似的不匹配问题也可能出现在 PPO、GRPO 或任何将 rollout 侧 logprob 视为优化目标一部分的在线 RL 系统中。

初始的 V1 运行清楚地暴露了问题。训练器侧的 logprob 和奖励在训练早期就偏离了 V0 基准。

图4
图4

图2. 训练更新过程中由训练器计算的当前策略 logprob(左)和奖励(右)。初始 vLLM V1 运行(红色)与 vLLM V0 基准(蓝色)分离。

同样的模式也出现在训练器指标中。裁剪率是在初步比较中最容易观察到的信号。

图5
图5

图3. vLLM V0 基准(蓝色)和初始 vLLM V1 尝试(红色)的训练器侧指标。裁剪率追踪 rollout 与训练器策略之间的差距;熵和奖励显示了这一差距如何传播到训练过程中。

失败模式

我们将可能的原因分为三个层次:

  1. 语义不匹配:后端返回的 logprob 与其相对于训练器预期含义不同。
  2. 推理路径不匹配:后端在缓存、调度或请求处理上使用了不同的运行时默认值,导致相同提示遵循不同的执行路径。
  3. 目标不匹配:RL 目标需要针对残留的延迟量或后端不匹配进行修正。

我们最初过早地怀疑了第三类原因。有效的诊断方法是先将前两类视为后端行为问题并逐一排除。

V1 后端修复

Logprob 语义

第一个问题是语义性的。vLLM V1 默认返回原始模型输出的 logprob,而未经过如温度缩放、惩罚项或 top-k/top-p 过滤等 logits 后处理步骤。但 PipelineRL 期望的是采样器所用处理后分布的 logprob。

所需的设置为:

  • logprobs-mode=processed_logprobs

这消除了 rollout logprob 中明显的均值偏移。然而训练曲线仍显示出与已知良好基准之间的差距,因此下一个问题必然出在推理路径上。

策略比率图可直接说明这一点。一旦 V1 开启 processed_logprobs,所有三次运行的平均策略比率都非常接近 1.0。这确认了均值偏差已被修复。剩余的不匹配则体现在裁剪率、KL 散度、熵及下游训练行为中。

图6
图6

图4. 每步 rollout/训练器策略比率偏离 1.0 的程度(乘以 10,000),展示 vLLM V0 基准(蓝色)、初始 vLLM V1 运行(红色)和修正后的 vLLM V1 运行(绿色)。

运行时默认值

早期的 V1 运行混合了引擎版本与 V1 的运行时默认设置:

  • 前缀缓存,在早期运行中未设置,因此采用 vLLM 0.18.1 的默认值
  • 异步调度,在早期运行中未设置,因此采用 vLLM 0.18.1 的默认值
  • 一个通过启动时 kwargs 传递设置的临时 disable-cascade-attn 覆盖项,不在提交的配置一致性配方中

为了实现一致性运行,我们显式指定了这些选项:

code
vllm_config:
  use_v1: true
  vllm_kwargs:
    logprobs-mode: processed_logprobs
    enable-prefix-caching: false
    async-scheduling: false

前缀缓存值得单独说明。它通常是对固定模型状态保持正确性的推理优化。但在这种在线 RL 设置中,它是相对于 V0 基准路径的 V1 独有差异。actor 还需处理重复前缀、并发请求、异步调度和飞行中权重更新。

当缓存策略忽略权重更新边界时,前缀缓存命中可能会复用权重更新前计算的状态。禁用前缀缓存从一致性比较中移除了一项仅存在于 V1 的自由度。

飞行中权重更新

权重同步也必须匹配在线 RL 的更新模型。一种选择是让 V1 比 V0 更严格,即每次更新时清空请求并清除缓存。但这会回答另一个问题。我们首先需要验证 V1 是否能够匹配现有的 V0 行为。

V0 实际上所做的更接近于:

  • 在引擎边界处阻塞执行
  • 加载新权重
  • 恢复运行而不显式使缓存状态失效

最接近的 V1 类比是:

code
await engine.pause_generation(mode="keep", clear_cache=False)
await engine_client.collective_rpc_async(
    "receive_weight_update",
    args=(request.model_dump_json(),),
)
await engine.resume_generation()

两个细节很重要:

  • mode="keep"waitabort 更贴近旧的飞行中更新模型
  • clear_cache=False 匹配 V0 包装器的行为,即更新时不破坏缓存状态

延迟是一个有用的运行时诊断指标。相比修正后的 V1 运行,初始 V1 路径在训练后期表现出更持久的延迟。

图7
图7

图5. rollout 服务器中权重落后于训练器策略的步数,展示 vLLM V0 基准(蓝色)、初始 vLLM V1 运行(红色)和修正后的 vLLM V1 运行(绿色)。

剩余差距:fp32 lm_head

上述 V1 后端修复消除了明显的迁移问题,但最终一致性仍需匹配用于计算 logits 的数值路径。训练器使用 fp32 lm_head 进行最终投影。rollout 后端必须匹配该行为。

一个密切相关的问题出现在 MiniMax-M1 技术报告 中:他们的 RL 运行显示出训练/推断 token 概率不匹配,追溯至语言模型输出头,并通过以 fp32 计算头部解决了该问题。

这一点之所以重要,是因为 RL 更新直接消耗 token logprob。logits 的微小变化可能在策略比率、KL 散度和裁剪中变得显著。因此,最终投影精度是在线 RL 正确性范围的一部分。后来的 ScaleRL 论文 将 fp32 logits/头部计算纳入其 RL 配方,并将其作为大规模 RL 的有效设计选择进行了消融分析。

包含 fp32 lm_head 路径后,奖励提供了最终一致性结果的简洁视图。在图6中,最终 V1 运行紧随 V0 基准;而初始 V1 尝试产生明显不同的奖励曲线。

图8
图8

图6. vLLM V0 基准(蓝色)、初始 vLLM V1 尝试(红色)和包含 fp32 lm_head 路径的最终 vLLM V1 运行(绿色)的奖励。包含 fp32 头部后,最终 V1 运行紧随 V0 基准。

消融实验

负向结果很重要,因为它们排除了常见解释。

  • 仅 `processed_logprobs`:修复了语义 logprob 错误;训练不匹配仍然存在。
  • 批处理不变性:在另一项测试中不匹配依然存在,且伴有更高延迟、更高裁剪率和 NCCL 复杂性。
  • 将首次 V1 运行视为公平基线:首次 V1 运行启用了多个仅 V1 存在的默认设置,因此它是一个混淆变量组合,不适合作为基线。