grpo-rl-training について
このスキルは、TRLを使ったGRPO強化学習で、カスタム報酬関数によるLLMのファインチューニングを行うための指針です。データ準備から報酬設計、設定、デバッグ、デプロイまでを扱い、各段階の検証を重視します。
主な機能
- 01GRPOアルゴリズムと手順の解説
- 02カスタム報酬関数の設計と組み合わせ
- 03TRLの学習パラメーター設定
- 04TransformersとUnslothの例
- 05LoRAのマージと推論の解説
活用シーン
- 01正解報酬による数学・コーディングタスクの学習
- 02報酬によるJSONなどの出力形式の制約
- 03複数の目的に向けた報酬信号の組み合わせ
- 04報酬関数と学習時の問題の調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ kalarislabs/ research-agent-skills --skill grpo-rl-trainingインストール後、Claude Code で/grpo-rl-trainingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mdexamples/reward_functions_library.pyreferences/advanced-patterns.mdcritical-training-insights.mdtemplates/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つの側面を担当します
- 報酬を適切にスケーリングします - 重みが大きいほど、より強いシグナルになります
- 段階的な報酬を使用します - 部分的な準拠にも部分点を与えます
- 報酬を個別にテストします - 各報酬関数を単独でデバッグします
報酬関数の種類:
| 種類 | 用途 | 重みの例 |
|---|---|---|
| 正確性 | 検証可能なタスク(数学、コード) | 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 の重みをマージする
- 多様なプロンプトでテストする
- ベースラインモデルと比較する
- 報酬の重みとハイパーパラメーターを記録する
- 再現性のための設定を保存する
トラブルシューティングガイド
デバッグのワークフロー
- 報酬関数を個別に切り分ける - それぞれを独立してテストする
- データ分布を確認する - プロンプトに多様性があることを確認する
- 複雑さを減らす - 単一の報酬から始め、段階的に追加する
- 生成結果を監視する - N ステップごとにサンプルを出力する
- 抽出ロジックを検証する - 回答の解析が機能することを確認する
すぐにできる対処法
# 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
参考資料とリソース
公式ドキュメント:
- TRL GRPO Trainer:https://huggingface.co/docs/trl/grpo_trainer
- DeepSeek R1 論文:https://arxiv.org/abs/2501.12948
- Unsloth ドキュメント:https://docs.unsloth.ai/
サンプルリポジトリ:
- Open R1 の実装:https://github.com/huggingface/open-r1
- TRL のサンプル:https://github.com/huggingface/trl/tree/main/examples
おすすめの参考資料:
- エージェント向け指示の段階的開示パターン
- RL における報酬シェーピング(Ng ら)
- LoRA 論文(Hu ら、2021 年)
エージェント向け使用方法
このスキルを読み込んだ場合:
- GRPO トレーニングを実装する前に、このファイル全体を読む
- 設定を検証するため、最もシンプルな報酬関数(例:長さベース)から始める
- 出発点として
templates/ディレクトリのテンプレートを使用する - タスクに応じた実装については
examples/の例を参照する - ワークフローに順番に従う(手順を飛ばさない)
- 段階的にデバッグする - 報酬関数を一度に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、選好トレーニングを取り上げます…