RM和PPO训练过程
RM 训练
编写 rm 训练的脚本 ds_rm.sh
,和上述的模板以及sft相应的模板内容,编写类似的sft过程的调用脚本,利用奖励机制对文本的生成内容进行一定的优化。
accelerate launch src/train_rm.py \
--model_name_or_path /home/mnt/workspace/model/chatglm2-6b-32k \
--dataset judgement \
--do_train \
--finetuning_type lora \
--output_dir /home/mnt/workspace/trained \
--overwrite_cache \
--per_device_train_batch_size 1 \
--gradient_accumulation_steps 1 \
--lr_scheduler_type cosine \
--logging_steps 10 \
--save_steps 1000 \
--learning_rate 1e-3 \
--num_train_epochs 15.0 \
--plot_loss \
--fp16
执行该sh
脚本,并对原模型进行训练调参,更具之前所写的代码:
使用的PairwisePeftTrainer
和整体结构来看,我们可以推测奖励策略的一些关键特点。这种类型的训练通常用于比较任务,其中模型需要评估一对样本,并决定哪个更好。这种训练通常应用于奖励模型(reward models),这类模型用来指导或调整其他模型的行为。PairwisePeftTrainer
类,继承自PeftTrainer
,专门用于计算成对损失(pairwise loss),这是在奖励模型训练中经常使用的一种方法。
-
初始化和属性:
- 类初始化时调用了基类
PeftTrainer
的初始化方法,并设置了can_return_loss
属性为True
。这表明这个训练器可以在评估过程中返回损失值,这对于监控和优化模型非常重要。
- 类初始化时调用了基类
-
计算损失:
-
compute_loss
方法是这个类的核心。在这里,它计算成对损失,即比较一对样本的奖励分数,并根据它们的差异计算损失。具体实现如下:
- 输入处理:输入字典
inputs
包含了批量数据,该方法首先通过input_ids
的大小确定批次大小(batch_size
),这假定输入的批次是成对的(即每两个样本为一组)。 - 模型计算:调用模型得到输出,其中
values
是从模型最后一个输出(EOS token,即句子结束符)得到的分数,代表整个句子的奖励。 - 分割奖励:将
values
分成两部分,r_accept
和r_reject
,分别代表接受和拒绝这个样本的奖励分数。假设成对的输入中,前半是"好"的样本,后半是"差"的样本。 - 损失计算:损失是基于
r_accept
和r_reject
的差异计算的,使用的是对数sigmoid损失函数,这种方法通常用于处理成对或二元选择任务,公式为-log(sigmoid(r_accept - r_reject))
。这种损失函数鼓励模型增加"好"样本的分数,减少"差"样本的分数,使模型能够区分高质量和低质量的输出。
- 输入处理:输入字典
-
-
输出:
- 如果
return_outputs
为True
,则返回一个元组,包括计算的损失值和每个样本的具体奖励分数(接受和拒绝)。这可以用于进一步的分析和优化。
- 如果
总结来说,PairwisePeftTrainer
通过对成对样本的比较,强化模型对"好"与"差"样本的区分能力。这种训练方式非常适合于那些需要精细评估和选择最佳响应的任务,如文本摘要、对话系统中的回复生成等。这类奖励模型训练策略强调了通过直接比较来学习和优化,是一种有效的训练手段。
成对损失(Pairwise Loss)是一种在机器学习中常用于比较任务的损失函数,尤其适用于那些需要模型学习区分两个样本优劣的场景。这种损失函数设计是为了直接比较成对的样本,并优化模型以正确区分它们。
成对损失的基本概念
成对损失主要用于排序问题、推荐系统和一些特定的分类任务中,它基于以下几个关键点:
- 成对样本:训练数据由成对的样本组成,通常一个样本是正面(更好)的,另一个是负面(较差)的。
- 目标:目标是使模型能够正确区分这两个样本的优劣,即让模型更倾向于将高质量的样本评分高于低质量的样本。
具体实现
在你提供的代码中,成对损失是通过以下方式实现的:
- 使用模型的输出,这里是每个样本句子结束符(EOS)的输出值,作为该样本的“奖励”。
- 计算两组样本(接受和拒绝)的奖励差异。
- 使用sigmoid函数和对数损失来计算最终损失。公式是
-log(sigmoid(r_accept - r_reject))
,这个函数形状鼓励模型增大接受样本的分数,减少拒绝样本的分数。
损失函数的选择
成对损失的一个典型选择是对数损失函数,它可以强化模型对成对样本间差异的识别能力。这种损失函数的优点包括:
- 直接优化差异:这种损失直接针对样本间的差异进行优化,这对于那些需要精确比较的任务尤为重要。
- 灵活性高:可以根据不同的应用需求调整差异的计算方式,例如通过不同的激活函数或不同的差异计算策略。
- 有助于排序和推荐:在推荐系统和信息检索领域尤为有用,因为这些领域经常需要对项目或信息进行排序。
应用场景
成对损失在多种应用场景中都非常有用,如:
- 推荐系统:优化模型以更好地排序推荐项。
- 信息检索:改进搜索算法,以便于更准确地排序搜索结果。
- 文本生成:比如你的代码所示的奖励模型训练,优化生成的文本质量。
总之,成对损失是一种强大的工具,可以帮助模型学习如何根据质量或相关性准确地排序或区分对象,这对于提升模型在特定任务上的表现至关重要。
训练后获得其loss并将其绘制成为图像:
PPO 训练策略
编写 rm 训练的脚本 ds_rm.sh
,和上述的模板以及sft相应的模板内容,编写类似的sft和rm过程的调用脚本,利用近端策略优化机制对文本的生成内容进行一定的优化。
accelerate launch src/train_ppo.py \
--model_name_or_path /home/mnt/workspace/model/chatglm2-6b-32k \
--dataset judgement \
--do_train \
--finetuning_type lora \
--output_dir /home/mnt/workspace/trained \
--overwrite_cache \
--per_device_train_batch_size 1 \
--gradient_accumulation_steps 1 \
--lr_scheduler_type cosine \
--logging_steps 10 \
--save_steps 1000 \
--learning_rate 1e-3 \
--num_train_epochs 15.0 \
--plot_loss \
--fp16
在之前所描述的代码中,PPO策略进行微调预训练模型而设计的。它继承自PPOTrainer
和PeftTrainer
,融合了两者的特点,实现了在序列到序列(seq2seq)任务中的应用。实际应用中使用PPO策略来优化序列生成任务。通过精心设计的训练循环和更新策略,它能够有效地利用PPO的优势,提高模型在特定任务上的表现。
PPO的实现和过程主要体现在PPOPeftTrainer
类中的ppo_train
方法。这个方法详细定义了如何使用PPO进行训练,包括数据的处理、模型响应的生成、奖励的计算,以及基于这些奖励进行的策略更新。下面逐步分析这一实现:
- 数据准备和迭代
- 使用
iter(self.dataloader)
初始化数据加载器,这保证了每个训练步骤都能从数据集中获取新的数据样本。
- 响应生成
- 在每个训练步骤中,
generate
函数被调用来生成模型对应的响应。这一部分主要利用当前模型策略(由模型参数决定)根据输入数据产生输出。
- 计算奖励
- 为了计算奖励,模型首先在生成响应之后,调整为奖励模型模式(可能通过改变其内部状态或使用特定的奖励计算模型)。奖励的计算是基于生成的响应和一些内部逻辑,可能涉及到与真实数据的比较或其他评估标准。
- 在
self.model(**self.prepare_model_inputs(queries, responses))
中,模型接收处理好的查询和响应,然后输出奖励值。
- PPO 更新步骤
- 在计算出奖励后,代码执行PPO的关键部分,即策略更新。这通常涉及计算新策略与旧策略之间的比例,然后根据PPO的目标函数来更新策略参数。具体的实现细节可能隐藏在
self.step(queries, responses, rewards)
调用中,这里的step
方法可能封装了梯度计算和参数更新的逻辑。 - 重要的是,更新过程中使用了梯度累积(
config.gradient_accumulation_steps
),这是一种常用的技术,可以在不增加显存需求的情况下,有效地处理更大的批次数据。
- 训练监控和日志记录
- 训练过程中使用了
loss_meter
和reward_meter
来追踪损失和奖励的平均值,这有助于监控训练的进展和效果。 - 在特定的训练步骤,通过日志记录当前的损失、奖励、学习率等信息,以及通过
self.log_callback.on_log
回调函数记录这些信息,这有助于外部监控和分析训练过程。
- 模型的保存和持久化
- 定期保存模型的状态,确保训练过程中的进展不会丢失,同时允许从特定检查点恢复训练。
这个PPO实现过程的核心在于如何根据奖励来调整和优化策略,以及如何在此基础上实现有效的训练和参数更新。通过将PPO策略集成到自定义的训练器中,代码有效地将PPO的理论优势转化为实际的训练性能提升。
并绘制训练过程的损失图像: