mcpField
G
grpo-rl-training

grpo-rl-training

github.com/kalarislabs開発9657 回インストール3 日前に更新
リポジトリ

grpo-rl-training について

このスキルは、TRLを使ったGRPO強化学習で、カスタム報酬関数によるLLMのファインチューニングを行うための指針です。データ準備から報酬設計、設定、デバッグ、デプロイまでを扱い、各段階の検証を重視します。

主な機能

  1. 01GRPOアルゴリズムと手順の解説
  2. 02カスタム報酬関数の設計と組み合わせ
  3. 03TRLの学習パラメーター設定
  4. 04TransformersとUnslothの例
  5. 05LoRAのマージと推論の解説

活用シーン

  1. 01正解報酬による数学・コーディングタスクの学習
  2. 02報酬によるJSONなどの出力形式の制約
  3. 03複数の目的に向けた報酬信号の組み合わせ
  4. 04報酬関数と学習時の問題の調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/kalarislabs/research-agent-skills --skill grpo-rl-training

インストール後、Claude Code で/grpo-rl-trainingを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
examples/
reward_functions_library.py
references/
advanced-patterns.md
critical-training-insights.md
templates/
basic_grpo_training.py

詳細

TRL を使用した GRPO/RL トレーニング

Transformer Reinforcement Learning(TRL)ライブラリを使用して Group Relative Policy Optimization(GRPO)を実装するためのエキスパート向けガイダンスです。このスキルでは、カスタム報酬関数を使用して言語モデルをファインチューニングするための、実戦で検証されたパターン、重要な知見、本番環境に対応したワークフローを紹介します。

このスキルを使用する場面

次のような場合に GRPO トレーニングを使用します。

  • 特定の出力形式を強制する(例:XML タグ、JSON、構造化された推論)
  • 検証可能なタスクを教える(数学、コーディング、ファクトチェックなど、客観的な正確性の指標があるタスク)
  • 思考の連鎖のパターンに報酬を与えて推論能力を向上させる
  • ラベル付きの選好データなしで、モデルをドメイン固有の動作に適応させる
  • 複数の目標(形式+正確性+スタイル)を同時に最適化する

次の用途には GRPO を使用しないでください。

  • 単純な教師ありファインチューニングタスク(代わりに SFT を使用してください)
  • 明確な報酬シグナルがないタスク
  • すでに高品質な選好ペアがある場合(代わりに DPO/PPO を使用してください)

基本概念

1. GRPO アルゴリズムの基礎

主な仕組み:

  • 各プロンプトに対して複数の補完を生成します(グループサイズ:4~16)
  • 報酬関数を使って各グループ内の補完を比較します
  • グループ内で相対的に高い報酬を得た応答を優先するよう、ポリシーを更新します

PPO との重要な違い:

  • 独立した報酬モデルが不要です
  • サンプル効率が高くなります(グループ内の比較から学習します)
  • 実装とデバッグがより簡単です

数学的な直感:

For each prompt p:
  1. Generate N completions: {c₁, c₂, ..., cₙ}
  2. Compute rewards: {r₁, r₂, ..., rₙ}
  3. Learn to increase probability of high-reward completions
     relative to low-reward ones in the same group
2. 報酬関数設計の考え方

基本原則:

  1. 複数の報酬関数を組み合わせます - それぞれが形式、正確性、スタイルなど1つの側面を担当します
  2. 報酬を適切にスケーリングします - 重みが大きいほど、より強いシグナルになります
  3. 段階的な報酬を使用します - 部分的な準拠にも部分点を与えます
  4. 報酬を個別にテストします - 各報酬関数を単独でデバッグします

報酬関数の種類:

種類用途重みの例
正確性検証可能なタスク(数学、コード)2.0(最高)
形式厳密な構造の適用0.5-1.0
長さ詳細さ/簡潔さの促進0.1-0.5
スタイル望ましくないパターンへのペナルティ-0.5~0.5

実装ワークフロー

ステップ 1:データセットの準備

重要な要件:

  • プロンプトはチャット形式('role' と 'content' を含む辞書のリスト)にします
  • 期待する出力を設定するために、システムプロンプトを含めます
  • 検証可能なタスクでは、追加の列に正解を含めます

構造の例:

from datasets import load_dataset, Dataset

SYSTEM_PROMPT = """
Respond in the following format:
<reasoning>
[Your step-by-step thinking]
</reasoning>
<answer>
[Final answer]
</answer>
"""

def prepare_dataset(raw_data):
    """
    Transform raw data into GRPO-compatible format.

    Returns: Dataset with columns:
    - 'prompt': List[Dict] with role/content (system + user messages)
    - 'answer': str (ground truth, optional but recommended)
    """
    return raw_data.map(lambda x: {
        'prompt': [
            {'role': 'system', 'content': SYSTEM_PROMPT},
            {'role': 'user', 'content': x['question']}
        ],
        'answer': extract_answer(x['raw_answer'])
    })

実践的なヒント:

  • 複雑な形式では、システムプロンプトにワンショットまたはフューショットの例を使用します
  • プロンプトは簡潔に保ちます(max_prompt_length:256~512 トークン)
  • トレーニング前にデータ品質を検証します(入力が不適切なら、出力も不適切になります)
ステップ 2:報酬関数の実装

テンプレート構造:

def reward_function_name(
    prompts,        # List[List[Dict]]: Original prompts
    completions,    # List[List[Dict]]: Model generations
    answer=None,    # Optional: Ground truth from dataset
    **kwargs        # Additional dataset columns
) -> list[float]:
    """
    Evaluate completions and return rewards.

    Returns: List of floats (one per completion)
    """
    # Extract completion text
    responses = [comp[0]['content'] for comp in completions]

    # Compute rewards
    rewards = []
    for response in responses:
        score = compute_score(response)
        rewards.append(score)

    return rewards

例 1:正確性の報酬(数学/コーディング)

def correctness_reward(prompts, completions, answer, **kwargs):
    """Reward correct answers with high score."""
    responses = [comp[0]['content'] for comp in completions]
    extracted = [extract_final_answer(r) for r in responses]
    return [2.0 if ans == gt else 0.0
            for ans, gt in zip(extracted, answer)]

例 2:形式の報酬(構造化出力)

import re

def format_reward(completions, **kwargs):
    """Reward XML-like structured format."""
    pattern = r'<reasoning>.*?</reasoning>\s*<answer>.*?</answer>'
    responses = [comp[0]['content'] for comp in completions]
    return [1.0 if re.search(pattern, r, re.DOTALL) else 0.0
            for r in responses]

例 3:段階的な形式の報酬(部分点)

def incremental_format_reward(completions, **kwargs):
    """Award partial credit for format compliance."""
    responses = [comp[0]['content'] for comp in completions]
    rewards = []

    for r in responses:
        score = 0.0
        if '<reasoning>' in r:
            score += 0.25
        if '</reasoning>' in r:
            score += 0.25
        if '<answer>' in r:
            score += 0.25
        if '</answer>' in r:
            score += 0.25
        # Penalize extra text after closing tag
        if r.count('</answer>') == 1:
            extra_text = r.split('</answer>')[-1].strip()
            score -= len(extra_text) * 0.001
        rewards.append(score)

    return rewards

重要な知見: 堅牢なトレーニングのために、3~5 個の報酬関数を組み合わせます。シグナルの多様性ほど、順序は重要ではありません。

ステップ 3:トレーニング設定

メモリ最適化設定(小型 GPU)

from trl import GRPOConfig

training_args = GRPOConfig(
    output_dir="outputs/grpo-model",

    # Learning rate
    learning_rate=5e-6,          # Lower = more stable
    adam_beta1=0.9,
    adam_beta2=0.99,
    weight_decay=0.1,
    warmup_ratio=0.1,
    lr_scheduler_type='cosine',

    # Batch settings
    per_device_train_batch_size=1,
    gradient_accumulation_steps=4,  # Effective batch = 4

    # GRPO-specific
    num_generations=8,            # Group size: 8-16 recommended
    max_prompt_length=256,
    max_completion_length=512,

    # Training duration
    num_train_epochs=1,
    max_steps=None,               # Or set fixed steps (e.g., 500)

    # Optimization
    bf16=True,                    # Faster on A100/H100
    optim="adamw_8bit",          # Memory-efficient optimizer
    max_grad_norm=0.1,

    # Logging
    logging_steps=1,
    save_steps=100,
    report_to="wandb",            # Or "none" for no logging
)

高性能設定(大型 GPU)

training_args = GRPOConfig(
    output_dir="outputs/grpo-model",
    learning_rate=1e-5,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=2,
    num_generations=16,           # Larger groups = better signal
    max_prompt_length=512,
    max_completion_length=1024,
    num_train_epochs=1,
    bf16=True,
    use_vllm=True,                # Fast generation with vLLM
    logging_steps=10,
)

重要なハイパーパラメーター:

パラメーター影響調整のアドバイス
num_generations比較時のグループサイズまず 8 から始め、GPU に余裕があれば 16 に増やします
learning_rate収束速度と安定性5e-6(安全)、1e-5(高速ですがリスクも高め)
max_completion_length出力の詳細さタスクに合わせます(推論には 512、短い回答には 256)
gradient_accumulation_steps実効バッチサイズGPU メモリが限られている場合は増やします
ステップ 4:モデルのセットアップとトレーニング

標準セットアップ(Transformers)

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig
from trl import GRPOTrainer

# Load model
model_name = "Qwen/Qwen2.5-1.5B-Instruct"
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
    attn_implementation="flash_attention_2",  # 2-3x faster
    device_map="auto"
)

tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token

# Optional: LoRA for parameter-efficient training
peft_config = LoraConfig(
    r=16,                         # Rank (higher = more capacity)
    lora_alpha=32,               # Scaling factor (typically 2*r)
    target_modules=[
        "q_proj", "k_proj", "v_proj", "o_proj",
        "gate_proj", "up_proj", "down_proj"
    ],
    task_type="CAUSAL_LM",
    lora_dropout=0.05,
)

# Initialize trainer
trainer = GRPOTrainer(
    model=model,
    processing_class=tokenizer,
    reward_funcs=[
        incremental_format_reward,
        format_reward,
        correctness_reward,
    ],
    args=training_args,
    train_dataset=dataset,
    peft_config=peft_config,      # Remove for full fine-tuning
)

# Train
trainer.train()

# Save
trainer.save_model("final_model")

Unsloth セットアップ(2~3 倍高速)

from unsloth import FastLanguageModel

model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="google/gemma-3-1b-it",
    max_seq_length=1024,
    load_in_4bit=True,
    fast_inference=True,
    max_lora_rank=32,
)

model = FastLanguageModel.get_peft_model(
    model,
    r=32,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                    "gate_proj", "up_proj", "down_proj"],
    lora_alpha=32,
    use_gradient_checkpointing="unsloth",
)

# Rest is identical to standard setup
trainer = GRPOTrainer(model=model, ...)
trainer.train()

重要なトレーニングに関する知見

詳細、コード例、パラメーター表:references/critical-training-insights.md。このステップが該当する場合は参照してください。

高度なパターン

詳細、コード例、パラメーター表:references/advanced-patterns.md。このステップが該当する場合は参照してください。

デプロイと推論

LoRA の保存とマージ
# Merge LoRA adapters into base model
if hasattr(trainer.model, 'merge_and_unload'):
    merged_model = trainer.model.merge_and_unload()
    merged_model.save_pretrained("production_model")
    tokenizer.save_pretrained("production_model")
推論の例
from transformers import pipeline

generator = pipeline(
    "text-generation",
    model="production_model",
    tokenizer=tokenizer
)

result = generator(
    [
        {'role': 'system', 'content': SYSTEM_PROMPT},
        {'role': 'user', 'content': "What is 15 + 27?"}
    ],
    max_new_tokens=256,
    do_sample=True,
    temperature=0.7,
    top_p=0.9
)
print(result[0]['generated_text'])

ベストプラクティスのチェックリスト

トレーニング前:

  • データセットの形式を検証する(プロンプトは List[Dict])
  • サンプルデータで報酬関数をテストする
  • データから想定される max_prompt_length を計算する
  • GPU メモリに応じて適切な num_generations を選択する
  • ロギングを設定する(wandb を推奨)

トレーニング中:

  • 報酬の推移を監視する(増加するはずです)
  • reward_std を確認する(0.1 を上回る状態を保つはずです)
  • OOM エラーに注意する(必要に応じてバッチサイズを減らします)
  • 50~100 ステップごとに生成結果をサンプリングする
  • 保留データセットで形式への準拠を検証する

トレーニング後:

  • PEFT を使用している場合は LoRA の重みをマージする
  • 多様なプロンプトでテストする
  • ベースラインモデルと比較する
  • 報酬の重みとハイパーパラメーターを記録する
  • 再現性のための設定を保存する

トラブルシューティングガイド

デバッグのワークフロー
  1. 報酬関数を個別に切り分ける - それぞれを独立してテストする
  2. データ分布を確認する - プロンプトに多様性があることを確認する
  3. 複雑さを減らす - 単一の報酬から始め、段階的に追加する
  4. 生成結果を監視する - N ステップごとにサンプルを出力する
  5. 抽出ロジックを検証する - 回答の解析が機能することを確認する
すぐにできる対処法
# Debug reward function
def debug_reward(completions, **kwargs):
    responses = [comp[0]['content'] for comp in completions]
    for i, r in enumerate(responses[:2]):  # Print first 2
        print(f"Response {i}: {r[:200]}...")
    return [1.0] * len(responses)  # Dummy rewards

# Test without training
trainer = GRPOTrainer(..., reward_funcs=[debug_reward])
trainer.generate_completions(dataset[:1])  # Generate without updating

参考資料とリソース

公式ドキュメント:

サンプルリポジトリ:

おすすめの参考資料:

  • エージェント向け指示の段階的開示パターン
  • RL における報酬シェーピング(Ng ら)
  • LoRA 論文(Hu ら、2021 年)

エージェント向け使用方法

このスキルを読み込んだ場合:

  1. GRPO トレーニングを実装する前に、このファイル全体を読む
  2. 設定を検証するため、最もシンプルな報酬関数(例:長さベース)から始める
  3. 出発点として templates/ ディレクトリのテンプレートを使用する
  4. タスクに応じた実装については examples/ の例を参照する
  5. ワークフローに順番に従う(手順を飛ばさない)
  6. 段階的にデバッグする - 報酬関数を一度に1つずつ追加する

重要な注意事項:

  • 常に複数の報酬関数を使用する(3~5 個が最適です)
  • 損失ではなく報酬の指標を監視する
  • トレーニング前に報酬関数をテストする
  • 小さく始め(num_generations=4)、段階的に規模を拡大する
  • チェックポイントを頻繁に保存する(100 ステップごと)

このスキルはエキスパートレベルの実装を想定しています。初心者は GRPO に取り組む前に、教師ありファインチューニングから始めてください。

関連スキル

  • fine-tuning-with-trl:TRL を使用して強化学習で LLM をファインチューニングします。指示チューニング向けの SFT、選好アライメント向けの DPO、報酬最適化向けの PPO/GRPO…
  • unsloth:Unsloth を使用した大規模言語モデルのファインチューニングに関するガイダンスを提供します。LoRA と QLoRA を使用して、より高速かつ少ないメモリでトレーニングできるライブラリです。基本…
  • axolotl:Axolotl を使用した大規模言語モデルのファインチューニングに関するガイダンスを提供します。YAML トレーニング設定、LoRA と QLoRA、選好トレーニングを取り上げます…

コメント