Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

報酬モデルの学習

報酬モデルは、人間の選好とRLの学習信号をつなぐ橋渡しです。十分に学習された報酬モデルはRLHFを成功させるために不可欠ですが、学習が不十分なものは報酬ハッキングやアラインメントのずれを引き起こします。この節では、報酬モデルの理論的基礎、実践的な学習技法、アーキテクチャ上の選択を扱います。

Bradley-Terryモデル — 完全導出

Bradley-Terryモデル (Bradley and Terry 1952) は、ペアワイズ選好学習の標準的な確率的枠組みです。2つの応答 \(y_1\) と \(y_2\) に対するプロンプト \(q\) について、モデルは次を仮定します。

\[ P(y_1 \succ y_2 \mid q) = \sigma(r(y_1, q) - r(y_2, q)) = \frac{e^{r(y_1,q)}}{e^{r(y_1,q)} + e^{r(y_2,q)}}, \]

ここで \(r: \mathcal{Y} \times \mathcal{Q} \to \mathbb{R}\) はスカラー報酬関数、\(\sigma\) はシグモイド関数です。

最尤推定

選好ペアのデータセット \(\mathcal{D} = \{(q^{(k)}, y_w^{(k)}, y_l^{(k)})\}_{k=1}^N\) が与えられたとき、MLEの目的関数は次のとおりです。

\[ \mathcal{L}_{\text{BT}}(\phi) = -\frac{1}{N}\sum_{k=1}^N \log \sigma!\bigl(r_\phi(y_w^{(k)}, q^{(k)}) - r_\phi(y_l^{(k)}, q^{(k)})\bigr), \]

ここで \(r_\phi\) は \(\phi\) でパラメータ化されたニューラルネットワークです。これは、正のクラスを選好された応答とする二値交差エントロピー損失です。

Important

Bradley-Terryの仮定

  1. 選好は推移的です。\(y_1 \succ y_2\) かつ \(y_2 \succ y_3\) ならば、\(y_1 \succ y_3\) です。

  2. 選好はスカラー報酬(多次元の選好ではない)によって決まります。

  3. 選好確率は報酬のだけに依存します。

  4. 選好はペア間で独立しています(アノテーターの影響はありません)。

これらの仮定は実際にはしばしば破られるため、ランキング向けのPlackett-Luceモデルや多次元報酬モデルなどの拡張が動機付けられます。

マージン損失への拡張

一般的な拡張では、勝者と敗者の報酬の間に最小の差を確保するため、マージン \(m\) を追加します。

\[ \mathcal{L}_{\text{margin}} = -\frac{1}{N}\sum_{k=1}^N \log \sigma!\bigl(r_\phi(y_w^{(k)}, q^{(k)}) - r_\phi(y_l^{(k)}, q^{(k)}) - m\bigr). \]

報酬モデルのアーキテクチャ

Tip

LLM上の分類ヘッド

標準的な報酬モデルのアーキテクチャは、事前学習済みLLMを取り、言語モデリングヘッド(隠れ状態を語彙のロジットへ写像するもの)を、スカラー回帰ヘッド(最終隠れ状態を1つの報酬値へ写像するもの)に置き換えます。

アーキテクチャは次のとおりです。

  1. バックボーン :プロンプトと応答のペアを隠れ状態の系列にエンコードする、事前学習済みLLM(Llama、Mistralなど)。

  2. プーリング :デコーダー専用モデルでは最後のトークン位置、エンコーダーモデルでは [CLS] トークンの隠れ状態を抽出します。

  3. 回帰ヘッド :プールされた隠れ状態をスカラー報酬へ写像する線形層 \(W \in \mathbb{R}^{d \times 1}\)。

Note

TRLでの報酬モデル学習

from trl import RewardConfig, RewardTrainer
from transformers import AutoModelForSequenceClassification

# Load model with scalar head (num_labels=1)
model = AutoModelForSequenceClassification.from_pretrained(
    "meta-llama/Llama-3.1-8B-Instruct",
    num_labels=1,
)

config = RewardConfig(
    output_dir="reward_model",
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=1e-5,
    num_train_epochs=1,
    # Margin loss
    center_rewards_coefficient=0.01,
)

trainer = RewardTrainer(
    model=model,
    args=config,
    train_dataset=dataset,  # must have chosen/rejected columns
)
trainer.train()

報酬モデルの学習テクニック

報酬の中心化

報酬モデルの生の出力は、スケールもオフセットも任意です。報酬を中心化(平均を引くこと)すると、RL学習が安定します。

\[ r_{\text{centered}}(y, q) = r_\phi(y, q) - \mathbb{E}_{y' \sim \pi_\theta}[r_\phi(y', q)]. \]

TRLでは、これは center_rewards_coefficient パラメータによって実装されます。このパラメータは、平均が0でない報酬を罰する正則化項を報酬モデルの損失に追加します。

長さバイアスの補正

報酬モデルには長さバイアスがあることが知られています。品質に関係なく、長い応答に高い報酬を割り当てる傾向です。これは次の方法で補正できます。

  1. 長さの正規化 :報酬を応答の長さで割ります。

  2. 長さを制御した学習 :長さを特徴量として含め、モデルが長さに依存しないよう学習します。

  3. 較正 :事後回帰によって長さの影響を取り除きます。

マージン損失

Bradley-Terry損失にマージン \(m\) を追加すると、報酬モデルは選好された応答と選好されていない応答に意味のある異なるスコアを割り当てるようになります。

\[ \mathcal{L}_{\text{margin}} = \max!\bigl(0,; m - (r_w - r_l)\bigr). \]

プロセス報酬モデルと結果報酬モデルの比較

Important

PRMとORMの比較

特性ORMPRM
報酬信号最終回答のみ各推論ステップ
学習データ(プロンプト、回答、正解?)(プロンプト、ステップ、ステップラベル)
アノテーションコスト低い高い
信用割当スパースデンス
報酬ハッキング容易困難
最適な用途単純なタスク複数ステップの推論
推論コスト低い高い(各ステップをスコアリング)

Tip

PRMを使う場合

プロセス報酬モデルは、次の場合に最も価値があります。

  • 複数ステップの推論(数学、コード、論理)が必要なタスク。

  • 最終回答は二値(正解/不正解)だが、中間ステップの品質が異なる場合。

  • 報酬モデルを探索に使いたい場合(ステップスコア付きのビームサーチなど)。

  • ステップレベルのアノテーションにアクセスできる場合(または自動生成できる場合)。

単純なタスク(感情分析、有害性、事実性)では、ORMで十分であり、はるかに低コストです。

Note

LLMのRLHFにおけるPBRS

元の報酬 :二値の正しさ(最終回答が正しければ1、そうでなければ0)—複数ステップ推論では非常にスパースです。

ポテンシャル関数 :\(\Phi(s) =\) 検証器からの部分点(たとえば、論理的に妥当な中間推論ステップの割合)。

整形された報酬 :最適方策が依然として最終回答の正しさを最大化する保証を保ちながら、エージェントは妥当な推論ステップごとに増分信号を得ます。

実装例

  • 思考の連鎖の各ステップをスコアリングするプロセス報酬モデル(PRM)

  • コード生成における中間コンパイルチェック

  • 複数部分からなる回答に対する部分一致スコア

これはPotential-Based Reward Shaping(PBRS) (Ng et al. 1999) をLLMに適用したものです。整形された報酬が最適方策を保つという理論的保証があるため、PRMは推論タスクに密な報酬を与える原理に基づいたアプローチです。

PRMアノテーションの自動化

ステップレベルのアノテーションは、次の方法で自動生成できます。

  1. モンテカルロ・ロールアウト :各中間ステップについて複数の完了をサンプリングし、正解に到達した割合をステップ報酬として使います。

  2. LLM-as-judge :強力なLLMを使って各ステップを評価します。

  3. 形式検証 :数学/コードでは、検証器を使って各ステップをチェックします。

RLVRのルールベース報酬

検証可能な報酬からの強化学習(RLVR)は、学習済み報酬モデルの代わりに決定論的なルールベース報酬関数を使います。これにより報酬ハッキングは大幅に減少します(ただし、モデルは形式上のトリック、エッジケース、テストの記憶をなお悪用できます)。このアプローチはDeepSeek-R1 (DeepSeek-AI et al. 2025) で使われています。

Note

TRLでのルールベース報酬関数

import re

def format_reward(completions, **kwargs):
    """Reward for using <think>...</think><answer>...</answer> format."""
    rewards = []
    pattern = r"<think>.*?</think>\s*<answer>.*?</answer>"
    for completion in completions:
        text = completion[0]["content"]
        rewards.append(1.0 if re.fullmatch(pattern, text, re.DOTALL) else 0.0)
    return rewards

def correctness_reward(completions, ground_truth, **kwargs):
    """Reward for correct final answer."""
    rewards = []
    for completion, gt in zip(completions, ground_truth):
        text = completion[0]["content"]
        match = re.search(r"<answer>(.*?)</answer>", text, re.DOTALL)
        if match:
            answer = match.group(1).strip()
            rewards.append(1.0 if answer == gt else 0.0)
        else:
            rewards.append(0.0)
    return rewards

def code_execution_reward(completions, test_cases, **kwargs):
    """Reward for code that passes test cases."""
    import subprocess, tempfile, os
    rewards = []
    for completion, tests in zip(completions, test_cases):
        code = completion[0]["content"]
        passed = 0
        for test in tests:
            with tempfile.NamedTemporaryFile(
                mode="w", suffix=".py", delete=False
            ) as f:
                f.write(code + "\n" + test)
                fname = f.name
            try:
                result = subprocess.run(
                    ["python", fname], capture_output=True,
                    timeout=5, text=True
                )
                passed += int(result.returncode == 0)
            except Exception:
                pass
            finally:
                os.unlink(fname)
        rewards.append(passed / len(tests))
    return rewards

Warning

ルールベース報酬の落とし穴

  • 形式のごまかし :モデルは正しい内容なしに正しい形式だけを生成することを学びます。形式報酬と正しさ報酬は必ず組み合わせてください。

  • テストケースの漏洩 :テストケースが学習データに含まれていると、モデルはそれを記憶します。

  • タイムアウトの悪用 :モデルは失敗を避けるため、タイムアウトするコードを生成することがあります。厳格なタイムアウトを使い、タイムアウトを明示的に罰してください。

  • 報酬のスパース性 :二値報酬(0/1)は複雑なタスクではスパースすぎることがあります。部分点や中間報酬を検討してください。

多目的報酬 — 組み合わせ戦略

複数の報酬信号で学習するとき、組み合わせ戦略は最終方策に大きく影響します。

Important

複数報酬の組み合わせ戦略

  1. 重み付き和 :\(r = \sum_n w_n r_n\)。単純ですが、スケールに敏感です。

  2. 正規化してから和(GDPO) :各報酬をグループ内で平均0、分散1に正規化してから、重み付きで合計します。スケールに依存しません。

  3. 辞書式 :優先順位に従って報酬を最適化し、優先度の高い報酬が同点の場合にだけ低い報酬を考慮します。

  4. 制約付き :二次報酬に制約を課しながら、主要報酬を最大化します。

  5. パレート :方策のパレートフロントを維持し、選好に基づいて選択します。

Note

TRLでの複数報酬学習

from trl import GRPOConfig, GRPOTrainer

config = GRPOConfig(
    # GDPO: normalise each reward independently
    multi_objective_aggregation="normalize_then_sum",
    reward_weights=[1.0, 0.3, 0.1],  # correctness, format, length
    num_generations=8,
)

trainer = GRPOTrainer(
    model=model,
    reward_funcs=[
        correctness_reward,
        format_reward,
        length_penalty_reward,
    ],
    args=config,
    train_dataset=dataset,
)

リストワイズ報酬

Bradley-Terryモデルはペアワイズ選好(\(y_w \succ y_l\))を扱いますが、実際には複数の応答を同時に順位付けする場面も多くあります。リストワイズ報酬モデルは完全な順序から学習し、より豊かな学習信号を提供するとともに、より良い較正を可能にします。

動機:ペアワイズを超えて

Tip

なぜリストワイズなのか?

  • 豊かな信号 :\(K\) 個の応答の順位には、\(\binom{K}{2}\) 個の暗黙的なペアワイズ比較が含まれますが、相対的なマージン(1位が3位よりどれだけ良いか)も捉えます。

  • より良い較正 :ペアワイズBTモデルは報酬のだけを学習しますが、リストワイズモデルは報酬の絶対スケールを学習します。

  • GRPOとの自然な適合 :GRPOはプロンプトごとに \(N\) 個の応答を生成して順位付けします。リストワイズ報酬はこのワークフローに直接適合します。

  • アノテーター効率 :5つの応答を順位付けする方が、考えられる10個のペアをすべて個別にラベル付けするより速いです。

Plackett-Luceモデル

Plackett-Luce(PL)モデル (Plackett 1975) は、Bradley-Terryを完全な順位付けへ拡張した標準モデルです。\(K\) 個の応答 \(y_1, \ldots, y_K\) と、順位 \(\pi\)(\(\pi(1)\) が最良)が与えられたとします。

Important

Plackett-Luceの尤度

\[ P(\pi \mid q) = \prod_{i=1}^{K} \frac{e^{r_\phi(y_{\pi(i)}, q)}}{\sum_{j=i}^{K} e^{r_\phi(y_{\pi(j)}, q)}} \] 直感 :残っている項目から最良のものを順番に選びます。各ステップで、項目 \(\pi(i)\) を選ぶ確率は残りの項目に対するsoftmaxです。

損失関数 : \[ \mathcal{L}_{\text{PL}}(\phi) = -\frac{1}{|\mathcal{D}|} \sum_{(q, \pi) \in \mathcal{D}} \sum_{i=1}^{K-1} \left[ r_\phi(y_{\pi(i)}, q) - \log \sum_{j=i}^{K} e^{r_\phi(y_{\pi(j)}, q)} \right] \]

Tip

Plackett-LuceはBradley-Terryに帰着する

\(K=2\) のとき、PLモデルは次を与えます:\(P(y_1 \succ y_2) = \frac{e^{r(y_1)}}{e^{r(y_1)} + e^{r(y_2)}} = \sigma(r(y_1) - r(y_2))\) — Bradley-Terryモデルと完全に同じです。PLは厳密な一般化です。

ListMLEと順位ベース損失

Important

リストワイズ損失関数

  • ListMLE (Xia et al. 2008):正解順位のPL尤度を直接最大化します。シンプルで効果的です。

  • ListNet (Cao et al. 2007):モデルのトップ1確率分布と正解の確率分布のKLダイバージェンスを最小化します。

    \mathcal{L}_{\text{ListNet}} = -\sum_{i=1}^{K} P_{\text{true}}(y_i \text{ is best}) \cdot \log P_{\text{model}}(y_i \text{ is best})
    

    ここで \(P_{\text{model}}(y_i \text{ is best}) = \frac{e^{r_\phi(y_i)}}{\sum_j e^{r_\phi(y_j)}}\)。

  • LambdaRank (Burges et al. 2006):ランキング指標の変化(NDCGなど)によってペアワイズ勾配に重みを付けます。ランキング品質が上位でより重要な場合に有用です。

  • RankNet (Burges et al. 2005):すべてのペアにわたるペアワイズ交差エントロピーの合計です。順位から抽出した \(\binom{K}{2}\) 個のすべてのペアに対するBTと同値です。

GRPOと棄却サンプリングのリストワイズ報酬

Important

GRPOとの統合

GRPOは自然に順位付けされたグループを生成します。各プロンプトについて \(N\) 個の応答がスコアリングされ、順位付けされます。リストワイズ報酬モデルは、これらの順位に対して直接学習できます。

  1. 生成 :方策からプロンプトごとに \(N=8\) 個の応答をサンプリングします。

  2. 順位付け :既存の報酬モデル(または人手のアノテーター)を使って完全な順位 \(\pi\) を生成します。

  3. リストワイズRMの学習 :\((q, \pi)\) タプルに対してPL損失を最適化します。

  4. GRPOで利用 :リストワイズRMは各応答にスカラー報酬 \(r(y_i, q)\) を割り当て、GRPOは \(\hat{A}_i = (r_i - \mu) / \sigma\) としてアドバンテージを計算します。

ペアワイズに対する利点 :リストワイズRMは \(N\) 個の応答をすべて同時に見て、1位は最下位 \(N\) よりはるかに高い報酬であるべきだと学習します(単に「別の1つの応答より少し良い」と学ぶだけではありません)。

実践上の考慮事項

Warning

リストワイズ学習の課題

  • アノテーションコスト :完全な順位付けにはコストがかかります。部分順位(8個中トップ3)なら、品質をほぼ維持したままコストを下げられます。

  • 同順位 :実際の順位には同順位がよくあります。同順位項目に等しい確率質量を割り当てる、同順位向けのPlackett-Luce拡張を使います。

  • 位置バイアス :アノテーターは最初に表示された項目を好む傾向があります。提示順をランダム化し、デバイアスを学習します。

  • リスト長 :\(K=4\)–8で学習するのが一般的です。より長いリスト(\(K>16\))は、利点があまりないままノイズを加えます。

  • 一貫性 :異なるアノテーターの順位は一致しない可能性があります。品質フィルタとしてアノテーター間一致度(\(\kappa > 0.6\))を使います。

Note

Plackett-Luceの学習コード

import torch
import torch.nn.functional as F

def plackett_luce_loss(rewards, rankings):
    """
    Args:
        rewards: (batch, K) - predicted scalar rewards for K responses
        rankings: (batch, K) - ground-truth ranking indices (0 = best)
    Returns:
        scalar loss
    """
    batch_size, K = rewards.shape
    # Sort rewards by ground-truth ranking order
    sorted_rewards = torch.gather(rewards, 1, rankings)  # (batch, K)

    # PL log-likelihood: sum over positions
    loss = 0.0
    for i in range(K - 1):
        # Log-softmax over remaining items (position i to K)
        remaining = sorted_rewards[:, i:]           # (batch, K-i)
        log_probs = remaining[:, 0] - torch.logsumexp(remaining, dim=1)
        loss -= log_probs.mean()

    return loss / (K - 1)

# Example: 8 responses per prompt, ranked by annotator
rewards = reward_model(responses)          # (batch, 8)
rankings = torch.argsort(human_scores, descending=True)  # best first
loss = plackett_luce_loss(rewards, rankings)
loss.backward()