TRL 文档
训练常见问题解答
并获得增强的文档体验
开始使用
训练常见问题解答
我应该关注哪些指标?
在对语言模型进行传统的有监督微调时,损失(尤其是验证损失)是衡量训练进度的良好指标。然而,在强化学习(RL)中,损失对于模型性能的指示作用减弱,其值可能会波动,而实际性能却在提高。
为解决此问题,我们建议首先关注两个关键指标:
平均奖励(Mean Reward):主要目标是在强化学习训练期间最大化模型获得的奖励。目标 KL 散度(Objective KL Divergence):KL 散度(Kullback-Leibler 散度)用于衡量两个概率分布之间的差异性。在强化学习训练的背景下,我们用它来量化当前模型与参考模型之间的差异。理想情况下,我们希望将 KL 散度保持在 0 到 10 之间,以确保模型生成的文本与参考模型生成的文本保持相近。
不过,还有更多对调试有用的指标,请查看日志部分。
为什么使用参考模型,KL 散度的作用是什么?
在训练强化学习模型时,仅为奖励进行优化可能会导致意想不到的行为,模型可能会以不符合良好语言生成的方式利用环境。在 RLHF(基于人类反馈的强化学习)中,我们使用一个奖励模型,该模型经训练用于预测生成的文本是否会获得人类的高排名。
然而,针对奖励模型进行优化的强化学习模型可能会学到一些能产生高奖励但并不代表良好语言的模式。这可能导致极端情况,例如模型为了最大化奖励而生成带有过多感叹号或表情符号的文本。在一些最坏的情况下,模型可能会生成与自然语言完全无关但却能获得高奖励的模式,类似于对抗性攻击。

图:没有 KL 惩罚的样本,来自 https://huggingface.co/papers/1909.08593。
为了解决这个问题,我们根据当前模型和参考模型之间的 KL 散度,在奖励函数中增加了一个惩罚项。通过这样做,我们鼓励模型保持与参考模型生成的内容相近。
负 KL 散度有什么问题?
如果你单纯从模型分布中采样生成文本,通常不会有问题。但当你使用 generate
方法时,会有一些需要注意的地方,因为它并不总是纯粹采样,这取决于设置,并可能导致 KL 散度变为负值。基本上,当活动模型达到 log_p_token_active < log_p_token_ref
时,我们就会得到负的 KL 散度。这可能在以下几种情况下发生:
- top-k 采样:模型可以平滑概率分布,导致 top-k 的词元概率小于参考模型的概率,但它们仍然被选中。
- min_length:这会忽略 EOS 词元,直到达到
min_length
。因此,模型可以为 EOS 词元分配一个非常低的对数概率,而为其他所有词元分配非常高的概率,直到达到 min_length。
这些只是一些例子。为什么负 KL 散度是个问题?总奖励 R
的计算公式为 R = r - beta * KL
,所以如果模型能学会如何使 KL 散度变为负值,它实际上会获得一个正奖励。在许多情况下,利用生成过程中的这样一个漏洞可能比真正学习奖励函数要容易得多。此外,KL 散度可以变得任意小,因此实际奖励与其相比可能非常小。
那么,你应该如何为 PPO 训练生成文本呢?让我们来看看吧!
如何为训练生成文本?
为了避免上述 KL 散度问题,我们建议使用以下设置:
generation_kwargs = {
"min_length": -1, # don't ignore the EOS token (see above)
"top_k": 0.0, # no top-k sampling
"top_p": 1.0, # no nucleus sampling
"do_sample": True, # yes, we want to sample
"pad_token_id": tokenizer.eos_token_id, # most decoder models don't have a padding token - use EOS token instead
"max_new_tokens": 32, # specify how many tokens you want to generate at most
}
使用这些设置,我们通常不会遇到任何问题。你也可以尝试其他设置,但如果遇到负 KL 散度的问题,请尝试恢复这些设置,看看问题是否仍然存在。
如何调试你自己的用例?
调试强化学习流程可能因其复杂性而具有挑战性。以下是一些使过程更轻松的技巧和建议:
- 从一个可行的示例开始:从 trl 仓库中一个可行的示例开始,并逐渐修改它以适应你的特定用例。一次性更改所有内容会使识别潜在问题的来源变得困难。例如,你可以先替换示例中的模型,一旦你找到了最佳的超参数,再尝试切换到你的数据集和奖励模型。如果你一次性更改所有内容,你将不知道潜在问题来自何处。
- 从小处着手,后续扩展:训练大型模型可能非常缓慢,需要数小时或数天才能看到任何改进。对于调试来说,这不是一个方便的时间尺度,所以尝试在开发阶段使用小型模型变体,一旦可行再进行扩展。话虽如此,有时你也必须小心,因为小型模型可能没有能力解决复杂的任务。
- 从简单开始:尝试从一个最简单的示例开始,并在此基础上增加复杂性。你的用例可能需要一个由许多不同奖励组成的复杂奖励函数——尝试先使用一个信号,看看你是否可以优化它,然后再增加更多的复杂性。
- 检查生成内容:检查模型生成的内容总是一个好主意。也许你的后处理或提示中有错误。由于设置不当,你可能会过早地截断生成内容。这些问题在指标上很难发现,但如果你查看生成内容,就会非常明显。
- 检查奖励模型:如果你的奖励没有随时间改善,可能是奖励模型有问题。你可以查看极端情况,看它是否按预期工作:例如,在情感分析的案例中,你可以检查简单的正面和负面示例是否真的得到不同的奖励。你还可以查看数据集的分布。最后,奖励可能被查询(query)主导,而模型无法影响查询,所以你可能需要对此进行归一化(例如,查询+响应的奖励减去查询的奖励)。
这些只是我们发现有帮助的一些技巧——如果你有更多有用的技巧,欢迎随时提交 PR 将它们也添加进来!
< > 在 GitHub 上更新