TRL documentation
非同期GRPO
非同期GRPO
このトレーナーには
vllm、transformers>=5.2.0、kernels(学習時にこれを通じて Hub から FlashAttention を読み込む)が必要です。分散学習では、FSDP2 のみサポートされています(DeepSpeed ZeRO はサポートされていません)。現在、
vllmとtransformersの依存関係の制約が競合しています。これを回避するには、まずvLLMをインストールし、次にtransformersを強制インストールし、その後TRLのextraを通じてkernelsを追加します。これにより、transformersが受け入れるバージョンが固定されます。pip install vllm pip install 'transformers>=5.2.0' --no-deps pip install 'trl[kernels]'
概要
experimental.async_grpo.AsyncGRPOTrainer は同じ GRPO アルゴリズムを実装していますが、ロールアウトの生成と学習を分離します。バックグラウンドワーカーが vLLM サーバーから補完を継続的にストリーミングで送信し、学習ループがそれらを消費するため、生成と勾配の更新が交互に実行されるのではなく、オーバーラップして実行されます。API は GRPOTrainer と同じ構成です。GRPO 手法自体の詳細(アドバンテージの計算、KL 推定、損失の定式化、報酬関数など)については、GRPO Trainer のドキュメントを参照してください。GRPOTrainer のすべての機能が利用可能というわけではなく、サポートされているパラメータについては experimental.async_grpo.AsyncGRPOConfig を参照してください。
このトレーナーは、Quentin Gallouédec氏とAmine Dirhoussi氏によって提供されました。
GRPOTrainerとの違い
標準的なGRPOTrainerでは、生成と学習が逐次実行されます。バッチを生成し、損失を計算し、重みを更新し、これを繰り返します。vLLM colocate モードのように生成が同じ GPU 上で実行される場合でも、一方のフェーズが完了するまで、もう一方のフェーズは開始できません。
experimental.async_grpo.AsyncGRPOTrainer は、これら2つの関心事を分離します:
- Rollout worker(バックグラウンドプロセス)— vLLMサーバーにプロンプトを送信し、報酬関数で補完をスコアリングし、アドバンテージを計算し、学習可能なサンプルをキューにプッシュします。
- 学習ループ(メインプロセス)— キューからサンプルを取得し、クリップされたサーロゲート損失を計算して、モデルの重みを更新します。
ロールアウトワーカーはトレーナーから生成された別プロセスで実行されるため、報酬の計算はトレーニングループとGILを競合しません。このため、reward_funcs、tools、environment_factory(後者については、OpenEnvガイドを参照してください。このガイドでは、契約と利用可能な統合について説明しています)として渡すことができるものについて、2つの制約が生じます:
ロールアウトワーカーは別プロセスで実行されるため、渡されるすべてのデータはピクルス化されます。したがって、各報酬関数、ツール、
environment_factory(およびそれらがクロージャとして保持しているオブジェクト)は、ピクルス化可能である必要があります。モジュールレベルの関数、functools.partial、または呼び出し可能なクラスインスタンスを使用してください。ツールは例外です。モデルはツールをその名前で呼び出すため、各ツールは__name__で登録され、モジュールレベルの関数である必要があります。ラムダ関数やクロージャは、trainer.train()時にTypeErrorを発生させます。これはGRPOTrainerとの違いで、ここでは報酬関数がプロセス内で呼び出されるため、クロージャが使用できます。ロールアウトプロセスも
CUDA_VISIBLE_DEVICES=""で実行されるため、GPUを使用できません。GPUバックの報酬モデル(例:AutoModelForSequenceClassificationスコアラー)はエラーなくロードされますが、CPUにサイレントにフォールバックします(GRPOTrainerでは、そのような報酬モデルはトレーナーのGPUを共有する点に注意してください)。報酬関数はCPU側で軽量なものにしてください(accuracy_rewardのような検証器、形式/長さチェックなど)。GPU 上の報酬モデルが必要な場合、推奨されるアプローチは、独自の推論エンジン(vLLM、TGI など)の背後で提供し、別の GPU 上で動作させ、軽量で pickle 可能な報酬関数から HTTP 経由で呼び出すことです。これにより、報酬モデルは独自のデバイス上で動作し、ロールアウトプロセスは CPU のみで実行されるため、トレーナーとは独立してスケーリングできます。
ツールおよび環境のメソッドは、同期または非同期のいずれかです。同期ツールはmax_concurrent_rolloutsに設定されたサイズのスレッドプール上で実行されるため、遅いツールが他の実行中のvLLMリクエストをブロックすることはありません。1つのアシスタントターン内では、ツール呼び出しはモデルが出力した順序で実行されます。したがって、最大max_concurrent_rollouts個の同期ツールが同時に実行されるため、共有状態を読み書きするツールはスレッドセーフである必要があります。
weight_sync_steps 回の学習ステップごとに、更新された重みが NCCL を介して vLLM サーバーに転送され、その後の生成が最新のポリシーを反映するようにします。
生成と学習が並行して実行されるため、学習サンプルは、やや古いバージョンのモデルによって生成された可能性があります。max_staleness パラメータは、サンプルが破棄される前に、何回の重み更新分遅れていてもよいかを制御します。
並行性
vLLMサーバーに送信される同時リクエストの数はmax_concurrent_rolloutsによって上限が設定されます。デフォルトでは、max(max_staleness, 1) × per_device_train_batch_size × gradient_accumulation_steps × num_processesに自動的に設定されます。これは、トレーナーがサンプルが古くなる前に消費できる最大サンプル数です。これを超えるサンプルを生成しても、余分なサンプルは破棄されるため無駄になります。
max_concurrent_rollouts は上限値であり、実際に処理中のリクエスト数ではありません。ワーカーは数秒ごとにサーバーの /metrics エンドポイントをポーリングし、その上限値の直下でライブキャップ(rollout/concurrency_cap)を維持します。ある一定の並行度を超えると、KV キャッシュが埋まり、シーケンスがプリエンプトされて再計算され、キャッシュされたプレフィックスが追い出されて再プリフィルされるため、リクエストを増やしても vLLM は 遅くなります。キャップは起動時にサーバーから読み取られる KV cache tokens / max_model_len から始まります。これはフルレングスで収まるリクエスト数であり、最初のステップでスラッシングが発生しないようにするためです。キューに何も待機しておらず、使用率が 0.6 未満のままである間、キャップ分のロールアウトが完了するたびにキャップは 25% ずつ増加し、上限値まで引き上げられます。KV キャッシュの使用率が 0.8 を超えると、キャップは 30% 削減されます。実行中のリクエストはキャンセルされず、プールが新しいキャップを下回るまで新規リクエストの受け入れが停止し、それまでさらなる削減は行われません。サーバーが /metrics を公開していない場合、キャップは上限値のまま維持されます。
チェックポイントと再開: ignore_data_skip のデフォルト値は True です。ベースの Trainer のスキップおよびリプレイのループは、ライブのロールアウトキューには適用されません。代わりに、まだ学習されていない最初のプロンプトのインデックスが、各チェックポイントとともに rollout_state.json に保存され、再開時に復元されます。これにより、ワーカーはサンプルをリプレイせずにそのプロンプトまで高速転送します。これは生成器の位置ではなく、学習済みの位置です。ワーカーはロールアウトキューの深さ分だけ学習より先行して動作し、これらのバッファリングされたサンプルは実行終了時に失われるため、生成器の位置から再開すると、生成されたが学習されなかったプロンプトがスキップされてしまいます。ストリーミングデータセット(IterableDataset)は再位置指定できません。そのため、再開時にワーカーはプロンプト 0 から再起動します。FSDP を bf16=True(デフォルト)または fp16=True で使用する場合、マスターウェイトが fp32 であるにもかかわらず、model.safetensors はその dtype で書き出されます。そのため、プッシュされたチェックポイントはサーブされるモデルのサイズであり、その 2 倍ではありません。fp32 のマスターウェイトとオプティマイザの状態は、再開ファイル(pytorch_model_fsdp.bin、optimizer.bin)に保存され、再開時に読み込まれるのはこれらなので、再開には影響しません。FSDP を使用しない場合、チェックポイントは再開ファイルでもあるため、マスターの dtype が保持されます。
クイックスタート
# train_async_grpo.py
from datasets import load_dataset
from trl.experimental.async_grpo import AsyncGRPOTrainer
from trl.rewards import accuracy_reward
dataset = load_dataset("trl-lib/DeepMath-103K", split="train")
trainer = AsyncGRPOTrainer(
model="Qwen/Qwen3-4B",
reward_funcs=accuracy_reward,
train_dataset=dataset,
)
trainer.train()vLLMサーバーとトレーナーは、別々のGPUで実行する必要があります。CUDA_VISIBLE_DEVICESを使用してGPUを分割してください。例えば、2つのGPUがある場合、vLLMサーバーをGPU 0で、トレーナーをGPU 1で実行するには、次のようにします:
# Terminal 1: vLLM server on GPU 0 (dev mode + NCCL weight transfer are required)
CUDA_VISIBLE_DEVICES=0 VLLM_SERVER_DEV_MODE=1 vllm serve Qwen/Qwen3-4B \
--max-model-len 4096 \
--logprobs-mode processed_logprobs \
--api-server-count 8 \
--weight-transfer-config '{"backend":"nccl"}'
--max-model-lenを、想定される最大合計シーケンス長(プロンプト + 補完)に設定してください。値を下げるとサーバーの GPU メモリ使用量が減少し、KV キャッシュに割り当てられるメモリが増えるため、スループットが向上します。適切な初期値は、プロンプトの長さに設定ファイルのmax_completion_lengthを加えたものです。
# Terminal 2: training on GPU 1
CUDA_VISIBLE_DEVICES=1 accelerate launch train_async_grpo.pyAMD GPU
Trainer は AMD GPU (ROCm) で追加のセットアップなしで動作します。上記のコマンドはそのまま使用できます。学習では、AMD GPU には kernels-community/aiter-flash-attn アテンションカーネル、NVIDIA Blackwell GPU には kernels-community/flash-attn4、その他の NVIDIA GPU には kernels-community/flash-attn3 が使用され、これらはすべて kernels ライブラリによって Hub からダウンロードされます。アテンションのロジットに上限を設ける (attn_logit_softcapping) モデル (Gemma 2 など) は、AMD GPU および NVIDIA Blackwell GPU ではサポートされていません。
ビジョン言語モデル
ビジョン言語モデル(Qwen3.5、Qwen3.6、Qwen3-VL など)は、テキストのみのデータセットで学習できます。モデル ID を通常通り渡すだけで、その他の変更は不要です:
CUDA_VISIBLE_DEVICES=0 VLLM_SERVER_DEV_MODE=1 vllm serve Qwen/Qwen3.5-2B \
--max-model-len 4096 \
--logprobs-mode processed_logprobs \
--api-server-count 8 \
--weight-transfer-config '{"backend":"nccl"}'ビジョンタワーは凍結されています。テキストのみのデータセットでは画像トークンは生成されないため、フォワードパスによってタワーは実行されません。テキストタワー以外のすべて(ビジョンタワー、マルチモーダルプロジェクター)はrequires_grad=Falseが設定されており、勾配もオプティマイザの状態も取得せず、重みの同期では完全にスキップされます。サーバーはチェックポイントから読み込んだ値を保持します。タワー自体は読み込まれるため、その重みはGPUメモリを消費します。
画像はまだサポートされていません。画像を含むプロンプトは、vLLMサーバーや学習のフォワードパスには渡されません。マルチモーダル学習には、画像グリッドから3次元のM-RoPE位置を構築するために、パディングなしのパッキングパスが必要ですが、ここでは実装されていません。
Top-kおよびTop-pサンプリング
Top-k と top-p は、語彙全体ではなく、制限された候補セット上でサンプリング分布を再正規化します。サーバーの対数確率はそれを反映しており(--logprobs-mode processed_logprobs)、トレーナーも同じセット上で正規化する必要があります。そうしないと、すべての重要度比がバイアスを持ちます。トークンの確率は、語彙全体での確率よりも、実際に抽出された候補セットでの確率の方が低くなるためです(DeepSeek-V3.2、セクション 3.1)。top_p < 1 または top_k > 0 の場合、ワーカーはサーバーに各サンプリングされたトークンの候補セットを要求し、トレーナーはそのセット上で対数確率を再正規化します。これにはサーバーのフラグがさらに 2 つ必要であり、vLLM が候補セットのサイズを top_k で制限するため、top_k を設定する必要があります。
CUDA_VISIBLE_DEVICES=0 VLLM_SERVER_DEV_MODE=1 vllm serve Qwen/Qwen3-4B \
--max-model-len 4096 \
--logprobs-mode processed_logprobs \
--api-server-count 8 \
--weight-transfer-config '{"backend":"nccl"}' \
--return-sampling-mask \
--enable-scale-outconfig = AsyncGRPOConfig(top_p=0.95, top_k=512)--return-sampling-mask を指定すると、vLLM は候補セットを記録します(vLLM 0.28 以降、V2 モデルランナー上で動作: サーバーがフラグを拒否する場合は VLLM_USE_V2_MODEL_RUNNER=1 を設定)。--enable-scale-out を指定すると、その候補セットを返すトークンイン・トークンアウトエンドポイントが公開されます。ワーカーは起動時にサーバーで両方の設定を確認します。古いバージョンの vLLM では候補セットを返せないため、トレーナーは語彙全体にわたって正規化を継続し、バイアスのかかった比率について警告を発します。
スコアの中央化
サーバーの log-probabilities は、トレーナーのものと完全に一致することはありません。カーネルの違い、精度の違い、数ステップ遅れたポリシーなどが原因です。重要度重みだけではこれを補正できません。なぜなら、サンプリングされたトークンのスコア は、サンプラーの下では平均がゼロにならないため、すべての更新がポリシーをサンプラーの方へ引き寄せてしまうからです(スコアの中心化). デフォルトでは、トレーナーは各位置でその期待値を差し引きます(score_centering=True), サンプラーの num_sampler_logprobs 最も可能性の高いトークンで推定し、サンプラーに対する重要度比が [vllm_importance_sampling_clip_min, vllm_importance_sampling_clip_max]. そのために、ワーカーはサーバーから生成されたすべてのトークンの上位 log-probabilities を要求し、トークンごとにシリアライズします。大きな num_sampler_logprobs はサーバーを遅くし、その --max-logprobs が受け入れる上限を決定します。 score_centering=False クリップされた目的関数のみで学習します。 sampling/masked_mean は、境界によって除外されたトークンの割合であり、 sampling/sampler_mass は、上位トークンでカバーされるサンプラーの確率質量です。
vLLM の API サーバーでは、上位の log-probabilities のシリアライズは CPU での処理であり、デフォルトの単一 API サーバー構成では
num_sampler_logprobs=8により生成スループットが半減します。vLLM 0.32 以降では、サーバーを--api-server-count 8で起動してください。1.5B から 7B のモデルを 1 台の H100 で測定したところ、この設定により上位 8 件の log-probabilities のコストは生成スループットの 3% 未満に抑えられます。vLLM 0.31 では同じフラグを使用しても 20% から 40% の損失が残りますが、これは vllm-project/vllm#58181 によりアップストリームで修正されています。
LoRA
peft_config を渡すことで、モデル全体ではなく LoRA アダプターを学習できます:
from peft import LoraConfig
trainer = AsyncGRPOTrainer(
model="Qwen/Qwen3-4B",
reward_funcs=reward_len,
train_dataset=dataset,
peft_config=LoraConfig(r=32, lora_alpha=64, target_modules="all-linear"),
)すべてのウェイト同期では、更新されたポリシーをサーバーに送信する必要があります。デフォルトでは、トレーナーはアダプターをベースモデルにマージし、マージ後の完全なウェイトを送信します。7Bモデルの場合、1回の同期あたり約15 GBになります。--enable-loraオプションでvLLMサーバーを起動すると、アダプターのみが送信され、r=32の場合には約160 MBになります。
CUDA_VISIBLE_DEVICES=0 VLLM_SERVER_DEV_MODE=1 VLLM_ALLOW_RUNTIME_LORA_UPDATING=1 vllm serve Qwen/Qwen3-4B \
--max-model-len 4096 \
--logprobs-mode processed_logprobs \
--api-server-count 8 \
--weight-transfer-config '{"backend":"nccl"}' \
--enable-lora \
--max-lora-rank 32 \
--max-loras 6VLLM_ALLOW_RUNTIME_LORA_UPDATING=1 を設定すると、トレーナーが各新しいアダプターを POST するエンドポイントが公開されます。--enable-lora を使用する場合でも、--weight-transfer-config を維持してください。トレーナーは起動時にのみ同期モードを選択しますが、その時点ではサーバーはすでに起動済みであり、マージされた同期がフォールバックとして使用されるためです。
--max-lora-rank は 1, 8, 16, 32, 64, 128, 256, 320, 512 のいずれかである必要があります。これはサーバーが提供できる最大のランクを設定するものであり、実際に提供するランクを指定するものではありません。そのため、r=4 のアダプターは 8 以下で問題なく動作します。--max-loras は少なくとも max_staleness + 2 である必要があります。トレーナーは max_staleness + 1 個のアダプターバージョンを登録したまま保持し、古いポリシーで開始されたロールアウトが生成の途中でポリシーを切り替えることなく、そのポリシーの下で完了できるようにします。また、各同期では、最も古いバージョンをアンロードする前に次のバージョンを読み込みます。トレーナーは起動時にこれらの値の両方をチェックし、サーバーを再起動するために必要な設定を通知します。
vLLM はネットワーク経由ではなくディスクからアダプターを読み込むため、トレーナーは各バージョンを<output_dir>/.vllm_lora/の下に書き出し、そのパスをサーバーに渡します。サーバーが別のマシンで実行される場合、そのディレクトリは両方のマシンからアクセス可能なファイルシステム上に存在する必要があります。
<output_dir>/.vllm_lora/はサービング用キャッシュであり、学習したアダプタが保存される場所ではありません。ここには最新のバージョンのみが保持され、staleness window から外れた直後に削除されます。学習したアダプタを保持するのはチェックポイントです。そのため、チェックポイントの保存を無効にしないでください。save_strategy="no"を設定すると、数時間かけて実行しても何も残らずに終了してしまいます。output_dirはサーバーから読み取れる必要があり、ジョブの終了後も残存する必要があります。そのため、ノードローカルのスクラッチ領域は、遅い共有ファイルシステムでの同期を回避できる利点があっても機能しません。
Adapter sync が常に高速であるとは限りません。vLLM は、マージ済み重みをサーブする場合と比べて、LoRA アダプタをサーブする場合にトークンあたり約 1.33〜1.39 倍遅くなります。RL では通常、生成が実時間(wall-clock time)の大部分を占めるためです。その代わりとして得られるのは、各 sync 時の停止時間が大幅に短くなることと、sync 帯域幅が約 1% になることです。生成スループットがボトルネックとなっている場合は、マージ済み sync の方が依然として良い選択であることが多いです。
ロールアウトループのカスタマイズ
生成、報酬、アドバンテージ、フィルタリングは、experimental.async_grpo.AsyncRolloutLoop 内のロールアウトプロセスで実行されます。これらを変更するには、ループをサブクラス化し、対象のステップのメソッドをオーバーライドして、そのサブクラスをトレーナーのサブクラスで loop_cls に設定します。トレーナーのコンストラクタは変更されません。
| メソッド | 呼び出されました | デフォルト |
|---|---|---|
filter_prompt(row_index, row, epoch) | プロンプトごとに1回、生成の前に | すべてのプロンプトを受け入れます |
generate_one(prompt, tools, group_id) | ロールアウトごとに1回 | マルチターンツールループ |
generate_one_turn(prompt_ids) | サンプリングリクエストごとに1回 | 設定のサンプリング設定を含む1つのvLLMリクエスト |
compute_advantages(group) | group.rewards に報酬が合計された後、グループごとに1回 | グループ内で標準化された報酬 |
setup(), close() | ループが開始し、停止するタイミング | nothing |
例えば、ポリシーがすでに解いているプロンプトのサンプリングを停止するカリキュラムは、そのしきい値をconfigのサブクラスに設定できます。
from dataclasses import dataclass
import numpy as np
from trl.experimental.async_grpo import AsyncGRPOConfig, AsyncGRPOTrainer, AsyncRolloutLoop
@dataclass
class CurriculumConfig(AsyncGRPOConfig):
pass_rate_cap: float = 0.9
class CurriculumRolloutLoop(AsyncRolloutLoop):
def filter_prompt(self, row_index, row, epoch):
return self.pass_rates.get(row_index, 0.0) < self.config.pass_rate_cap
async def setup(self):
self.pass_rates = {}
def compute_advantages(self, group):
scored = group.rewards[~np.isnan(group.rewards)]
if len(scored):
self.pass_rates[group.row_index] = float(np.mean(scored > 0))
return super().compute_advantages(group)
class CurriculumTrainer(AsyncGRPOTrainer):
loop_cls = CurriculumRolloutLoopreward_funcs、get_reward を定義する環境、およびカスタムの generate_one がその experimental.async_grpo.Rollout に設定する reward について、報酬は合計されます。ジャッジでスコアリングする場合は非同期の報酬関数を渡し、generate_one の内部でスコアリングを行ってください。compute_advantages はすべてのグループに対して実行されます。スコアリングされた報酬がすべて等しいため後に除外されるグループも含まれます。除外の判定は報酬に基づき、アドバンテージには基づきません。ループは生成されたプロセス内で構築されるため、サブクラスはモジュールレベルで定義してください。クライアントは __init__ をオーバーライドするのではなく、ループのイベントループ上で実行される setup で作成してください。filter_prompt によって拒否されたプロンプトは、そのエポックではスキップされ、除外されたグループと同様にエポックの回数にカウントされます。あるエポックのプロンプトがすべて拒否された場合、ループは例外を送出します。
設計思想
このトレーナーは意図的に最小限に保たれており、汎用的なソリューションとして拡張されることを想定していません。サポートされていない機能が必要な場合は、リポジトリをクローンし、ご自身のニーズに合わせてトレーナーを直接調整することをお勧めします。新機能の追加は、コミュニティからの需要が顕著な場合のみ検討されます。
記録されたメトリクス
ロールアウトが勾配になるまで、いくつかの段階を通過します。プロンプトから最終的なバッチ構成までの各段階を、まず見ていきましょう。
Dataset row = PROMPT (message list + reward kwargs)
└─ GROUP (1 prompt, `num_generations` rollouts, 1 advantage baseline)
└─ ROLLOUT (1 conversation, keyed by `rollout_id`)
├─ TURN (1 vLLM /v1/completions call + tool messages fed back)
│ └─ TurnRecord (prompt_ids, output_ids, output_log_probs)
└─ reconcile (a turn that doesn't extend the held tokens forks a new sequence)
└─ SEQUENCE (≥1 per rollout; new one per fork; dropped if no trained token)
└─ SAMPLE (Sequence + group advantage + reward + metrics)
════════════ Trainer process boundary: `rollout_buffer` (mp.Queue) ════════════
└─ SAMPLE (Pulled 1 at a time; dropped if staleness > `max_staleness`)
└─ ROW (Planner inserts it into one of `dp` prefix tries, attention-cost-balanced)
└─ MICRO-BATCH (`dp` rows, one per rank)
└─ PACKED ROW (Collator lays each trie out: unique tokens, depth as `position_ids`)
└─ FORWARD (`compute_loss`, bs=1, padding stripped, FA3 per trie segment)
└─ OPTIMIZER STEP (from `grad_accum` micro-batches)上から下へ読んでいくと:
- groupとは、1つのプロンプトを
num_generations回生成したものです。アドバンテージベースラインはグループ内で計算されるため、グループが採点の単位となります。 - rolloutとは1回の会話です。各ターンではメッセージリスト全体が再トークン化されるため、ターン間のドリフトは最後に調整する必要があります。
- reconciling は 1 つの rollout を複数の sequences に fork できるため、1 つの会話から複数の学習サンプルが生成されることがあります。
- サンプルとは、シーケンスとそのアドバンテージ、報酬、メトリクスからなるものです。これがプロセスの境界を越えて渡されます。
- 境界を越えると、trainer はサンプルを rows(DP ランクごとに 1 つ)に計画し、各行をプレフィックス トライに折りたたんで共有トークンを 1 回だけ転送し、
grad_accumのマイクロバッチを 1 つのオプティマイザーステップに集約します。
そのため、メトリクスは、どのステージ(またはエンティティ)に関するものかによって分割されます:
| 名前空間 | カウントするエンティティ |
|---|---|
rollout/ | 1つの完全な会話を表します。そのターン、フォーク、生成にかかった時間です。 |
completions/ | モデル(vLLM)が1つのプロンプトに対して生成した内容 |
tools/ | ツール呼び出しのメトリクス |
sample/ | represents one training sample, as it arrives in the queue |
batch/ | 1つのマイクロバッチまたは1つのオプティマイザステップ(1つ以上のサンプルから構築) |
perf/ | 測定された秒数とFLOPs |
sampling/ | 学習済みポリシーが、トークンを生成したサンプラーからどれだけ離れているか |
トークン指標を明確にするために、いくつかの用語を定義しておきましょう。
- generated トークンは、モデルが生成したものです(
completions/*)。 - forwarded トークンとは、forward パスが処理するすべてのトークンを指します。プロンプト、ツール結果、生成されたトークンすべてが含まれます。
- trainedトークンは、
completion_mask == 1のトークンの部分集合であり、損失が計算される対象です。これは、生成されたトークンから、ハーネスのキャプチャによってマスクされたものを除いたものです。
バッチ番号の構成
rowとは、1つの DP rank が 1 つの micro-batch で forward する単位です。複数のサンプルを単一の prefix forest にパックするため、共有されるトークンは 1 回だけ forward されます。Tree packingを参照してください。プランナーはどのサンプルをどの row に配置するかを決定し(attention コストをバランスさせ、どの rank も遅延しないようにします)、データコラテーターがパックを実行します。
すべてのメトリクスにおいて、「step」は常にフルのオプティマイザーステップを指し、マイクロバッチを指すことはありません。gradient_accumulation_steps 個のマイクロバッチで 1 ステップを構成し、_per_step という名前のメトリクスはすべてオプティマイザーステップ単位であり、global_step、logging_steps などの Trainer の用語体系と一致しています。マイクロバッチ単位のメトリクスである場合はその旨が明記されています(batch/microbatches_per_step)、または行単位(サンプル単位)の量です(batch/row_*、batch/samples_per_row)。
したがって、1ステップには固定数のrow-slotsが含まれます:
row-slots per step = gradient_accumulation_steps x world_sizeこれにより、バッチメトリクスは互いに照合できる階層構造として構成されます。
sample sample/forwarded_tokens_mean
└─ packed into a ROW batch/samples_per_row, batch/row_tokens_mean
└─ one row per DP rank = one micro-batch
└─ gradient_accumulation_steps micro-batches = one STEP
batch/samples_per_step, batch/forwarded_tokens_per_stepしたがって、batch/samples_per_step ≈ row-slots x batch/samples_per_row となり、トークンについても同様です。両辺が一致するのは、ステップ内のマイクロバッチ間のばらつきまでです。ステップごとの指標は合計値、行ごとの指標は平均値であるため、完全な一致ではなく、数パーセント未満の誤差が生じることが予想されます。
batch/row_fill_frac は、サンプルが長い場合に注目すべき指標です。10k トークンのサンプルでは 32k の予算へのタイルリングが非常に悪く(3 個は収まるが 4 個は絶対に収まらないため、パッカーは多くの場合 2 個しか詰められず、行の充填率は約 77% になります)、一方、1k トークンのサンプルではほぼ完璧にタイルリングできます。これはバグではなく量子化(切り捨て)によるもので、token_budget が調整レバーです。ただし、アテンションはシーケンスごとに O(L²) であるため、長いシーケンスで構成される行がより満杯であっても、メモリコストは線形に増加しません。
ツリーパッキング
行は連結ではなくプレフィックストライです。複数のサンプルで共有されるトークンは1回だけ転送され、アテンションは各サンプルにそのサンプル自身の履歴のみを正確に表示します。1つのプロンプトのロールアウトはすべてそれを繰り返し、マルチターンロールアウトの各ターンでは会話が再送信されるため、デコーダーの処理量はパッキング比(生トークン数 ÷ 転送トークン数)だけ減少します。これはレイアウトの変更のみであり、学習された各トークンは自身のターゲット、アドバンテージ、旧ログ確率を保持し、そのログ確率はサンプルを単独で転送した場合と一致します。
発生場所:
planner TreeRow.add the trie grows sample by sample; a sample is priced by its novel tokens
│ (TreeRow.fits), so `token_budget` bounds unique tokens, not raw ones
collator TreeRow.pack DFS layout: unique tokens, depth as position_ids, one loss term per
│ original trained token (token_index), and per segment its queries and
│ the K/V indices of its root-to-segment path, all built on CPU
attention tree_attention gather K/V along the paths, one FA3 varlen call, causal1つのプロンプトの2回のロールアウトにおける動作:
1. Rollouts r0: p1 p2 p3 a1 a2
r1: p1 p2 p3 b1 b2 10 raw tokens
2. Trie (one per row) S0 [p1 p2] ─┬─ S1 [p3 a1 a2] nodes are keyed on (token, next token),
└─ S2 [p3 b1 b2] so the fork happens one token early and
every node predicts exactly one token;
chains without a fork become segments
3. Packed row idx 0 1 | 2 3 4 | 5 6 7
(DFS order) input_ids p1 p2 | p3 a1 a2 | p3 b1 b2 8 tokens: MLPs, norms and projections
position_ids 0 1 | 2 3 4 | 2 3 4 run once per unique token
segment S0 | S1 | S2
4. Attention seg queries K/V gathered kv_index
(one FA3 call) S0 [p1 p2] [p1 p2] 0 1
S1 [p3 a1 a2] [p1 p2 | p3 a1 a2] 0 1 2 3 4
S2 [p3 b1 b2] [p1 p2 | p3 b1 b2] 0 1 5 6 7
FA3 aligns the causal mask bottom-right K: p1 p2 p3 a1 a2
when queries are fewer than keys, so a Q: p3 ■ ■ ■ · ·
segment's queries see their ancestors and a1 ■ ■ ■ ■ ·
their own causal past, and nothing else. a2 ■ ■ ■ ■ ■
5. Loss p2 (idx 1) predicts p3 for both rollouts; token_index points every trained
token of every rollout at the position that predicts itいくつかの帰結:
- 共通の接頭辞は共有される: プロンプトのロールアウト、およびプロンプト間で共通のシステムプロンプトやツールスキーマです。プランナーは、サンプルを、そのプロンプトが既に存在する
group_idを持つ行に送信します。その行が満杯の場合、ランクがまだ空いている行があるか、最も負荷の高い行の負荷が増えない場合は、サンプルは別の行に送られます。これによりマイクロバッチの時間が決まります。それ以外の場合は、マイクロバッチがクローズされます。 - 共有されないものはプレーンなパッキングです。各サンプルは、パスが自身である1つのセグメントとなり、通常のpaddingなしFA3 varlenパッキングになります。
- K/Vのみが複製される: 共有プレフィックスは各降下セグメントごとに1回だけ集められ、これはアンパックされた学習が保持する量とほぼ同じであり、GQAでは小さくなります。
- Gated DeltaNetハイブリッドがサポートされています(Qwen3.5、Qwen3.6、Qwen3-Next など):その畳み込みは各トークン自身の先行トークンを参照し、チャンク化されたデルタルールは各セグメントを親の最終状態から開始します(
trl/experimental/async_grpo/tree_gated_delta_rule.py)。これには、これらのレイヤーがツリーパッキングがパッチを当てるモジュールレベルの関数を呼び出すtransformers>=5.15.0が必要です。他の非アテンションレイヤーを含むモデルは、初期化時に拒否されます。
購入できるもの: 共有なしの場合、通常のpaddingなしパッキングとほぼ同じ速度で動作し、速度向上はパッキング比に概ね比例して増加します(Qwen3-0.6B/1.7B、H100では、比3.4で約2.8〜3倍)。比は共有プレフィックス×行ごとのサンプル数に等しいため、batch/samples_per_rowが主要な指標となります。1に近い場合は何も共有できず、調整レバーはtoken_budgetです。
スループットで評価してください。batch/trained_tokens_per_step / perf/fwd_bwd_sです。パックされたマイクロバッチはより多くのサンプルを含むため、perf/fwd_bwd_sは上昇し、フォワードされたトークンで割るperf/mfu_*は低下します。どちらもリグレッションではありません。1行あたりのサンプル数が増えることは、ステップごとにサンプリングされるロールアウト数が増えることを意味するため、生成がボトルネックとなる実行は、さらにその傾向が強まります。
行が長くなったり、数が減ったりする処理は共有を解除します。分岐しないマルチターン会話では、1つの長いサンプルとなり、
rollout/samples_per_rolloutは1つの会話から得られるサンプル数を示します。
ロールアウトキュー
ワーカーはスコア付きサンプルをキューにプッシュし、トレーナーはそこからプルします。この1つのキューを説明する4つのメトリクスがあり、それぞれ異なる質問に答えます。
| メトリック | 質問 |
|---|---|
sample/rollout_queue_size | 現在、待機中のサンプルはいくつありますか |
sample/time_in_queue_s | 1つのサンプルが学習に使用される前にどれだけ待たされていたか — オフポリシー性の半分を占める秒数 |
perf/rollout_wait_s | キューが空だったため、トレーニングがブロックされたまま待機していた時間 |
rollout/backpressure_s | キューが満杯だったため、生成(ワーカー)がブロックされたまま待機していた時間 |
最後の2つのメトリクス(perf/rollout_wait_sとrollout/backpressure_s)は鏡像の関係にあり、同時に大きくなることはありません。これらをキューサイズと併せて読むことで、ボトルネックがどちら側にあるかを知ることができます。
- キューがほぼ空で、
perf/rollout_wait_sが高い場合 → 生成がボトルネックです。トレーナーが飢えている状態です。rollout/generated_tok_s、rollout/concurrency、rollout/score_queue_sizeを確認してください。 - キューがほぼ満杯で、
rollout/backpressure_sが高い場合 → trainer-boundです。生成がスロットリングされ、その出力がキュー内で滞留しているため、sample/staleness_meanの上昇に注意してください。 - どちらもほぼゼロ → バランスがとれている!
補完
completionとは、vLLMが1つのプロンプトに対して生成したもので、ロールアウトのすべてのターンにわたって集計されます。
| メトリック | 意味 |
|---|---|
completions/mean_length | ロールアウトごとの生成トークン数(全ターンで平均) |
completions/min_length, completions/max_length | ウィンドウ内での最短および最長のロールアウト |
completions/clipped_ratio | max_completion_lengthによって打ち切られた、つまり最後のターンがEOSで終わらなかったロールアウトの割合。 |
ロールアウト
rolloutとは、1回の完全な会話です。プロンプトが完了するまで生成されたもので、そこに至るまでに発生したすべてのツールとの往復を含みます。num_generations個のrolloutは同じプロンプトを共有し、1つのグループを形成します。
| メトリック | 意味 |
|---|---|
rollout/duration_s | 1回のロールアウトのウォールタイム。ディスパッチからループが完了したロールアウトを収集するまでの時間です。 |
rollout/generated_tok_s | 直近の区間(ウィンドウ方式)での生成スループット。これにより、スタール(停止)が発生した場合にそれが検出されます |
rollout/concurrency | vLLM への実行中のロールアウト。 |
rollout/turns_mean, rollout/turns_max | 会話ごとの平均ターン数と最大ターン数 |
rollout/samples_per_rollout | 1回の会話ごとに生成されるsamplesの訓練用数。1.0はフォークが発生しないことを意味します(<1.0は、訓練可能なサンプルが1つも生成されなかった会話があることを意味します)。 |
rollout/fork_frac | ターン境界のうち、再トークン化されたプロンプトが保持されたトークンを拡張せず、ターンが新しいサンプルを開始した割合 |
rollout/drift_tokens_mean, rollout/drift_tokens_max | フォークが再レンダリングした保持トークンの数(ターン境界で平均化。クリーンな境界は0とカウント)。新しいサンプルは分岐点以前のトークンを共有するため、各フォークがトレーナーのフォワードに追加する量です。 |
rollout/score_queue_size | スコアリング待ちの完了したグループ。 |
rollout/score_s, rollout/score_wait_s, rollout/score_block_s | scoring: グループのスコアリングにかかる時間、スコアリング待ち時間、スコアリングキューが満杯だったために生成がブロックされていた時間 |
rollout/vllm_retry_total | vLLMのリクエストの再試行回数です。劣化したサーバーは、原因不明の遅延のように見えます。この指標は生成されたテキストではなくサーバーへのリクエストをカウントするため、completions/ ではなくここに配置されています。再試行されたリクエストは、そもそもcompletionを生成しなかったためです。 |
rollout/backpressure_s | ロールアウトキューが満杯だったため、生成がブロックされていた時間です。ロールアウトキューを参照してください。 |
rollout/concurrency_cap | 実行中のロールアウトの現在の上限。初期値はKV cache tokens / max_model_len(最大max_concurrent_rollouts)で、vLLMの負荷に応じて変動します。並行性を参照してください。 |
rollout/kv_cache_usage | 最後のポーリング時点での vLLM KV キャッシュ使用量(エンジン間の最大値)。0.8 を超えると上限が削減され、0.6 以下を維持している間は増加します |
rollout/vllm_running_requests | サーバーのエンジンがデコードしているリクエスト数(vLLMのnum_requests_runningをエンジン間で合計したもの)です。rollout/concurrencyとの差は、APIサーバープロセス内でレスポンスを構築している部分です |
rollout/vllm_queued_requests | サーバーが受け入れたがまだスケジュールされていないリクエストの数(vLLMのnum_requests_waitingをエンジン全体で合計した値)です。この値がゼロでない間、上限は増加しません |
rollout/vllm_preemptions_total | ログ出力ウィンドウ中にサーバーが先送りしたリクエストの数(vLLMのnum_preemptions_totalをエンジン全体で合計したもの)です。報告のみ行います。重みの同期によりサーバーのキャッシュがリセットされ、実行中のすべてのリクエストが先送りされるため、負荷のシグナルとしては機能しません。 |
frac_reward_zero_std, reward_kept | スコア付き報酬がすべて等しかった、またはスコア付け可能なロールアウトが2回未満だったために破棄されたグループの割合(GRPOは前者のケースのみをカウントします)、および学習に使用されたグループの平均報酬。rewardは、破棄されたグループも含めたすべてのスコア付きグループに対するポリシーの報酬であり、追跡すべき指標です |
すべてのロールアウトが同じ報酬を受け取ったグループ(またはスコアリング可能なロールアウトが2つ未満のグループ)は、キューに追加されるのではなく破棄されます。デフォルトのアドバンテージでは、このグループはすべての位置でアドバンテージがゼロになるため、フォワードとバックワードのコストが発生しても何も更新されないからです。バッチ自体には影響がなく、保持されたグループから引き続きsamples_per_stepを埋めるため、多くのグループが破棄される場合は、1ステップあたりの生成時間が長くなります。破棄されたグループもエポックのカウントには含まれ、エポックはプロンプトを1回通すこととして維持されます。
ツール
モデルがツールを実行した場合にのみ記録されます。tools/<name>/* はツール名ごとに繰り返されますが、これは rewards/<func>/* が報酬関数ごとに繰り返されるのと同じです。なぜなら、1つのツールの失敗は、すべてのツールの平均値では見えないからです。組み込みのツールループと OpenEnv ハーネスのトレーナー(HarnessAsyncGRPOTrainer、ハーネスでの学習を参照)は同じ名前を記録するため、1つのダッシュボードで両方を確認できます。path 列は、どのプロセスが各メトリクスを生成しているかを示します。
| メトリック | path | 意味 |
|---|---|---|
tools/call_frequency, tools/failure_frequency | 組み込み、ハーネス | ロールアウトあたりの呼び出し回数と、失敗した割合です。ループを所有するハーネスのパスでは、失敗とは、テキストがエラーのように見えるツール結果を指します |
tools/latency_s, tools/<name>/latency_s | 組み込みのホワイトボックスハーネス | ツールの実行に費やされた時間です。ホワイトボックスハーネスのパスでは、1つのモデルターンの応答から次のターンのリクエストまでの実時間(ウォールタイム)であり、ハーネスのオーバーヘッドを含みます。ループ所有パスにはレイテンシはありません。OpenEnvのトレースはエントリにタイムスタンプを付与しないため、レイテンシを導出するための情報が存在しないためです。 |
tools/<name>/call_total, tools/<name>/failure_total | 組み込み、ハーネス | ツールごとの呼び出し数と失敗数 |
tools/unknown_name_total | 組み込み | モデルが存在しないツールを要求しました: これは、実行されて例外を送出したツールとは異なり、ポリシーエラーを追跡します |
tools/parallel_calls_mean | 組み込み | 1つのアシスタントメッセージ内で要求されたツール呼び出し |
tools/loop_exhausted_frac | 組み込み | ツールを要求しているにもかかわらず、max_tool_calling_iterations で打ち切られた会話 |
環境
environment_factory を使用した場合のみ記録されます。両方の呼び出しはワーカーのツールスレッドプールで実行されるため、遅い環境は自身のロールアウトのみを遅延させ、進行中の他のロールアウトには影響しません。
| メトリック | 意味 |
|---|---|
env/reset_s | ロールアウト開始前にreset()にかかった時間 |
env/reward_s | ロールアウト終了後のget_reward()内の所要時間 |
キューから到着するサンプル
各サンプルは1つのRolloutSampleです。グループ内のすべての生成が完了してスコアリングされた時点で、_score_group内のワーカーによって組み立てられる、調整済みのシーケンスとグループのアドバンテージ、報酬、およびサンプルごとのメトリクスです。ワーカーはこれらをrollout_bufferにプッシュします。以下はすべて、学習用にそれらをプルするトレーナー側で測定されます。
| メトリック | 意味 |
|---|---|
sample/forwarded_tokens_mean, sample/forwarded_tokens_max | 1つのサンプル内のトークン数: プロンプト + ツールコンテキスト + 生成部分。パッキングは行レベルの関心事であり、batch/row_*を参照してください。 |
sample/trained_tokens_mean | そのうち、損失が計算されるのは何個か |
sample/rollout_queue_size | キューに待機しているスコアリング済みサンプル |
sample/time_in_queue_s | このサンプルが学習に使用されるまで、そのキューにどれだけ待たされていたかを示します。perf/rollout_wait_s とは異なります。ロールアウトキューを参照してください。 |
sample/staleness_mean, sample/staleness_max | データがどの程度古いポリシーバージョンに遅れているかを示します。sampling/importance_sampling_ratio/*とsampling/sampling_logp_difference/*は、オフポリシー性が損失に与える影響を示しており、これは原因を示しています |
sample/dropped_stale_total | max_staleness を超えたため破棄されたサンプル |
報酬とオフポリシー性
| メトリック | 意味 |
|---|---|
reward_group_std | 各サンプルのグループ内における報酬の標準偏差で、学習に使用されたサンプル全体で平均した値です。デフォルトのcompute_advantagesはこの値で割ります。GRPOのreward_stdはバッチ全体の標準偏差であり、別の量です。例えば、簡単なプロンプトがすべて1、難しいプロンプトがすべて0であるバッチでは、バッチの標準偏差は0.5ですが、グループの標準偏差は0になります。 |
rewards/<func>/mean, rewards/<func>/group_std | 各報酬関数の平均値、および各サンプルのグループ内での標準偏差(学習に使用されたサンプルで平均化)。GRPOのrewards/<func>/meanはバッチ内のすべての生成済み補完に対する平均値であり、rewards/<func>/stdはバッチ全体の標準偏差です。 |
sampling/importance_sampling_ratio/mean, /min, /max | π_θ / π_sampler は各 completion token ごとに計算され、π_sampler はそれを生成した vLLM のポリシーです。これは train/inference の不一致だけでなく、staleness も含みます。 |
sampling/sampling_logp_difference/mean, /max | \|log π_θ − log π_sampler\| 1トークンあたり |
num_tokens | トレーニング開始以降に転送されたトークン数。ツリーパッキングを使用する場合、複数のサンプルで共有されるプレフィックスは1回のみカウントされます |
バッチ
1つのマイクロバッチはworld_size行です(パッキングにより1つのシーケンスにフラット化されることをお忘れなく)。そのため、DPランクごとに1つずつ割り当てられ、ランクiは行iをフォワードします。これらのgradient_accumulation_steps回分が1回のオプティマイザーステップを構成します。したがって、1ステップでは合計でgradient_accumulation_steps × world_size行をカバーします。以下のすべての_per_stepメトリックは、ステップ全体およびすべてのランクにわたる合計値です。batch/row_*のメトリックは、行にわたる平均値です。
| メトリック | 意味 |
|---|---|
batch/forwarded_tokens_per_step, batch/trained_tokens_per_step | 1回のオプティマイザーステップで、それぞれフォワードとトレーニングされたトークン |
batch/samples_per_step, batch/groups_per_step | トレーニングサンプル、およびオプティマイザーステップごとの個別のプロンプトです。これらはフォークレートによって異なります |
batch/microbatches_per_step | 設定から読み取ったものではなく、カウントされたものです |
batch/masked_token_frac | completion_mask == 0 のトークンが転送される割合 — 勾配が得られないフォワードの割合 |
batch/samples_per_row, batch/row_tokens_mean, batch/row_tokens_max | plannerが各ランクの行をどれだけ高密度に詰め込んだか |
batch/row_fill_frac | token_budgetに対する行トークン。低い値は、予算が十分に活用されていないことを示します |
batch/row_imbalance | 行全体にわたるmax cost / mean cost。ここでコストは、各行の注意機構の計算量です。これにより、どのランクが勾配のall-reduceをボトルネックにしているかを予測できます。1.0が最適です |
batch/packing_ratio | 転送されるトークンあたりの生トークン数: デコーダーの処理量が縮小される係数。何も共有されていない場合は1.0 |
batch/pad_frac | ランク間パディング。コストはブロードキャストのバイト数のみで、フォワードの前に除去されます |
batch/dropped_oversize_total | token_budget を超えたため破棄されたサンプル |
パフォーマンス
スループットは、トレーナーが1秒間に処理するトークン数を測定します。モデルFLOPs利用率(MFU)は、モデルのフォワードパスとバックワードパスに使用される、トレーニングデバイスの理論的な計算能力の割合を推定します。この推定に使用される能力は、ハードウェアとトレーニングの精度によって異なります。
スループットとMFUは、2つの時間基準で報告されます:
_fwd_bwdは、フォワードパスとバックワードパス中のパフォーマンスを測定します。_wall_clockは、オプティマイザーの更新、重みの同期、ロールアウトを待機している時間を含まれた、オプティマイザーステップ全体でのパフォーマンスを測定します。
この差により、計算性能と待機および調整のコストを区別できます。両方のMFU指標はトレーニングデバイスのみを記述しており、外部のロールアウトサーバーや教師サーバーの計算やハードウェア容量は含まれません。Wall-clock MFUは、これらのサービス自体の利用率ではなく、トレーナーがそれらのサービスを待機している時間を反映しています。
MFUは、選択した精度におけるローカルトレーニングデバイスのピーク計算能力が既知の場合にのみ報告されます。それ以外の場合は、MFUは省略されますが、トレーニングは継続され、スループットおよびタイミングのメトリクスは引き続き利用可能です。
| メトリック | 意味 |
|---|---|
perf/step_s | オプティマイザーステップ間の実時間: 計算、オプティマイザ、重み同期、キュー待ちを含む |
perf/fwd_bwd_s | forward + backward、ステップのマイクロバッチ全体で合計したもの。これは以下のすべての_fwd_bwdメトリックの分母です |
perf/fwd_s | そのフォワード部分です。fwd_s / fwd_bwd_sが1/3付近であるのが通常の比率です。これより高い値は、バックワードが安価であるか、フォワードで再計算のコストが発生していることを意味します。 |
perf/optimizer_s | optimizer.step() |
perf/rollout_wait_s | キューが空だったため、トレーナーがブロックされた状態が続いた時間です。ロールアウトキューを参照してください。 |
perf/weight_sync_s | 完全な同期、および_pause_s(vLLMの待機)、_barrier_s(ランクのズレ)、_transfer_s(バイト数) |
perf/forwarded_tok_s_fwd_bwd, perf/forwarded_tok_s_wall_clock | 各基準における1秒あたりのフォワードされたトークン数 |
perf/trained_tok_s_wall_clock | 同じで、損失が参照したトークンのみを数えます |
perf/mfu_fwd_bwd, perf/mfu_wall_clock | 各基準におけるモデルのFLOPs利用率 |
AsyncGRPOConfig
クラス trl.experimental.async_grpo.AsyncGRPOConfig
< source >( output_dir: str | None = Noneper_device_train_batch_size: int = 8num_train_epochs: float = 3.0max_steps: int = -1learning_rate: float = 1e-06lr_scheduler_type: str = 'constant'lr_scheduler_kwargs: dict | str | None = Nonewarmup_steps: float = 0optim: transformers.training_args.OptimizerNames | str = 'adamw_torch_fused'optim_args: str | None = Noneweight_decay: float = 0.0adam_beta1: float = 0.9adam_beta2: float = 0.999adam_epsilon: float = 1e-08optim_target_modules: None | str | list[str] = Nonegradient_accumulation_steps: int = 1average_tokens_across_devices: bool = Truemax_grad_norm: float = 1.0label_smoothing_factor: float = 0.0bf16: bool | None = Nonefp16: bool = Falsebf16_full_eval: bool = Falsefp16_full_eval: bool = Falsetf32: bool | None = Nonegradient_checkpointing: bool = Truegradient_checkpointing_kwargs: dict[str, typing.Any] | str | None = Nonetorch_compile: bool = Falsetorch_compile_backend: str | None = Nonetorch_compile_mode: str | None = Noneuse_liger_kernel: bool = Falseliger_kernel_config: dict[str, bool] | None = Noneuse_cache: bool = Falseneftune_noise_alpha: float | None = Nonetorch_empty_cache_steps: int | None = Noneauto_find_batch_size: bool = Falselogging_strategy: transformers.trainer_utils.IntervalStrategy | str = 'steps'logging_steps: float = 1logging_first_step: bool = Falselog_on_each_node: bool = Truelogging_nan_inf_filter: bool = Trueinclude_num_input_tokens_seen: str | bool = 'no'log_level: str = 'passive'log_level_replica: str = 'warning'disable_tqdm: bool | None = Nonereport_to: None | str | list[str] = 'none'run_name: str | None = Noneproject: str = 'huggingface'trackio_space_id: str | None = Nonetrackio_bucket_id: str | None = Nonetrackio_static_space_id: typing.Union[str, NoneType, typing.Literal[False]] = Noneeval_strategy: transformers.trainer_utils.IntervalStrategy | str = 'no'eval_steps: float | None = Noneeval_delay: float = 0per_device_eval_batch_size: int = 8prediction_loss_only: bool = Falseeval_on_start: bool = Falseeval_do_concat_batches: bool = Trueeval_use_gather_object: bool = Falseeval_accumulation_steps: int | None = Noneinclude_for_metrics: list[str] = <factory>batch_eval_metrics: bool = Falsesave_only_model: bool = Falsesave_strategy: transformers.trainer_utils.SaveStrategy | str = 'steps'save_steps: float = 500save_on_each_node: bool = Falsesave_total_limit: int | None = Noneenable_jit_checkpoint: bool = Falsepush_to_hub: bool = Falsehub_token: str | None = Nonehub_private_repo: bool | None = Nonehub_model_id: str | None = Nonehub_strategy: transformers.trainer_utils.HubStrategy | str = 'every_save'hub_always_push: bool = Falsehub_revision: str | None = Noneload_best_model_at_end: bool = Falsemetric_for_best_model: str | None = Nonegreater_is_better: bool | None = Noneignore_data_skip: bool = Truerestore_callback_states_from_checkpoint: bool = Falsefull_determinism: bool = Falseseed: int = 42data_seed: int | None = Noneuse_cpu: bool = Falseaccelerator_config: dict | str | None = Noneparallelism_config: accelerate.parallelism_config.ParallelismConfig | None = Nonedataloader_drop_last: bool = Falsedataloader_num_workers: int = 0dataloader_pin_memory: bool = Truedataloader_persistent_workers: bool = Falsedataloader_prefetch_factor: int | None = Nonedataloader_multiprocessing_context: str | None = Nonedataloader_in_order: bool = Trueremove_unused_columns: bool = Truelabel_names: list[str] | None = Nonetrain_sampling_strategy: str = 'random'length_column_name: str = 'length'ddp_find_unused_parameters: bool | None = Noneddp_bucket_cap_mb: int | None = Noneddp_broadcast_buffers: bool | None = Noneddp_static_graph: bool | None = Noneddp_backend: str | None = Noneddp_timeout: int = 1800fsdp: str | None = Nonefsdp_config: dict[str, typing.Any] | str | None = Nonedeepspeed: dict | str | None = Nonedebug: str | list[transformers.debug_utils.DebugOption] = ''skip_memory_metrics: bool = Truedo_train: bool = Falsedo_eval: bool = Falsedo_predict: bool = Falseresume_from_checkpoint: str | None = Nonelocal_rank: int = -1model_init_kwargs: dict[str, typing.Any] | str | None = Nonedtype: str = 'float32'trust_remote_code: bool = Falserouter_aux_loss_coef: float | None = Nonenum_generations: int = 8max_completion_length: int = 2048temperature: float = 1.0top_p: float = 1.0top_k: int = 0min_p: float | None = Nonerepetition_penalty: float = 1.0chat_template_kwargs: dict | str | None = Nonemax_tool_calling_iterations: int | None = Nonevllm_server_base_url: str = 'http://localhost:8000'vllm_server_timeout: float = 1800.0epsilon: float = 0.2epsilon_high: float | None = Nonescore_centering: bool = Truevllm_importance_sampling_clip_min: float = 0.5vllm_importance_sampling_clip_max: float = 5.0num_sampler_logprobs: int = 8token_budget: int | None = Nonemax_concurrent_rollouts: int | None = Nonemax_staleness: int = 4queue_maxsize: int = 1024weight_sync_steps: int = 1rollout_worker_timeout: float = 300.0log_completions: bool = Falsenum_completions_to_print: int | None = None )
モデルを制御するパラメータ
- model_init_kwargs (
dict[str, Any]またはstr、省略可) — パスからモデルをインスタンス化する場合に from_pretrained に渡すキーワード引数です。revisionの値は、処理クラスの読み込み時にも使用されます。 - dtype (
str, 省略可, デフォルトは"float32") — モデルを読み込む際のデータ型。"auto","bfloat16","float16"または"float32". デフォルトは"float32"です。このトレーナーが基準とするトレーニングと推論の不一致(FP16 によるトレーニングと推論の不一致の克服, 、このトレーナーについて TRL におけるトレーナーとジェネレーターの精度不一致の克服) )は、トレーナー自体の精度に敏感です。このギャップをエンドツーエンドで解消するには、vLLM サーバーも同じ dtype で提供する必要があります(vllm serve --dtype); 不一致は、トレーニング開始時に警告としてログに記録されます。dtype内のmodel_init_kwargsが優先されます。これは、重みがロードされる際のdtypeのみを設定します。FSDPによる混合精度(
bf16=Trueがデフォルト)の場合、accelerateはシャーディングの前に、すべての学習可能なパラメータをfp32にアップキャストします。そのため、dtypeの値に関わらず、マスターの重みとオプティマイザの状態はfp32となり、フォワードとバックワードはbf16またはfp16で実行されます。その結果、チェックポイントはfp32ではなく、その混合精度のdtypeで書き出されます。FSDPを使用しない場合は、アップキャストは行われません。dtype="bfloat16"とbf16=Trueを組み合わせると、重みとオプティマイザの状態がbf16のまま保持され、純粋なbf16での学習となります。 - trust_remote_code (
bool, optional, defaults toFalse) — Whether to allow loading models and tokenizers that ship custom Python code from the Hub. Forwarded to from_pretrained and from_pretrained. - router_aux_loss_coef (
float, 任意) — Mixture-of-Experts (MoE) モデルにおける負荷分散用の補助損失の係数です。この重みで学習損失に追加されます。設定されていない場合、モデル設定で宣言された値が使用されます。0.0に設定すると無効になります。MoE 以外のモデルで使用するとエラーになります。
生成を制御するパラメータ
- num_generations (
int、任意、デフォルトは8) — プロンプトごとにサンプリングする生成の回数。 - max_completion_length (
int、任意、デフォルトは2048) — 生成される補完の最大長。 - temperature (
float、任意、デフォルトは1.0) — サンプリング用の温度です。温度が高いほど、補完はランダムになります。 - top_p (
float、任意、デフォルト値は1.0) — 考慮する上位トークンの累積確率を制御する浮動小数点数です。値は (0, 1] の範囲でなければなりません。すべてのトークンを考慮するには 1.0 に設定します。1.0未満の場合、top_kも設定する必要があり、--return-sampling-mask --enable-scale-outを指定して vLLM サーバー (>= 0.28) を起動する必要があります。サーバーと同様に、トレーナーは各トークンがサンプリングされた候補セットに対して対数確率を再正規化します。古いバージョンの vLLM では、語彙全体が保持されます。 - top_k (
int、任意、デフォルトは0) — トップkフィルタリングのために保持する、確率の高い語彙トークンの数。0の場合、トップkフィルタリングは無効になり、すべてのトークンが対象となります。その他の値には、top_pの項で説明されているサーバーフラグが必要です。 - min_p (
float, 省略可) — トークンの最小確率です。最も確率の高いトークンの確率でスケーリングされます。0.0 から 1.0 までの値である必要があります。一般的な値は 0.01 から 0.2 の範囲です。0.0以上の場合、top_pの下に説明されているサーバーフラグとともに、top_kも設定する必要があります。 - repetition_penalty (
float、任意、デフォルト値は1.0) — プロンプトとこれまでに生成されたテキストにトークンが出現しているかどうかに基づいて、新しいトークンをペナルティする浮動小数点数です。 値が 1.0 より大きい場合、モデルは新しいトークンを使用するよう促され、値が 1.0 より小さい場合、モデルはトークンを繰り返すよう促されます。 - chat_template_kwargs (
dict[str, Any], 省略可) — 補完を生成する際にapply_chat_template関数に渡す追加のキーワード引数。 - max_tool_calling_iterations (
int, 省略可) — エージェントの学習におけるツール呼び出しのターン数の上限です。Noneの場合、上限はなく、モデルがツール呼び出しを含まない応答ターンを生成したとき、または応答の総長がmax_completion_lengthに達したときに生成が停止します。
vLLMサーバーを制御するパラメータ
- vllm_server_base_url (
str, 任意、デフォルトは"http --//localhost:8000"): 生成に使用される vLLM サーバーのベース URL (例:"http://localhost:8000")。 - vllm_server_timeout (
float、任意、デフォルトは1800.0) — vLLM サーバーへの呼び出しのタイムアウト(秒)です。起動時のサーバーの準備完了待ち、各生成リクエスト、および各ウェイト同期呼び出しに適用されます。サーバーの待機とウェイト同期呼び出しでは、タイムアウト時に例外が発生します。生成リクエストがタイムアウトした場合は、リトライされます。
学習を制御するパラメータ
- epsilon (
float, 任意、デフォルトは0.2) — クリッピング用のエプシロン値。 - epsilon_high (
float, オプション) — クリッピング用の上限エプシロン値です。指定しない場合、引数epsilonで指定された下限値と同じ値がデフォルトとして使用されます。論文 DAPO では0.28が推奨されています。 - score_centering (
bool、任意、デフォルトはTrue) — クリップされた目的関数の代わりに、スコアセンタリング (論文) を用いて学習するかどうかです。これは、サンプリングされた各トークンの重要度重み付きスコアから、vLLM サンプラー下での期待値を引いたものとし、一定のアドバンテージがポリシーをサンプラー側に引き寄せるのを防ぐことを目的としています。期待値は、各位置におけるnum_sampler_logprobs個の最尤トークンに対して取り、その対数確率はサンプラーが報告します。 - vllm_importance_sampling_clip_min (
float、任意、デフォルト値は0.5) — ポリシーと vLLM サンプラー間の重要性比の下限 C_min です。比が [vllm_importance_sampling_clip_min,vllm_importance_sampling_clip_max] の範囲外にあるトークンは、損失から除外されます(マスクされた重要性サンプリング)。 - vllm_importance_sampling_clip_max (
float、任意、デフォルトは5.0) — 重要度比の上限 C_max。 - num_sampler_logprobs (
int、任意、デフォルトは8) — 生成された各トークンについて、vLLM のサンプラーから要求する上位の対数尤度の数です。スコア中心化に使用されます。数を増やすとサンプラーの確率質量をより多くカバーできますが、シリアライズのコストが増加します。サーバーの--max-logprobsによって上限が設定されます。 - token_budget (
int, 任意) — 動的トークンバジェット付きマイクロバッチングにおいて、1 行(1 つの DP ランクのフォワード)で転送されるトークンの最大数です。> 0の場合、TokenBudgetBatcherがアテンションコストをバランスさせたマイクロバッチを形成し、各行がこのバジェット内に収まるようにします。これにより、サンプル数(1 行あたりのサンプル数は動的になります)に依存せずにピークメモリを上限できます。このバジェットは生トークンではなくユニークなトークンを上限とするため、複数のサンプルで共有されるトークンは 1 回のみカウントされます。また、行の損失項も上限に含まれます。None(デフォルト)の場合、vLLM サーバーのmax_model_len(学習開始時にクエリされます)に設定されます。これはプロンプトと補完の長さの上限であり、どのロールアウトサンプルもバジェットを超えないことを保証します。token_budgetより長いサンプルはどの行にも収まらず、警告とともに破棄されます。<= 0に設定すると、トークンバジェットを無効にし、代わりにper_device_train_batch_size × num_processesのサンプルをマイクロバッチごとに固定してパックし、行間でバランスを取ります。
非同期ロールアウトパイプラインを制御するパラメータ
- max_concurrent_rollouts (
int, 省略可能) — vLLM サーバーに同時に実行中のロールアウトの最大数。None, の場合、`max(max_staleness, 1)` * `per_device_train_batch_size` * `gradient_accumulation_steps` * `num_processes` に設定されます。これを超えるサンプルを生成しても、トレーナーが消費する前に stale として破棄されるため無駄です。ツール使用環境を使用している場合は、実行できる並列環境の数に基づいてこの値を手動で設定することを検討してください。- per_device_train_batch_size gradient_accumulation_steps num_processes`: これを超えるサンプルを生成しても、トレーナーが消費する前に古いものとして破棄されるため無駄です。ツール使用環境を使用している場合は、並列で実行できる環境の数に基づいて、この値を手動で設定することを検討してください。
- max_staleness (
int、任意、デフォルトは4) — ロールアウトサンプルが破棄される前に、現在のモデルバージョンに対して許容される最大ウェイト更新ステップの遅れ。 - queue_maxsize (
int、任意、デフォルトは1024) — ロールアウトキューにバッファリングするロールアウトサンプルの最大数。 - weight_sync_steps (
int、任意、デフォルトは1) — vLLMサーバーへの重みの同期の間隔となる学習ステップ数。 - rollout_worker_timeout (
float、任意、デフォルト値は300.0) — rollout workerの最後のハートビートから、トレーナーがハングと判断して処理を中断するまでの秒数。
ログ出力を制御するパラメータ
experimental.async_grpo.AsyncGRPOTrainer用の設定クラスです。
このクラスには、非同期GRPO学習に固有のパラメータのみが含まれています。学習引数の完全なリストについては、TrainingArgumentsのドキュメントを参照してください。なお、このクラス内のデフォルト値は、TrainingArgumentsのものと異なる場合があります。
これらのパラメータは、TrainingArgumentsとは異なるデフォルト値を持っています:
logging_steps: デフォルト値が500ではなく1になります。gradient_checkpointing: デフォルト値がFalseではなくTrueに変更されました。bf16:fp16が設定されていない場合、デフォルトでFalseではなくTrueになります。learning_rate:5e-5ではなく、デフォルト値が1e-6に変更されました。lr_scheduler_type:linearではなく、デフォルトがconstantになっています(下記を参照)。ignore_data_skip: 既定値がFalseではなくTrueに変更されました。ベースのTrainerのスキップおよびリプレイのループは、非同期のロールアウトキューには適用されません。
メッセージモードの調整における学習期間と学習率: マルチターン会話では、書き換えによって新しい行が開始されるため、1つの会話が可変数の学習行に分岐します。そのため、エポックあたりのサンプル数、ひいてはオプティマイザーステップ数は事前には確定しません。その結果:
num_train_epochsは、prompt データセットに対する完全なパスの数でトレーニングを制限します。これは、実際にトレーニングに使用された個別のプロンプトの数としてカウントされます。これはフォークが生成する行数とは独立しており、N エポックを要求すると、常にデータを N 回パスしてトレーニングが行われます。max_stepsが設定されていない場合、これが停止条件となり、max_stepsは安全上の上限としてのみ機能します。max_stepsが明示的に設定されている場合(> 0)、停止条件として優先的に適用され(エポックではなくオプティマイザのステップ数で上限を定める)、エポックベースの停止が無効になります。lr_scheduler_typeのデフォルト値はconstantです。減衰の期間(ホライズン)はオプティマイザーステップ数で測定されるため、ステップ数がフォークレートに依存して事前には確定できない場合があるためです。減衰する学習率を使用するには、減衰スケジュールと明示的なmax_stepsをセットで設定してください。
AsyncGRPOTrainer
クラス trl.experimental.async_grpo.AsyncGRPOTrainer
< source >( model: str | PreTrainedModelreward_funcs: collections.abc.Callable[..., list[float]] | list[collections.abc.Callable[..., list[float]]] | None = Noneargs: trl.experimental.async_grpo.async_grpo_config.AsyncGRPOConfig | None = Nonetrain_dataset: datasets.arrow_dataset.Dataset | datasets.iterable_dataset.IterableDataset | None = Noneprocessing_class: transformers.tokenization_utils_base.PreTrainedTokenizerBase | None = Nonecallbacks: list[transformers.trainer_callback.TrainerCallback] | None = Noneoptimizers: tuple[typing.Optional[torch.optim.Optimizer], typing.Optional[torch.optim.lr_scheduler.LambdaLR]] = (None, None)peft_config: PeftConfig | None = Nonetools: list[collections.abc.Callable] | None = Noneenvironment_factory: collections.abc.Callable[[], trl.experimental.async_grpo.async_grpo_trainer._SupportsReset] | dict[str, collections.abc.Callable[[], trl.experimental.async_grpo.async_grpo_trainer._SupportsReset]] | None = None )
パラメータ
- model (
strまたは PreTrainedModel) — 学習対象のモデル。以下のいずれかです:- 文字列。huggingface.co のモデルリポジトリにホストされている事前学習モデルの model id、または save_pretrained を使用して保存されたモデルの重みを含む ディレクトリ へのパス(例:
'./my_model_directory/')です。モデルは、その設定で宣言されたアーキテクチャで読み込まれます。ビジョン・ランゲージのチェックポイントの場合は AutoModelForImageTextToText(ビジョンタワーは読み込まれますが凍結されます。Vision-language models を参照)、それ以外の場合は AutoModelForCausalLM です。 - PreTrainedModelオブジェクトです。そのアテンション実装は、パックトレーニング用に、トレーナーのツリーアテンションバックエンドに切り替えられます。
config のモデル名は、生成に使用される vLLM サーバー上でモデルを識別するために使用されます。
- 文字列。huggingface.co のモデルリポジトリにホストされている事前学習モデルの model id、または save_pretrained を使用して保存されたモデルの重みを含む ディレクトリ へのパス(例:
- reward_funcs (
RewardFunc | list[RewardFunc], 省略可能) — 報酬の計算に使用する報酬関数です。報酬を計算するには、プロンプトと補完を引数としてすべての報酬関数を呼び出し、その報酬を合計します。environment_factory(以下を参照) によって環境から報酬が供給される場合は省略できます。以下のいずれかの形式を指定できます:- 単一の報酬関数: 関数には、プロンプトと生成された補完、およびデータセット内の追加の列が渡されます。報酬のリストを返す必要があります。報酬関数は同期または非同期のいずれかであり、報酬が該当サンプルに適用されない場合は
Noneを返すこともできます。これは、異なる報酬関数が異なるタイプのサンプルに適用されるマルチタスク学習に有用です。報酬関数がサンプルに対してNoneを返した場合、その報酬関数はそのサンプルの報酬計算から除外されます。詳細については、カスタム報酬関数の使用を参照してください。 - …は報酬関数のリストです。各項目は上記で説明した報酬関数です。すべての関数からの報酬は合計されます。
GRPOTrainer とは異なり、報酬は生成された子プロセス内で計算されるため、各報酬関数(
toolsおよびenvironment_factoryを含む)は picklable である必要があります。モジュールレベルの関数、functools.partial、または callable なクラスインスタンスを使用してください。ラムダやクロージャは起動時に失敗します。ツールは__name__によって登録されるため、モジュールレベルの関数である必要があります。また、子プロセスはCUDA_VISIBLE_DEVICES=""で実行されるため、GPU ベースの報酬モデルはトレーナーの GPU ではなく CPU(低速)で実行されます。 - 単一の報酬関数: 関数には、プロンプトと生成された補完、およびデータセット内の追加の列が渡されます。報酬のリストを返す必要があります。報酬関数は同期または非同期のいずれかであり、報酬が該当サンプルに適用されない場合は
- args (experimental.async_grpo.AsyncGRPOConfig、任意) —
このトレーナーの設定です。
Noneの場合、デフォルトの設定が使用されます。 - train_dataset (Dataset または IterableDataset, 省略可) —
学習に使用する Dataset。
"prompt". Dataset 内の追加の列は無視されます。サンプルの形式は次のいずれかです:environment_factoryが提供され、環境がデータを所有(または手続き的に生成)し、reset()メソッドからプロンプトを返す場合のみ、省略できます。その場合、max_stepsを設定してトレーニングの長さを定義する必要があります。 - processing_class (PreTrainedTokenizerBase、任意) —
データを処理するために使用される処理クラスです。パディング側は “left” に設定する必要があります。
Noneの場合、from_pretrained を使用してモデル名から処理クラスを読み込みます。パディングトークンtokenizer.pad_tokenが設定されている必要があります。処理クラスにパディングトークンが設定されていない場合、tokenizer.eos_tokenがデフォルトとして使用されます。 - callbacks (のリスト TrainerCallback, 省略可) —
トレーニングループをカスタマイズするためのコールバックのリスト。デフォルトのコールバックのリストに追加されます。デフォルトのコールバックの詳細は こちら.
デフォルトで使用するコールバックの1つを削除したい場合は、remove_callbackメソッドを使用します。
- optimizers (
tuple[torch.optim.Optimizer | None, torch.optim.lr_scheduler.LambdaLR | None]、任意、デフォルトは(None, None)) — 使用するオプティマイザーとスケジューラーを含むタプルです。デフォルトでは、モデルに対してAdamWのインスタンスと、argsによって制御される get_linear_schedule_with_warmup によって与えられるスケジューラーが使用されます。 - peft_config (PeftConfig、任意) —
モデルをラップするために使用される PEFT 設定です。
Noneの場合、モデルはラップされません。vLLM サーバーが--enable-loraを指定して起動された場合、LoRA アダプターはマージされた重みとしてではなく、アダプターとして同期されます。詳細は、AsyncGRPO ドキュメントの LoRA セクションを参照してください。 - tools (
Callableのリスト、省略可) — モデルが生成中に呼び出すことができる、呼び出し可能なツール関数(同期または非同期)のリストです。各ツールは、適切に型ヒントが付けられた引数と戻り値を持つ標準的な Python 関数であり、その目的、引数、戻り値を説明する Google スタイルのドキュメント文字列(docstring)が必要です。詳細については、https://huggingface.co/docs/transformers/en/chat_extras#passing-toolsを参照してください。モデルは、関数名、型ヒント、ドキュメント文字列を用いて、関数の呼び出し方法を決定します。モデルのチャットテンプレートがツールの使用をサポートしており、ツール呼び出し用にファインチューニングされていることを確認してください。 - environment_factory (
EnvironmentFactoryまたはdict[str, EnvironmentFactory], 省略可) — 環境インスタンスを作成して返す呼び出し可能オブジェクト、または環境名をそのような呼び出し可能オブジェクトにマッピングする辞書です。環境クラスには、生成中にツールとして呼び出せるメソッドを定義する必要があります。各メソッドは、上記で説明したtoolsの要件に準拠する必要があります。環境は、生成間で状態をリセットするために使用できる呼び出し可能なresetメソッドも実装する必要があります。resetメソッドはNoneまたは文字列を返す必要があります。文字列を返す場合、その文字列は生成前に最後のユーザーメッセージに追加されます。環境は、引数を取らずget_rewardを返すfloat: メソッドを定義することもできます。このメソッドが存在する場合、環境が報酬を所有し、get_rewardは完了したロールアウトごとに1回呼び出され、環境の内部状態からスコアを評価します。これは追加の報酬ソースとして機能し(重みは1で、環境のクラス名で記録されます)、同時に、その後の報酬関数である、reward_funcs, は省略可能になります。単一の callable を使用する場合、すべての例は同じ環境を使用し、ロールアウトごとに1つのインスタンスが作成されるため、それらの相互作用は分離された状態に保たれます。辞書を使用する場合、各例には環境を名前で選択するための
environmentフィールドを含める必要があり、その環境のツールのみがプロンプトに公開されます。これにより、単一のランでタスクを混合(例: コーディング環境とゲーム)できます。この機能は実験的であり、事前の通知なしにいつでも変更または削除される可能性があります。
Group Relative Policy Optimization (GRPO) 手法用の Trainer です。このアルゴリズムは、論文 DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models で初めて提案されました。この Trainer は GRPO の非同期版であり、生成を外部の vLLM サーバーにオフロードします。このサーバーは学習と並行して非同期に動作し、ロールアウトを勾配更新ループから分離します。
例:
>>> from trl.experimental.async_grpo import AsyncGRPOTrainer
>>> from trl.rewards import accuracy_reward
>>> from datasets import load_dataset
>>> dataset = load_dataset("trl-lib/DeepMath-103K", split="train")
>>> trainer = AsyncGRPOTrainer(
... model="Qwen/Qwen2.5-0.5B-Instruct",
... reward_funcs=accuracy_reward,
... train_dataset=dataset,
... )
>>> trainer.train()サンプリングするプロンプト、ロールアウトの生成方法、アドバンテージの計算方法をカスタマイズするには、experimental.async_grpo.AsyncRolloutLoopをサブクラス化し、それをトレーナーのloop_clsとして設定します。TRLはループを
AsyncRolloutLoop
class trl.experimental.async_grpo.AsyncRolloutLoop
< source >( config: AsyncGRPOConfigmodel_name: strdataset: Datasetreward_funcs: list[collections.abc.Callable[..., list[float]]]processing_class: PreTrainedTokenizerBaseeos_token_ids: list[int]rollout_buffer: Queuemodel_version_value: Synchronizedheartbeat_value: Synchronizedfailed_event: Eventexception_info_queue: Queuemetrics_queue: Queuetools: list[collections.abc.Callable] | None = Noneenvironment_factory: collections.abc.Callable[[], object] | dict[str, collections.abc.Callable[[], object]] | None = Nonescore_queue_maxsize: int = 16lora_name: str | None = Nonedataset_start_index: int = 0 )
スポンされたロールアウトプロセス内で、experimental.async_grpo.AsyncGRPOTrainerのロールアウトを生成してスコアリングします。
デフォルトではGRPOを実装しています。実行をカスタマイズするには、サブクラスを作成し、変更するメソッドのみをオーバーライドして、そのサブクラスをトレーナーのloop_clsに設定します。各プロンプトは、以下の順序で処理されます。
- filter_prompt(): プロンプトに対して生成を行うかどうか。
- generate_one(): 1回の完全なロールアウト。各サンプリングリクエストに対してgenerate_one_turn()を呼び出します。
num_generations個のロールアウトからなるグループにスコアが付けられます。その報酬は、トレーナーのreward_funcs、get_rewardを定義する環境、および Rollout.rewardの合計です。その後、compute_advantages() がグループごとに 1 回実行されます。
setup() と close() は、HTTP クライアントのように、ループのイベントループ上でリソースの作成と解放を行います。フックは self.config(experimental.async_grpo.AsyncGRPOConfig のサブクラスは独自のフィールドを持つことができます)と self.tokenizer を読み取ることができます。ループは生成されたプロセス内で構築されるため、サブクラスはインポート可能である必要があります(モジュールレベルで定義されている必要があります)。
filter_prompt
< source >( row_index: introw: dict[str, typing.Any]epoch: int ) → bool
プロンプトに対して生成を行うかどうかを指定します。拒否されたプロンプトは、このエポックではスキップされ、ドロップされたグループと同様に消費済みとしてカウントされます。デフォルトではすべてのプロンプトを許可します。エポック全体のプロンプトを拒否すると、その後バッチがトレーナーに到達できなくなるため、例外が発生します。
generate_one
< source >( prompt: list[dict[str, str]]tools: list[collections.abc.Callable]group_id: int = 0 ) → Rollout
プロンプトに対して1つのロールアウトを生成します。
デフォルトでは、マルチターンのツールループが実行されます。各ターンでは、チャットテンプレートで会話全体をレンダリングし、generate_one()で応答をサンプリングし、含まれるツール呼び出しを実行します。モデルがツール呼び出しを停止するか、max_tool_calling_iterationsに達するまで続行します。エージェントフレームワークなどを使用して異なる方法で生成する場合は、このループをオーバーライドしてください。学習シーケンスはこれらから構築されるため、Rollout.turnsにすべてのサンプリングリクエストを返してください。また、ここでロールアウトをスコアリングするためにRollout.rewardを設定してください。
generate_one_turn
< source >( prompt_ids: list[int] ) → TurnRecord
vLLMサーバーから1つの応答をサンプリングします。設定のサンプリング設定(temperature、top_p、top_k、min_p、repetition_penaltyおよびmax_completion_length)を使用します。
compute_advantages
< source >( group: RolloutGroup ) → np.ndarray
パラメータ
- group (RolloutGroup) —
1つのプロンプトの
num_generations個のロールアウトで、その総報酬はgroup.rewardsに格納されています。
戻り値
np.ndarray
group.rewardsの順序に従って、ロールアウトごとの1つの利点。
グループの各ロールアウトごとに1つのアドバンテージを計算します。デフォルトでは、各報酬はグループ内で標準化されます。報酬がNaNのロールアウトにはアドバンテージ0が割り当てられ、平均と標準偏差の計算から除外されます。
It runs for every group. スコア付き報酬がすべて等しいグループは、この処理がどのようなアドバンテージを返すかを問わず、除外されます。
他のフックが必要とするリソース(HTTPクライアントなど)を作成します。最初のプロンプトの前に、ループのイベントループ上で実行されます。デフォルトでは何も行いません。
setup() が作成したものを解放します。ループが停止したときに実行されます。失敗した場合にも実行されます。デフォルトでは何も行いません。
ロールアウト
class trl.experimental.async_grpo.Rollout
< source >( completion: list[dict[str, str]]completion_ids: list[int]turns: list[trl.experimental.async_grpo.async_rollout_worker.TurnRecord]tool_call_count: int = 0tool_failure_count: int = 0reward: float | None = Nonerollout_id: str = <factory> )
パラメータ
- completion (
list[dict[str, Any]]) — Messages generated after the prompt, in conversational format. Passed to the reward functions ascompletions. - completion_ids (
list[int]) — 生成された completion のトークン ID です。completion_idsとして報酬関数に渡されます。 - turns (
list[TurnRecord]) — ロールアウトを生成したサンプリングリクエストを、順序どおりに並べたものです。学習シーケンスはこれらから構築されます。サンプリングされたトークンは学習対象となり、各プロンプトの残りはコンテキストとして扱われます。 - tool_call_count (
int、任意、デフォルトは0) — ロールアウト中に実行されたツール呼び出しの回数です。 - tool_failure_count (
int、任意、デフォルトは0) — 失敗したツール呼び出しの数。 - reward (
float, 任意) — 生成中に計算される報酬です。例えば、外部のグレーダーによって計算されたものなどが該当します。この値は、報酬関数や環境の報酬に追加されます。Noneの場合、このロールアウトにはこのソースからの報酬が与えられません。 - rollout_id (
str, 任意) — デバッグ用に、学習行におけるロールアウトを識別します。デフォルトでは、新しいランダムな16進IDが使用されます。
generate_one()によって返される、1回のロールアウトの完了結果。
TurnRecord
class trl.experimental.async_grpo.async_rollout_worker.TurnRecord
< source >( prompt_ids: list[int]output_ids: list[int]output_log_probs: list[float] = <factory>output_mask: list[int] | None = Noneoutput_sampling_mask: list[list[int]] | None = Noneoutput_sampler_logprobs: list[dict[int, float]] | None = None )
パラメータ
- prompt_ids (
list[int]) — このターンに送信されたプロンプト全体のトークン ID。会話の以前のすべてのターンを含みます。 - output_ids (
list[int]) — サンプラーが生成したトークンIDです。 - output_log_probs (
list[float]、任意、デフォルトは[]) —output_ids内の各トークンの Sampler の対数確率。いずれかが学習対象の場合に必要です。 - output_mask (
list[int]、省略可) —output_idsの各トークンに対応する値: トークンを学習対象にする場合は1、コンテキストとしてのみ保持する場合は0。Noneの場合、すべての出力トークンが学習対象になります。 - output_sampling_mask (
list[list[int]], 省略可) —output_idsの各トークンに対応するリスト:top_k/top_pによる切り詰めにおいて、サンプラーが選択し得たトークン ID です。Noneの場合は、語彙全体です。 - output_sampler_logprobs (
list[dict[int, float]], 任意) —output_idsの各トークンに対応する辞書: トークン ID をキーとして、サンプラーが最も可能性が高いと判断したトークンの対数確率を格納します。スコア中心化 (num_sampler_logprobs) に使用されます。
1つのサンプリングリクエスト: サンプラーに送信されたプロンプトと、それによって生成されたトークン。
RolloutGroup
class trl.experimental.async_grpo.async_rollout_worker.RolloutGroup
< source >( prompts: list[list[dict[str, str]]]reward_kwargs: dict[str, list[typing.Any]]completions: list[list[dict[str, str]]]completions_ids: list[list[int]]completions_sequences: list[list[trl.experimental.async_grpo.async_rollout_worker.TrainingSequence]]tool_call_counts: list[int]tool_failure_counts: list[int]model_version: intgroup_id: introw_index: intenv_rewards: list[tuple[type, float] | None]rollout_rewards: list[float | None]queued_at: float = 0.0rewards: numpy.ndarray | None = None )
パラメータ
- prompts (
list[list[dict[str, Any]]]) — 各ロールアウトのプロンプト。 - reward_kwargs (
dict[str, list[Any]]) — プロンプトのデータセット行の他のカラムで、キーワード引数として報酬関数に渡されます。 - completions (
list[list[dict[str, Any]]]) — 各ロールアウトの補完メッセージ。 - completions_ids (
list[list[int]]) — 各ロールアウトの補完トークンIDです。 - completions_sequences (
list[list[TrainingSequence]]) — 各ロールアウトから構築されたトレーニングシーケンスです。ターン間で再トークナイズされた履歴が変更されたロールアウトでは、1つ以上のシーケンスが生成されます。 - tool_call_counts (
list[int]) — 各ロールアウトにおけるツール呼び出しの数。 - tool_failure_counts (
list[int]) — 各ロールアウトにおける失敗したツール呼び出しの数。 - model_version (
int) — グループの最初のロールアウトが開始された時点のポリシーバージョン。 - group_id (
int) — ロールアウトプロセスにおいて0から数えたグループの識別子。 - row_index (
int) — 学習データセットにおけるプロンプトの行のインデックス。 - env_rewards (
list[tuple[type, float] or None]) —get_rewardを定義している環境を持つロールアウトの場合、環境クラスとその報酬。それ以外の場合はNone。 - rollout_rewards (
list[float or None]) — 各ロールアウトのRollout.reward。 - queued_at (
float、任意、デフォルトは0.0) — グループがスコアリング用にキューに投入された時点のtime.monotonic()。 - rewards (
np.ndarray, 任意) — 各ロールアウトの総報酬。すべての報酬ソースで合計された値で、どのソースもスコアリングしなかった場合は NaN になります。compute_advantages() が呼び出される前に設定されます。
1つのプロンプトのnum_generations回のロールアウトをまとめてスコアリングします。各リストには、ロールアウトごとに1つのエントリが含まれます。