TRL documentation
GRPO 训练器
GRPO 训练器
概述
TRL 支持 GRPO Trainer,用于训练语言模型,如 Zhihong Shao、Peiyi Wang、Qihao Zhu、Runxin Xu、Junxiao Song、Mingchuan Zhang、Y. K. Li、Y. Wu 和 Daya Guo 在论文 DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models 中所述。
该论文的摘要如下:
数学推理因其复杂且结构化的特性,对语言模型构成了重大挑战。在本文中,我们介绍了 DeepSeekMath 7B,该模型使用源自 Common Crawl 的 120B 数学相关 token,并结合自然语言和代码数据,对 DeepSeek-Coder-Base-v1.5 7B 进行继续预训练。在不依赖外部工具包和投票技术的情况下,DeepSeekMath 7B 在竞赛级 MATH 基准测试中取得了 51.7% 的惊人分数,其性能接近 Gemini-Ultra 和 GPT-4 的水平。对 DeepSeekMath 7B 的 64 个样本进行自一致性(Self-consistency)处理,在 MATH 上达到了 60.9%。DeepSeekMath 的数学推理能力归因于两个关键因素:首先,我们通过精心设计的 数据选择 流水线,充分利用了公开网络数据的巨大潜力。其次,我们引入了 Group Relative Policy Optimization (GRPO),这是 Proximal Policy Optimization (PPO) 的一种变体,它在增强数学推理能力的同时,优化了 PPO 的内存使用。
此训练后方法由 Quentin Gallouédec 贡献。
快速入门
本示例演示了如何使用 GRPO 方法训练模型。我们使用 DeepMath-103K 数据集 中的提示词来训练 Qwen2.5 0.5B Instruct 模型。您可以在此处查看该数据集中的数据:
以下是用于训练模型的脚本。accuracy_reward 需要 math-verify,您可以通过 pip install trl[math_verify] 进行安装。
# train_grpo.py
from datasets import load_dataset
from trl import GRPOTrainer
from trl.rewards import accuracy_reward
dataset = load_dataset("trl-lib/DeepMath-103K", split="train")
trainer = GRPOTrainer(
model="Qwen/Qwen2.5-0.5B-Instruct",
reward_funcs=accuracy_reward,
train_dataset=dataset,
)
trainer.train()使用以下命令执行该脚本:
torchrun --nproc_per_node 8 train_grpo.py
在 8 个 GPU 上分布式训练,大约需要 1 天。

注意: 上述奖励曲线是使用
Qwen/Qwen2-0.5B-Instruct生成的。使用Qwen/Qwen2.5-0.5B-Instruct的结果在定性上相似。
深入了解 GRPO 方法
GRPO 是一种在线学习算法,这意味着它通过利用训练过程中由已训练模型自身生成的数据来迭代地改进。GRPO 目标背后的直觉是最大化生成补全的优势,同时确保模型保持在参考策略附近。为了理解 GRPO 的工作原理,可以将其分解为四个主要步骤:生成补全、计算优势、估计 KL 散度以及计算损失。

生成补全
在每个训练步骤中,我们采样一批提示词,并为每个提示词生成一组 补全(记为 ).
计算优势
对于每个 序列,我们使用奖励模型或奖励函数来计算奖励。为了与奖励模型的比较性质保持一致——这些模型通常在针对同一问题的输出比较数据集上进行训练——优势的计算方式旨在反映这些相对比较。其归一化方式如下:
这种方法赋予了该算法其名称:组相对策略优化(GRPO)。
论文 Understanding R1-Zero-Like Training: A Critical Perspective 指出,按 进行缩放可能会导致问题级别的难度偏差。你可以通过设置
scale_rewards=False在 GRPOConfig. 中关闭此缩放。请注意,关闭基于 std 的缩放也会移除方差归一化,因此更新幅度将直接取决于原始奖励尺度和批次组成。
如第一部分:技巧还是陷阱?深入探讨用于 LLM 推理的 RL(Lite PPO)所示,在本地(组)级别计算均值,并在全局(批次)级别计算标准差,可以实现更稳健的奖励整形。您可以在GRPOConfig中设置
scale_rewards="batch"来使用此缩放策略。
估计 KL 散度
KL 散度使用由 Schulman 等人(2020). 引入的估计器进行估计。该估计器定义如下:
计算损失
目标是在确保模型保持接近参考策略的同时最大化优势。因此,损失函数定义如下:
其中第一项表示缩放后的优势值,第二项通过 KL 散度对偏离参考策略的行为进行惩罚。
请注意,与 DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models, 中的原始公式相比,我们不再乘以 ,因为论文 Understanding R1-Zero-Like Training: A Critical Perspective 指出这会引入响应级别的长度偏差。更多详情请参阅 损失类型.
请注意,与 DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models, 中原始的公式相比,我们默认使用 ,这意味着不使用 KL 散度项。这一选择受到多项近期研究(例如 Open-Reasoner-Zero: An Open Source Approach to Scaling Up Reinforcement Learning on the Base Model) )的启发,这些研究表明 KL 散度项对于使用 GRPO 进行训练并非必不可少。因此,将其排除已成为常见做法(例如 Understanding R1-Zero-Like Training: A Critical Perspective, DAPO: An Open-Source LLM Reinforcement Learning System at Scale). 如果您希望包含 KL 散度项,可以将
beta中的 GRPOConfig 设置为非零值。
在原始论文中,该公式被推广以考虑每次生成后的多次更新(记为 , ,可通过 num_iterations 中的 GRPOConfig) 利用 截断的代理目标:
其中 通过将策略比率限制在 和 . 当 ((TRL 中的默认值)时,带裁剪的代理目标简化为原始目标。
损失类型
文献中已提出目标函数的多种表述形式。最初,GRPO 的目标函数定义如下:
其中
这篇 DAPO 论文 指出了 GRPO 算法的样本级损失在长思维链(long-CoT)场景下的局限性:较长的回复受到的惩罚不足,从而导致输出质量下降。提出的解决方案是令牌级归一化,它通过为单个令牌分配更均衡的奖励,更好地处理了较长的序列,而无需考虑回复的长度:
要使用此公式,请在 GRPOConfig 中设置 loss_type="dapo"。
此外,论文 Understanding R1-Zero-Like Training: A Critical Perspective 证明了初始的 GRPO 公式引入了响应长度偏差。他们指出,虽然 DAPO 公式减轻了这种偏差,但并未完全消除它。为了彻底消除这种偏差,他们提出用常数代替序列长度进行除法运算,从而得到以下公式:
建议将此常量设置为最大生成长度。要使用此公式,请在 GRPOConfig 中设置 loss_type="dr_grpo"。
或者,在 SAPO 论文中,Qwen 团队提出用一种平滑的、温度可控的软门控机制来替代 GRPO 的“硬”裁剪机制。当策略偏离参考策略过远时,GRPO 会将梯度置零,而 SAPO 则使用一个软信任域来平滑地衰减梯度权重。这使得模型能够保留来自“近策略”(near-on-policy)标记的有用学习信号,同时抑制极端偏差带来的噪声。
损失函数定义为:
软门控函数 使用 sigmoid 函数 定义如下:
温度 根据优势 :
他们建议使用非对称温度, (默认值为 ). 这确保模型对“不良”动作施加更严格的惩罚以防止不稳定,同时对“良好”动作更加宽容。
要使用此公式,请在 GRPOConfig 中设置 loss_type="sapo"。
记录的指标
在训练和评估过程中,我们记录以下指标:
num_tokens:迄今为止处理的 token 总数,包括 prompt 和 completion。使用工具时,仅统计非工具 token。step_time:每个训练步骤(包括生成)的平均耗时(以秒为单位)。completions/mean_length:生成补全的平均长度。使用工具时,仅统计非工具 token。completions/min_length:生成补全的最小长度。使用工具时,仅统计非工具 token。completions/max_length:生成补全的最大长度。使用工具时,仅计算非工具 token。completions/mean_terminated_length:以 EOS 终止的生成补全的平均长度。使用工具时,仅统计非工具 token。completions/min_terminated_length:以 EOS 终止的生成补全的最小长度。使用工具时,仅统计非工具 token。completions/max_terminated_length:以 EOS 终止的生成补全的最大长度。使用工具时,仅统计非工具 token。completions/clipped_ratio:被截断(裁剪)的补全比例。tools/call_frequency:生成批次中每次补全的平均工具调用次数。仅在提供tools时记录。tools/failure_frequency:工具调用失败的比例(工具未找到、抛出异常或调用类型不受支持)。当未调用任何工具时,该值为0.0。仅在提供tools时记录。rewards/{reward_func_name}/mean:特定奖励函数的平均奖励。当环境通过get_reward拥有奖励时,{reward_func_name}为环境的类名。rewards/{reward_func_name}/std:特定奖励函数的奖励标准差。reward:对各个函数的奖励求和(按reward_weights加权)后得到的总体平均奖励。reward_std:跨函数求和奖励的标准差(按reward_weights加权),在完整批次上计算。frac_reward_zero_std:生成批次中奖励标准差为零的样本比例,表明该提示词下的多样性较低(所有回答均正确或均错误)。sampling/sampling_logp_difference/mean:采样器(vLLM)返回的对数概率与训练模型重新计算的对数概率之间,在补全 token 上的平均绝对差值。该值增大表明训练与推理之间的不匹配正在加剧。仅在use_vllm=True且vllm_importance_sampling_correction=True时记录。sampling/sampling_logp_difference/max:此类绝对差值的最大值。仅在use_vllm=True且vllm_importance_sampling_correction=True时记录。sampling/importance_sampling_ratio/min:用于校正训练与推理不一致的最小重要性采样比率,在应用由vllm_importance_sampling_mode选择的约束 之后(对于*_truncate模式,裁剪至[C_min, C_max];对于*_mask模式,设为零)。在 completion tokens 上计算,对于sequence_*模式则在序列上计算。仅在use_vllm=True且vllm_importance_sampling_correction=True时记录。sampling/importance_sampling_ratio/mean:平均约束重要性采样比率。仅在use_vllm=True且vllm_importance_sampling_correction=True时记录。sampling/importance_sampling_ratio/max:最大的受限重要性采样比率。仅在use_vllm=True且vllm_importance_sampling_correction=True时记录。policy_loss:策略梯度损失值(未添加任何熵奖励之前)。当entropy_coef非零或use_adaptive_entropy=True时记录。entropy:生成的补全中 token 预测的平均熵。(如果mask_truncated_completions=True,则排除被掩码序列的 token。)entropy_coef:当前的熵正则化系数。当entropy_coef非零或use_adaptive_entropy=True时记录。当use_adaptive_entropy=True时,每个优化器步骤更新一次。aux_loss:混合专家(Mixture-of-Experts)模型的负载均衡辅助损失,在乘以router_aux_loss_coef并加到总损失之前。仅当模型为 MoE 模型且router_aux_loss_coef非零时记录。kl:模型与参考模型之间的平均 KL 散度,基于生成的补全内容计算。仅在beta非零时记录。clip_ratio/region_mean: token(或当importance_sampling_level="sequence") 时,sequence)的概率中,GRPO 目标被裁剪以保持在信任区域内的比例: . 值越高,表示被裁剪的 token 越多,从而限制了策略 的变化幅度。clip_ratio/low_mean: 被信任区域下界截断的 token(或当importance_sampling_level="sequence") 时,为序列)概率的平均比率: .clip_ratio/low_min: 每个 completion 中被截断的 token 的最小比例(如果importance_sampling_level="sequence") importance_sampling_level="sequence",则为序列本身)在信任区域下界处被截断: .clip_ratio/high_mean: 被信任区域上界截断的 token(或当importance_sampling_level="sequence") 时,为序列)概率的平均比率: .clip_ratio/high_max: 每个 completion 中被截断的 token 的最大比例(如果importance_sampling_level="sequence") importance_sampling_level="sequence",则为序列本身)在信任区域上界处被截断: .cispo_clip_ratio: 被截断的 token(或序列,如果importance_sampling_level="sequence") 重要性采样权重在epsilon_high处被截断且具有正优势的比例: . 仅在loss_type="cispo".vespo/phi_seq_mean: VESPO Gamma 权重的平均值 应用于序列级重要性权重。低于1.0的值表示序列被降权。仅在loss_type="vespo".
自定义
使用 vLLM 驱动的生成来加速训练
在使用在线方法训练时,生成过程往往是主要的性能瓶颈。为了加速生成,你可以使用 vLLM,这是一个面向 LLM 的高吞吐量、低延迟推理引擎。要启用它,首先使用以下命令安装该包
pip install trl[vllm]
我们支持在训练期间使用 vLLM 的两种方式:服务器模式和共置模式。
默认情况下,vLLM 生成会启用序列级 Masked Importance Sampling(
vllm_importance_sampling_mode="sequence_mask"),以解决使用不同框架时产生的生成-训练不匹配问题。可以通过设置vllm_importance_sampling_correction=False将其关闭。更多信息,请参阅 Masked Importance Sampling 和 Sequence-level Importance Sampling
选项 1:Colocate 模式
在此模式下,vLLM 在训练器进程内运行,并与训练模型共享 GPU 内存。这避免了启动单独的服务器,并可能提高 GPU 利用率,但可能导致训练 GPU 上的内存争用。这是默认模式。
from trl import GRPOConfig
training_args = GRPOConfig(
...,
use_vllm=True, # vllm_mode="colocate" by default
)选项 2:服务器模式
在此模式下,vLLM 在独立进程中运行(并使用独立的 GPU),并通过 HTTP 与训练器进行通信。如果您拥有专门用于推理的 GPU,则此模式非常理想。
启动 vLLM 服务器:
VLLM_SERVER_DEV_MODE=1 vllm serve <model_name> \ --weight-transfer-config '{"backend": "nccl"}' \ --logprobs-mode processed_logprobs \ --max-logprobs -1在训练脚本中启用服务器模式:
from trl import GRPOConfig training_args = GRPOConfig( ..., use_vllm=True, vllm_mode="server", )
请确保服务器使用的 GPU 与训练器不同,否则可能会遇到 NCCL 错误。您可以通过
CUDA_VISIBLE_DEVICES环境变量来指定要使用的 GPU。
根据模型大小以及训练所需的整体 GPU 内存,您可能需要调整 GRPOConfig 中的
vllm_gpu_memory_utilization参数,以避免资源利用率不足或内存溢出错误。我们提供了一个 HF Space,用于根据您的模型配置和实验设置来估算推荐的 GPU 内存利用率。只需按以下方式使用,即可获得
vllm_gpu_memory_utilization的推荐值:如果推荐值在您的环境中不起作用,我们建议在推荐值上添加一个小缓冲(例如 +0.05 或 +0.1),以确保稳定性。
如果您仍然遇到内存不足错误,请将
vllm_enable_sleep_mode设置为 True,这样在优化步骤期间,vllm 参数和缓存将被卸载。有关更多信息,请参阅 使用 vLLM Sleep Mode 减少内存使用。
默认情况下,GRPO 使用
MASTER_ADDR=localhost和MASTER_PORT=12345作为 vLLM 的配置,但你可以通过相应地设置环境变量来覆盖这些值。
有关更多信息,请参阅 使用 vLLM 加速训练。
处理训练与推理之间的不匹配
虽然 vLLM 极大地加速了推理,但它也将推理引擎与训练引擎解耦。理论上,这两个引擎在数学上是完全一致的,但在实践中,由于精度效应和特定于硬件的优化,它们可能会产生不同的输出。这种差异反映了两个系统不同的优化目标。推理引擎旨在最大化采样吞吐量(通常以每秒生成的 token 数衡量),同时保持可接受的采样保真度。而训练框架则侧重于梯度计算的数值稳定性和精度,通常使用 FP32 等更高精度的格式来存储主权重和优化器状态。这些不同的优先级和约束条件,在训练和推理之间引入了不可避免的、尽管细微的失配。
这种不匹配会导致有偏的梯度更新,据观察这会 destabilize 训练([1][2][3][4][5]). 为简化起见,考虑 REINFORCE 策略梯度:
此处 表示从某个数据分布中采样的提示词,而 是训练引擎实现的策略。引入 vLLM 后,我们获得了一个独立的推理策略 , 因此,有效的策略梯度变为
这将原本属于同策略的强化学习问题转变为异策略问题。
The standard way to correct for this distribution shift is importance sampling (IS). We provide two IS variants: Truncated Importance Sampling (TIS) and Masked Importance Sampling (MIS). Both variants can be applied either at the token level or at the sequence level. Let denote the importance weight, for example per token or per sequence. Under TIS, ratios outside of the range [vllm_importance_sampling_clip_min, vllm_importance_sampling_clip_max] are clipped,
原始的 TIS 论文 提出了一种单侧上界裁剪机制,即 . TRL 中的实现对此进行了推广,通过引入下界,得出了上述双侧公式,其灵感来源于 IcePop 方法。
请注意,在 IcePop 中,边界被标记为 和 而在 TRL 中我们使用 和 .
在 MIS 中,超出此范围的比例会被设为零,因此这些样本不会对梯度产生贡献。换句话说,异常样本在 TIS 中会被降权,而在 MIS 中会被丢弃。配置标志 vllm_importance_sampling_mode 同时决定了 IS 变体(掩码或截断)以及粒度(token 级别或序列级别)。
重要性采样是对训练-推理不匹配问题的原则性算法解决方案。然而,也存在一些更直接的方法,试图减少这两个引擎本身之间的不匹配。其中大多数是工程层面的解决方案。例如,MiniMax M1 在推理引擎中使用了 FP32 语言模型头。Thinking Machines 探索了确定性推理内核,但这会带来显著的效率成本。vLLM 通过基于 Thinking Machines 的批不变确定性内核,展示了逐位一致的策略,但截至 2025 年 11 月,与标准 vLLM 推理相比,仍存在相当大的吞吐量惩罚。
使用 transformers 连续批处理加速训练
作为 vLLM 的替代方案,您可以使用 transformers 内置的连续批处理引擎来加速生成。连续批处理会立即从批次中移除已完成的序列,而不是等待最慢的序列完成。对于完成长度不固定的任务(例如数学推理),在大批次大小(N≥32)下,与默认的 generate() 相比,它能带来更快的生成速度和更低的 VRAM 占用。
连续批处理是一种即插即用的升级方案,无需配置服务器或同步权重。它在进程内运行,非常适合单 GPU 训练或内存受限的环境。若要在大规模场景下实现最高的生成吞吐量,请改用 vLLM。
from trl import GRPOConfig
training_args = GRPOConfig(
...,
use_transformers_continuous_batching=True,
transformers_continuous_batching_config={
"use_cuda_graph": False,
"max_memory_percent": 0.4, # lower values leave more VRAM for the training backward pass
},
)TRL 将
max_memory_percent的默认值设为0.5(而非 Transformers 的0.9),以便为训练的反向传播留出足够的 VRAM。对于较大的生成批次(N≥32)或出现内存不足错误时,请将其调低至0.3–0.4。
完整的训练示例,请参阅 examples/grpo_continuous_batching/grpo_continuous_batching.py。
大规模 GRPO:在多节点上训练 70B+ 模型
在训练 Qwen2.5-72B 这样的大模型时,你需要多项关键优化,以确保训练在多 GPU 和多节点环境下高效且可扩展。这些优化包括:
- DeepSpeed ZeRO Stage 3:ZeRO 利用数据并行将模型状态(权重、梯度、优化器状态)分布在多个 GPU 和 CPU 上,从而降低每个设备的内存和计算需求。由于大模型无法装入单个 GPU,训练此类模型必须使用 ZeRO Stage 3。更多详情请参阅 DeepSpeed Integration。
- torchrun:PyTorch 的启动器会在每个节点上的每张 GPU 上启动一个进程,并通过公共的会合点将它们连接起来。更多详情,请参阅 分布式训练。
- vLLM:请参阅上一节,了解如何使用 vLLM 来加速生成。
以下是一个使用 GRPO 在多节点上训练 70B 模型的 SLURM 脚本示例。该脚本在 4 个节点上训练模型,并使用第 5 个节点进行基于 vLLM 的生成。
#!/bin/bash
#SBATCH --nodes=5
#SBATCH --gres=gpu:8
# Get the list of allocated nodes
NODELIST=($(scontrol show hostnames $SLURM_JOB_NODELIST))
# Assign the first 4 nodes for training and the 5th node for vLLM
TRAIN_NODES="${NODELIST[@]:0:4}" # Nodes 0, 1, 2, 3 for training
VLLM_NODE="${NODELIST[4]}" # Node 4 for vLLM
# Run training on the first 4 nodes (Group 1)
srun --nodes=4 --ntasks=4 --nodelist="${NODELIST[@]:0:4}" torchrun \
--nnodes 4 \
--nproc_per_node 8 \
--node_rank $SLURM_PROCID \
--rdzv_backend c10d \
--rdzv_endpoint ${NODELIST[0]}:29500 \
train_grpo.py \
--server_ip $VLLM_NODE &
# Run vLLM server on the 5th node (Group 2)
srun --nodes=1 --ntasks=1 --nodelist="${NODELIST[4]}" env VLLM_SERVER_DEV_MODE=1 vllm serve Qwen/Qwen2.5-72B --tensor-parallel-size 8 \
--weight-transfer-config '{"backend": "nccl"}' \
--logprobs-mode processed_logprobs \
--max-logprobs -1 &
waitimport argparse
from datasets import load_dataset
from trl import GRPOTrainer, GRPOConfig
from trl.rewards import accuracy_reward
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--vllm_server_host", type=str, default="", help="The server IP")
args = parser.parse_args()
dataset = load_dataset("trl-lib/DeepMath-103K", split="train")
training_args = GRPOConfig(
per_device_train_batch_size=4,
deepspeed="examples/deepspeed_configs/zero3.json",
use_vllm=True,
vllm_mode="server",
vllm_server_host=args.vllm_server_host.replace("ip-", "").replace("-", "."), # from ip-X-X-X-X to X.X.X.X
)
trainer = GRPOTrainer(
model="Qwen/Qwen2.5-72B",
args=training_args,
reward_funcs=accuracy_reward,
train_dataset=dataset
)
trainer.train()
if __name__=="__main__":
main()使用自定义奖励函数
GRPOTrainer 支持使用自定义奖励函数,而非稠密奖励模型。为确保兼容性,您的奖励函数必须满足以下要求:
奖励函数可以是同步的 Python 可调用对象,也可以是异步的 async def 协程。当您提供多个异步奖励函数时,它们会被并发等待(通过 asyncio.gather 并行执行),从而使它们的延迟相互重叠。
输入参数:
该函数必须接受以下关键字参数:
prompts(包含提示词),completions(包含生成的补全内容),completion_ids(包含分词后的补全内容),trainer_state(TrainerState):训练器的当前状态。可用于实现动态奖励函数,例如课程学习,其中奖励会根据训练进度进行调整。log_extra:一个可调用对象log_extra(column: str, values: list),用于向 completions 表添加额外的列。参见示例 6。log_metric:一个可调用对象log_metric(name: str, value: float),用于将标量指标记录为图表,与kl、entropy等并列显示。参见示例 6。environments:环境实例列表,每个 completion 对应一个。仅在提供了environment_factory时存在。使用此参数来读取回合期间累积的状态(例如env.counter)。对于有状态的环境,建议通过get_reward方法让环境自身管理奖励——参见 奖励。- 数据集可能包含的所有列名(
prompt除外)。例如,如果数据集包含名为ground_truth的列,则函数将以ground_truth作为关键字参数被调用。
满足此要求的最简单方法是在函数签名中使用
**kwargs。根据数据集格式的不同,输入会有所不同:
返回值:该函数必须返回一个浮点数列表。每个浮点数代表对应单个补全的奖励。
示例 1:奖励更长的补全
以下是一个标准格式奖励函数的示例,该函数会奖励更长的补全:
def reward_func(completion_ids, **kwargs):
"""Reward function that assigns higher scores to longer completions (in terms of token count)."""
return [float(len(ids)) for ids in completion_ids]您可以按以下方式测试:
>>> prompts = ["The sky is", "The sun is"] # not used in the reward function, but the trainer will pass it
>>> completions = [" blue.", " in the sky."] # not used in the reward function, but the trainer will pass it
>>> completion_ids = [[6303, 13], [304, 279, 12884, 13]]
>>> reward_func(prompts=prompts, completions=completions, completion_ids=completion_ids)
[2.0, 4.0]示例 1.1:奖励更长的补全(基于字符数)
与上一个示例相同,但这次奖励函数基于字符数而非 token 数。
def reward_func(completions, **kwargs):
"""Reward function that assigns higher scores to longer completions (in terms of character count)."""
return [float(len(completion)) for completion in completions]您可以按以下方式测试:
>>> prompts = ["The sky is", "The sun is"]
>>> completions = [" blue.", " in the sky."]
>>> completion_ids = [[6303, 13], [304, 279, 12884, 13]] # not used in the reward function, but the trainer will pass it
>>> reward_func(prompts=prompts, completions=completions, completion_ids=completion_ids)
[6.0, 12.0]示例 2:奖励具有特定格式的补全
以下是一个奖励函数的示例,用于检查补全内容是否具有特定格式。该示例受论文 DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning 中使用的 format reward 函数启发。 它专为对话格式设计,其中提示和补全内容均由结构化消息组成。
import re
def format_reward_func(completions, **kwargs):
"""Reward function that checks if the completion has a specific format."""
pattern = r"^<think>.*?</think><answer>.*?</answer>$"
completion_contents = [completion[0]["content"] for completion in completions]
matches = [re.match(pattern, content) for content in completion_contents]
return [1.0 if match else 0.0 for match in matches]您可以按以下方式测试此函数:
>>> prompts = [
... [{"role": "user", "content": "What is the result of (1 + 2) * 4?"}],
... [{"role": "user", "content": "What is the result of (3 + 1) * 2?"}],
... ]
>>> completions = [
... [{"role": "assistant", "content": "<think>The sum of 1 and 2 is 3, which we multiply by 4 to get 12.</think><answer>(1 + 2) * 4 = 12</answer>"}],
... [{"role": "assistant", "content": "The sum of 3 and 1 is 4, which we multiply by 2 to get 8. So (3 + 1) * 2 = 8."}],
... ]
>>> format_reward_func(prompts=prompts, completions=completions)
[1.0, 0.0]示例 3:基于参考的奖励完成
以下是一个奖励函数的示例,用于检查补全内容是否正确。该示例受论文 DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning 中使用的 accuracy reward 函数启发。
此示例针对 standard format 设计,其中数据集包含一个名为 ground_truth 的列。
import re
def reward_func(completions, ground_truth, **kwargs):
# Regular expression to capture content inside \boxed{}
matches = [re.search(r"\\boxed\{(.*?)\}", completion) for completion in completions]
contents = [match.group(1) if match else "" for match in matches]
# Reward 1 if the content is the same as the ground truth, 0 otherwise
return [1.0 if c == gt else 0.0 for c, gt in zip(contents, ground_truth)]您可以按以下方式测试此函数:
>>> prompts = ["Problem: Solve the equation $2x + 3 = 7$. Solution:", "Problem: Solve the equation $3x - 5 = 10$."]
>>> completions = [r" The solution is \boxed{2}.", r" The solution is \boxed{6}."]
>>> ground_truth = ["2", "5"]
>>> reward_func(prompts=prompts, completions=completions, ground_truth=ground_truth)
[1.0, 0.0]示例 4:多任务奖励函数
以下是在 GRPOTrainer 中使用多个奖励函数的示例。在此示例中,我们定义了两个针对特定任务的奖励函数:math_reward_func 和 coding_reward_func。math_reward_func 根据数学问题的正确性给予奖励,而 coding_reward_func 则根据代码解决方案是否可运行来给予奖励。
from datasets import Dataset
from trl import GRPOTrainer
# Define a dataset that contains both math and coding problems
dataset = Dataset.from_list(
[
{"prompt": "What is 2+2?", "task": "math"},
{"prompt": "Write a function that returns the sum of two numbers.", "task": "code"},
{"prompt": "What is 3*4?", "task": "math"},
{"prompt": "Write a function that returns the product of two numbers.", "task": "code"},
]
)
# Math-specific reward function
def math_reward_func(prompts, completions, task, **kwargs):
rewards = []
for prompt, completion, t in zip(prompts, completions, task):
if t == "math":
# Calculate math-specific reward
correct = check_math_solution(prompt, completion)
reward = 1.0 if correct else -1.0
rewards.append(reward)
else:
# Return None for non-math tasks
rewards.append(None)
return rewards
# Coding-specific reward function
def coding_reward_func(prompts, completions, task, **kwargs):
rewards = []
for prompt, completion, t in zip(prompts, completions, task):
if t == "code":
# Calculate coding-specific reward
works = test_code_solution(prompt, completion)
reward = 1.0 if works else -1.0
rewards.append(reward)
else:
# Return None for non-coding tasks
rewards.append(None)
return rewards
# Use both task-specific reward functions
trainer = GRPOTrainer(
model="Qwen/Qwen2.5-0.5B-Instruct",
reward_funcs=[math_reward_func, coding_reward_func],
train_dataset=dataset,
)
trainer.train()在此示例中,math_reward_func 和 coding_reward_func 旨在配合包含数学和编程问题的混合数据集使用。数据集中的 task 列用于确定对每个问题应用哪个奖励函数。如果数据集中的某个样本没有相关的奖励函数,该奖励函数将返回 None,GRPOTrainer 将继续使用有效的函数和任务。这使得 GRPOTrainer 能够处理具有不同适用性的多个奖励函数。
请注意,GRPOTrainer 会忽略奖励函数返回的 None 奖励,仅考虑相关函数返回的奖励。这确保了模型在相关任务上进行训练,并忽略没有相关奖励函数的任务。
示例 5:异步奖励函数
自定义奖励函数也可以定义为 async def 协程。如果您的奖励依赖于缓慢的 I/O(例如,调用远程服务),这将非常有用。当您传入多个异步奖励函数时,GRPOTrainer 会并发执行它们,从而使它们的延迟相互重叠。
以下是一个异步奖励函数的最小示例,用于模拟 I/O 密集型操作:
import asyncio
async def async_reward_func(prompts, completions, **kwargs):
# Simulate an I/O-bound call (e.g., HTTP request, database lookup)
await asyncio.sleep(0.01)
# Simple toy reward: 1.0 if the completion is non-empty, else 0.0
return [1.0 if completion else 0.0 for completion in completions]示例 6:记录额外的列和指标
以下是一个奖励函数的示例,该函数会将额外的列记录到 completions 表中,并将标量指标记录为图表。
import re
def reward_func(completions, ground_truth, log_extra=None, log_metric=None, **kwargs):
extracted = [re.search(r"\\boxed\{(.*?)\}", c) for c in completions]
extracted = [m.group(1) if m else None for m in extracted]
rewards = [1.0 if e == gt else 0.0 for e, gt in zip(extracted, ground_truth)]
if log_extra:
log_extra("golden_answer", list(ground_truth))
log_extra("extracted_answer", [e or "[none]" for e in extracted])
if log_metric:
log_metric("accuracy", sum(rewards) / len(rewards))
return rewards将奖励函数传递给训练器
要将自定义奖励函数用于 GRPOTrainer,请按以下方式传入:
from trl import GRPOTrainer
trainer = GRPOTrainer(
reward_funcs=reward_func,
...,
)您可以将多个奖励函数作为列表传入;该列表可以同时包含同步函数和异步函数:
from trl import GRPOTrainer
trainer = GRPOTrainer(
reward_funcs=[reward_func, async_reward_func1, async_reward_func2],
...,
)奖励将计算为每个函数奖励的总和,或者如果配置中提供了reward_weights,则为加权总和。
请注意,GRPOTrainer 支持多种不同类型的奖励函数。有关更多详细信息,请参阅参数文档。
熵正则化
为了鼓励探索并防止策略坍缩为近确定性输出,您可以在训练目标中添加熵奖励。熵正则化对 GRPO 损失的增强方式如下:
其中 是策略的平均逐 token 熵, 是熵系数。无论 loss_type; 为何,该奖励始终为平均逐 token 熵, batch_size * max_completion_length 它不会根据损失类型的策略归一化进行重新缩放(例如 Dr. GRPO 的 entropy_coef 分母),因此
静态熵 — 整个训练过程中保持固定的系数:
from trl import GRPOConfig, GRPOTrainer
training_args = GRPOConfig(entropy_coef=0.05, ...)自适应熵 — 系数会根据目标熵在每个优化器步骤中更新,如 Skywork-OR1 中所介绍。当当前熵小于或等于 entropy_target 时,系数增加 entropy_coef_delta;否则减少。仅当熵小于或等于目标值时,该系数才会生效(即非零):
training_args = GRPOConfig(
entropy_coef=0.01, # initial coefficient
use_adaptive_entropy=True,
entropy_target=5.0, # target mean per-token entropy (nats); tune for your model
entropy_coef_delta=0.005, # step size per optimizer step
entropy_coef_min=0.0,
entropy_coef_max=1.0,
...
)典型的语言模型每个 token 的熵通常在 2–10 nats 之间,因此默认的
entropy_target=0.2几乎不会触发正则化——只有当熵降至目标值或更低时(即接近完全坍缩时),该奖励才会生效。请将其设置为对您的模型有意义的值,例如接近训练初期观察到的熵值(记录为entropy指标)。当使用top_entropy_quantile < 1.0时,entropy_target应用于高熵 token 子集——该子集的熵会高于记录的全量 tokenentropy,因此请据此进行校准。
当 use_adaptive_entropy=True 时,当前的熵系数 entropy_coef 会随每个检查点一起保存,并在恢复时还原,因此训练完全可恢复。
GRPO 的快速实验
RapidFire AI 是一个构建在 TRL 之上的开源实验引擎,允许你同时启动多个 GRPO 配置,即使只有一块 GPU 也是如此。与按顺序尝试配置不同,RapidFire 让你能够更早地查看所有配置的学习曲线,停止表现不佳的运行,并在运行过程中克隆有前景的配置并应用新设置,而无需重启。有关更多信息,请参阅 RapidFire AI Integration。
Agent 训练
GRPO 支持智能体训练:模型在生成过程中调用工具,并根据结果进行学习。
- 工具是暴露给模型的普通 Python 函数(同步或异步)。对于无状态调用(如计算器、网络搜索),请使用
tools。 - 环境是更通用的形式:一个在每次 rollout 时全新构建的有状态对象,其公开方法作为工具暴露,并包含一个
reset生命周期钩子以及一个可选的get_reward,使其能够自行管理奖励。当您需要每次 rollout 的独立状态、重置钩子或由环境管理的奖励时,请使用environment_factory。
它们可以组合使用——你可以在 environment_factory 旁边传入独立的 tools。
工具
tools 参数需要一个 Python 函数(同步或异步)列表,用于定义智能体可用的工具:
from trl import GRPOTrainer
trainer = GRPOTrainer(
tools=[tool1, tool2],
...,
)每个工具必须是一个标准的 Python 函数,具有带类型提示的参数和返回类型,并附带一个Google 风格的 docstring,用于描述其用途、参数和返回值。 有关更多详细信息,请参阅传递工具指南。
GRPO 工具调用循环要求聊天模板是前缀保持的(追加一条工具消息时,不得改变之前消息的渲染方式)。对于已知的模型系列(例如 Qwen3、DeepSeek-V3),当启用工具时,TRL 会自动替换为经过修补的训练模板。完整的列表请参阅聊天模板。
在 GRPOConfig 中使用 max_tool_calling_iterations 来限制工具调用轮次的数量。默认情况下没有上限,生成会在以下情况停止:模型生成了一轮不包含任何工具调用的响应;补全内容(所有轮次和工具结果)达到 max_completion_length 个 token;或者完整序列达到模型的最大长度(在 vllm_mode="colocate" 下为 vllm_max_model_length,否则为模型的 max_position_embeddings)。
示例:
from trl import GRPOTrainer
def multiply(a: int, b: int) -> int:
"""
Multiplies two integers.
Args:
a: The first integer.
b: The second integer.
Returns:
The product of the two integers.
"""
return a * b
async def async_add(a: int, b: int) -> int:
"""
Asynchronously adds two integers.
Args:
a: The first integer.
b: The second integer.
Returns:
The sum of the two integers.
"""
return a + b
trainer = GRPOTrainer(
tools=[multiply, async_add],
...,
)环境
你还可以通过 environment_factory 提供工具。在此模式下,GRPOTrainer 会为每个 rollout 创建一个环境实例,并将该环境的公开方法作为工具暴露出来。
environment_factory需要transformers>=5.2.0。
使用 environment_factory 时,环境拥有数据:不存在外部的 train_dataset。在每次 rollout 中,reset() 会生成任务——从环境持有的语料库中自采样,或以程序化方式生成状态——并返回提示词。max_steps 设置训练长度。以下是一个最小示例,展示了一个自采样目标并暴露 increment 方法(作为工具暴露)的环境。
import random
from trl import GRPOConfig, GRPOTrainer
class IncrementEnv:
# Reserved methods
def reset(self, **kwargs) -> str | None: # required; called at the start of each rollout
self.counter = 0
self.target = random.randint(1, 6) # self-sample the task
return f"Increment the counter by {self.target}." # returned string becomes the prompt
def get_reward(self) -> float: # optional: the environment scores itself from its own state
return float(self.counter == self.target)
# Public methods (exposed as tools)
def increment(self, step: int) -> int:
"""
Increment the internal counter.
Args:
step: Value to add to the counter.
Returns:
The updated counter value.
"""
self.counter += step
return self.counter
trainer = GRPOTrainer(
model="Qwen/Qwen3-0.6B",
args=GRPOConfig(max_steps=1000, chat_template_kwargs={"enable_thinking": False}),
environment_factory=IncrementEnv,
)
trainer.train()环境类有两个保留方法:reset 和 get_reward。与其他任何公共方法不同,这些方法不会作为工具暴露给模型。
reset(必需)在 rollout 开始时被调用。它可以返回None或一个字符串。在 GRPO 中,当它返回一个字符串时,该字符串即为用户提示词。get_reward(可选,同步或异步)不接收任何参数,并返回一个float:环境根据其自身的内部状态对刚刚运行的回合进行评分(游戏是否以胜利结束?单词是否被猜中?)。它在每个完成的 rollout 中被调用一次,并作为奖励来源。
由于环境在每次
reset()时进行自采样,GRPO 组中的G个成员可能不共享相同的初始状态,这使得组基线略微更具噪声。对于组内相同的状态,请让reset()从共享的键中确定性地派生状态。
提供外部数据集(可选)
与其让环境自行采样,您可以提供一个外部的 train_dataset。例如,当您的任务已经存在于数据集中,或者需要在 多个环境 之间进行路由时。在每次 rollout 中,训练器会采样一行,将其 "prompt" 列用作提示,并将该行的其他列作为关键字参数传递给 reset()(以便环境从数据集中读取任务)。
from datasets import Dataset
from trl import GRPOTrainer
# Each row carries the prompt and the task data (here, the counter target to reach).
dataset = Dataset.from_dict(
{
"prompt": [[{"role": "user", "content": f"Increment the counter to {i}."}] for i in range(1, 7)],
"target": list(range(1, 7)),
}
)
class IncrementEnv:
def reset(self, target, **kwargs) -> None: # the row's `target` column arrives as a keyword argument
self.counter = 0
self.target = target
def get_reward(self) -> float:
return float(self.counter == self.target)
def increment(self, step: int) -> int: # exposed as a tool (see the full docstring above)
self.counter += step
return self.counter
trainer = GRPOTrainer(
model="Qwen/Qwen3-0.6B",
train_dataset=dataset, # the dataset owns the task; the "target" column reaches reset(target=...)
environment_factory=IncrementEnv,
)
trainer.train()奖励
环境拥有的奖励和训练器拥有的奖励并非互斥。对于从补全结果中自然计算得出的奖励(例如对文本进行格式检查),请传入 reward_funcs,并让环境通过 get_reward 返回其状态相关的奖励。所有来源的奖励将被求和;reward_weights 仅适用于 reward_funcs(环境拥有自己的缩放比例)。
def format_reward(completions, **kwargs): # trainer-owned: scores the completion text
...
trainer = GRPOTrainer(
model="Qwen/Qwen3-0.6B",
args=GRPOConfig(max_steps=1000),
reward_funcs=format_reward, # trainer-owned: scores the completion
environment_factory=IncrementEnv, # env-owned: scores its internal state via `get_reward`
)reward_func 也可以直接读取环境状态:当设置了 environment_factory 时,训练器会传入一个 environments 关键字参数(每个 completion 对应一个实例)。这在某些情况下有用,但对于依赖状态的奖励,建议优先使用 get_reward。
对于 AsyncGRPOTrainer,其工作方式完全相同。
多个环境
要在单次运行中混合训练多种任务(例如编码任务和游戏任务),请传入一个将环境名称映射到工厂的字典,而不是单个可调用对象。每次 rollout 都会通过数据集中的 environment 字段选择其环境,并且 仅暴露该环境的工具。这可以避免泄露无关工具(例如将游戏的 move 工具暴露给编码示例,反之亦然)。每个环境仍然拥有自己的数据,并从 reset() 返回提示,因此数据集只需要 environment 列来在它们之间进行路由。
import random
from datasets import Dataset
from trl import GRPOConfig, GRPOTrainer
class CodingEnv:
def reset(self, **kwargs) -> str:
n = random.randint(1, 20)
return f"Compute the {n}th Fibonacci number."
def run_code(self, code: str) -> str: # exposed as a tool only for "coding" examples
"""Run the given Python code and return its stdout.
Args:
code: The Python source to execute.
Returns:
The captured standard output.
"""
...
class GameEnv:
def reset(self, **kwargs) -> str:
return "Reach the goal tile."
def move(self, action: str) -> str: # exposed as a tool only for "game" examples
"""Apply an action to the game and return the new observation.
Args:
action: One of "up", "down", "left", "right".
Returns:
The observation after the move.
"""
...
# The dataset only routes: each row picks the environment for that rollout
dataset = Dataset.from_dict({"environment": ["coding", "game"] * 500})
trainer = GRPOTrainer(
model="Qwen/Qwen3-0.6B",
args=GRPOConfig(chat_template_kwargs={"enable_thinking": False}),
train_dataset=dataset,
reward_funcs=reward_func,
environment_factory={"coding": CodingEnv, "game": GameEnv},
)
trainer.train()奖励函数仍然通过 reward_kwargs["environments"] 接收每个示例的环境,因此可以根据环境类型进行分支处理(例如 isinstance(env, CodingEnv))。环境实例会在多个步骤之间复用(在回合之间重置),因此昂贵的 __init__ 只需支付一次,而不是每个步骤都支付。environment 字段由训练器消费,并且 不会 转发给 reset。
多模态工具响应
工具可以通过返回内容块列表,在文本之外同时返回图像。这在 VLM 智能体训练中非常有用,因为工具可以提供视觉反馈(例如,屏幕截图、图表、摄像头捕获)。
from PIL import Image
def take_screenshot() -> list:
"""
Takes a screenshot of the current screen.
Returns:
The screenshot image with a description.
"""
img = Image.open("screenshot.png")
return [{"type": "image", "image": img}, {"type": "text", "text": "Here is the screenshot."}]返回的图像会自动注入到对话中,并传递给 VLM 用于后续的生成轮次。
支持的模型
已测试:
- Beam — 例如
reflection/Beam-1.0-501B-A23B - DeepSeek-R1 — 例如
deepseek-ai/DeepSeek-R1 - Gemma4 — 例如
google/gemma-4-E2B-it - GLM-4-MoE(4.5、4.6 或 4.7)——例如
zai-org/GLM-4.7 - GPT-OSS — 例如
openai/gpt-oss-20b - Llama 3.1 — 例如
meta-llama/Llama-3.1-8B-Instruct - Llama 3.2 — 例如
meta-llama/Llama-3.2-3B-Instruct - Qwen2.5 — 例如
Qwen/Qwen2.5-0.5B-Instruct - Qwen3 — 例如
Qwen/Qwen3-0.6B - Qwen3-VL — 例如
Qwen/Qwen3-VL-2B-Instruct - Qwen3.5 — 例如
Qwen/Qwen3.5-2B - Qwen3.6 — 例如
Qwen/Qwen3.6-35B-A3B
不保证与所有 LLM 兼容。如果您认为某个模型应当被支持,欢迎在 GitHub 上提交 issue——或者更好的是,提交一个包含所需更改的 pull request。
环境集成
所有环境都接入同一个 environment_factory 插槽,因此在 TRL 层面它们可以互换——选择与你的任务生态相匹配的那个即可:
| 集成 | 它是什么 | 使用时 |
|---|---|---|
| OpenEnv | 开放环境标准(Gymnasium 风格 API,通过 WebSocket 提供或容器化执行),由 Hugging Face 和社区提供支持。 | 您正在使用 Hub 上现成的 OpenEnv 环境,或者基于开放标准定义自己的环境(例如 Wordle、Sudoku、Catch)。 |
| OpenReward | 与 ORS 语言环境的集成(openreward.ai 目录或您自己的 ORS 服务器);任务 和 奖励通过 HTTP 提供。 | 您希望针对 ORS 环境进行训练:可以是目录(例如 Eigent/SETA),也可以是您在自有基础设施上自托管的环境,或您正在开发的本地服务器。 |
| Harbor | 与 Harbor 任务套件的集成:每个任务包含一条指令、一个真实的沙箱镜像(docker、e2b……)以及一个沙箱内的验证器。 | 您希望针对 Harbor 任务套件进行训练:该套件是一棵任务树,每个任务都是一个自包含的沙箱加上验证器(例如,一个数据分析智能体在沙箱中探索文件并写出答案,由评分器进行检查)。 |
训练视觉语言模型
GRPO 支持在包含文本和图像的多模态数据集上训练视觉语言模型(VLM)。
支持的模型
已测试:
- Gemma3 — 例如
google/gemma-3-4b-it - LLaVA-NeXT — 例如
llava-hf/llava-v1.6-mistral-7b-hf - Qwen2-VL — 例如
Qwen/Qwen2-VL-2B-Instruct - Qwen2.5-VL — 例如
Qwen/Qwen2.5-VL-3B-Instruct - SmolVLM2 — 例如
HuggingFaceTB/SmolVLM2-2.2B-Instruct
无法保证与所有 VLM 的兼容性。如果您认为某个模型应当被支持,欢迎在 GitHub 上提交 issue——或者更好的是,提交一个包含所需更改的 pull request。
快速入门
使用 grpo_vlm.py 对 VLM 进行微调。在 lmms-lab/multimodal-open-r1-8k-verified 上训练的示例命令:
torchrun --nproc_per_node 8 examples/grpo_visual_math/grpo_visual_math.py \
--deepspeed examples/deepspeed_configs/zero3.json \
--model_name_or_path Qwen/Qwen2.5-VL-3B-Instruct \
--output_dir grpo-Qwen2.5-VL-3B-Instruct \
--learning_rate 1e-5 \
--dtype bfloat16 \
--max_completion_length 1024 \
--use_vllm \
--vllm_mode colocate \
--use_peft \
--lora_target_modules "q_proj", "v_proj" \
--log_completions配置技巧
- 在视觉-语言投影层上使用 LoRA
- 启用 4 位量化以降低内存使用
- VLM 对内存需求较高 — 请从较小的批处理大小开始
- 大多数模型都兼容 vLLM(
server和colocate模式)
数据集格式
每个训练样本应包含:
prompt:通过处理器的聊天模板格式化的文本image/images:PIL Image 或 PIL Image 列表
Trainer 会通过模型的图像处理器自动处理图像到张量的转换。
GRPOTrainer
类 trl.GRPOTrainer
< source >( model: str | PreTrainedModel | PeftModelreward_funcs: str | transformers.modeling_utils.PreTrainedModel | collections.abc.Callable[..., list[float | None]] | list[str | transformers.modeling_utils.PreTrainedModel | collections.abc.Callable[..., list[float | None]]] | None = Noneargs: trl.trainer.grpo_config.GRPOConfig | None = Nonetrain_dataset: datasets.arrow_dataset.Dataset | datasets.iterable_dataset.IterableDataset | None = Noneeval_dataset: datasets.arrow_dataset.Dataset | datasets.iterable_dataset.IterableDataset | datasets.dataset_dict.DatasetDict | datasets.dataset_dict.IterableDatasetDict | dict[str, datasets.arrow_dataset.Dataset | datasets.iterable_dataset.IterableDataset] | None = Noneprocessing_class: transformers.tokenization_utils_base.PreTrainedTokenizerBase | transformers.processing_utils.ProcessorMixin | None = Nonereward_processing_classes: transformers.tokenization_utils_base.PreTrainedTokenizerBase | list[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)quantization_config: BitsAndBytesConfig | None = Nonepeft_config: PeftConfig | None = Nonetools: list[collections.abc.Callable] | None = Nonerollout_func: collections.abc.Callable[[list[str], 'GRPOTrainer'], dict[str, typing.Any]] | None = Noneenvironment_factory: collections.abc.Callable[[], trl.trainer.grpo_trainer._SupportsReset] | dict[str, collections.abc.Callable[[], trl.trainer.grpo_trainer._SupportsReset]] | None = None )
参数
- model (
str或 PreTrainedModel 或 PeftModel) — 要训练的模型。可以是以下之一:- 一个字符串,可以是托管在 huggingface.co 模型仓库中的预训练模型的 model id,也可以是包含使用 save_pretrained 保存的模型权重的 目录 的路径,例如
'./my_model_directory/'。该模型使用<ModelArchitecture>.from_pretrained加载(其中<ModelArchitecture>由模型配置推导得出),并传入args.model_init_kwargs中的关键字参数。如果未在args.model_init_kwargs中指定dtype,则默认为float32。这与 from_pretrained 不同,在后者中(自 Transformers v5 起),dtype 是从模型配置中推断得出的。 - 一个 PreTrainedModel 对象。仅支持因果语言模型。
- 一个 PeftModel 对象。仅支持因果语言模型。
- 一个字符串,可以是托管在 huggingface.co 模型仓库中的预训练模型的 model id,也可以是包含使用 save_pretrained 保存的模型权重的 目录 的路径,例如
- reward_funcs (
RewardFunc | list[RewardFunc], 可选) — 用于计算奖励的奖励函数。为了计算奖励,我们会使用提示词和补全内容调用所有奖励函数,并将奖励求和。当奖励由环境通过environment_factory((见下文)提供时,可以省略此参数。可以是以下任一形式:-
单个奖励函数,例如:
-
字符串:model ID,即托管在 huggingface.co 模型仓库中的预训练模型,或指向使用 save_pretrained 保存模型权重的目录的路径,例如
'./my_model_directory/'。该模型通过 from_pretrained 加载,并设置num_labels=1以及args.model_init_kwargs中的关键字参数。 -
一个 PreTrainedModel 对象:仅支持序列分类模型。
-
自定义奖励函数:该函数会接收提示词和生成的补全内容,以及数据集中的其他附加列。它应返回一个奖励列表。自定义奖励函数可以是同步的,也可以是异步的,并且当奖励不适用于某些样本时,也可以返回
None。这在多任务训练中非常有用,因为不同的奖励函数适用于不同类型的样本。当某个奖励函数对某个样本返回None时,该奖励函数将被排除在该样本的奖励计算之外。更多详情,请参阅 使用自定义奖励函数。Trainer 的状态也会传递给奖励函数。Trainer 的状态是 TrainerState 的一个实例,可以通过访问奖励函数签名中的
trainer_state参数来获取。
-
-
奖励函数列表,其中每个项可以独立为上述任意类型。允许在列表中混合使用不同类型(例如,字符串模型 ID 和自定义奖励函数)。
-
- args (GRPOConfig, 可选) —
此训练器的配置。如果为
None,则使用默认配置。 - train_dataset (Dataset 或 IterableDataset, 可选) —
用于训练的 Dataset。它必须包含一个名为
"prompt". 数据集中的其他列将被忽略。样本的格式可以是以下两种之一: 标准格式:每个样本包含纯文本。对话格式:每个样本包含结构化消息(例如 role 和 content)。只有在提供了 environment_factory 且环境拥有(或程序化生成)数据,并通过其 reset() 方法返回 prompt 时,才可以省略此参数。在这种情况下,必须设置 max_steps 以定义训练长度。当 train_dataset 是 IterableDataset(例如流式数据集)时,必须在训练参数中设置 max_steps,因为其长度无法推断,且需要总训练步数来限制训练循环并配置学习率调度器。仅当提供了
environment_factory且环境拥有(或程序化生成)数据,并从其reset()方法返回提示时,才可以省略。在这种情况下,必须设置max_steps以定义训练长度。当
train_dataset是一个 IterableDataset(例如流式数据集)时,必须在训练参数中设置max_steps,因为其长度无法推断,而确定训练循环的上限并配置学习率调度器需要知道总的训练步数。 - eval_dataset (Dataset、IterableDataset、DatasetDict、IterableDatasetDict 或
dict[str, Dataset | IterableDataset]) — 用于评估的数据集。它必须满足与train_dataset相同的要求。 - processing_class (PreTrainedTokenizerBase、ProcessorMixin、可选) —
用于处理数据的处理类。填充侧必须设置为“left”。如果为
None,则使用 from_pretrained 从模型名称加载处理类。必须设置填充标记tokenizer.pad_token。如果处理类未设置填充标记,则默认使用tokenizer.eos_token。 - reward_processing_classes (PreTrainedTokenizerBase 或
list[PreTrainedTokenizerBase], 可选) — 与在reward_funcs. 中指定的奖励函数相对应的处理类。可以是以下形式之一:- 单个处理类:当
reward_funcs仅包含一个奖励函数时使用。 - 处理类列表:必须与
reward_funcs中奖励函数的顺序和长度一致。 如果设置为None,或者列表中对应 PreTrainedModel 的元素为None,则会使用 from_pretrained 自动加载该模型的 tokenizer。对于reward_funcs中属于自定义奖励函数(而非 PreTrainedModel)的元素,reward_processing_classes中对应的条目将被忽略。
- 单个处理类:当
- callbacks (列表 TrainerCallback, 可选) —
用于自定义训练循环的回调列表。这些回调将被添加到 此处.
如果要移除其中一个默认使用的回调,请使用 remove_callback 方法。
- optimizers (
tuple[torch.optim.Optimizer | None, torch.optim.lr_scheduler.LambdaLR | None],可选,默认为(None, None)) — 一个包含要使用的优化器和调度器的元组。默认情况下,将在您的模型上使用AdamW的实例,并使用由args控制的、通过 get_linear_schedule_with_warmup 给出的调度器。 - quantization_config (BitsAndBytesConfig, 可选) —
从模型标识符加载模型时使用的量化配置。与
peft_config结合用于 QLoRA 训练。如果模型已经实例化,则忽略此配置。 - peft_config (PeftConfig,可选) —
用于包装模型的 PEFT 配置。如果为
None,则不包装模型。 - tools(
Callable列表,可选)— 一个可调用工具函数(同步或异步)的列表,模型可在生成过程中调用这些工具。每个工具应是一个标准的 Python 函数,具有正确类型提示的参数和返回值,以及一个 Google 风格的 docstring,用于描述其用途、参数和返回值。更多详情,请参阅:https://huggingface.co/docs/transformers/en/chat_extras#passing-tools。模型利用函数的名称、类型提示和 docstring 来确定如何调用它。请确保模型的 chat template 支持工具使用,并且该模型已针对工具调用进行了微调。 - rollout_func (
RolloutFunc, 可选) — 用于生成补全的函数。它接收分配给当前进程的提示列表以及 trainer 实例。它必须返回一个包含"prompt_ids"、"completion_ids"和"logprobs"字段的字典,并可选择返回"logprob_token_ids"(形状与"logprobs"相同)。其他任何字段都会转发给奖励函数。该函数接收的是每个进程的原始提示切片,没有重复;它负责为每个提示返回正确数量的补全(参见 trainer 上的num_generations/num_generations_eval)。此功能处于实验阶段,可能会随时更改或移除,恕不另行通知。 - environment_factory (
EnvironmentFactory或dict[str, EnvironmentFactory], 可选) — 一个可调用对象,用于创建并返回环境实例;或一个将环境名称映射到此类可调用对象的字典。环境类应定义可在生成期间作为工具调用的方法。每个方法都应符合上述tools中描述的相同要求。环境还必须实现一个可调用reset方法,用于在生成之间重置状态。reset方法应返回None或字符串:当返回字符串时,该字符串会在生成前追加到最后一条用户消息中。环境还可以定义一个get_reward方法,该方法不接受参数并返回float: :如果存在该方法,则环境拥有奖励,并且get_reward会在每个完成的 rollout 中被调用一次,根据环境的内部状态对其进行评分。它作为额外的奖励来源(权重为 1,记录在环境的类名下),与reward_funcs, 此时变为可选。使用单个可调用对象时,所有示例都使用相同的环境,每个 rollout 对应一个实例,从而确保它们的交互相互隔离。使用字典时,每个示例必须包含一个
environment字段,通过名称选择其环境,并且只有该环境的工具会暴露在其提示中——这使得单次运行可以混合不同的任务(例如,一个编码环境和一个游戏)。此功能处于实验阶段,可能会随时更改或移除,恕不另行通知。
Trainer for the Group Relative Policy Optimization (GRPO) method. This algorithm was initially proposed in the paper DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models.
示例:
>>> from trl import GRPOTrainer
>>> from trl.rewards import accuracy_reward
>>> from datasets import load_dataset
>>> dataset = load_dataset("trl-lib/DeepMath-103K", split="train")
>>> trainer = GRPOTrainer(
... model="Qwen/Qwen2.5-0.5B-Instruct",
... reward_funcs=accuracy_reward,
... train_dataset=dataset,
... )
>>> trainer.train()训练
< source >( resume_from_checkpoint: str | bool | None = Nonetrial: optuna.Trial | dict[str, Any] | None = Noneignore_keys_for_eval: list[str] | None = None ) → ~trainer_utils.TrainOutput
参数
- resume_from_checkpoint (
str或bool,可选) — 如果为str,则为之前Trainer实例保存的检查点的本地路径。如果为bool且等于True,则加载之前Trainer实例保存在 args.output_dir 中的最后一个检查点。如果存在,训练将从此处加载的模型/优化器/调度器状态中恢复。 - trial (
optuna.Trial或dict[str, Any],可选) — 用于超参数搜索的试验运行或超参数字典。 - ignore_keys_for_eval (
list[str],可选) — 在训练期间收集预测结果以进行评估时,应忽略的模型输出(如果输出是字典)中的键列表。
返回值
~trainer_utils.TrainOutput
包含全局步数、训练损失和指标的 Object。
主要训练入口。
将保存模型,以便您可以使用 from_pretrained() 重新加载它。
仅从主进程保存。
push_to_hub
< source >( commit_message: str | None = 'End of training'blocking: bool = Truetoken: str | None = Nonerevision: str | None = None**kwargs )
将 self.model 和 self.processing_class 上传到 🤗 模型库中的仓库 self.args.hub_model_id。
GRPOConfig
类 trl.GRPOConfig
< 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: transformers.trainer_utils.SchedulerType | str = 'linear'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 = 10logging_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 = Falserestore_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 | None = Falselabel_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 = Nonetrust_remote_code: bool = Falserouter_aux_loss_coef: float | None = Nonedisable_dropout: bool = Falsecast_lm_head_to_fp32: bool = Falsenum_generations: int | None = 8num_generations_eval: int | None = Nonemax_completion_length: int | None = 512ds3_gather_for_generation: bool = Trueshuffle_dataset: bool | None = Truepad_to_multiple_of: int | str | None = 'auto'generation_batch_size: int | None = Nonesteps_per_generation: int | None = Nonetemperature: float = 1.0top_p: float = 1.0top_k: int = 0min_p: float | None = Nonegeneration_kwargs: dict | str | None = Nonechat_template_kwargs: dict | str | None = Nonerepetition_penalty: float = 1.0cache_implementation: str | None = Noneuse_vllm: bool = Falsevllm_mode: str = 'colocate'vllm_model_impl: str = 'vllm'vllm_enable_sleep_mode: bool = Falsevllm_structured_outputs_regex: str | None = Nonevllm_server_base_url: str | None = Nonevllm_server_host: str = '0.0.0.0'vllm_server_port: int = 8000vllm_server_timeout: float = 240.0vllm_group_port: int = 51216vllm_gpu_memory_utilization: float = 0.3vllm_max_model_length: int | None = Nonevllm_tensor_parallel_size: int = 1beta: float = 0.0num_iterations: int = 1epsilon: float = 0.2delta: float | None = Noneepsilon_high: float | None = Nonesapo_temperature_neg: float = 1.05sapo_temperature_pos: float = 1.0vespo_k_pos: float = 2.0vespo_lambda_pos: float = 3.0vespo_k_neg: float = 3.0vespo_lambda_neg: float = 2.0importance_sampling_level: str = 'token'reward_weights: list[float] | None = Nonemulti_objective_aggregation: str = 'sum_then_normalize'scale_rewards: str = 'group'loss_type: str = 'dapo'mask_truncated_completions: bool = Falsesync_ref_model: bool = Falseref_model_mixup_alpha: float = 0.6ref_model_sync_steps: int = 512top_entropy_quantile: float = 1.0entropy_coef: float = 0.0use_adaptive_entropy: bool = Falseentropy_coef_min: float = 0.0entropy_coef_max: float = 1.0entropy_coef_delta: float = 0.005entropy_target: float = 0.2max_tool_calling_iterations: int | None = Nonevllm_importance_sampling_correction: bool = Truevllm_importance_sampling_mode: str = 'sequence_mask'vllm_importance_sampling_clip_max: float | None = 3.0vllm_importance_sampling_clip_min: float | None = Noneoff_policy_mask_threshold: float | None = Noneuse_bias_correction_kl: bool = Truelog_completions: bool = Falselog_multimodal: bool = Truenum_completions_to_print: int | None = Nonelog_unique_prompts: bool = Falselog_completions_hub_repo: str | None = Noneuse_transformers_continuous_batching: bool = Falsetransformers_continuous_batching_config: dict | str | None = Noneuse_transformers_paged: bool = Falsevllm_importance_sampling_cap: float | None = None )
控制模型和参考模型的参数
- model_init_kwargs (
str或dict[str, Any],可选) — 用于 from_pretrained 的关键字参数,当 GRPOTrainer 的model参数以字符串形式提供时使用。加载处理类时也会使用revision的值。 - trust_remote_code (
bool,可选,默认为False) — 是否允许加载包含自定义 Python 代码的模型和分词器。此参数会传递给 from_pretrained 和 from_pretrained。 同样适用于奖励模型和奖励分词器的加载。 - router_aux_loss_coef (
float, 可选) — 混合专家(MoE)模型中负载均衡辅助损失的系数,以该权重添加到训练损失中。如果未设置,则使用模型配置中声明的值。设置为0.0可将其禁用。与非 MoE 模型一起使用时会失败。 - disable_dropout (
bool,可选,默认为False) — 是否禁用模型中的 dropout。这在配合参考模型进行训练时非常有用,因为它可以防止模型对相同的输入生成不同的 logprobs。 - cast_lm_head_to_fp32 (
bool, 可选,默认为False) — 是否将策略模型和参考模型的语言建模头转换为 float32。这是 ScaleRL 配方所推荐的做法。仅当模型的词嵌入层和语言建模头层未绑定(即模型配置中的tie_word_embeddings为 False)时,才支持此标志。
控制数据预处理的参数
- remove_unused_columns (
bool,可选,默认为False) — 是否仅保留数据集中的"prompt"列。如果您使用的自定义奖励函数需要"prompts"和"completions"以外的任何列,则应保持此参数为False。 - num_generations (
int, 可选, 默认为8) — 每个提示词采样的生成数量。有效批次大小(num_processes * per_device_batch_size * gradient_accumulation_steps)必须能被该值整除。- gradient_accumulation_steps) 必须能被该值整除。
- num_generations_eval (
int, 可选) — 评估期间采样的生成数量。这允许在评估期间使用更少的生成数量以节省计算资源。如果为None,则使用num_generations的值。 - max_completion_length (
int或None,可选,默认为512) — 生成补全的最大长度。 - ds3_gather_for_generation (
bool,可选,默认为True) — 此设置适用于 DeepSpeed ZeRO-3。如果启用,策略模型权重将在生成时进行聚合,从而提升生成速度。但是,禁用此选项允许训练超出单个 GPU 显存容量的模型,代价是生成速度变慢。禁用此选项与 vLLM 生成不兼容。 - shuffle_dataset (
bool,可选,默认为True) — 是否打乱训练数据集。 - pad_to_multiple_of (
int或str,可选,默认为"auto") — 如果设置,提示词 ID 和补全 ID 将被填充为该值的倍数。"auto"在 Neuron (AWS Trainium) 上填充为 128 的倍数,因为 Neuron 针对每种输入形状只编译一次,而在其他平台上不进行填充。
控制生成的参数
- generation_batch_size (
int, 可选) — 用于生成的批大小。如果为None,则默认为有效训练批大小:per_device_train_batch_size * num_processes * steps_per_generation。换句话说,每个优化步骤处理一个生成批次。与steps_per_generation互斥。 - steps_per_generation (
int,可选) — 每次生成的步数。如果为None,则默认为gradient_accumulation_steps。与generation_batch_size互斥。 - temperature (
float,可选,默认为1.0) — 用于采样的温度。温度越高,生成的补全内容越随机。 - top_p (
float,可选,默认为1.0) — 用于控制所考虑的前几个 token 的累积概率的浮点数。取值必须在 (0, 1] 范围内。设置为1.0表示考虑所有 token。 - top_k (
int,可选,默认为0) — 用于 top-k 过滤时保留的最高概率词汇表 token 数量。如果为0,则禁用 top-k 过滤,并考虑所有 token。 - min_p (
float, 可选) — 最小 token 概率,该值会按最可能 token 的概率进行缩放。它必须是0.0和1.0之间的值。典型值在0.01-0.2范围内。 - generation_kwargs (
dict[str, Any], 可选) — 在采样补全时传递给 GenerationConfig(如果使用 transformers)或SamplingParams(如果使用 vLLM)的额外关键字参数。可用于进一步自定义 生成行为,例如设置suppress_tokens、num_beams等。如果其中包含与其他生成参数(如min_p、top_p等)冲突的键,则会覆盖它们。 - chat_template_kwargs (
dict[str, Any], 可选) — 在生成补全时传递给apply_chat_template函数的其他关键字参数。 - repetition_penalty (
float,可选,默认为1.0) — 一个浮点数,根据新 token 是否出现在提示词和迄今为止生成的文本中来对其进行惩罚。 值 >1.0会鼓励模型使用新的 token,而值 <1.0会鼓励模型重复使用 token。 - cache_implementation (
str, 可选) — 当use_vllm设置为False时,用于加速生成的缓存方法实现。
控制由 vLLM 驱动的生成加速的参数
- use_vllm (
bool,可选,默认为False) — 是否使用 vLLM 来生成补全。如果设置为True,训练器将使用 vLLM 进行生成,而不是默认的 model.generate()。需要安装vllm。 - vllm_mode (
str, 可选, 默认为"colocate") — 当use_vllm设置为True. 时,用于 vLLM 集成的模式。必须是"server"或"colocate"."server":训练器将把生成请求发送到独立的 vLLM 服务器。请确保 vLLM 服务器正在运行(使用vllm serve启动)。"colocate":vLLM 将在同一进程中运行,并共享用于训练的 GPU。这避免了部署独立服务器的需求,但可能会与训练过程产生资源争用。
- vllm_model_impl (
str,可选,默认为"vllm") — 用于 vLLM 的模型实现。必须是"transformers"或"vllm"之一。"transformers":使用transformers后端作为模型实现。"vllm":使用vllm库作为模型实现。 - vllm_enable_sleep_mode (
bool,可选,默认为False) — 启用 vLLM 睡眠模式,以便在优化器步骤期间卸载权重/缓存。这可以保持较低的 GPU 内存占用,但唤醒引擎会增加主机与设备之间的传输延迟。 - vllm_structured_outputs_regex (
str, 可选) — 用于 vLLM 结构化输出的正则表达式。如果为None(默认值),则禁用结构化输出。
用于控制 vLLM 服务器的参数(仅在 `vllm_mode` 为 `"server"` 时使用)
- vllm_server_base_url (
str, 可选) — vLLM 服务器的基础 URL(例如"http://localhost:8000")。如果提供了该参数,vllm_server_host和vllm_server_port将被忽略。 - vllm_server_host (
str,可选,默认为"0.0.0.0") — 要连接的 vLLM 服务器的主机地址。如果提供了vllm_server_base_url,则忽略此参数。 - vllm_server_port (
int,可选,默认为8000) — 要连接的 vLLM 服务器端口。如果提供了vllm_server_base_url,则忽略此参数。 - vllm_server_timeout (
float, 可选, 默认值为240.0) — 等待 vLLM 服务器启动的总超时时间(秒)。如果超时后服务器仍未启动,则会引发ConnectionError。 - vllm_group_port (
int, 可选,默认为51216) — 权重更新组的端口号。用于与 vLLM 服务器通信。除非端口被占用,否则无需更改。
控制共置 vLLM 执行的参数(仅在 `vllm_mode` 为 `"colocate"` 时使用)
- vllm_gpu_memory_utilization (
float,可选,默认值为0.3) — 控制 vLLM 的 GPU 内存利用率。此设置仅在vllm_mode设置为"colocate"时生效。如果您使用的是vllm_mode="server",则必须在通过--vllm_gpu_memory_utilization标志启动 vLLM 服务器时单独传递此参数。 - vllm_max_model_length (
int, 可选) — vLLM 的上下文窗口。请将其设置为至少等于数据集中的最大提示长度加上max_completion_length;如果省略,则从模型配置中推断。 - vllm_tensor_parallel_size (
int,可选,默认为1) — 控制 vLLM 的张量并行大小。此设置仅在vllm_mode设置为"colocate"时生效。如果您使用的是vllm_mode="server",则必须在通过--vllm_tensor_parallel_size标志启动 vLLM 服务器时单独传递此参数。
控制训练的参数
- beta (
float,可选,默认为0.0) — KL 系数。如果为0.0(默认值),则不会加载参考模型,从而减少内存占用并提高训练速度。DeepSeek-R1 incentivizes reasoning in LLMs through reinforcement learning 使用0.001的值。 - num_iterations (
int,可选,默认为1) — 每个批次的迭代次数(在算法中记为 μ)。 - epsilon (
float, 可选, 默认为0.2) — 用于裁剪的 Epsilon 值。 - delta (
float, 可选) — 当设置为浮点数时,启用双侧 GRPO 损失的上限裁剪。如果为None(默认值),则使用标准 GRPO 裁剪。启用时,建议其值大于1 + ε。该方法在 INTELLECT-2 技术报告中引入。 - epsilon_high (
float, 可选) — 用于裁剪的上限 epsilon 值。如果未指定,则默认与参数epsilon中指定的下限值相同。论文 DAPO 建议设置为0.28。 当与loss_type='cispo'一起使用时,这对应于 ScaleRL 论文 中指定的 ε_max 参数,其默认值为推荐值5.0。 - sapo_temperature_neg (
float, 可选,默认为1.05) — 用于sapo损失函数中优势分数非正的 token 的温度。该参数在 Soft Adaptive Policy Optimization 论文 中引入。 - sapo_temperature_pos (
float, 可选,默认为1.0) — 用于sapo损失函数中优势分数为正值的 token 的温度。该参数在 Soft Adaptive Policy Optimization 论文 中引入。 - vespo_k_pos (
float,可选,默认为2.0) — 正优势对应的 k 参数,它是 VESPO 损失中的幂指数。控制我们如何降低重要性权重较低的样本的权重(当重要性采样比率 < 1 时)。 - vespo_lambda_pos (
float, 可选,默认为3.0) — 正优势(positive advantages)的 lambda 参数,它是 VESPO 损失中的衰减因子。控制我们如何降低具有高重要性权重(当重要性采样比率 > 1 时)的样本的权重。 - vespo_k_neg (
float, 可选, 默认值为3.0) — 负优势值的 k 参数,它是 VESPO 损失中的幂指数。控制我们如何降低重要性权重较低的样本的权重(当重要性采样比率 < 1 时)。 - vespo_lambda_neg (
float, 可选, 默认值为2.0) — 负优势(negative advantages)的 lambda 参数,它是 VESPO 损失中的指数衰减因子。控制对具有高重要性权重(当重要性采样比率 > 1 时)的样本进行降权的激进程度。 - importance_sampling_level (
str, 可选,默认为"token") — 控制重要性采样比率是在"token"级别还是"sequence"级别计算。"token"保留原始的逐 token 对数概率比率(每个 token 一个权重)。"sequence"对有效 token 的对数概率比率取平均,从而为每个序列生成一个比率。GSPO 论文表明,序列级采样通常能带来更稳定的训练,并与序列级奖励更好地对齐。 - reward_weights (
list[float], 可选) — 每个奖励函数的权重。必须与奖励函数的数量相匹配。如果为None,则所有奖励的权重均相等,权重为1.0。 - multi_objective_aggregation (
str, 可选, 默认为"sum_then_normalize") — 聚合多个奖励函数的方法。支持的值为:"sum_then_normalize"(默认):首先对每个奖励函数的加权奖励求和,然后应用由 scale_rewards 指定的奖励缩放/归一化(详见 scale_rewards)。"normalize_then_sum":首先对每个奖励函数在生成之间(在每个组内)进行归一化/缩放,然后使用指定的权重对归一化后的奖励求和。在形成优势时,聚合后的奖励会在批次级别进行归一化。这是论文 GDPO: Group reward-Decoupled Normalization Policy Optimization for Multi-reward RL Optimization 中建议的方法。"sum_then_normalize"(默认值):首先对每个奖励函数的加权奖励求和,然后按照scale_rewards的指定应用奖励缩放/归一化(详见scale_rewards)。"normalize_then_sum":首先对每一代(在每个组内)的每个奖励函数进行归一化/缩放,然后使用指定的权重对归一化后的奖励进行求和。在形成优势值时,聚合后的奖励会在批次级别进行归一化。这是论文 GDPO: Group reward-Decoupled Normalization Policy Optimization for Multi-reward RL Optimization 中建议的方法。
- scale_rewards (
str或bool, 可选, 默认为"group") — 指定奖励的缩放策略。支持的值为:True或"group"(默认值):奖励会根据每个组内的标准差进行缩放,确保组内具有单位方差。"batch":奖励会根据整个批次的标准差进行缩放,如 PPO Lite 论文中所建议的那样。False或"none":不应用任何缩放。Dr. GRPO 论文建议不对奖励进行缩放,因为按标准差缩放会引入问题级别的难度偏差。
- loss_type (
str, 可选, 默认为"dapo") — 指定要使用的损失函数形式。支持的值为:"grpo":通过对序列长度进行归一化来聚合 token 级别的损失。由于存在长度偏差,不推荐使用此方法——该方法倾向于偏好具有正优势值的较短补全和具有负优势值的较长补全。"dr_grpo":通过全局常数进行归一化来聚合 token 级别的损失。该方法在 Dr. GRPO 论文中提出,旨在消除长度偏差。该常数的值对应于 max_completion_length。"dapo"(默认值):通过全局累积批次中活跃 token 的数量进行归一化来聚合 token 级别的损失。该方法在 DAPO 论文中提出,旨在消除长度偏差。"bnpo":通过本地批次中活跃 token 的数量进行归一化来聚合 token 级别的损失。请注意,归一化仅在本地批次上进行,因此尽管有效批次大小恒定,结果可能会因本地批次大小而异。当使用 per_device_train_batch_size==1 时,损失等同于 GRPO 损失。"cispo":对重要性采样权重进行裁剪,而不是对优势值缩放后的重要性权重进行裁剪。裁剪后的权重随后与优势值以及策略模型的对数概率相乘。单个 token 的损失通过全局累积批次中活跃 token 的数量进行归一化来聚合。该方法在 MiniMax-M1 论文中提出。"sapo":软自适应策略优化(Soft Adaptive Policy Optimization)损失,如 Soft Adaptive Policy Optimization 论文中所述。用平滑的、温度控制的门控机制替代硬裁剪,在保留有用学习信号的同时自适应地衰减离策略更新。"luspo":无长度偏差的序列策略优化(Length-Unbiased Sequence Policy Optimization)损失。这是一种序列级别的损失,会根据序列长度对每个序列的损失进行缩放。这是对 GSPO 的修改,需要 importance_sampling_level="sequence"。在 LUSPO 论文中提出。"vespo":变分序列级软策略优化(Variational Sequence-Level Soft Policy Optimization)。用平滑的、非对称的 Gamma 加权函数替代硬裁剪,直接应用于序列级重要性权重。在 VESPO 论文中提出。"grpo":通过对序列长度进行归一化来聚合 token 级别的损失。由于存在长度偏差,不推荐此方法——该方法倾向于偏好具有正优势值的较短补全和具有负优势值的较长补全。"dr_grpo":通过全局常数进行归一化来聚合 token 级别的损失。该方法在 Dr. GRPO 论文 中提出,用于消除长度偏差。该常数的值对应于max_completion_length。"dapo"(默认值):通过全局累积批次中活跃 token 的数量对 token 级损失进行归一化,从而聚合损失。该方法在 DAPO 论文 中提出,旨在消除长度偏差。"bnpo":通过本地批次中活跃 token 的数量对 token 级损失进行归一化,从而聚合这些损失。请注意,归一化仅在本地批次上进行,因此尽管有效批次大小保持不变,结果仍可能因本地批次大小不同而略有差异。当使用per_device_train_batch_size==1时,该损失与 GRPO 损失等效。"cispo":对重要性采样权重进行裁剪,而不是对优势缩放后的重要性采样权重进行裁剪。随后,将裁剪后的权重与优势以及策略模型的对数概率相乘。单个 token 的损失通过全局累积批次中活跃 token 的数量进行归一化来聚合。该方法在 MiniMax-M1 论文 中提出。"sapo":Soft Adaptive Policy Optimization 损失,如Soft Adaptive Policy Optimization 论文中所述。用平滑的、温度控制的门控机制替代硬截断,在保留有用学习信号的同时自适应地衰减离策略更新。"luspo":Length-Unbiased Sequence Policy Optimization 损失。这是一种序列级损失,会根据每个序列的长度对其损失进行缩放。这是对 GSPO 的改进,需要设置importance_sampling_level="sequence"。该损失在 LUSPO 论文 中提出。"vespo":变分序列级软策略优化(Variational Sequence-Level Soft Policy Optimization)。用一种平滑的、非对称的 Gamma 加权函数直接作用于序列级重要性权重,以替代硬截断。该方法在 VESPO 论文 中提出。
- mask_truncated_completions (
bool,可选,默认为False) — 启用后,被截断的补全内容将被排除在损失计算之外,从而避免其受到错误惩罚并在训练过程中引入噪声。根据 DAPO 论文,这是保证训练稳定性的良好实践。 - sync_ref_model (
bool,可选,默认为False) — 是否每隔ref_model_sync_steps步使用ref_model_mixup_alpha参数将参考模型与当前活动模型进行同步。此同步机制源自 TR-DPO 论文。 - ref_model_mixup_alpha (
float,可选,默认为0.6) — 来自 TR-DPO 论文的 α 参数,用于控制更新过程中当前策略与先前参考策略之间的混合比例。参考策略根据以下公式更新:π_ref = α * π_θ + (1 - α) * π_ref_prev。要使用此参数,必须将sync_ref_model=True设置为sync_ref_model=True。 - ref_model_sync_steps (
int,可选,默认为512) — 来自 TR-DPO 论文的 τ 参数,用于确定当前策略与参考策略同步的频率。要使用此参数,必须 设置sync_ref_model=True。 - top_entropy_quantile (
float,可选,默认为1.0) — 来自 Beyond the 80/20 Rule 的 ρ 参数。在策略损失项中,仅保留每个序列位置上概率分布熵值最高的前 ρ 分位数 token,从而提升效果。取值范围:[0.0-1.0]。值为0.0时,仅保留熵值最高的 token;1.0时保留所有 token。论文建议取值为0.2。若与mask_truncated_completions=True一起使用,则仅考虑未截断补全中的 token。 - entropy_coef (
float,可选,默认为0.0) — 损失函数中熵正则化项的系数。正值会添加一个熵奖励,通过防止策略坍缩为近确定性输出来鼓励探索。无论loss_type为何,该奖励始终为每 token 的平均熵;它不会根据损失类型的策略归一化进行重新缩放,因此entropy_coef对所有损失类型具有相同的含义。当use_adaptive_entropy=True时,此值作为初始系数,并在每个优化器步骤中更新。设置为0.0(默认值)时无效。 - use_adaptive_entropy (
bool, 可选,默认为False) — 是否使用自适应熵控制,该功能在 Skywork-OR1 中引入。启用后,熵系数entropy_coef将在每个优化器步骤中更新:当当前熵低于entropy_target时,增加entropy_coef_delta;否则减少。仅当熵小于或等于entropy_target时,才会应用该系数。 - entropy_coef_min (
float,可选,默认为0.0) — 在使用自适应熵控制时,熵系数的下界。 - entropy_coef_max (
float,可选,默认为1.0) — 在使用自适应熵控制时,熵系数的上限。 - entropy_coef_delta (
float,可选,默认为0.005) — 在自适应熵控制期间,每个优化器步骤调整熵系数时的步长。 - entropy_target (
float,可选,默认为0.2) — 自适应熵控制所使用的目标平均每 token 熵(单位为 nats)。仅当当前熵小于或等于该值时,才会应用该系数。其测量范围与策略损失相同:默认情况下为所有补全 token,或者当top_entropy_quantile < 1.0时,仅为高熵子集。典型语言模型的每 token 熵通常在 2–10 nats 范围内,因此默认值0.2几乎不会触发正则化(仅在熵几乎完全坍缩时才会触发);建议将其设置为接近训练初期观察到的熵值(记录为entropy指标),以便在策略坍缩之前启用该奖励(如果使用top_entropy_quantile,请考虑 token 子集的影响)。 - max_tool_calling_iterations (
int, 可选) — 训练智能体时,工具调用轮次的最大数量。如果为None,则没有上限,生成将在以下情况停止:模型生成了一个不包含工具调用的响应轮次;补全内容(所有轮次和工具结果)达到max_completion_length个 token;或者完整序列达到模型的最大长度(在vllm_mode="colocate"时为vllm_max_model_length,否则为模型的max_position_embeddings)。 - vllm_importance_sampling_correction (
bool, optional, defaults toTrue) — Whether to apply Importance Sampling (IS) to correct for the mismatch between vLLM completion logprobs and recomputed training logprobs. If set toFalse, no IS is applied regardless ofvllm_importance_sampling_mode. WhenTrue, the selected mode determines how the IS ratios are computed and constrained. Withtop_p < 1,top_k > 0ormin_p > 0, the recomputed logprobs are normalized over the candidate set each token was sampled from, which requiresvllm_mode="colocate"and vLLM 0.28 or later; otherwise, the IS ratios are biased. vLLM bounds that candidate set withtop_k, sotop_p < 1,min_p > 0and structured outputs, which restrict it to the tokens the grammar allows, requiretop_k > 0(e.g.top_k=512). Structured outputs, which would otherwise stall training, also requirevllm_mode="colocate"and vLLM 0.28 or later. vLLM also appliesrepetition_penaltyto the logprobs it returns, sorepetition_penalty != 1.0requiresvllm_importance_sampling_correction=False. - vllm_importance_sampling_mode (
str, 可选, 默认为"sequence_mask") — 指定在vllm_importance_sampling_correction=True. 可能的取值如下:"token_truncate":Token 级截断 IS。每个 Token 的比率被裁剪到 [C_min, C_max]。"token_mask":Token 级别的掩码 IS。超出 [C_min, C_max] 范围的每个 token 的比率将被设为零。"sequence_truncate":序列级截断重要性采样。将单个序列比率裁剪至 [C_min, C_max],并应用于该序列中的所有 token。"sequence_mask":序列级掩码 IS。比率超出 [C_min, C_max] 范围的序列将被掩码。
- vllm_importance_sampling_clip_max (
float,可选,默认值为3.0) —vllm_importance_sampling_mode使用的重要性采样上界 C_max。对于*_truncate模式,重要性比率将从上方裁剪至 C_max。对于*_mask模式,大于 C_max 的比率将被设为零。 - vllm_importance_sampling_clip_min (
float, 可选) —vllm_importance_sampling_mode使用的重要性采样下界 C_min。对于*_truncate模式,比率会从下方被截断至 C_min。对于*_mask模式,低于 C_min 的比率会被置为零。若要严格屏蔽低于 C_min 的比率且不设上界,请将vllm_importance_sampling_clip_max=None。 - off_policy_mask_threshold (
float, 可选) — 用于离策略序列掩码的阈值。如果为None,则禁用离策略序列掩码。当设置该值时,具有负优势和高 KL 散度的序列将被掩码,以稳定训练。此参数对应于 DeepSeek-V3.2 论文 中公式 9 的delta阈值。它需要一个正值(例如,0.5)。 - use_bias_correction_kl (
bool,可选,默认为True) — 是否将 KL 项乘以重要性采样比率,从而使 KL 梯度变为无偏的 reverse-KL 梯度,如 DeepSeek-V3.2 论文 中所述。只要beta != 0,此设置就会改变 KL 梯度,包括在 on-policy 情况下:由于该比率是可微的,即使其值恰好为 1,它也会影响梯度。无偏 reverse-KL 性质适用于importance_sampling_level="token";对于"sequence",序列级权重会被广播到每个 token 的 KL 上。
控制日志记录的参数
- log_completions (
bool,可选,默认为False) — 是否每隔logging_steps步记录一组 (prompt, completion) 对的样本。如果已安装rich,则会打印该样本。如果启用了wandb和/或trackio日志记录,则会将其记录到wandb和/或trackio。 - log_multimodal (
bool,可选,默认为True) — 是否将多模态内容(图像、视频等)与补全内容一起记录。当使用高分辨率多模态数据时,可禁用此选项以减小日志大小。 - num_completions_to_print (
int, 可选) — 使用rich打印的补全数量。如果为None,则记录所有补全。 - log_unique_prompts (
bool,可选,默认为False) — 是否记录唯一的提示词。如果为True,则仅记录唯一的提示词。如果为False,则记录所有提示词。 - log_completions_hub_repo (
str, 可选) — 用于保存补全结果的 Hugging Face Hub 仓库。应为一个完整的仓库名称,例如'username/reponame'或'orgname/reponame',或者仅为'reponame',在这种情况下,仓库将在当前登录的 Hugging Face 用户的命名空间中创建。请注意,除非您设置hub_private_repo=True或您的组织默认创建私有仓库,否则该仓库将是公开的。
控制由 Transformers 连续批处理驱动的生成加速的参数
- use_transformers_continuous_batching (
bool, 可选,默认为False) — 是否使用 transformers 的连续批处理引擎来生成补全。需要transformers>=5.8.0。 - transformers_continuous_batching_config (
dict, 可选) —ContinuousBatchingConfig的关键字参数。
已弃用的参数
GRPOTrainer 的配置类。
此类仅包含 GRPO 训练特有的参数。完整的训练参数列表,请参阅 TrainingArguments 文档。请注意,此类中的默认值可能与 TrainingArguments 中的不同。
使用 HfArgumentParser,我们可以将该类转换为 argparse 参数,从而在命令行中指定。
这些参数的默认值与 TrainingArguments 不同:
logging_steps:默认值为10,而非500。gradient_checkpointing:默认值为True,而非False。bf16:如果未设置fp16,则默认值为True,而不是False。learning_rate:默认值为1e-6,而非5e-5。