TRL documentation

CPO 训练器

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v1.17.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

CPO 训练器

model badge

概述

由 Haoran Xu、Amr Sharaf、Yunmo Chen、Weiting Tan、Lingfeng Shen、Benjamin Van Durme、Kenton Murray 和 Young Jin Kim 在论文 Contrastive Preference Optimization: Pushing the Boundaries of LLM Performance in Machine Translation 中提出的对比偏好优化(Contrastive Preference Optimization,CPO)。从宏观层面来看,CPO 旨在训练模型,使其在机器翻译(MT)任务中避免生成尚可但并不完美的译文。然而,CPO 是 DPO 损失的一种通用近似,因此也可应用于其他领域,例如聊天。

CPO 旨在缓解 SFT 的两个根本性缺陷。首先,SFT 通过最小化预测输出与黄金标准参考之间的差异来训练模型,这种方法本质上将模型性能的上限锁定在训练数据的质量水平上。其次,SFT 缺乏一种机制来防止模型拒绝翻译中的错误。CPO 的目标函数是从 DPO 的目标函数推导而来的。

快速入门

本示例演示了如何使用 CPO 方法训练模型。我们使用 Qwen 0.5B 模型 作为基础模型。我们使用来自 UltraFeedback 数据集 的偏好数据。您可以在这里查看该数据集的数据:

以下是用于训练模型的脚本:

# train_cpo.py
from datasets import load_dataset
from trl.experimental.cpo import CPOConfig, CPOTrainer
from transformers import AutoModelForCausalLM, AutoTokenizer

model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2-0.5B-Instruct")
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2-0.5B-Instruct")
train_dataset = load_dataset("trl-lib/ultrafeedback_binarized", split="train")

training_args = CPOConfig(output_dir="Qwen2-0.5B-CPO")
trainer = CPOTrainer(model=model, args=training_args, processing_class=tokenizer, train_dataset=train_dataset)
trainer.train()

使用以下命令执行该脚本:

torchrun --nproc_per_node 8 train_cpo.py

预期的数据集类型

CPO 需要一个偏好数据集。experimental.cpo.CPOTrainer 同时支持对话式和标准数据集格式。当提供对话式数据集时,训练器会自动将聊天模板应用于该数据集。

记录的指标

在训练和评估过程中,我们记录以下指标:

  • rewards/chosen:策略模型对已选响应的平均对数概率,按 beta 缩放
  • rewards/rejected:策略模型对拒绝响应的平均对数概率,乘以 beta
  • rewards/accuracies:所选奖励大于对应被拒绝奖励的频率均值
  • rewards/margins:所选奖励与对应被拒绝奖励之间的平均差值
  • nll_loss:策略模型针对所选回复的平均负对数似然损失

CPO 变体

简单偏好优化(SimPO)

Simple Preference Optimization(SimPO)由 Yu Meng、Mengzhou Xia 和 Danqi Chen 提出,这是一种比 DPO 更简单且更有效的偏好优化算法,且无需使用参考模型。SimPO 的关键设计包括:(1) 使用长度归一化的对数似然作为隐式奖励,以及 (2) 在 Bradley-Terry 排序目标中引入目标奖励间隔。官方代码可在 princeton-nlp/SimPO 中找到。

该论文的摘要如下:

直接偏好优化(DPO)是一种广泛使用的离线偏好优化算法,它重新参数化了基于人类反馈的强化学习(RLHF)中的奖励函数,以提升简洁性和训练稳定性。在这项工作中,我们提出了 SimPO,一种更简单但更有效的方法。SimPO 的有效性归因于一个关键设计:使用序列的平均对数概率作为隐式奖励。这种奖励公式与模型生成过程更加一致,并消除了对参考模型的需求,从而在计算和内存方面更加高效。此外,我们在 Bradley-Terry 目标中引入了目标奖励间隔,以鼓励获胜响应和失败响应之间产生更大的间隔,从而进一步提升算法性能。我们在各种最先进的训练设置中,包括 Mistral 和 Llama3 等基础模型和指令微调模型,将 SimPO 与 DPO 及其最新变体进行了比较。我们在广泛的指令遵循基准上进行了评估,包括 AlpacaEval 2、MT-Bench 以及近期具有挑战性的 Arena-Hard 基准。我们的结果表明,SimPO 在不显著增加响应长度的情况下,持续且显著地优于现有方法。具体而言,SimPO 在 AlpacaEval 2 上比 DPO 高出多达 6.4 分,在 Arena-Hard 上高出多达 7.5 分。我们表现最佳的模型基于 Llama3-8B-Instruct 构建,在 AlpacaEval 2 上取得了 44.7 的长度控制胜率——超越了排行榜上的 Claude 3 Opus,并在 Arena-Hard 上取得了 33.8 的胜率——使其成为最强的 8B 开源模型。

SimPO 损失已集成到 experimental.cpo.CPOTrainer 中,因为它是一种替代损失,可添加奖励间隔,支持长度归一化,并且不使用 BC 正则化。要使用此损失,只需在 experimental.cpo.CPOConfig 中开启 loss_type="simpo" 和 cpo_alpha=0.0,并将 simpo_gamma 设置为推荐值。

CPO-SimPO

我们还提供了 CPO 和 SimPO 的组合使用方式,以实现更稳定的训练并提升性能。有关更多详细信息,请参阅 CPO-SimPO GitHub。要使用此方法,只需在 experimental.cpo.CPOConfig 中设置 loss_type="simpo" 以及非零的 cpo_alpha 来启用 SimPO 即可。

AlphaPO

Aman Gupta、Shao Tang、Qingquan Song、Sirou Zhu、Jiwoo Hong、Ankan Saha、Viral Gupta、Noah Lee、Eunki Kim、Jason Zhu、Natesh Pillai 和 S. Sathiya Keerthi 提出的 AlphaPO — Reward shape matters for LLM alignment(AlphaPO)方法也在 experimental.cpo.CPOTrainer 中实现了。AlphaPO 是一种替代方法,它在 SimPO 损失的上下文中对奖励函数的形状进行变换。该论文的摘要如下:

基于人类反馈的强化学习(Reinforcement Learning with Human Feedback,RLHF)及其变体在有效对齐大型语言模型(LLMs)以遵循指令并体现人类价值观方面取得了巨大进展。最近,直接对齐算法(Direct Alignment Algorithms,DAAs)应运而生,它们通过直接将奖励表征为正在学习的策略的函数,从而跳过了 RLHF 中的奖励建模阶段。DAAs 的一些流行示例包括直接偏好优化(Direct Preference Optimization,DPO)和简单偏好优化(Simple Preference Optimization,SimPO)。这些方法通常存在似然位移(likelihood displacement)问题,即偏好响应的概率往往会被不必要地降低。在本文中,我们认为对于 DAAs 而言,奖励(函数)的形状至关重要。我们提出了 AlphaPO,这是一种新的 DAA 方法,它利用 α 参数来帮助改变奖励函数的形状,使其超越标准的对数奖励。AlphaPO 有助于对似然位移和过度优化保持细粒度的控制。与表现最佳的 DAAs 之一 SimPO 相比,AlphaPO 在 Mistral-7B 和 Llama3-8B 的指令版本上,将对齐性能相对提升了约 7% 到 10%,而在相同模型上,相较于 DPO 实现了 15% 到 50% 的相对提升。本文展示的分析与结果凸显了奖励形状的重要性,以及如何系统地改变它来影响训练动态,并提升对齐性能。

要在论文中描述的方式下使用该损失函数,我们可以设置 loss_type="alphapo",它会自动将 loss_type="simpo" 和 cpo_alpha=0.0 设置为推荐值,同时将 alpha 和 simpo_gamma 设置为 experimental.cpo.CPOConfig 中的推荐值。或者,您可以手动设置 loss_type="simpo"、cpo_alpha=0.0,并将 alpha 和 simpo_gamma 设置为推荐值。该方法的其他变体也是可行的,例如将 loss_type="ipo" 和 alpha 设置为任意非零值。

损失函数

CPO 算法支持多种损失函数。可以通过 experimental.cpo.CPOConfig 中的 loss_type 参数来设置损失函数。支持的损失函数如下:

loss_type=描述
"sigmoid"(默认)给定偏好数据,我们可以根据 Bradley-Terry 模型拟合一个二分类器。事实上,DPO 的作者提出通过对归一化似然使用 logsigmoid 上的 sigmoid 损失来拟合逻辑回归。
"hinge"RSO 的作者建议对 SLiC 论文中的归一化似然使用铰链损失。在这种情况下,beta 是间隔的倒数。
"ipo"IPO 的作者们对 DPO 算法提供了更深入的理论理解,指出了过拟合问题,并提出了一种替代损失函数。在这种情况下,beta 是所选完成与拒绝完成对之间对数似然比差距的倒数,因此 beta 越小,该差距就越大。根据论文,该损失是对完成的对数似然取平均值(而 DPO 仅进行求和)。
"simpo"SimPO 方法也在 experimental.cpo.CPOTrainer 中实现。SimPO 是一种替代损失函数,它引入了奖励间隔,支持长度归一化,并且不使用 BC 正则化。要使用此损失函数,只需在 experimental.cpo.CPOConfig 中设置 loss_type="simpo" 和 cpo_alpha=0.0,并将 simpo_gamma 设置为推荐值。
"alphapo"AlphaPO 方法也在 experimental.cpo.CPOTrainer 中实现。这是一种语法糖,会自动设置 loss_type="simpo" 和 cpo_alpha=0.0。当 alpha 参数不为零时,AlphaPO 会在 SimPO 损失的上下文中对奖励函数的形状进行变换。

对于混合专家模型:启用辅助损失

当负载在专家之间大致均匀分布时,MOE 的效率最高。
为了确保在偏好调优期间以类似的方式训练 MOE,将负载均衡器的辅助损失添加到最终损失中是有益的。

通过在模型配置中设置 output_router_logits=True(例如 MixtralConfig)来启用此选项。
要调整辅助损失对总损失的贡献程度,请在模型配置中使用超参数 router_aux_loss_coef=...(默认值:0.001)。

CPOTrainer

类 trl.experimental.cpo.CPOTrainer

< >

( model: typing.Union[transformers.modeling_utils.PreTrainedModel, torch.nn.Module, str, NoneType] = Noneargs: trl.experimental.cpo.cpo_config.CPOConfig | None = Nonedata_collator: collections.abc.Callable[[list[typing.Any]], dict[str, typing.Any]] | None = Nonetrain_dataset: datasets.arrow_dataset.Dataset | None = Noneeval_dataset: datasets.arrow_dataset.Dataset | dict[str, datasets.arrow_dataset.Dataset] | None = Noneprocessing_class: transformers.tokenization_utils_base.PreTrainedTokenizerBase | transformers.image_processing_utils.BaseImageProcessor | transformers.feature_extraction_utils.FeatureExtractionMixin | transformers.processing_utils.ProcessorMixin | None = Nonemodel_init: collections.abc.Callable[[], transformers.modeling_utils.PreTrainedModel] | None = Nonecallbacks: list[transformers.trainer_callback.TrainerCallback] | None = Noneoptimizers: tuple[torch.optim.Optimizer, torch.optim.lr_scheduler.LambdaLR] = (None, None)preprocess_logits_for_metrics: collections.abc.Callable[[torch.Tensor, torch.Tensor], torch.Tensor] | None = Nonepeft_config: PeftConfig | None = Nonecompute_metrics: collections.abc.Callable[[transformers.trainer_utils.EvalLoopOutput], dict] | None = None )

参数

  • model (PreTrainedModel) — 要训练的模型,最好是 AutoModelForSequenceClassification。
  • args (experimental.cpo.CPOConfig) — 用于训练的 CPO 配置参数。
  • data_collator (DataCollator) — 用于训练的数据整理器。如果指定为 None,则使用默认的数据整理器(experimental.utils.DPODataCollatorWithPadding),该整理器会将序列填充到批次中序列的最大长度,适用于成对序列的数据集。
  • train_dataset (Dataset) — 用于训练的 dataset。
  • eval_dataset (Dataset) — 用于评估的数据集。
  • processing_class (PreTrainedTokenizerBase、BaseImageProcessor、FeatureExtractionMixin 或 ProcessorMixin,可选) — 用于处理数据的处理类。如果提供,将用于自动处理模型的输入,并随模型一起保存,以便更容易地重新运行中断的训练或复用微调后的模型。
  • model_init (Callable[[], transformers.PreTrainedModel]) — 用于训练的模型初始化器。如果指定为 None,则使用默认的模型初始化器。
  • callbacks (list[transformers.TrainerCallback]) — 训练时使用的回调。
  • optimizers (tuple[torch.optim.Optimizer, torch.optim.lr_scheduler.LambdaLR]) — 用于训练的优化器和调度器。
  • preprocess_logits_for_metrics (Callable[[torch.Tensor, torch.Tensor], torch.Tensor]) — 用于在计算指标之前对 logits 进行预处理的函数。
  • peft_config (PeftConfig, 可选) — 用于训练的 PEFT 配置。如果传入 PEFT 配置,模型将被包装为一个 PEFT 模型。
  • compute_metrics (Callable[[EvalPrediction], dict], 可选) — 用于计算指标的函数。必须接受一个 EvalPrediction 并返回一个从字符串到指标值的字典。

Initialize CPOTrainer

训练

< >

( 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。

主要训练入口。

save_model

< >

( output_dir: str | None = None_internal_call: bool = False )

将保存模型,以便您可以使用 from_pretrained() 重新加载它。

仅从主进程保存。

push_to_hub

< >

( commit_message: str | None = 'End of training'blocking: bool = Truetoken: str | None = Nonerevision: str | None = None**kwargs )

参数

  • commit_message (str,可选,默认为 "End of training") — 推送时提交的提交信息。
  • blocking (bool,可选,默认为 True) — 是否仅在 git push 完成后才返回。
  • token (str,可选,默认为 None) — 具有写入权限的 Token,用于覆盖 Trainer 的原始参数。
  • revision (str, 可选) — 要从中提交内容的 git 版本。默认为 “main” 分支的头部。
  • kwargs (dict[str, Any],可选) — 传递给 ~Trainer.create_model_card 的额外关键字参数。

将 self.model 和 self.processing_class 上传到 🤗 模型库中的仓库 self.args.hub_model_id。

CPOConfig

类 trl.experimental.cpo.CPOConfig

< >

( 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 = 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 = -1max_length: int | None = 1024max_completion_length: int | None = Nonebeta: float = 0.1label_smoothing: float = 0.0loss_type: str = 'sigmoid'disable_dropout: bool = Truecpo_alpha: float = 1.0simpo_gamma: float = 0.5alpha: float = 0.0generate_during_eval: bool = Falseis_encoder_decoder: bool | None = Nonemodel_init_kwargs: dict[str, typing.Any] | str | None = Nonetrust_remote_code: bool = Falsedataset_num_proc: int | None = None )

参数

  • max_length (int 或 None,可选,默认为 1024) — 批次中序列(提示 + 补全)的最大长度。如果您想使用默认的数据整理器,则必须提供此参数。
  • max_completion_length (int, 可选) — 补全的最大长度。如果您希望使用默认的数据整理器(data collator)且您的模型是编码器-解码器(encoder-decoder)模型,则此参数为必填项。
  • beta (float, 可选, 默认为 0.1) — 控制与参考模型偏差的参数。β 值越高,与参考模型的偏差越小。对于 IPO 损失(loss_type="ipo"),β 是论文中用 τ 表示的正则化参数。
  • label_smoothing (float,可选,默认为 0.0) — 标签平滑系数。如果您想使用默认的数据整理器,则必须提供此参数。
  • loss_type (str, 可选, 默认为 "sigmoid") — 要使用的损失类型。可能的值包括:
    • "sigmoid":来自原始 DPO 论文的 sigmoid 损失。
    • "hinge":对来自 SLiC 论文的归一化似然计算铰链损失。
    • "ipo":来自 IPO 论文的 IPO 损失。
    • "simpo":来自 SimPO 论文的 SimPO 损失。
    • "alphapo":来自 AlphaPO 论文的 AlphaPO 损失。这会自动设置 loss_type="simpo" 和 cpo_alpha=0.0。
  • disable_dropout (bool,可选,默认为 True) — 是否禁用模型中的 dropout。
  • cpo_alpha (float, 可选, 默认为 1.0) — CPO 训练中 BC 正则项的权重。
  • simpo_gamma (float, 可选, 默认值为 0.5) — SimPO 损失的目标奖励间隔,仅在 loss_type="simpo" 时使用。
  • alpha (float, 可选,默认为 0.0) — 控制所有损失类型下奖励函数形状的 Alpha 参数。当 alpha=0(默认值)时,使用标准的对数概率奖励。当 alpha != 0 时,应用来自 AlphaPO 论文 的 AlphaPO 变换:r = (1 - p^(-alpha)) / alpha。此参数适用于所有损失类型。
  • generate_during_eval (bool,可选,默认为 False) — 如果为 True,则在评估期间生成模型补全并将其记录到 W&B 或 Comet。
  • is_encoder_decoder (bool, 可选) — 当使用 model_init 参数(可调用对象)来实例化模型,而不是使用 model 参数时, 您需要指定该可调用对象返回的模型是否为编码器-解码器模型。
  • model_init_kwargs (dict[str, Any], 可选) — 从字符串实例化模型时传递给 AutoModelForCausalLM.from_pretrained 的关键字参数。revision 值在加载处理类时也会使用。
  • trust_remote_code (bool,可选,默认为 False) — 是否允许加载从 Hub 提供自定义 Python 代码的模型。该参数会传递给 from_pretrained。
  • dataset_num_proc (int, 可选) — 用于处理数据集的进程数。

experimental.cpo.CPOTrainer 的配置类。

此类仅包含 CPO 训练特有的参数。完整的训练参数列表,请参阅 TrainingArguments 文档。请注意,此类中的默认值可能与 TrainingArguments 中的不同。

使用 HfArgumentParser,我们可以将该类转换为 argparse 参数,从而在命令行中指定。

这些参数的默认值与 TrainingArguments 不同:

  • logging_steps:默认值为 10,而非 500。
  • gradient_checkpointing:默认值为 True,而非 False。
  • bf16:如果未设置 fp16,则默认值为 True,而不是 False。
  • learning_rate:默认值为 1e-6,而非 5e-5。
Update on GitHub