DPOとは?選好データからLLMを直接学習する仕組みと実装上の注意点

DPO(直接選好最適化)の全体像

DPO(直接選好最適化)の全体像

DPO(Direct Preference Optimization、直接選好最適化)は、同じプロンプトに対する「好ましい回答」と「好ましくない回答」を使い、言語モデルを直接更新する手法です。PPO型RLHFで必要だった独立した報酬モデル、価値モデル、学習中の回答生成を省き、教師あり学習に近い形で選好を反映できます。

ただし、DPOは「RLHFを簡単な式へ置き換えれば同じ結果になる」という万能な近道ではありません。学習できる範囲は収集済みの選好ペアに強く依存し、参照モデル、\(\beta\)、回答長、ラベル品質、学習と評価の分割によって結果が変わります。

この記事では、KL制約付きRLHFからDPOの目的関数が導かれる考え方、4本のlog probability、暗黙報酬、実装時のmaskと長さ、失敗パターン、評価まで順に解説します。

先に結論:DPOが省くものと、残るもの

PPO型RLHFとDPOの学習経路を比較した図

DPOが省くのは、主にPPO型RLHFのオンライン学習基盤です。人間の選好データそのものや、元のモデルから離れすぎないための基準が不要になるわけではありません。

項目 PPO型RLHF DPO
選好データ 報酬モデル学習に使う 方策モデル学習へ直接使う
明示的な報酬モデル 必要 不要
価値モデル 通常必要 不要
学習中のrollout生成 必要 通常不要
参照モデル KL制約に使う 確率比の基準に使う
主な学習入力 promptと生成回答 固定されたchosen/rejected pair
主な難しさ 複数モデル、生成、RL安定化 データ品質、確率計算、過学習
新しい回答分布の探索 学習中に可能 固定データの範囲へ依存

DPOの利点は、学習系を短くできることです。一方、選好収集、独立評価、安全設計、知識の正確性確認は残ります。

選好データの1件は三つの要素からなる

DPOの基本データは、プロンプト \(x\)、chosen回答 \(y_w\)、rejected回答 \(y_l\) の組です。

\[(x,y_w,y_l)\]

DPOで使う選好ペアの構造

たとえば「確認できない製品仕様を説明して」というプロンプトに対して、次のような比較を作れます。

要素 内容
prompt 確認できない製品仕様を説明して
chosen 確認できない点を明示し、公式資料の確認方法を案内する
rejected 根拠のない数値を推測して断定する

SFT(Supervised Fine-Tuning、教師あり追加学習)ならchosenだけを模倣できます。DPOはrejectedも使い、同じプロンプト内で「何を相対的に避けるか」を学びます。

pairの品質は勝敗ラベルだけでは決まらない

良い選好ペアには、少なくとも次の条件が必要です。

  • chosenとrejectedが同じプロンプトへ答えている
  • 差が評価基準で説明できる
  • 表示順やモデル名で評価者を誘導していない
  • ほぼ同等なら同点や判断不能として扱える
  • 専門知識が必要な質問を適切な評価者が見ている
  • 候補生成モデルとsampling条件を記録している

chosenが常に長く、rejectedが常に短いデータでは、内容ではなく長さを学ぶ可能性があります。安全性データでchosenが常に拒否文なら、無害な依頼まで拒否する近道を学ぶかもしれません。

prompt単位で分割する

同じプロンプトから4候補を生成すると、複数のpairを作れます。しかし、それらを行単位で無作為分割すると、同じpromptや同じresponseがtrainとvalidationへまたがる可能性があります。

分割単位はpairの行ではなく、prompt IDや会話IDを基本にします。テンプレートだけが異なる重複プロンプト、同一ソース文書から作った要約も、必要に応じてgroup化します。

DPOの出発点はKL制約付きRLHF

DPOの導出は、次のKL制約付き報酬最大化から始まります。

\[\max_{\pi} \; \mathbb{E}_{x\sim D,\;y\sim\pi(\cdot\mid x)} \left[ r(x,y) - \beta \log \frac{\pi(y\mid x)} {\pi_{\mathrm{ref}}(y\mid x)} \right]\]

ここで、\(r(x,y)\) は人間の選好を表す報酬、\(\pi\) は学習する方策、\(\pi_{\mathrm{ref}}\) は参照モデルです。\(\beta\) は報酬を追う強さと参照モデルへ留まる強さの関係を決めます。

この目的に対する最適方策は、概念的に次の形で書けます。

\[\pi^*(y\mid x) = \frac{1}{Z(x)} \pi_{\mathrm{ref}}(y\mid x) \exp\left(\frac{1}{\beta}r(x,y)\right)\]

\(Z(x)\) は同じプロンプトに対する確率を正規化する分配関数です。式を報酬について解くと、次の関係が得られます。

\[r(x,y) = \beta \log \frac{\pi^*(y\mid x)} {\pi_{\mathrm{ref}}(y\mid x)} + \beta\log Z(x)\]

KL制約付きRLHFからDPO lossへ変形する流れ

同じプロンプトのchosenとrejectedで報酬差を取ると、\(\beta\log Z(x)\) は打ち消されます。

\[r(x,y_w)-r(x,y_l) = \beta \left[ \log\frac{\pi^*(y_w\mid x)}{\pi_{\mathrm{ref}}(y_w\mid x)} - \log\frac{\pi^*(y_l\mid x)}{\pi_{\mathrm{ref}}(y_l\mid x)} \right]\]

これをBradley–Terry型の選好確率へ代入すれば、明示的な報酬モデルを別に学習せず、方策の確率比で比較を表現できます。

DPO lossは4本のlog probabilityを比べる

学習する方策を \(\pi_\theta\) とすると、代表的なDPO lossは次です。

\[\mathcal{L}_{\mathrm{DPO}}(\theta) = - \mathbb{E}_{(x,y_w,y_l)\sim D} \left[ \log\sigma \left( \beta \left[ \log\frac{\pi_\theta(y_w\mid x)}{\pi_{\mathrm{ref}}(y_w\mid x)} - \log\frac{\pi_\theta(y_l\mid x)}{\pi_{\mathrm{ref}}(y_l\mid x)} \right] \right) \right]\]

長く見えますが、必要なのは次の4値です。

  1. 方策モデルにおけるchosenのlog probability
  2. 方策モデルにおけるrejectedのlog probability
  3. 参照モデルにおけるchosenのlog probability
  4. 参照モデルにおけるrejectedのlog probability

DPO lossを構成する4本のlog probability

次の二つの相対変化を作ります。

\[\Delta_w = \log\pi_\theta(y_w\mid x) - \log\pi_{\mathrm{ref}}(y_w\mid x)\]
\[\Delta_l = \log\pi_\theta(y_l\mid x) - \log\pi_{\mathrm{ref}}(y_l\mid x)\]

DPOは \(\Delta_w-\Delta_l\) を大きくします。つまり、chosenをrejectedよりも参照モデルから相対的に優遇します。

ここで注意したいのは、chosenの絶対確率が必ず上がるとは限らない点です。rejectedの確率がより大きく下がれば、差は改善します。DPOを「chosenを上げ、rejectedを下げる」とだけ説明すると、実際の勾配を誤解します。

暗黙報酬は何を表すのか

DPOでは、次の値を暗黙報酬として監視できます。

\[\hat{r}_\theta(x,y) = \beta \log \frac{\pi_\theta(y\mid x)} {\pi_{\mathrm{ref}}(y\mid x)}\]

chosenとrejectedの暗黙報酬差はDPO logitに対応します。

\[m_\theta = \hat{r}_\theta(x,y_w) - \hat{r}_\theta(x,y_l)\]

このmarginが正なら、方策は参照モデルと比べてchosenを相対的に優遇しています。validationでは次を記録します。

指標 意味 注意点
loss pairwise分類目的の平均 生成品質そのものではない
reward chosen chosenの暗黙報酬 単独増加だけでは不十分
reward rejected rejectedの暗黙報酬 大幅低下でmarginが増える場合がある
reward margin chosenとrejectedの差 過学習でも増え得る
reward accuracy marginが正のpair比率 難易度や重複に依存
policy KL 参照モデルからの距離 推定方法と対象tokenを揃える

暗黙報酬は人間満足度の絶対尺度ではありません。学習方策と参照モデルの確率比から作った内部指標です。

回答全体の確率はtoken log probabilityの和

自己回帰型LLMでは、回答全体のlog probabilityをtokenごとの和で計算します。

\[\log\pi_\theta(y\mid x) = \sum_{t=1}^{|y|} \log \pi_\theta \left( y_t\mid x,y_{<t} \right)\]

prompt maskと回答tokenのlog probability集計

実装では、prompt部分をloss集計から除外し、chosen/rejectedの回答tokenだけを足します。次の境界を検査します。

  • chat templateが学習時と推論時で一致しているか
  • BOS、EOSが二重に付いていないか
  • assistant開始tokenをどちら側へ含めるか
  • padding tokenを集計していないか
  • truncationでchosenとrejectedの重要部分が落ちていないか
  • 空回答やEOSだけの回答を除外したか

長い回答は和の項数が増える

log probabilityは通常負なので、token数が多い回答ほど和が小さくなる傾向があります。ただしDPOは方策と参照の差をさらにchosenとrejectedで比較するため、単純に「短文が常に有利」とは言えません。

それでも、長さと内容が強く相関したデータ、truncation、EOS確率、batch内paddingは学習へ影響します。少なくとも次のsliceを確認します。

  • chosenが長いpairと短いpair
  • 長さがほぼ同じpair
  • promptが長いpair
  • 最大長で切れたpair
  • EOSを含む場合と含まない場合

token平均で正規化する変種もありますが、元のDPO目的と同じではありません。採用するなら、式、実装、評価条件を明記します。

\(\beta\) はlearning rateではない

\(\beta\) はDPO logitを拡大・縮小し、元のKL制約付き目的との対応を決める係数です。

DPOのbetaが作る学習強度のトレードオフ

同じmarginでも、\(\beta\) が大きいほどsigmoidへ入る絶対値は大きくなります。ただし、実際の学習結果はoptimizer、learning rate、epoch数、データ難易度と相互作用します。

状態 起こり得ること 確認方法
\(\beta\) が小さすぎる logitが小さく、広いmarginを要求しやすい KL、margin、生成比較
適度 選好差と参照維持の均衡 held-out評価と回帰
\(\beta\) が大きすぎる 少ないmarginでlossが飽和しやすい gradient、accuracy、改善停滞

「小さい\(\beta\)ほど必ず参照モデルへ近い」といった覚え方は危険です。論文の目的式における係数と、実装されたlossの係数がどう対応するかを確認します。libraryや派生lossでは定義が異なる場合があります。

\(\beta\) を選ぶときはtraining loss最小だけで決めません。複数候補を同じheld-out promptで生成し、人間評価、タスク成功率、安全性、長さ、KLを比較します。

参照モデルは「比較の原点」

DPOの参照モデルには、通常、DPO開始時のSFTモデルを使います。学習中は固定し、勾配を流しません。

参照モデルが担うのは、chosenとrejectedが元のモデルからどれだけ相対変化したかを測る原点です。参照モデル自体の品質が低い、chat templateが異なる、tokenizer revisionが違うと、比率の意味が崩れます。

参照log probabilityを事前計算する

offline学習では、データと参照モデルが固定なら、chosen/rejectedの参照log probabilityを事前計算できます。学習中の参照モデルforwardを省けるため、GPUメモリと計算時間を削減できます。

一方、次の変更をしたら再計算が必要です。

  • tokenizerまたはchat template
  • 最大長とtruncation規則
  • BOS/EOSの付与
  • 参照モデルcheckpoint
  • 回答tokenのmask
  • sequence log probabilityの集計方法

cacheにはcheckpoint hash、tokenizer revision、preprocess設定、sample IDを紐付けます。値だけを保存すると、古いcacheを誤利用しても検出できません。

DPOの1 batchで何が起きるか

DPO学習の流れを、1 batch単位で整理します。

  1. prompt、chosen、rejectedを同じchat templateで直列化する
  2. prompt部分とpadding部分のmaskを作る
  3. policyでchosen/rejectedをforwardする
  4. referenceでchosen/rejectedをforwardする、またはcacheを読む
  5. 回答tokenだけのlog probabilityを合計する
  6. policy-reference差をchosen/rejectedで計算する
  7. \(\beta\) を掛けてlogsigmoid lossを計算する
  8. policyだけをbackpropagationで更新する
  9. loss、margin、accuracy、KL、長さを記録する

PPO型RLHFのようなrollout生成と価値推定はありませんが、同じ回答をpolicyとreferenceで評価するため、通常のSFTよりforward量が増えます。chosenとrejectedを連結して一度のforwardへまとめる実装もあります。

数値例でDPO logitを追う

説明用の仮想値で計算します。論文の実験結果ではありません。

chosen rejected
policy log probability -8.0 -10.5
reference log probability -8.6 -10.2
policy-reference差 0.6 -0.3

相対marginは次です。

\[\Delta_w-\Delta_l = 0.6-(-0.3) = 0.9\]

\(\beta=0.2\)ならDPO logitは \(0.18\) です。

\[-\log\sigma(0.18) \approx 0.607\]

このpairでは、policyは参照モデルよりchosenを出しやすくし、rejectedを出しにくくしています。

別のpairでchosenの差が \(-0.1\)、rejectedの差が \(-1.0\) なら、marginは同じ \(0.9\) です。chosenの確率が参照より下がっていても、rejectedがより大きく下がればDPO lossは改善します。これが、chosenとrejectedの値を別々に監視すべき理由です。

DPOで起こりやすい失敗

DPOのデータ・学習・評価における失敗経路

chosenまで確率が下がる

marginだけを見ると、rejectedを強く下げることでlossを減らせます。chosen log probability、rejected log probability、SFT loss、生成品質を併せて確認します。

選好ラベルへ過学習する

train accuracyが上がり続け、held-out accuracyや生成評価が停滞する場合があります。同じprompt由来のpair漏洩、重複回答、近いtemplateを疑います。

IPO論文は、DPOを含む選好学習の理論的な近似と潜在的な問題を分析し、別の目的関数を提案しています。DPOの分類lossも、ノイズのある有限データで無制限に最適化すればよいわけではありません。

長さや文体の近道を学ぶ

chosenに共通する長さ、Markdown見出し、丁寧語、拒否定型文などが、内容より簡単な識別特徴になることがあります。pairの長さ差とmarginの相関を測り、長さを揃えた評価setも用意します。

参照モデルとの対応を失う

policy初期値、reference checkpoint、adapter構成がずれると、期待した確率比になりません。LoRAで学習する場合も、reference側でどのadapterを有効・無効にするかを明示します。

offlineデータの範囲から出られない

DPOは固定されたpair上で学習するのが基本です。新しいpolicyが生成する未知の失敗を、その学習runの中で自動収集するわけではありません。

対策はDPOを一度で終えることではなく、更新後のpolicyから候補を生成し、新たな比較を収集して次のdataset versionを作ることです。

PPO型RLHFとDPOのどちらを選ぶか

条件 DPOが向く PPO型RLHFが向く
高品質な固定pair すでにある 報酬モデルにも利用できる
学習基盤 SFTに近い構成を優先 rollout/RL基盤を運用できる
学習中の探索 必要性が低い 新しい方策分布を扱いたい
報酬 比較だけで十分 複数の報酬や検証器を組み合わせたい
計算資源 2モデルforwardを中心にしたい 4モデルと生成workerを扱える
診断 pair単位のmarginを見たい 明示的な報酬モデルを分析したい

DPO原論文は、感情制御、要約、単一turn対話において、同論文の設定でPPO型RLHFと同等以上の結果を報告しました。これはすべてのモデル、データ、タスクでDPOが優れるという保証ではありません。

正誤を自動判定できるコードや数学では、選好だけでなくunit testやverifierによる直接報酬が適する場合もあります。DPO、PPO、SFTを流行で選ぶのではなく、利用できる教師信号と更新後に探索が必要かで決めます。

評価はpair accuracyと生成品質を分ける

DPOの学習評価とリリース評価を分ける

学習中の診断

  • train/validation loss
  • chosen/rejectedの暗黙報酬
  • reward marginとaccuracy
  • chosen/rejectedのpolicy log probability
  • 参照モデルからのKL
  • prompt長、chosen長、rejected長
  • gradient norm
  • task別、source別、長さ別のslice

リリース判断

  • blindな人間比較
  • タスク成功率と事実正確性
  • 無害な依頼への過剰拒否
  • 危険な依頼への安全性
  • 冗長さと指示された長さの遵守
  • 知識、推論、コード、多言語の回帰
  • 未知プロンプトと敵対例

pair accuracyが高くても、生成時に同じ品質差が出るとは限りません。teacher forcingで既存回答を採点する評価と、自由生成した回答の評価を分けます。

比較評価ではモデル名を隠し、左右をランダム化し、同点と判断不能を許可します。勝率には標本数と不確実性を付けます。

実装前のチェックリスト

データ

  • prompt、chosen、rejectedの境界が明確か
  • 同じpromptやresponseが分割をまたいでいないか
  • 候補生成モデルとsampling条件を記録したか
  • 表示順、rubric、評価者不一致を保存したか
  • 長さ、文体、拒否率の偏りを確認したか

前処理

  • policyとreferenceで同じtokenizerを使うか
  • chat templateとBOS/EOSが一致するか
  • promptとpaddingをlog probability集計から除外したか
  • truncation後も品質差の根拠が残るか
  • 空回答、同一回答、壊れたpairを除外したか

学習

  • policy初期値とreference checkpointを固定したか
  • \(\beta\)、learning rate、epochを独立に記録したか
  • reference cacheの作成条件をhash化したか
  • chosen/rejectedの値をmarginとは別に監視したか
  • 複数checkpointを保持したか

評価

  • prompt単位のheld-out setを使ったか
  • 自由生成で人手比較したか
  • 長さ、安全性、task別sliceを見たか
  • SFT baseline、DPO、必要ならPPOと比較したか
  • rollbackと次回データ収集の条件を決めたか

まとめ

DPOは、選好ペアから言語モデルを直接更新し、PPO型RLHFの明示的な報酬モデル、価値モデル、学習中のrollout生成を省く手法です。

理解の中心は三つです。

  • KL制約付きRLHFの最適方策を使うと、報酬差をpolicy/referenceのlog probability ratioで表せる
  • DPO lossはchosen/rejectedに対する4本のlog probabilityから相対marginを作る
  • pipelineが短くなっても、選好データの偏り、参照モデル、長さ、過学習、独立評価の問題は残る

DPOの成功条件は、training lossが下がることではありません。更新後の自由生成を、held-out prompt、人手比較、タスク指標、回帰テストで確認することです。

次の記事では、Fine-tuningで更新するパラメータを低ランク行列へ限定するLoRAを扱います。DPOとLoRAは競合する概念ではなく、DPO lossをLoRAで学習する組み合わせも可能です。

参考資料

コメント

タイトルとURLをコピーしました