适用于大模型的强化学习
在上一章节中,我们介绍了强化学习的基本概念和一些传统算法。不过,这些算法里有很多内容和大模型语境下的强化学习并不是直接对应的。比如在大模型训练中,我们通常不会显式求解 Bellman 方程,也很少像传统表格型强化学习那样维护一个完整的 state value table 或 Q table。
这并不意味着上一节不重要。恰恰相反,上一节真正需要保留下来的,是强化学习的基本问题定义:状态、动作、策略、轨迹、奖励、return、value、on-policy / off-policy、policy-based / value-based 等概念。这些概念是我们理解大模型训练中的 RLHF、PPO、GRPO、DPO 等方法的框架和地基.
这一节开始,我们尝试从头建立大模型体系下的强化学习视角(LLM 是怎么被建模成RL的? LLM相关的RL算法是如何定义的,它们之间的联系又是什么?):
- LLM 为什么可以被看成一个强化学习里的 policy?
- LLM 生成文本时,状态、动作、轨迹、奖励分别是什么?
- 为什么 value-based 方法不太适合 LLM,而 policy-based 方法更自然?
- Policy Gradient 如何成为 PPO、GRPO、RLHF 这条线的起点?
- RLHF、PPO、GRPO、DPO 之间到底是什么关系?
LLM 如何被建模成一个 RL 问题?
Q: 为什么大模型训练会用到强化学习?
预训练语言模型的基本目标是 next-token prediction。给定一段文本前缀,模型学习预测下一个 token。这个目标可以写成最大化训练语料的似然,或者等价地最小化交叉熵损失。
如果只做预训练,模型学到的是“在互联网文本分布中,下一个 token 最可能是什么”。但是我们真正希望聊天模型具备的能力,往往不是简单地复现互联网文本分布,而是:
- 回答应该有帮助。
- 回答应该符合人类偏好。
- 回答应该遵循指令。
- 回答应该避免有害内容。
- 在推理任务中,回答应该尽量正确。
这些目标很难直接写成一个逐 token 的监督学习标签。对于同一个 prompt,可能有很多种合理回答;而且人类偏好通常是对完整回答的整体评价,而不是对每个 token 单独打分。
这时,强化学习的视角就自然出现了:模型生成一段回答,外部环境或奖励模型对这段回答给出一个奖励,然后我们希望调整模型参数,让未来生成的回答获得更高的奖励。
换句话说,监督学习更像是在问:
给定这个前缀,下一个 token 应该是什么?
而强化学习更像是在问:
给定这个 prompt,模型应该生成怎样的一整段回答,才能获得更高的整体评价?
这就是 LLM 与 RL 建立联系的入口。
Q: LLM 如何被建模成一个 RL 问题?
回忆上一节中强化学习的基本对象。一个智能体在状态 \(S_t\) 下,根据策略 \(\pi\) 选择动作 \(A_t\),环境给出奖励 \(R_{t+1}\),并转移到下一个状态 \(S_{t+1}\)。
在 LLM 生成文本的场景中,我们可以把一次回答生成建模成一个有限长度的 episode。
设用户输入的 prompt 为 \(x\),模型生成的回答 token 序列为:
其中:
- \(x\) 表示 prompt。
- \(y_t\) 表示第 \(t\) 个生成 token。
- \(y_{<t}=(y_1,\dots,y_{t-1})\) 表示第 \(t\) 步之前已经生成的 token 前缀。
- \(T\) 表示回答长度,可以是固定长度,也可以由终止 token 决定。
于是,LLM 的 RL 建模可以写成:
| RL 概念 | LLM 中的对应对象 |
|---|---|
| 状态 \(s_t\) | prompt 和当前已生成前缀 \((x,y_{<t})\) |
| 动作 \(a_t\) | 下一个 token \(y_t\) |
| 策略 \(\pi_\theta(a_t\mid s_t)\) | 语言模型的 next-token 分布 \(\pi_\theta(y_t\mid x,y_{<t})\) |
| 轨迹 \(\tau\) | 一次完整生成 \((x,y_1,\dots,y_T)\) |
| 奖励 \(R\) | 对完整回答或中间步骤的评分 |
| episode | 从 prompt 开始,到回答结束的一次生成过程 |
因此,语言模型本身就是一个参数化策略,我们使用\( \pi_\theta \) 替代之前的 \( P \) 来更好的符合强化学习的语境:
其中:
- \(\pi_\theta\) 是由参数 \(\theta\) 决定的语言模型策略。
- \(x\) 是 prompt。
- \(y_{<t}\) 是当前状态中已经生成的 token 前缀。
- \(y_t\) 是当前动作,也就是下一个 token。
一整段回答的生成概率可以写成自回归分解:
这个公式非常重要。它说明:虽然奖励通常是对完整回答 \(y\) 给出的,但是模型实际做决策时,是一步一步选择 token。LLM 的强化学习训练,本质上就是用完整回答级别的奖励,去更新每一步 token 选择的概率。
Q: LLM 中的奖励是什么?
在传统 RL 中,奖励 \(R_{t+1}\) 通常来自环境。例如游戏中得分增加、机器人到达目标位置等。
在 LLM 中,奖励的来源更加灵活。常见情况包括:
- 人工偏好奖励:人类标注者比较两个回答,指出哪个更好。
- 奖励模型 reward model:先用人类偏好数据训练一个模型,再由这个模型给回答打分。
- 规则奖励:例如答案是否匹配标准答案、代码是否通过测试、数学题结果是否正确。
- 混合奖励:把格式、正确性、安全性、长度惩罚、KL 惩罚等组合起来。
LLM引入强化学习框架,就是为了引入更灵活的Reward系统.比如你很难通过之前的NLL损失来定义一个模型具体的表现,比如它是否符合某个风格,或者模型正确的完成了某个指令,或者做了哪个操作.尤其是操作这种思想,非常符合RL的框架.
最常见的 RLHF 设置中,奖励通常是回答级别的。也就是说,模型先完整生成回答 \(y\),然后 reward model 给出一个标量:
其中:
- \(r_\phi\) 是参数为 \(\phi\) 的奖励模型。
- \(x\) 是 prompt。
- \(y\) 是模型生成的完整回答。
- \(r_\phi(x,y)\) 是这段回答的奖励分数。
这和传统 RL 中每一步都有奖励的情况略有不同。对于 LLM 来说,很多时候中间 token 并没有明确奖励,只有整段回答结束后才知道好坏。因此,LLM 强化学习经常面对的是一种 sparse reward 或 sequence-level reward。
为了把它放回上一节的 return 记号中,可以把回答结束时的奖励看成最终奖励:
而中间步骤的奖励近似看成 0:
这时,从生成开始的 return 主要由最终回答奖励决定。
Q: 为什么 value-based 方法在 LLM 中不常用?
上一节介绍的 Q-learning、DQN 等很多传统RL方法都属于 value-based 方法。它们通常先学习 action value:
然后通过比较不同动作的 Q value 来选择动作。最典型的是 Q-learning 中的 greedy 目标:
但是在 LLM 中,这条路线会遇到几个困难。
第一,状态空间极大。LLM 的状态 \(s_t=(x,y_{<t})\) 是 prompt 加任意长度的 token 前缀。这个空间的维度非常惊人.
第二,动作空间很大。动作是词表中的 token,常见词表大小可以达到几万到十几万。每一步都显式估计所有 token 的 Q value,成本很高。
第三,奖励通常是完整回答级别的。一个 token 的好坏高度依赖后续 token。比如同一个 token 在不同推理链条中可能有完全不同的意义。单独学习 \(q(s_t,y_t)\) 并不容易。
第四,LLM 本身已经天然是一个 policy。预训练模型直接给出:
也就是说,我们已经有了一个非常强的参数化策略。与其重新学习一个 Q function 再由 Q function 导出策略,不如直接优化这个策略本身。
所以在 LLM 场景中,主流方法更多走 policy-based 的路线:直接调整 \(\pi_\theta\),让它生成更高奖励的回答。
不过,从传统 RL 的视角看,即使我们直接优化策略,value function 也没有完全消失。PPO 这类 actor-critic 方法通常仍然会训练 value model,用来估计 advantage、降低梯度方差。区别在于,value 在这里主要是 policy update 的辅助量,而不是像 Q-learning 那样作为导出策略的核心对象。
这也是 LLM 中 RL 和传统 RL 的一个重要差异:在大模型训练里,reward 和 value 的地位会被进一步改写。奖励通常来自规则、偏好数据或 reward model;下一节会先从 RL 视角重新解释介绍 Policy Gradient族算法,然后在下一章节再回到LLM语境下的RL.
Policy Gradient
至此,我们开始进入 policy-based 方法的主线。前面介绍 value-based 方法时,核心是先估计 value 或 Q value,再从 value 中导出策略;而 Policy Gradient 的想法更直接:既然策略本身可以写成一个带参数的函数 \(\pi_\theta(a\mid s)\),那就直接优化这个策略。
这部分先从传统 RL 的视角推导,再回到 LLM。原因是 PPO、GRPO、RLHF 虽然应用在大模型上,但它们背后的梯度形式、advantage、critic、GAE 等概念都来自传统 Policy Gradient 和 Actor-Critic。
Q: Policy Gradient 要解决什么问题?
在表格型 RL 中,策略可以直接存成一张表 \(\pi(a\mid s)\)。但一旦状态空间很大,我们通常会把策略表示成参数化函数:
其中:
- \(\theta\) 是策略函数的参数。
- \(s\) 是状态。
- \(a\) 是动作。
- \(\pi_\theta(a\mid s)\) 表示在状态 \(s\) 下选择动作 \(a\) 的概率。
这时,策略优化的问题就变成了:如何选择一组参数 \(\theta\),让策略的整体表现最好?
因此我们需要先构造一个标量目标函数:
然后用梯度上升更新参数:
这就是 Policy Gradient 的基本形式。真正困难的地方在于两个问题:
- \(J(\theta)\) 应该怎么定义?
- \(\nabla_\theta J(\theta)\) 应该怎么计算和采样估计?
Q: 为什么先回顾 value 和 Q value?
虽然 Policy Gradient 是 policy-based 方法,但它并没有完全摆脱 value。相反,Policy Gradient 的推导中会自然出现 \(q_\pi(s,a)\),后面的 Actor-Critic、Advantage、GAE 也都依赖 value function。
先回顾 return。设从时刻 \(t\) 开始的折扣回报为:
也可以写成:
其中:
- \(G_t\) 是从时刻 \(t\) 开始的 return。
- \(R_{t+i+1}\) 是未来第 \(i+1\) 步的奖励。
- \(\gamma\in[0,1)\) 是折扣因子。
State value 定义为:
Action value 定义为:
通过全期望公式,可以得到:
这一步很关键。后面我们会看到目标函数式根据 State Value 构造的,但是我们如果想要优化策略,就需要通过Action Value建立桥梁(变成 Action 的期望 策略显式的出现在目标里面.)
另一个很重要的点会在后面体现,就是所有的Reward都体现在 State Value 或者 Action Value 里面.所以即使我们直接优化策略,也无法完全摆脱 value 的概念.
Q: Policy Gradient 的目标函数怎么构造?
在参数化策略中,我们通常不再要求“每个状态的 value 都同时最大”,而是定义一个整体标量目标。一个常见目标是平均 state value:
其中:
- \(d(s)\) 是状态 \(s\) 的权重,可以理解为某种状态分布。
- \(v_{\pi_\theta}(s)\) 是策略 \(\pi_\theta\) 下状态 \(s\) 的 value。
- \(J(\theta)\) 是策略的整体表现。
如果把 \(v_{\pi_\theta}(s)\) 展开成 action value,就得到:
这个式子很直观:对于每个状态,策略会给不同动作分配概率;动作越好,也就是 \(q_{\pi_\theta}(s,a)\) 越大,我们越希望策略给它更高概率。
为了书写更简洁,后面把状态权重记作 \(\eta(s)\)。我们的核心是想要求损失函数的梯度:
这里暂时可以先把它理解成“对策略概率求梯度,再用动作价值加权”。更完整的推导中,\(q_{\pi_\theta}\) 也依赖 \(\theta\),但 Policy Gradient 定理会把这些间接影响整理进状态分布权重里,最终得到上面的紧凑形式。对于理解后续算法,记住这个形式已经足够。
Q: \(q_{\pi_\theta}(s,a)\) 也依赖 \(\theta\),为什么 Policy Gradient 里不显式对它求导?
这是 Policy Gradient 里最容易困惑的一点。直觉上,\(q_{\pi_\theta}(s,a)\) 当然依赖 \(\theta\),因为它表示在当前策略 \(\pi_\theta\) 下,从 \((s,a)\) 出发之后的期望 return:
后续动作如何采样由 \(\pi_\theta\) 决定,所以 \(q_{\pi_\theta}\) 不可能真的和 \(\theta\) 无关。
因此,Policy Gradient 并不是假设:
更准确地说,Policy Gradient Theorem 说明:当我们从完整轨迹分布出发对目标求导时,\(q_{\pi_\theta}\) 对 \(\theta\) 的间接依赖,会被轨迹概率 \(p_\theta(\tau)\) 的求导统一吸收。最终梯度可以整理成:
一个更直接的理解方式是从 trajectory 形式开始。设一条轨迹为 \(\tau\),目标是:
这里把 \(G(\tau)\) 写成不带 \(\theta\) 的形式,是因为 \(G(\tau)\) 表示“给定一条已经确定的轨迹后,这条轨迹上实际得到的 return”。例如:
那么:
一旦 \(\tau\) 固定,里面的状态、动作、奖励序列都已经固定,所以 \(G(\tau)\) 对 \(\theta\) 不再变化。策略参数 \(\theta\) 真正影响的是:什么样的轨迹更容易被采样出来,也就是 \(p_\theta(\tau)\)。
对 \(\theta\) 求导:
使用 log-derivative trick:
于是:
而轨迹概率可以分解为策略概率和环境转移概率。环境转移概率通常不依赖 \(\theta\),所以:
这就是为什么最终梯度只需要对 policy 的 log probability 求导。\(q_{\pi_\theta}(s,a)\) 或 return 作为权重出现,用来告诉策略“这个动作后续结果好不好”;但 actor 更新时,不需要沿着 \(q_{\pi_\theta}\) 本身继续反传。
不过,这里有一个重要前提:reward 本身不能显式依赖策略参数 \(\theta\)。在标准 RL 里,reward 通常来自环境,所以满足这个前提。LLM 中如果 reward 是冻结的 reward model:
并且 \(\phi\) 在 policy update 时固定,那么对给定的 \((x,y)\),\(R(x,y)\) 也可以看成和 \(\theta\) 无关。
但如果把 KL penalty 也合并进 reward,情况就要小心。例如:
这个 \(R_\theta(x,y)\) 显式依赖 \(\theta\)。严格求导时,除了 policy gradient 项,还会出现:
所以在推导 Policy Gradient 时,最好先把 reward 看成不显式依赖 \(\theta\) 的外部反馈;KL penalty 则作为额外 regularization / penalty 单独处理。这样记号和梯度路径都会更清楚。
在 actor-critic 的实现中,这一点通常表现为:critic / value model 单独训练,actor 更新时把 advantage 当作一个标量权重使用。例如伪代码常写成:
policy_loss = - log_prob(action) * advantage.detach()
这里的 \(\operatorname{detach}\) 并不是说 advantage 真的和策略无关,而是说在 policy gradient 这条更新里,advantage 是 sampled weight;critic 的参数通过自己的 value loss 更新。
所以,这个处理是靠谱的,但它不是一个朴素的“\(q\) 与 \(\theta\) 独立”的假设,而是 Policy Gradient Theorem / likelihood-ratio trick 的结果。
这个目标也可以直接写成期望形式。因为 \(d(s)\) 可以看成状态 \(S\) 的分布,所以:
继续把 state value 展开成 action value:
于是总目标也可以写成:
这个写法更接近后面 Policy Gradient 的推导,因为它明确告诉我们:目标函数本质上是一个关于状态和动作的期望。后面要做的事情,就是对这个期望关于 \(\theta\) 求梯度,并把它改写成可以用样本估计的形式。
Q: log-derivative trick 是什么?
上面的式子里有 \(\nabla_\theta \pi_\theta(a\mid s)\),但实际采样时,我们更希望把梯度写成某个期望的形式。这里要用到 log-derivative trick:
因此:
把它代入 Policy Gradient:
于是可以写成期望形式:
这个公式就是 Policy Gradient 的核心。它把“对整个策略函数求梯度”的问题,变成了“从策略中采样状态和动作,然后构造一个随机梯度估计”的问题。
从期望的角度看,这个变换的思想非常明确:\(\nabla_\theta \pi_\theta(a\mid s)\) 本身并不难计算,真正困难的是状态 \(S\) 的期望不容易直接求。经过 log-derivative trick 之后,目标里显式引入了动作 \(A\) 的期望,而动作可以直接从策略 \(\pi_\theta(\cdot\mid S)\) 中采样,所以我们得到了一种可行的随机梯度估计。不过严格来说,一条有限 rollout 中的状态样本并不自动等同于从理论状态分布 \(\eta(s)\) 中采样,下面单独解释这一点。
Q: 为什么 Q value 仍然会出现在 Policy Gradient 里?
Policy Gradient 是直接优化策略,但更新方向仍然需要知道某个动作好不好。这个“动作好不好”的信号就是 \(q_{\pi_\theta}(S,A)\)。
如果 \(q_{\pi_\theta}(S,A)\) 很大,那么梯度项:
会推动策略提高动作 \(A\) 在状态 \(S\) 下的概率。反过来,如果某个动作带来的 return 很低,它对更新的贡献也会更小,甚至在使用 advantage 后会变成负向更新。
所以,Policy Gradient 和 value-based 方法的区别不是“要不要 value”,而是:
- value-based 方法通常先学习 value,再由 value 导出策略。
- policy-based 方法直接学习策略,但需要 value / return 信号来告诉策略哪些动作值得增加概率。
从期望推导的理论上来看,为了让策略的参数直接出现在目标函数里,我们引入了 \(\pi_\theta(a \mid s)\) 这个可以优化的目标,也就引入了 \(A\) 的期望。从 state value \(v_{\pi_\theta}(S)\) 转变到了 action value \(q_{\pi_\theta}(S,A)\)。
Q: Policy Gradient 如何用样本估计?
真实的期望:
通常无法直接计算。我们能做的是从当前策略 \(\pi_\theta\) 中采样数据。一次 episode 可以写成轨迹:
然后用轨迹中的样本 \((s_t,a_t)\) 构造随机梯度:
其中 \(\hat{q}(s_t,a_t)\) 是 \(q_{\pi_\theta}(s_t,a_t)\) 的估计。不同的 Policy Gradient 算法,核心差别之一就在于:如何估计这个 \(\hat{q}(s_t,a_t)\)。
rollout 采样到的状态真的来自 \(\eta(s)\) 吗?
这里有一个容易混淆的点:Policy Gradient 公式中的状态权重 \(\eta(s)\) 是理论上的状态分布或状态权重,而一次有限长度 rollout 中出现的状态序列,并不一定严格服从这个分布。
换句话说,我们在 rollout 中拿到的是一串相关的样本 \((s_t,a_t)\),它们是否真的可以看成来自理论联合分布 \(\eta(s)\pi_\theta(a\mid s)\),需要更仔细地区分。
如果我们讨论的是 continuing task,并且把 \(\eta(s)\) 取为策略 \(\pi\) 诱导的稳态分布 \(d^\pi(s)\),那么它满足:
这个式子表示:如果当前状态服从 \(d^\pi\),经过一步策略选择和环境转移之后,下一个状态仍然服从 \(d^\pi\)。
但是 rollout 通常从某个初始分布 \(\mu(s_0)\) 开始:
如果初始分布 \(\mu\) 本身不是稳态分布,那么 rollout 前期的状态分布就不是 \(d^\pi(s)\)。这部分通常称为 transient phase,也就是过渡阶段。
在马尔可夫链满足不可约、非周期、正再生等条件时,随着时间趋于无穷,状态分布会收敛到唯一稳态分布:
所以更严谨的说法是:有限 rollout 中的状态样本不严格服从 \(d^\pi(s)\);足够长的 rollout,在丢弃前期 transient 后,可以近似看作来自 \(d^\pi(s)\)。
这也是为什么 REINFORCE、A2C、PPO 这类 on-policy 方法通常不显式估计 \(\eta(s)\)。它们直接用当前策略采样 rollout,再用这些样本对期望做 Monte Carlo 近似。
不过还要注意:在 episodic 或 discounted setting 中,\(\eta(s)\) 不一定是严格的稳态分布。它也可以表示从初始状态分布出发、在策略 \(\pi\) 下产生的 discounted visitation distribution。此时 rollout 近似的是这个访问分布,而不是 continuing task 中的 stationary distribution。
Q: REINFORCE 是什么?
REINFORCE 是最经典、最简单的 Policy Gradient 算法。它用 Monte Carlo return 来估计 \(q_\pi(s_t,a_t)\)。
根据 Q value 的定义:
如果我们已经采样到一整条 episode,就可以用这条 episode 中从 \(t\) 开始的实际 return:
作为 \(q_\pi(s_t,a_t)\) 的样本估计。这里使用 \(\hat{G}_t\) 而不是 \(G_t\),是为了强调它是这一次 rollout 中实际算出来的样本值;而 \(G_t\) 更像是理论上的随机变量。
于是 REINFORCE 在时刻 \(t\) 的样本梯度方向是:
如果把一整条 episode 中每个时间步的贡献加起来,那么一次 episode 给出的梯度估计可以写成:
如果用梯度上升写参数更新:
从操作流程上看,REINFORCE 可以分成几步。
第一步,用当前策略 \(\pi_\theta\) 和环境交互,采样一条完整 episode:
第二步,从 episode 末尾往前计算每个时间步的样本 return \(\hat{G}_t\)。这一步是 Monte Carlo 估计,因为它直接使用这条轨迹中真实发生的后续奖励。
第三步,把每个动作的 log probability 梯度乘上对应的 \(\hat{G}_t\)。如果某个时间步之后得到的 return 高,就增加当时动作的概率;如果 return 低,就减少它的概率。
第四步,把整条 episode 上的梯度贡献加起来,用梯度上升更新策略参数。
举一个很小的例子。假设一条 episode 是:
并且折扣因子 \(\gamma=0.9\)。那么从后往前可以算出:
于是这条 episode 给出的策略梯度估计是:
这个例子体现了 REINFORCE 的直觉:一条轨迹最终表现好,那么轨迹中导致这个结果的动作会得到更大的正向更新;如果 return 本身为负,或者后面引入 baseline / advantage 后相对表现为负,那么对应动作概率就会被压低。
REINFORCE 的优点是概念非常干净:采样一条轨迹,用实际 return 来更新策略。缺点也很明显:必须等到 episode 结束才能得到完整 return,而且 Monte Carlo return 的方差通常很大。后面的 baseline、advantage、actor-critic 和 GAE,都是在这个基础上让估计更稳定。
Q: 为什么可以加入 baseline?
为了降低方差,可以从 \(q_\pi(S,A)\) 中减去一个只依赖状态的 baseline \(b(S)\)。新的梯度形式是:
为什么这样不改变期望?因为:
展开来看:
而:
所以 baseline 不改变梯度的期望,但会改变随机梯度的方差。一个好的 baseline 可以让采样估计更稳定。
直觉上看baseline提供一个参考线,用动作的相对水平来代替动作的绝对水平.理论上这就像是归一化,降低估计的方差,稳定估计结果.
Q: Advantage function 是什么?
常见的 baseline 选择是 state value:
这样就得到 advantage function:
其中:
- \(q_\pi(S,A)\) 表示在状态 \(S\) 下采取动作 \(A\) 后的期望 return。
- \(v_\pi(S)\) 表示在状态 \(S\) 下按照当前策略平均行动的期望 return。
- \(A_\pi(S,A)\) 表示动作 \(A\) 相对于当前状态平均水平的优势。
使用 advantage 后,Policy Gradient 可以写成:
这个形式比直接使用 \(q_\pi(S,A)\) 更合理。因为策略更新真正关心的不是“这个动作的绝对回报是多少”,而是“这个动作是否比当前状态下的平均选择更好”。
如果 \(A_\pi(S,A)>0\),说明动作 \(A\) 比平均水平好,应该提高它的概率;如果 \(A_\pi(S,A)<0\),说明动作 \(A\) 比平均水平差,应该降低它的概率。
Q: Actor-Critic 是什么?
REINFORCE 用完整 return 估计 \(q_\pi(s,a)\),方差比较大。Actor-Critic 的想法是:既然我们需要 value 信号来更新策略,那就额外训练一个 value function 估计器来提供这个信号。
Actor-Critic 中有两个角色:
- Actor:策略函数 \(\pi_\theta(a\mid s)\),负责选择动作,并通过 Policy Gradient 更新。
- Critic:value function 的函数近似器,例如 \(v_w(s)\) 或 \(q_w(s,a)\),负责评估当前策略的动作或状态。
这里的 \(w\) 是 critic 的参数。也就是说,真实的 \(v_\pi(s)\) 通常无法直接计算,我们用一个带参数的函数 \(v_w(s)\) 去拟合它:
所以 Actor-Critic 实际上通常要同时维护两个函数:
- actor network:\(\pi_\theta(a\mid s)\),参数是 \(\theta\),负责产生动作概率。
- critic network:\(v_w(s)\) 或 \(q_w(s,a)\),参数是 \(w\),负责给 actor 提供 value / advantage 信号。
最直接的 actor update 可以写成:
critic 的任务则是学习 \(\hat{q}(s_t,a_t)\) 或 \(\hat{v}(s_t)\)。如果 critic 用 TD learning,就可以不等完整 episode 结束,而是用一步 transition 来更新。
如何估计 state value 或者 action value. 这些就是之前提到的 value-based 方法的内容了,可以参阅之前一节.虽然我们一开始就提到了LLM中使用 Policy based方法就是为了避开对Value的估计.(因为LLM系统中不好定义Value).不过原始RL算法中的Policy Gradient方法并没有完全摆脱Value的概念,它在推导过程中依然要引入Value function(Baseline,Advantage,GAE等算法都是为了估计Value function而设计). 不过幸运的是,LLM中的Value一般和传统RL语境中的Value不太一样.我们后续会看到.
Q: Advantage 如何用 TD error 估计?
在 Advantage Actor-Critic 中,我们通常不单独估计 \(q_\pi(s,a)\),而是用 state value \(v_w(s)\) 构造 advantage 的近似。这里 \(v_w(s)\) 是用函数近似拟合出来的 \(v_\pi(s)\),\(w\) 是 critic 的参数;actor 仍然是 \(\pi_\theta(a\mid s)\),\(\theta\) 是策略参数。因此整个算法同时维护 actor 和 critic 两个网络。
回忆 Bellman 关系:
因此 advantage 可以写成:
把上面的两个式子合在一起,可以看到 advantage 本身也是一个条件期望:
实际训练时,我们从 rollout 里拿到一个 transition 样本 \((s_t,a_t,r_{t+1},s_{t+1})\),再用 \(v_w\) 代替真实的 \(v_\pi\)。这样就得到一步 TD error:
这个 \(\delta_t\) 就可以看成 \(A_\pi(s_t,a_t)\) 的一步样本估计:
于是 A2C (Advantage Actor-Critic) 的 actor update 可以写成:
critic 则用同一个 TD error 更新 value function:
这就是 Actor-Critic 的基本闭环:critic 用 TD error 学 value,actor 用 TD error 作为 advantage 信号更新策略。
Q: GAE 是什么?
一步 TD error 方差较小,但可能有偏;完整 Monte Carlo return 偏差较小,但方差大。GAE,也就是 Generalized Advantage Estimation,试图在两者之间折中。
这句话有点费解: 为什么一般的 MCMC(样本数越多方差越小),但 RL 里的 Monte Carlo return 却随着 horizon 增长方差越来越大?这是因为: MCMC 说的是“估计器的方差随样本数减少”。RL 里的 MC return 说的是“单个样本本身的方差随 horizon 增加而变大”。
它要估计的对象仍然是 advantage:
使用的样本来自当前策略采样得到的一段 rollout:
critic 提供每个状态上的 value 估计:
从期望的角度看,\(n\)-step bootstrap 版本的 advantage 估计对象可以写成:
对应到一条 rollout 样本,就把随机变量替换成采样值,并用 \(v_w\) 近似 \(v_\pi\):
先定义每一步 TD error:
如果只看一步,那么 advantage 的估计就是 TD error:
如果向前多展开一步,就会得到二步 advantage 估计:
继续展开,\(n\)-step advantage 估计可以写成:
这和上面的 \(n\)-step return 写法是等价的,只是改写成了 TD error 的累加形式。这个式子说明了 GAE 的直觉:一步是 TD,展开很多步就越来越接近 Monte Carlo return。更准确地说,GAE 不是只选择某一个 \(n\),而是把不同长度的 \(n\)-step advantage 做指数加权平均:
把 \(\hat{A}_t^{(n)}\) 展开并交换求和顺序,可以得到更常见的形式:
其中:
- \(\hat{A}_t^{\text{GAE}(\gamma,\lambda)}\) 是时刻 \(t\) 的 advantage 估计。
- \(\gamma\) 是奖励折扣因子。
- \(\lambda\in[0,1]\) 控制 bias 和 variance 的折中。
实际实现时,GAE 通常不是从前往后显式求无穷和,而是在一段 rollout 上从后往前递推。令 \(\hat{A}_{t+1}^{\text{GAE}}\) 已经算好,则:
如果 rollout 在 \(T\) 处终止,通常令终止状态之后的 advantage 为 0;如果只是截断了一段固定长度的 rollout,则可以用 critic 对最后一个状态 \(s_T\) 的估计 \(v_w(s_T)\) 做 bootstrap。
当 \(\lambda=0\) 时,GAE 退化为一步 TD error:
当 \(\lambda\) 接近 1 时,它会利用更长的未来轨迹,更接近 Monte Carlo return。也就是说,GAE 可以看成从 TD 到 MC 的连续过渡:\(\lambda\) 越小,越依赖短期 bootstrap;\(\lambda\) 越大,越依赖长轨迹回报。
所以 GAE 估计的是 \(A_\pi(s_t,a_t)\) 这个期望对象;它使用的是 on-policy rollout 中的 reward、next state,以及 critic 给出的 \(v_w(s)\)。PPO 中常用 GAE 来估计 advantage,因为它在稳定性和样本效率之间比较平衡。
Q: PPO 是什么?
PPO,全称 Proximal Policy Optimization,是一种基于 Policy Gradient 的 actor-critic 算法。它要解决的问题是:我们希望用当前策略采样到的 rollout 改进 actor,但又不希望一次更新把新策略推得离旧策略太远。
如果策略更新过大,会出现两个问题。第一,旧策略 \(\pi_{\theta_{\text{old}}}\) 采样得到的数据很快变得“不像”新策略 \(\pi_\theta\) 下的数据,on-policy 估计会变差;第二,actor 的概率变化过猛,可能把原本还不错的行为直接破坏掉,训练会变得不稳定。
PPO 的核心想法是:允许新策略在旧策略附近改进,但限制新旧策略的差异。这里的“附近”不是指参数 \(\theta\) 的欧氏距离,而是指同一个状态动作样本上,新旧策略给出的概率不要相差太多。
更具体地说,PPO 在一次更新中会区分两个策略:
- \(\pi_{\theta_{\text{old}}}\):采样 rollout 时使用的旧策略。
- \(\pi_\theta\):当前正在优化的新策略。
给定旧策略采样得到的样本 \((s_t,a_t)\),PPO 比较新旧策略对同一个动作的概率:
其中 \(r_t(\theta)\) 称为 probability ratio。如果 \(r_t(\theta)>1\),说明新策略提高了旧样本中这个动作的概率;如果 \(r_t(\theta)<1\),说明新策略降低了这个动作的概率。
PPO 的策略目标不是直接最大化 \(r_t(\theta)\hat{A}_t\),而是使用 clipped surrogate objective:
其中:
- \(\hat{A}_t\) 是 advantage 估计,通常来自 TD error 或 GAE。
- \(\epsilon\) 是裁剪范围,常见取值是 0.1 或 0.2。
- \(\operatorname{clip}(r_t,1-\epsilon,1+\epsilon)\) 会把 ratio 限制在 \([1-\epsilon,1+\epsilon]\) 内。
- \(\min\) 的作用是:当新策略相对旧策略改得过猛时,不再继续给这个方向额外收益。
因为 PPO 是 actor-critic 算法,它通常还会同时训练 critic。critic 的目标是让 \(v_w(s_t)\) 接近某个 return 目标 \(\hat{R}_t\),例如 Monte Carlo return 或 bootstrapped return:
实际实现中,还经常加入 entropy bonus,鼓励策略保持一定探索性:
把这些部分合在一起,PPO 的常见优化目标可以写成:
这里 \(c_1\) 控制 value loss 的权重,\(c_2\) 控制 entropy bonus 的权重。因为我们通常把整体目标写成“最大化”,所以 value loss 前面是负号;如果实现里写成 loss 最小化,符号会相应反过来。
从一个完整训练循环看,PPO 大致做这些事:
- 用旧策略 \(\pi_{\theta_{\text{old}}}\) 与环境交互,采样一批 rollout。
- 对 rollout 中每个时间步,计算 reward、return 目标 \(\hat{R}_t\),以及 advantage 估计 \(\hat{A}_t\)。
- 保存旧策略在样本动作上的 log probability,也就是 \(\log \pi_{\theta_{\text{old}}}(a_t\mid s_t)\)。
- 固定这批 rollout,打乱成 mini-batch,对 actor 和 critic 做多轮梯度更新。
- actor 更新时计算 \(r_t(\theta)\),并最大化 clipped surrogate objective。
- critic 更新时最小化 value loss,让 \(v_w(s_t)\) 更接近 \(\hat{R}_t\)。
- 若达到最大 epoch、KL 超过阈值,或这批数据已经用完,就停止本轮更新。
- 把当前策略作为新的旧策略,重新采样 rollout,进入下一轮。
这里有一个很重要的细节:PPO 会对同一批 on-policy rollout 做多轮 mini-batch 更新,但不会无限重复使用旧数据。因为更新次数太多以后,\(\pi_\theta\) 会离 \(\pi_{\theta_{\text{old}}}\) 越来越远,这批旧样本就不再适合估计当前策略的梯度。clipping 正是在这个局部范围内,让“多用几轮样本”和“保持 on-policy 近似”之间取得折中。
因此 PPO 可以理解为:在 Actor-Critic 框架上,加了一个“不要离旧策略太远”的策略更新约束。下一节的 surrogate objective,就是在解释这个约束对应的目标函数从哪里来。
Q: PPO 的 surrogate objective 从哪里来?
其实PPO的思想很直接,从数据样本的角度看,每次更后我的策略已经变了,所以我也不能直接用之前的样本继续更新我的现在的策略.就像是 off-policy 学习一样,我需要使用 importance sampling 来对旧策略进行修正. 而 Clipping 就是确保新旧策略不会偏离的太远,虽然在数学上没有这个限制,但是实际使用中差异过大意味着数值不稳定性,极大可能导致训练崩溃.
如果样本来自旧策略 \(\pi_{\theta_{\text{old}}}\),而我们要更新的是新策略 \(\pi_\theta\),就需要用 importance sampling 把旧策略下的样本改写成新策略下的局部目标:
定义概率比值:
那么 PPO 的基础 surrogate objective,也就是还没有裁剪的目标,就是:
但是如果 \(r_t(\theta)\) 变化太大,策略会更新得过猛。PPO 在这个 surrogate objective 上加入 clipping,限制新旧策略差异,也就是上一节写到的 clipped surrogate objective。
Q: PPO 是 on-policy 还是 off-policy?
这个问题很容易让人困惑,因为 PPO 同时具有两个看起来有点矛盾的特点:
第一,PPO 使用旧策略 \(\pi_{\theta_{\text{old}}}\) 采样得到的数据来更新新策略 \(\pi_\theta\)。这看起来像 off-policy。
第二,PPO 又通常被归类为 on-policy 算法。这看起来又和第一点冲突。
要解开这个问题,需要先区分两组概念:
| 维度 | 问的是什么 | 典型区别 |
|---|---|---|
| online / offline | 数据是不是训练过程中不断重新采样? | online 会持续和环境交互,offline 只用固定数据集 |
| on-policy / off-policy | 更新的策略和采样数据的策略是否一致或足够接近? | on-policy 用当前策略数据,off-policy 可以用其他策略的数据 |
PPO 首先是 online 的。因为它的典型训练流程是:
用当前策略采样 rollout
→ 用这批 rollout 更新几轮
→ 丢掉旧 rollout
→ 用更新后的策略重新采样 rollout
→ 继续训练
所以 PPO 不是 offline RL。Offline RL 指的是只给定一个固定数据集,训练过程中不再和环境交互采样。
更微妙的是 on-policy / off-policy。严格来说,PPO 的一次更新确实不是用“完全同一个策略”做采样和优化。数据来自旧策略:
而正在优化的是新策略:
所以 PPO 需要 importance sampling ratio:
从这个形式看,PPO 确实带有一点 off-policy correction 的味道。
但是 PPO 不是典型的 off-policy 算法。因为 \(\pi_{\theta_{\text{old}}}\) 不是很久以前的任意 behavior policy,而是刚刚用来采样 rollout 的上一版策略。PPO 还会通过 clipping 或 KL 约束限制 \(\pi_\theta\) 不要离 \(\pi_{\theta_{\text{old}}}\) 太远,并且通常只对同一批 rollout 做有限轮 mini-batch 更新,然后就重新采样。
因此 PPO 更准确的说法是:
PPO 是 online、近似 on-policy 的 policy optimization 算法。
或者说:
PPO 用上一版策略采样的数据,对当前策略做一个局部、小步的近似 on-policy 更新。
所以在常见分类中,PPO 通常放在 on-policy 一侧,而不是和 DQN、Q-learning 这类典型 off-policy 方法放在一起。
可以粗略对比如下:
| 算法 | online / offline | on-policy / off-policy |
|---|---|---|
| REINFORCE | online | on-policy |
| A2C / A3C | online | on-policy |
| PPO | online | near on-policy |
| Q-learning | online | off-policy |
| DQN | online | off-policy |
| Offline RL | offline | 通常是 off-policy |
一句话总结:
PPO 不是严格的纯 on-policy,但在算法分类里通常算 on-policy 或 near on-policy;它不是典型 off-policy,更不是 offline RL。