原文:
https://yugeten.github.io/posts/2025/01/ppogrpo/
Translated by jina ai + GPT + 人工校对
公式均使用 MathJax 语法
标题:一位视觉研究者对强化学习的一些见解:PPO与GRPO
URL来源:A vision researcher’s guide to some RL stuff: PPO & GRPO
发布时间:2025-01-31
Markdown内容:
20分钟阅读
发布时间: 2025年1月31日
先来一些日常的随想。
自从我上次写博客以来已经过去很久了。自从我开始工作以来,生活一直很忙碌,机器学习领域也和我在2023年初毕业时大不相同了。如今,普通父母在手机上安装大型语言模型(LLM)应用已经不是什么新鲜事了——我休了两周假去中国过春节,这反而让我有大量时间在推特上浏览,目睹了DeepSeek在除夕夜达到的(当之无愧的)热度巅峰,我完全被这种热潮所淹没。
所以,现在似乎是一个重新开始阅读、学习、做些基础数学运算并再次写下一些东西的好时机。
本文内容及面向对象
这篇文章深入探讨了近端策略优化(PPO),这是用于LLM的强化学习人类反馈(RLHF)中最流行的算法之一,以及由DeepSeek团队提出的群体相对策略优化(GRPO)。文章最后还简要总结了我在DeepSeek R1技术报告中发现的一些令人印象深刻的技巧。
这些内容都是由一个主要研究视觉、对强化学习了解不多的人完成的。如果你也属于这种情况,我希望你能从中受益。
LLM的预训练和后训练
LLM的训练可以分为预训练和后训练两个阶段:
-
预训练:经典的“向模型投喂数据”阶段,模型通过大规模网络数据进行下一个token的预测训练;
-
后训练:这是我们尝试提升模型推理能力的阶段。后训练通常包括两个阶段,分别是SFT(监督式微调),目的是使得模型可以模拟专家的行为;RLHF,这个阶段的存在是因为,SFT阶段的专家数据往往不够多,于是使用RL来在有限的数据里学到更微妙的内容,相当于是对齐。
DeepSeek高效的后训练
值得注意的是,DeepSeek R1技术报告中最令人惊讶的一点是,他们的R1-zero模型完全跳过了监督微调(SFT)部分,直接对基础模型(DeepSeek V3)应用强化学习。这种方法有几大好处:
-
计算效率:跳过一个后训练阶段可以带来计算效率的提升;
-
开放式学习:允许模型通过探索“自我进化”推理能力;
-
对齐:避免了由人工策划的SFT数据引入的偏差。
注意:虽然跳过整个后训练阶段以节省计算资源看起来像是一个“显而易见”的想法,但我怀疑如果没有一个非常好的基础模型,你可能无法做到这一点。
但他们并没有止步于此!DeepSeek还通过引入GRPO来替代PPO,使RLHF部分更加高效,从而消除了对单独的critic model评估者模型(通常与policy model策略模型一样大)的需求,将内存和计算开销减少了约50%。为了了解他们为何以及如何做到这一点,并满足我们自己的好奇心,让我们现在来看看RLHF是如何实现的,以及这些算法是如何发挥作用的。
RLHF
让我们将RLHF的工作流程分解为以下步骤:
-
步骤1:对于每个提示,从模型中采样多个响应;
-
步骤2:人类根据质量对这些输出进行排名;
-
步骤3:训练一个reward model奖励模型,以预测人类对任何模型响应的偏好/排名;
-
步骤4:使用 RL 强化学习(例如PPO、GRPO) 来微调模型,以最大化奖励模型的分数。
正如我们所见,这个过程相对简单,只有两个可学习的组件,即 reward model 和 “the RL” 。现在,让我们更详细地探讨每个组件。
奖励模型
奖励模型是自动化工作的前沿:现实情况下,我们无法让人类对模型的所有输出进行排名。一种节省成本的方法是让标注者对LLM的部分输出进行评分,然后训练一个模型来预测这些标注者的偏好——这就是奖励模型的作用。现在,让我们来看一些数学公式:
假设我们的可学习奖励模型为 R_\phi 。给定一个提示 p ,LLM生成了 N 个响应 r_1, r_2, \dots, r_N 。然后,假设根据人类评分者的偏好,响应 r_i 优于 r_j ,奖励模型被训练以最小化以下目标函数:
其中, \sigma 表示sigmoid函数。
补充说明:该目标函数来源于Bradley-Terry模型,该模型定义了一个评分者偏好 r_i 胜过 r_j 的概率为:
P(r_i \succ r_j) = \frac{\exp(R_\phi(p, r_i))}{\exp(R_\phi(p, r_i)) + \exp(R_\phi(p, r_j))}
对该概率取负对数似然,就得到了上面的损失函数 \mathcal{L}(\phi)。sigmoid函数 \sigma 是通过重新排列Bradley-Terry比率自然产生的。
请注意,对于部分响应,奖励始终为0;只有对于LLM生成的完整响应,奖励模型才会返回一个非零标量分数。这个重要的事实稍后会变得相关。
“强化学习部分”:PPO
这部分内容仅针对对PPO感兴趣的读者。如果你打开这篇文章的目的是为了理解GRPO,那么你其实不需要理解PPO。我只能说,当我终于理解了PPO的工作原理时,我感到非常高兴,而当我意识到GRPO比PPO简单得多时,我更是有一种如释重负的感觉。所以,如果你准备好经历一场情感过山车之旅——让我们深入探讨吧。
首先,做一个高层次的概述。PPO代表近端策略优化,它需要以下组件:
-
策略( \pi_\theta ):已经进行过预训练/监督微调的LLM;
-
奖励模型( R_\phi ):一个经过训练且固定的网络,给定一个提示的完整响应,提供标量奖励;
-
评估者( V_\gamma ):也称为价值函数,这是一个可学习的网络,它接收一个提示的部分响应,并预测标量奖励。
恭喜你——通过将LLM称为“策略”,你已经成为一个强化学习专家了!一旦我们了解了工作流程,每个组件的目的就会变得更加清晰,该工作流程包含五个阶段:
-
生成响应:LLM为给定提示生成多个响应;
-
对响应评分:奖励模型为每个响应分配奖励;
-
计算优势:使用GAE计算优势(稍后会详细介绍,这是用于训练LLM的);
-
优化策略:通过优化总目标函数更新LLM;
-
更新评估者:训练价值函数,使其更好地预测部分响应的奖励。
现在,让我们更详细地了解这些阶段/组件,然后看看它们是如何协同工作的。
术语:状态和动作
在继续之前,我们再介绍一些强化学习的术语。在本节的讨论中,我们将使用术语状态,记作 s_t,以及动作,记作 a_t。请注意,这里的下标 t 用于表示token级别的状态和动作;相比之下,我们之前定义的提示 p 和响应 r_i 中的下标 i 用于表示实例级别的响应。
为了更清楚地说明这一点,假设我们给LLM一个提示 p 。然后,LLM开始逐个token地生成一个长度为 T 的响应 r_i :
-
t=0 时:我们的状态仅仅是提示,即 s_0 = p ,第一个动作 a_0 是LLM生成的第一个词token;
-
t=1 时:状态变为 s_1 = \{p, a_0\} ,因为LLM在生成下一个动作 a_1 时会依赖于当前的状态;……
-
t=T-1 时:状态是 s_{T-1} = \{p, a_{0:T-2}\} ,LLM生成最后一个动作 a_{T-1} 。
再次联系之前的符号,所有动作串联起来就构成了一个响应,即 r_i = \{a_0, a_1, \dots, a_{T-1}\} 。
一般优势估计(GAE)
我们的策略是通过优化优势来更新的——直观来说,它定义了一个特定动作 a_t (即一个词)相比于在状态 s_t (即提示+已生成的词)下策略的平均动作有多好。形式化地表示为:
其中, Q(s_t, a_t) 是在状态 s_t 下采取特定动作 a_t 的预期累积奖励,而 V(s_t) 是在状态 s_t 下策略采取的平均动作的预期累积奖励。
估计这种优势主要有两种方法,每种方法都有其权衡,分别是:1)蒙特卡洛(MC):使用完整轨迹(即完整响应)的奖励。这种方法由于奖励稀疏而具有高方差——从LLM中采样以使用MC进行优化的成本很高,但它具有低偏差,因为我们能够准确地建模奖励;2)时间差分(TD):使用单步轨迹奖励(即衡量刚刚生成的词在给定提示下的好坏)。通过这样做,我们可以在token级别计算奖励,这显著降低了方差,但同时偏差会增加,因为我们无法准确地预测部分生成响应的最终奖励。
GAE就是为了解决这个问题而提出的——它通过多步TD来平衡偏差和方差。然而,回想一下我们之前提到的,如果响应不完整,奖励模型将返回0:那么我们如何在不知道生成一个词之前和之后奖励的变化的情况下计算TD呢?因此,我们引入了一个能够做到这一点的模型,我们称之为“评估者”。
评估者(价值函数)
评估者被训练用来预测仅给定部分状态的最终奖励,以便我们可以计算TD。训练评估者 V_\gamma 是相当直接的:
给定一个部分状态 s_t ,我们希望预测完整状态 s_T = \{p, r\} 下奖励模型的输出。评估者的训练目标可以写为:
其中, \text{sg} 表示停止梯度操作。正如我们所见,评估者是通过简单的L2损失来训练的,以预测奖励模型的分数。
你可能会注意到,尽管奖励模型 R_\phi 是在PPO之前训练的并且是固定的,但评估者是与LLM一起训练的,尽管它的任务也是预测奖励。这是因为价值函数必须根据当前策略来估计部分响应的奖励;因此,它必须与LLM一起更新,以避免其预测变得过时和不一致。这就是强化学习中的所谓“演员-评论家”方法(掌声)。
回到GAE
有了评估者 V_\gamma ,我们现在有了一个方法来预测部分状态下的奖励。现在让我们继续介绍GAE,正如前面提到的,GAE计算一个多步TD目标:
其中, K 表示TD步数,且 K < T (因为显然你不能在轨迹长度之外计算TD)。 \delta_t 表示第 t 步的TD误差,计算公式为:
简单来说,TD误差计算了一个时间步的预期总奖励之间的差异,而 A^{\text{GAE}}_K 通过计算 K 步的单步TD误差的聚合来估计优势。GAE公式中的 \lambda 控制了方差和偏差之间的权衡:当 \lambda = 0 时,GAE简化为单步TD;而当 \lambda = 1 时,GAE变成了MC。
在RLHF中,我们希望最大化这个优势项,从而最大化LLM生成的每个token的奖励。
补充说明:好吧,为了简化,我在这里省略了一些内容。原本GAE中还有一个折扣因子 \eta : A^{\text{GAE}}_K = \sum_{t=0}^{K-1} (\lambda \eta)^t \delta_t ,它也用于TD误差 \delta_t ,并且还有一个额外的奖励项 \delta_t = R_\phi(s_t) + \eta V_\gamma(s_{t+1}) - V_\gamma(s_t) 。但由于我们几乎总是有 \eta = 1 ,且对于 t < T 的情况, R_\phi(s_t) = 0 ,所以我在这里为了简化而省略了这些项。
综合起来——PPO目标函数
PPO目标函数包含几个部分,分别是:1)裁剪后的替代目标函数;2)熵奖励;3)KL惩罚。
1. 裁剪后的替代目标函数
这里,我们最大化 A^{\text{GAE}}_K ,以便LLM预测的每个token都能最大化奖励(或者根据前面定义的优势,LLM预测的每个token都应该比其平均预测好得多)。裁剪后的替代目标函数通过概率比率 c_t(\pi_\theta) 来约束策略更新:
其中, \epsilon 控制裁剪范围, c_t(\pi_\theta) 是在更新前后,给定累积状态 s_t 时预测特定token a_t 的概率比率:
具体例子:
-
假设LLM为单词
unlimited
分配了以下概率: -
更新前:0.1,
-
更新后:0.3。那么概率比率 c_t = 0.3 / 0.1 = 3 ;
-
如果我们取 \epsilon = 0.2 ,那么 c_t 会被裁剪到1.2;
-
最终的裁剪后替代损失函数为 \mathcal{L}^{\text{clip}}(\pi_\theta) = 1.2 A^{\text{GAE}}_K 。
你可以把裁剪看作是一种防止过度自信的方法——如果没有裁剪,一个较大的 A^{\text{GAE}}_K 可能会导致策略过度承诺一个动作。
2. KL散度惩罚
此外,我们还有KL散度惩罚,它防止当前策略 \theta 偏离我们正在微调的原始模型 \theta_{\text{orig}} 太远:
KL散度仅仅是通过对序列和批次取平均值来估计的。
伪代码:
# 计算原始策略/模型与当前策略/模型之间的KL散度
logits_orig = original_model(states) # 原始模型的logits
logits_current = current_model(states) # 当前模型的logits
probs_orig = F.softmax(logits_orig, dim=-1)
log_probs_orig = F.log_softmax(logits_orig, dim=-1)
log_probs_current = F.log_softmax(logits_current, dim=-1)
kl_div = (probs_orig * (log_probs_orig - log_probs_current)).sum(dim=-1)
kl_penalty = kl_div.mean() # 对序列和批次取平均值
3. 熵奖励
熵奖励通过惩罚低熵来鼓励LLM的生成进行探索:
伪代码:
# 计算当前策略的熵
probs_current = F.softmax(logits_current, dim=-1)
log_probs_current = F.log_softmax(logits_current, dim=-1)
entropy = -(probs_current * log_probs_current).sum(dim=-1)
entropy_bonus = entropy.mean() # 对序列和批次取平均值
最终,PPO目标函数
鉴于上述三个项,加上与LLM一起优化的价值函数MSE损失,PPO目标函数定义如下:
以下是这个目标函数中各个项的总结:
Term 项 | Purpose 目的 |
---|---|
\mathcal{L}_{\text{clip}}(\theta) | 最大化高优势动作的奖励(通过裁剪避免不稳定) |
H(\theta) | 最大化熵以鼓励探索 |
\text{KL}(\theta) | 惩罚与参考策略的偏差(稳定性) |
\mathcal{L}(\gamma) | 最小化价值预测误差(评估者L2损失) |
“强化学习部分”:GRPO
现在我们已经很好地理解了PPO,理解GRPO就很容易了,这两种算法估计优势 A 的关键区别在于:与PPO通过评估者估计优势不同,GRPO通过使用相同的提示从LLM中采样多个样本来估计优势。
工作流程:
-
对于每个提示 p ,从LLM策略 \pi_\theta 中采样一组 N 个响应 \mathcal{G} = \{r_1, r_2, \dots, r_N\} ;
-
使用奖励模型 R_\phi 为每个响应计算奖励 R_\phi(r_1), R_\phi(r_2), \dots, R_\phi(r_N) ;
-
计算每个响应的组归一化优势: A_i = \frac{R_\phi(r_i) - \text{mean}(\mathcal{G})}{\text{std}(\mathcal{G})} ,其中 \text{mean}(\mathcal{G}) 和 \text{std}(\mathcal{G}) 分别表示组内的均值和标准差。
很简单,对吧?在GRPO中,优势被近似为每个响应在其组内的归一化奖励。这消除了需要计算每步奖励的评估者网络的需求,更不用说数学上的简洁和优雅了。这确实让人不禁要问——为什么我们没有早点这么做呢?
由于缺乏实践经验,我无法很好地回答这个问题。我猜测这与硬件能力有关,因为我们现在使用的现代GPU/TPU使得采样变得更加快速和高效。再次声明,我不是专家,所以欢迎大家分享见解!
更新:来自@him_sahni的一些见解,他“曾在过去从事过强化学习”:“为什么以前没人尝试过GRPO”的原因是——我们其实尝试过。在REINFORCE中,你通过减去一个基线(通常是几条轨迹的平均奖励)来更新策略,以减少变异性。事实上,理论表明,理想的基线是从一个状态出发的预期总未来奖励,通常被称为“价值”。使用价值函数作为基线被称为演员-评论家方法,而PPO是这种方法的一个稳定版本。现在,在传统的REINFORCE中,基线可以是当前状态的任何函数,传统上只是一个批次中轨迹的奖励;而在GRPO中,这个基线是通过对每个提示生成的1000个样本进行计算得出的,这是新颖的。
GRPO目标函数
与PPO类似,GRPO仍然使用裁剪后的替代损失函数以及KL惩罚。这里没有使用熵奖励项,因为基于群体的采样已经鼓励了探索。裁剪后的替代损失函数与PPO中使用的完全相同,但为了完整性,这里再写一次:
然后加上KL惩罚项,最终的GRPO目标函数可以写为:
关于R1的更多思考:残酷的简洁性
最后,让我们来谈谈R1。
无论R1是否被过度炒作,从阅读论文中可以看出,它采用了一种简化到极致、毫不花哨的LLM训练方法,优先选择残酷的简洁性而非复杂性。GRPO只是冰山一角。以下是一些更多关于其简洁性的例子:
1. 基于规则的、确定性的奖励
-
内容:放弃神经过程奖励模型(PRMs)或结果奖励模型(ORMs)。使用二元检查,包括:
-
答案正确性:最终答案与真实值匹配(例如,数学解、代码编译)。
-
格式化:强制答案使用
<think>...</think><answer>...</answer>
模板。 -
语言一致性:惩罚混合语言的输出(例如,用英语推理中文问题)。
-
原因:确定性规则可以避免奖励欺骗(例如,模型通过看似合理但错误的步骤欺骗神经奖励模型),并消除了奖励模型训练的成本。
2. 冷启动数据:最小化人工干预
-
内容:而不是策划大量的SFT数据集,通过以下方式收集几千个高质量的CoT示例:
-
使用少量示例提示基础模型。
-
轻微的人工后处理(例如,添加Markdown格式)。
-
原因:避免了成本高昂的SFT阶段,同时为RL提供了一个“足够好”的起点。
3. 拒绝采样:严格筛选,努力训练
-
内容:在RL训练后,生成600k推理轨迹,然后丢弃所有错误的响应。只保留“胜利者”(正确答案)用于监督微调(SFT)。没有复杂的重新排名,没有偏好对。只是适者生存式的筛选。
-
原因:它有效,为什么不用呢?
4. 知识蒸馏:复制粘贴推理
-
内容:为了训练更小的模型,直接在DeepSeek-R1生成的800k响应上进行微调。没有RL,没有迭代对齐——只是模仿。
-
原因:较小的模型继承了大型模型通过暴力RL发现的推理模式,从而避免了小规模部署中昂贵的RL。
DeepSeek-R1的设计反映了AI领域的一个更广泛趋势:规模和简洁性往往优于巧妙的工程设计。通过无情地走捷径——用规则取代学习组件,利用大规模并行采样,并依赖预训练基线——R1以更少的失败模式实现了SOTA结果。它可能不够优雅,但它_有效_。
谁会想到,激励良好思维的最佳方式是停止过度思考。