事業紹介 事業紹介トップ 経営データ分析基盤 Claude / MCP 導入 複雑な SaaS を専用 UI に Shopify Plus 移行・拡張 生成AI 活用(Multi AI) SEO / AIO / 広告運用 顧問・アドバイザリ インフラ構築 自社メディア投資・開発
Claude Claude / MCP 総合 Claude Cowork Claude Code Claude Design MCP サーバー実装
Shopify Plus Shopify Plus トップ EC-CUBE からの移行 大手カートからの移行 Shopify 通常プラン
実績
業界ニュース 業界ニュース トップ AI ニュース Shopify ニュース SaaS ニュース お知らせ(自社発信)
会社情報 お問い合わせ
2026.05.12

vLLM V0→V1 移行で強化学習の再現性を確保した4つの修正点(ServiceNow AI)

記事のサマリー(TL;DR)

  • vLLM V1(0.18.1)はデフォルトで「生の」logprobを返すため、processed_logprobs設定が必須
  • prefix caching・async schedulingのデフォルト差異と重み更新パスの不一致がRL指標(clip rate・KL・entropy・reward)をズラした
  • fp32 lm_headによる最終投影の数値精度が、policy ratioとKLに直接影響するため正確性のサーフェスに含まれる

生成AI基盤でvLLMを利用する開発チームへの影響

vLLMはオープンソースLLM推論の事実上の標準エンジンとして、国内でもGPU推論サーバーやRL(強化学習)パイプラインに広く採用されています。本記事が示す「バックエンドの正確性を目的関数の修正より先に確認する」という原則は、GRPO・PPO・GSPOなどオンラインRLを伴う学習基盤全般に適用できます。特にvLLM V1への移行を検討しているチームでは、①logprobs-mode=processed_logprobsの明示設定、②enable-prefix-caching: falseasync-scheduling: falseによるデフォルト差異の排除、③fp32 lm_headパスの統一、の3点を移行チェックリストに加えることで、訓練曲線の予期しない乖離を防げます。また、MiniMax-M1やScaleRLなど複数の大規模RL事例でfp32 lm_headが共通の修正項目として登場しており、推論エンジンと訓練エンジンの数値精度を揃える重要性が広く認識されつつあります。

詳細

背景:なぜlogprobの一致が重要か

PipelineRLはロールアウト生成の推論エンジンとしてvLLMを使用します。推論エンジンはトークンをサンプリングしてtoken logprobsを返し、トレーナーはそのlogprobsを使ってpolicy ratio・KL・clip rate・entropy・rewardを計算します。logprobsの計算方法に少しでも差異があると、訓練ダイナミクスが変化します。これが今回のvLLM V0→V1移行で排除すべき「train-inference mismatch(訓練-推論の不一致)」でした。

  • 参照環境:vLLM 0.8.5(V0)
  • 移行先:vLLM 0.18.1(V1)

Figure 1で示すように、赤いrunが最初のV1試行、緑のrunが修正後の最終V1 runです。最終V1 runはclip rate・KL・entropy・rewardすべてでV0の軌跡に近い値を示しています。


移行の目的(Migration Objective)

vLLM V1はV0エンジンの実質的な書き直しです。そのため移行目標を意図的に狭く設定しました。

  1. V1がトレーナーの期待する形式でロールアウトlogprobsを返すことを検証する
  2. 同一ワークロードをV0参照と照らし合わせて再実行する
  3. バックエンドの同等性が確認されて初めて、目的関数レベルの変更を評価する

最初に可視化された症状は以下のメトリクスに現れました。

  • clamp_log_ratio_new_old_indicator
  • kl_new_old
  • entropy
  • reward

これらは今回の実験で使用したGSPO(Generalized Soft Policy Optimization)訓練runから得られたものです。同種の不一致はPPO・GRPO、あるいはロールアウト側logprobsを最適化ターゲットの一部として扱うあらゆるオンラインRLシステムで発生しえます。


失敗モードの分類(Failure Modes)

考えられる原因を3層に分類しました。

  1. Semantic mismatch(意味論的不一致):バックエンドがトレーナーの期待と異なる意味のlogprobsを返す
  2. Inference-path mismatch(推論パス不一致):キャッシュ・スケジューリング・リクエスト処理のランタイムデフォルトが異なるため、同じプロンプトが異なる実行パスをたどる
  3. Objective mismatch(目的関数不一致):RLの目的関数が、残存する staleness やバックエンド不一致の量に応じた補正を必要としている

当初は第3カテゴリを早計に疑いましたが、有用な診断は最初の2つをバックエンドの動作問題として扱い、先に除外することで得られました。


V1バックエンドの修正(V1 Backend Fixes)

Logprob Semantics(logprobの意味論)

最初の問題は意味論的なものでした。vLLM V1はデフォルトで、temperature scaling・penalties・top-k/top-pフィルタリングなどのlogits後処理前の生のモデル出力からlogprobsを返します。 PipelineRLはサンプラーが使用した処理済み分布からのlogprobsを期待していました。

必要な設定は以下のとおりです。

logprobs-mode=processed_logprobs

これによりロールアウトlogprobsの明らかな平均オフセットが除去されました。ただし訓練曲線は既知の良好な参照との差が残っており、次の問題は推論パスにあることが示唆されました。

processed_logprobsをV1でオンにすると、ステップごとのpolicy ratio(ロールアウト÷トレーナー)の平均は3つのrunすべてで1.0ごく近くに安定します。これが平均バイアスの修正です。残りの不一致はclip rate・KL・entropy・下流の訓練動作に現れます。

Runtime Defaults(ランタイムデフォルト)

初期V1 runではエンジンバージョンとV1ランタイムデフォルトが混在していました。

  • prefix caching:初期runで未設定のためvLLM 0.18.1のデフォルトが適用
  • async scheduling:初期runで未設定のためvLLM 0.18.1のデフォルトが適用
  • cascade-attn無効化:起動時のkwargパススルーで設定されており、コミット済みconfigのparity recipeの外に存在

parity runでは以下を明示的に設定しました。

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

Prefix cachingについての補足。 これは通常、固定モデル状態に対して正確性を保つ推論最適化です。しかしこのオンラインRLの設定では、V0参照パスに対してV1固有のキャッシュ有効期間と再利用の差異が生じていました。actorはrepeated prefix・並行リクエスト・async scheduling・inflight weight updateも処理しており、prefix-cacheヒットが重み更新境界を無視したキャッシュポリシーのもとで更新前に計算された状態を再利用する可能性がありました。Prefix cachingを無効化することで、parity比較からV1固有の自由度を1つ除去しました。

Inflight Weight Updates(インフライト重み更新)

重み同期もオンラインRLの更新モデルに合わせる必要がありました。V0が実質的に行っていたのは以下に近い動作です。

エンジン境界で実行をブロック
↓
新しい重みをロード
↓
キャッシュ状態の明示的な無効化なしに再開

最も近いV1の対応実装は以下のとおりです。

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()

2点のポイントがあります。

  • mode="keep"waitabort よりも旧来のinflight更新モデルに近い
  • clear_cache=False は更新時にキャッシュ状態をそのまま残すV0ラッパーの動作に合致

残差ギャップ:fp32 lm_head

上記のV1バックエンド修正により明白な移行問題は除去されましたが、最終的なparityにはlogitsの計算に使用される数値パスの統一が必要でした。トレーナーは最終投影にfp32 lm_headを使用しており、ロールアウトバックエンドもその動作に合わせる必要がありました。

密接に関連する問題がMiniMax-M1のテクニカルレポートに登場します。彼らのRL runではLM出力ヘッドに起因する訓練/推論のtoken确率不一致が発生し、ヘッドをfp32で計算することで修正しました。

これが重要な理由は、RLの更新がtoken logprobsを直接消費するからです。logitsのわずかな変化がpolicy ratio・KL・clippingに可視化されます。最終投影の精度はオンラインRLの正確性サーフェスの一部です。

後にScaleRLの論文でも、fp32 logits/headの計算がRLレシピの一部として含まれ、大規模RLにおける有用な設計選択として ablateされています。

fp32 lm_headパスを含めると、Figure 6に示すように最終V1 runはV0参照を追跡し、最初のV1試行とは明確に異なるreward曲線になります。


アブレーション(Ablations)

ネガティブな結果は一般的な説明を排除するために重要です。

  • processed_logprobs単独:logprobの意味論バグは修正されたが、訓練不一致は残存
  • バッチ不変性(Batch invariance):別のテストで不一致が残存(より高いlag・clip rate、NCCLの複雑化)
  • 最初のV1 runをフェアなベースラインとして扱う:最初のV1 runには複数のV1固有デフォルトが有効化されており、混同された移行比較となっていた

なぜバックエンドの正確性を先に修正したか(Why We Fixed Backend Correctness First)

truncated importance samplingやimportance-ratio reweightingなどの目的関数側の補正は有用なツールです。ロールアウトが意図的にstaleである場合、非同期で生成される場合、またはトレーナー側policyとの等価性が得られないバックエンドで生成される場合、何らかの補正を追加することはしばしば正しい選択です。

しかし今回の最初の問題は推論の正確性でした。V1へ移行後、ロールアウトバックエンドはトレーナーの前提を破るlogprobsとランタイム動作を返していました。その時点で目的関数側の補正を追加すると、2つの問いが混在してしまいます。

  1. 推論バックエンドは正しいlogprobsを生成しているか?
  2. 正しいlogprobsが得られた上で、目的関数はまだoff-policyまたは非同期補正を必要とするか?

この2つは分離する必要があります。そうしないと目的関数側の補正が壊れた推論バックエンドの動作を補ってしまい、訓練曲線の解釈が困難になります。

現在の目的関数はまだ改善の余地があります。推論parityが確認された後、次の改善は通常のasync/off-policyのクリーンアップです。

  • ロールアウト時点での明示的なbehavior-policy logprobsの保持
  • 最適化時点でのトレーナー側old-policy logprobsの再計算
  • バックエンド不一致補正とpolicy-update ratioの分離
  • 補正項のESSなどの診断指標を集約トレーナー指標と並行してトラッキング

今回の移行から得られる主な教訓は狭いがはっきりしています:まずバックエンドの正確性を修正し、それから残存する不一致への補正を追加する。