LLM・RAG

PPOとDPOの違いとは?強化学習PPOの仕組みとDPOの選好学習をコードで比較【TRL 1.16対応】

PPOとDPOの違いとは?強化学習PPOの仕組みとDPOの選好学習をコードで比較【TRL 1.16対応】

PPOとDPOは、大規模言語モデル(LLM)を人間の好みに合わせる選好学習(アライメント)で比べられる2つの手法です。PPOは報酬モデルの採点を使って方策を少しずつ更新する強化学習アルゴリズムで、DPOは報酬モデルを作らずに「良い応答と悪い応答のペア」から直接学ぶ手法です。ここでのPPOは強化学習のProximal Policy Optimizationを指し、医療保険のPPOや樹脂のPPOとは別物です。

この記事では、両者の仕組みを式とコードで確かめたうえで、性能比較の論文が出した数字と、2026年10月時点のHugging Face TRLで実際にどう動かすかを整理します。TRLは2026年9月の1.13.0でPPOの学習クラスを削除しており、それ以前の解説の手順はそのままでは動きません。

まとめ:PPOとDPOの違いと選び方の結論

結論から言うと、選好ペアが用意でき、GPUが限られているならDPOから始める。正解判定が厳しいタスクで到達性能を詰めたいならPPO系のオンライン学習へ進む、が基準です。

  • PPOは方策・参照・報酬・価値の4モデルを動かすオンライン学習。DPOは方策と参照の2モデルで、選好ペアに対する分類損失を下げるだけのオフライン学習です。
  • DPOの原論文(NeurIPS 2023)は「PPOと同等以上」と報告し、ICML 2024の比較研究は「調整したPPOが全タスクでDPOを上回る」と報告しました。コード生成のCodeContestsでは、DPOが正答率0.0%、PPOが22.4%です。
  • ただし同じ研究で、調整前のPPOはSFTより成績が下がっています。PPOは調整の手間とセットで選ぶ手法です。
  • TRL 1.16ではDPOは DPOTrainer で十数行で動きます。PPOの PPOTrainer は1.13.0で削除されたため、LLMでPPOを回すならTRLを1.12以下に固定するか、verlやOpenRLHFを使います。

PPOとは:方策の更新幅をクリップして安定させる強化学習アルゴリズム

PPO(Proximal Policy Optimization、近接方策最適化)は、OpenAIのSchulmanらが2017年に発表した方策勾配法です(Proximal Policy Optimization Algorithms(arXiv:1707.06347))。ロボット制御やAtariゲームのような一般の強化学習で使われ、のちにLLMのRLHFで最終段の学習アルゴリズムになりました。報酬・方策・価値関数といった強化学習の基本用語は強化学習とは?報酬から学ぶ仕組みとQ学習・方策勾配・企業導入の判断を実装目線で解説で整理しています。

クリップ付き目的関数の式とε=0.2が使われる根拠

PPOは、新しい方策と古い方策の確率比 r を一定の範囲に切り詰めた目的関数を最大化します。原論文の式(7)は次のとおりです。

L_CLIP(θ) = E[ min( r(θ)·A, clip(r(θ), 1−ε, 1+ε)·A ) ]
r(θ) = π_θ(a|s) / π_θold(a|s)    A:優位性(advantage)

優位性が正なら確率比の上側、負なら下側で目的関数の改善を打ち切り、過大な更新を抑えます。ただし、確率比や方策の変化量を厳密に制限するものではありません。先行手法のTRPOは同じ狙いを2次の制約付き最適化で実現していましたが、PPOは1次の勾配法だけで済み、同じデータで複数エポックの更新を回せる点が違いです。

εの既定値が0.2になっている根拠は、原論文の表1にあります。MuJoCoの連続制御7タスクを各3シード、合計21回実行した平均正規化スコアは、クリップ無しが-0.39、ε=0.1が0.76、ε=0.2が0.82、ε=0.3が0.70でした。KLペナルティで更新幅を抑える方式(固定係数で0.62〜0.72、適応調整で0.68〜0.74)よりも、ε=0.2のクリップが上回っています。

Stable-Baselines3でCartPoleをPPO学習させる最小コード

LLMを使わずにPPOそのものを動かすなら、Stable-Baselines3のPPOが手早い選択です。次のコードは、棒を倒さずに台車を動かすGymnasiumのCartPole-v1を5万ステップ学習させます。

pip install stable-baselines3==2.9.2 gymnasium==1.4.0
import gymnasium as gym
from stable_baselines3 import PPO
from stable_baselines3.common.monitor import Monitor
from stable_baselines3.common.evaluation import evaluate_policy

env = Monitor(gym.make("CartPole-v1"))
model = PPO("MlpPolicy", env, seed=0, verbose=0)  # clip_range=0.2 などは既定値のまま

model.learn(total_timesteps=50_000)

mean, std = evaluate_policy(model, env, n_eval_episodes=20)
print(f"平均報酬 {mean:.1f} ± {std:.1f}")  # 1エピソードの上限は500
model.save("ppo_cartpole")

Python 3.12・CPUのみのDocker環境で実行すると、出力は 平均報酬 500.0 ± 0.0 でした。CartPole-v1は1エピソード500ステップで打ち切られ、475が「解けた」とみなす閾値なので、20回とも上限まで倒れずに保てたことになります。Stable-Baselines3 2.9.2の既定値は学習率3e-4、n_steps=2048、batch_size=64、n_epochs=10、clip_range=0.2 です。

RLHFでのPPO:SFT・報酬モデル・PPOの3段階と4モデル構成

LLMでのPPOは、InstructGPT(Ouyangら, 2022(arXiv:2203.02155))で確立したRLHFの第3段です。第1段で人間の模範回答によるSFT(教師あり微調整)を行い、第2段で応答の比較データから報酬モデルを学習し、第3段で報酬モデルの点数を報酬としてPPOで方策を更新します。同論文では、この手順で調整した13億パラメータのモデルの出力が、1,750億パラメータのGPT-3より人間の評価で好まれました。

LLM版のPPOでは、CartPoleの「行動」が次のトークン、「報酬」が報酬モデルの点数に置き換わります。学習中は、更新する方策モデル、離れすぎを抑える参照モデル、採点する報酬モデル、優位性を推定する価値(critic)モデルの4つをメモリに置きます。3段階それぞれのデータの集め方はRLHFとは?人間のフィードバックで言語モデルを調整する3段階の仕組みと採用判断【2026年版】で扱っています。

DPOとは:報酬モデルを学習せず選好ペアから直接学ぶ手法

DPOはDirect Preference Optimizationの略で、Rafailovらが2023年に発表し、NeurIPS 2023に採録された手法です(Direct Preference Optimization: Your Language Model is Secretly a Reward Model(arXiv:2305.18290))。「Direct Policy Optimization」と書かれることがありますが誤りです。RLHFの報酬最大化問題の解を式変形し、報酬モデルを方策の中に暗黙的に含めることで、強化学習のループを分類問題に置き換えました。

DPOの損失関数とβが決める参照モデルからの離れにくさ

DPOの損失は、好まれた応答 y+ と好まれなかった応答 y− の対数確率比の差をβ倍し、シグモイドを適用した値の負の対数を、選好ペア全体で平均したものです。

L_DPO = −E[ log σ( β · ( log π_θ(y+|x)/π_ref(y+|x) − log π_θ(y−|x)/π_ref(y−|x) ) ) ]

βは参照モデルからの離れにくさで、大きいほど元のモデルに近い位置にとどまります。TRLのDPO Trainerドキュメントには、実際の学習では好まれた応答の尤度を上げるより、好まれなかった応答の尤度を下げる方向で差が開くことが多いと書かれています。学習ログで logps/chosen も下がっていくのは、この性質によるものです。

選好データの形式:prompt・chosen・rejectedと会話形式

TRLが推奨する形式は、1件ごとに prompt・chosen・rejected の3つを持つ「明示プロンプト」形式です。JSONLなら次のように1行1ペアで書けます。以下の就業規則の条番号・申請期限・返品期間は、データ形式を示すための架空の設定です。

{"prompt": "有給休暇の申請期限は?", "chosen": "就業規則第12条により、取得日の3営業日前までに申請します。", "rejected": "いつでも大丈夫だと思います。"}
{"prompt": "返品の受付期間は?", "chosen": "商品到着後8日以内に、注文番号を添えてご連絡ください。", "rejected": "わかりません。"}

role と content を持つ会話形式でも渡せ、プロンプトを chosen と rejected の両方に含める「暗黙プロンプト」形式にも対応しています。後述のコードで使う trl-lib/ultrafeedback_binarized は後者で、列は chosen・rejected と点数だけです。プロンプトは学習開始時にトレーナーが自動で切り出します。ペアの件数や品質の基準はファインチューニング用データセットの作り方|サンプル形式・必要件数・品質要件【2026年10月】が参考になります。

PPOとDPOの違い:報酬モデル・学習方式・メモリ・到達性能で比較

観点 PPO(RLHF) DPO
報酬モデル 学習して使う 不要(暗黙化)
学習方式 オンライン(生成して採点) オフライン(既存ペアを読む)
同時に動かすモデル 4(方策・参照・報酬・価値) 2(方策・参照)
主なハイパーパラメータ ε・KL係数・学習率・バッチ β・学習率
TRL 1.16での実装 なし(1.13.0で削除) DPOTrainer
提唱 2017年 Schulmanら 2023年 Rafailovら

オンライン学習とオフライン学習の差が運用に出る場面

PPOは学習中に方策モデル自身が応答を生成し、それを報酬モデルが採点します。そのため、学習の途中でモデルが新しく出すようになった応答にも報酬が付き、誤りを自分で修正する経路があります。代わりに、報酬モデルの採点の穴を突いて点数だけを上げる「報酬ハッキング」が起きます。

通常のオフラインDPOは既存の選好ペアを使うため、学習ループ内での応答生成が不要です。報酬モデルと価値モデルも不要ですが、実際のメモリ使用量はモデル規模やPEFT、参照対数確率の事前計算などによって変わります。参照モデルの対数確率を事前計算する precompute_ref_log_probs=True を使えば、学習中に参照モデルをGPUに置く必要もありません。その反面、モデルの出力の傾向とペアデータの分布がずれると、学習が的外れな方向へ進みます。

性能比較:DPO原論文とICML 2024論文で結論が分かれた理由

DPOの原論文は、感情制御の生成でPPOベースのRLHFを上回り、要約と単一ターン対話では同等以上だったと報告しました。一方、ICML 2024のIs DPO Superior to PPO for LLM Alignment? A Comprehensive Study(arXiv:2404.10719)は、対話からコード生成までのすべての実験で、調整したPPOがDPOを上回ったと報告しています。

差が最も大きいのはコード生成です。CodeContestsのテストセット(1,000回生成して10件を提出する10@1k)で、Code Llama 34BのSFTが15.2%、DPOが0.0%、自己生成ペアで繰り返すDPO-Iterが3.2%、PPOが22.4%でした。著者らは、DPOのモデルが意味のないコード断片を出すようになったと書いています。これは同研究のCode Llama 34B・CodeContestsという条件での結果で、正誤を判定できるタスク全般でDPOが機能しないことまでは示していません。

同じ論文は、DPOが学習データに無い応答を突いて偏った解に落ちることを理論面でも示しました。PPO側の成績を引き出した要因として、優位性の正規化、大きなバッチ、参照モデルの指数移動平均(EMA)更新の3つを挙げています。どちらの結論を採るにしても、学習の前後を同じ評価セットで比べないと差は判断できません。評価セットの組み方はLLM評価とは?指標・データセット設計・評価ツールの選び方を実装視点で解説【2026年版】で解説しています。

DPOをTRL 1.16で動かす手順

Hugging Face TRLの最新版は2026年10月15日公開の1.16.0です。以下のコードは、TRL 1.16.0・transformers 5.21.0・peft 0.21.2の組み合わせで、学習が始まりLoRAアダプタが保存されるところまで確認しました。確認実行はCPU上の trl-internal-testing/tiny-Qwen3ForCausalLM、先頭16件、max_length=256、勾配蓄積1、ログ間隔1、max_steps=2、bf16=False、use_cpu=True の条件です。掲載するQwen3-0.6Bの設定そのものは実行していません。

TRL 1.16のインストールと依存バージョンの確認

python -m venv .venv
source .venv/bin/activate
pip install "trl==1.16.0" "transformers==5.21.0" "peft==0.21.2" "datasets==5.1.0"
python -c "import trl, transformers, peft; print(trl.__version__, transformers.__version__, peft.__version__)"

DPOConfig は fp16 を指定しない限り bf16=True が既定です。bf16に対応しないGPUやCPUで試すときは bf16=False を明示します。

DPOTrainerの最小コード:Qwen3-0.6BをLoRAで学習させる例

公式ドキュメントのクイックスタートと同じモデルとデータを使い、LoRAで学習する例です。動作確認用に、データは先頭2,000件に絞っています。

from datasets import load_dataset
from peft import LoraConfig
from trl import DPOConfig, DPOTrainer

# chosen / rejected の会話形式(プロンプトはトレーナーが自動で切り出す)
dataset = load_dataset("trl-lib/ultrafeedback_binarized", split="train[:2000]")

args = DPOConfig(
    output_dir="dpo-qwen3-0.6b",
    beta=0.1,                  # 既定値0.1。大きいほど参照モデルから離れにくい
    loss_type=["sigmoid"],     # 既定値。リストで渡す
    learning_rate=1e-5,        # LoRA用の目安。全体学習の既定は1e-6
    per_device_train_batch_size=2,
    gradient_accumulation_steps=8,
    max_length=1024,
    logging_steps=10,
)

trainer = DPOTrainer(
    model="Qwen/Qwen3-0.6B",
    args=args,
    train_dataset=dataset,
    peft_config=LoraConfig(r=16, lora_alpha=32, task_type="CAUSAL_LM"),
)
trainer.train()
trainer.save_model("dpo-qwen3-0.6b")

ref_model を省略すると、PEFT利用時はアダプタを外した状態のモデルが参照になります。全パラメータを学習する場合は peft_config を外し、学習率を既定の1e-6前後に戻します。LoRAの仕組みはPEFTとLoRAの違いとは?peftライブラリの使い方とQLoRA・DoRAの比較【2026年10月】、さらにメモリを減らす4bit量子化はQLoRAとは?4bit量子化+LoRAの仕組み・VRAM目安・実装手順と採用判断を解説【2026年版】で解説しています。

loss_type は1.16.0で15種類から選べます。"ipo"(IPO)、"robust"(ラベルの誤りに強いRobust DPO)、"sigmoid_norm"(SimPOの長さ正規化)などに差し替えるだけで派生手法になり、loss_type=["sigmoid", "sft"] のように並べて loss_weights で重みを付けることもできます。

学習ログの読み方:lossの初期値0.693とrewards/margins

更新前の方策は参照モデルと同じなので、対数確率比の差が0になり、sigmoid損失は −log σ(0)=ln 2=0.6931 から始まります。ログ間隔1の確認実行でも、1ステップ目は loss 0.6931、rewards/margins 0 でした。掲載コードは10ステップごとの記録なので、最初に表示される loss はこの値から少し動いている場合があります。

そこから rewards/margins(chosenとrejectedの暗黙報酬の差)が増え、rewards/accuracies(chosenの暗黙報酬が上回った割合)が上がっていけば、学習データの選好に合ってきています。開始時は両者の暗黙報酬が同じで、同点は上回ったと数えないため、accuraciesは0から始まります。学習データへの適合と実際の応答品質は別物なので、仕上がりは評価セットで確かめます。lossが0.693から動かないときは、学習率が低すぎるか、chosenとrejectedがほぼ同じ文になっているデータを疑います。

LLMでPPOを回す方法:TRL 1.13でPPOTrainerが削除された後の選択肢

TRLはv1.13.0(2026年9月10日公開)で PPOTrainer・PPOConfig と価値ヘッド付きモデルのクラスを削除しました。リリースノートが挙げた理由は、1年以上機能追加が無かったこと、入力形式がほかのトレーナーと揃っていなかったこと、利用がほぼ無かったことです。from trl import PPOTrainer はv1.10の時点で使えなくなっており、v1.10〜1.12は trl.experimental.ppo にだけ残っていました。TRL 1.16.0で試すと、前者は ImportError、後者は ModuleNotFoundError になります。

2026年10月時点で、LLMにPPOをかける道は次の3つです。

  • TRLを1.12以下に固定する:pip install "trl<1.13" とし、from trl.experimental.ppo import PPOConfig, PPOTrainer で読み込みます。保守されていないコードなので、検証用にとどめます。
  • verlを使う:verlのPPOは、GRPOなどと同じ仕組みでPPOを動かせる強化学習フレームワークです。PyPIの最新版は0.9.1です。
  • OpenRLHFを使う:OpenRLHFはRayとvLLMを土台にした分散型のRLHFフレームワークで、最新版はv0.11.2(2026年9月14日)です。Rayの仕組みはRayとは?分散処理フレームワークの仕組みと採用判断を実装目線で解説【2026年版】を参照してください。

報酬を機械的に計算できるタスク(テストの合否や数式の正誤)なら、TRLに残っている GRPOTrainer や RLOOTrainer を先に検討します。どちらも価値モデルを持たないオンライン手法で、PPOより1モデル少なく済みます。

PPOとDPOの使い分け:条件別の採用基準

DPOを選ぶ条件:選好ペアがあり限られたGPUで安定して回したい場合

人の目で「こちらが良い」と判定できるタスク(回答の口調、社内規程に沿った言い回し、不適切な応答の抑制)で、数千件規模の選好ペアを用意できるならDPOが第一候補です。TRLで十数行のコードになり、報酬モデルの構築と保守が要りません。小型モデルをLoRAで学習するなら、単一GPUで回せる水準まで負荷が下がります。

PPOを選ぶ条件:正誤が厳しいタスクで到達性能を詰めたい場合

コード生成のように出力の正しさが機械的に判定でき、SFTの先の性能を詰めたい場合はPPO系のオンライン学習が有利です。ICML 2024の研究でDPOが0.0%に落ちたCodeContestsで、PPOは22.4%まで上げています。ただし、これは複数GPUで学習基盤を組み、ハイパーパラメータを詰められる体制がある場合の話です。

採用を見送る場面:調整なしのPPOと分布外データでのDPO

調整の体制が無いままPPOを入れるのは避けるべきです。同じ論文の表3では、バッチサイズ64のままの素のPPOがAPPSの入門問題でpass@5 18.0%となり、SFTの38.6%を大きく下回りました。優位性の正規化・大きなバッチ・参照モデルのEMA更新を加えて、はじめて44.4%に届いています。

DPOも、別のモデルが生成した応答を集めた選好データをそのまま使うと、学習対象のモデルの出力分布とずれて効果が出にくくなります。手元のモデルで応答を生成し、それにラベルを付け直す手間をかけられないなら、DPOより先にSFTのデータを見直すほうが確実です。選好データの設計から学習・評価までを一続きで回す体制が社内に無い場合は、AIエンジン開発のような外部の開発支援で最初の1サイクルを回す方法もあります。

GRPO・KTO・ORPOなど周辺手法とPPO・DPOの位置づけ

GRPO(Group Relative Policy Optimization)はDeepSeekがDeepSeekMath(arXiv:2402.03300)で提案したPPOの派生です。価値モデルを廃し、同じプロンプトへの複数の応答をグループ内で比べて優位性を推定します。式とPPOとの違いはGRPOとは?DeepSeekの強化学習アルゴリズムの公式・仕組みとPPOとの違いで詳しく扱っています。

DPOの側には、ペアでなく「良い」「悪い」の単独ラベルで学べるKTO、SFTと選好学習を1段で行うORPO、参照モデルを使わずに長さの偏りを抑えるSimPOがあります。TRL 1.16.0では、KTOは本体の KTOTrainer、ORPOとCPOは trl.experimental 配下、SimPOの長さ正規化は DPOTrainer の loss_type="sigmoid_norm" で扱います。

よくある質問

強化学習のPPOとは何をするアルゴリズムですか?

方策(どの行動を選ぶかの確率)の更新で、クリップ付き目的関数を使って過大な変化を抑える方策勾配法です。確率比が1±εの範囲内に収まる保証はありません。2017年にOpenAIのSchulmanらが発表し、εは0.2がよく使われます。LLMではRLHFの最終段として、報酬モデルの点数が高くなる方向へモデルを更新します。

DPOとは何の略ですか?

Direct Preference Optimizationの略です。Direct Policy Optimizationではありません。報酬モデルを学習せず、好まれた応答と好まれなかった応答のペアから直接モデルを更新する手法で、2023年にNeurIPSで発表されました。

DPOとPPOはどちらが優れていますか?

タスクと体制によります。DPOの原論文は感情制御・要約・対話で同等以上と報告し、ICML 2024の比較研究は、調整したPPOが対話とコード生成のすべての実験でDPOを上回ったと報告しました。選好ペアで手早く調整するならDPO、正誤が厳しいタスクで性能を詰めるならPPOです。

RLHFとDPOの関係はどうなっていますか?

RLHFはSFT・報酬モデル学習・PPOの3段階で人間の選好を学ぶ枠組みで、DPOはそのうち報酬モデル学習とPPOの2段を1つの分類損失に置き換えたものです。DPOを使うと、手順はSFTとDPOの2段になります。

TRLの最新版でPPOTrainerが見つからないのはなぜですか?

TRL 1.13.0(2026年9月10日公開)でPPOTrainerとPPOConfigが削除されたためです。1.12以下に固定すれば trl.experimental.ppo から読み込めますが、継続して使うならverlやOpenRLHFに移るか、価値モデルの要らないGRPOTrainer・RLOOTrainerを検討します。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.27 テックブログ Brotli 脆弱性:CVE-2026-111497の影響確認とNode.js・Python・.NETの更新手順
  2. 2026.10.28 テックブログ リンツ不正アクセス:314万件の対象確認とパスワード強制リセット後の対処
  3. 2026.10.27 テックブログ Joshin(ジョーシン)不正アクセス:最大600万件の対象とサブスク初期パスワードの対処
  4. 2026.10.23 テックブログ Renta!はいつ再開?不正アクセスでメールアドレス等が流出したおそれ・再開時のパスワード再設定と運営側の対応
  5. 2026.10.28 テックブログ 楽天トラベル不正アクセス:最大約260万件の対象確認とカード下4桁の詐欺対策

RELATED POSTS 関連記事

目次