type
Post
status
Published
date
Apr 9, 2026
slug
summary
tags
category
技术分享
category (1)
icon
password
comment
论文地址:
arxiv.org![arxiv.org]()
arxiv.org
1.背景
PPO(Proximal Policy Optimization,近端策略优化)是一种强化学习算法,由OpenAI于2017年提出,旨在解决策略梯度方法中的训练不稳定问题。PPO通过限制策略更新的幅度,确保每次更新不会偏离当前策略太远,从而提升训练的稳定性和效率。
在Introduction部分,作者介绍了强化学习领域中使用神经网络作为函数逼近器的几种主要方法,包括深度Q学习(Deep Q-Learning)、标准的策略梯度方法(Vanilla Policy Gradient Methods)和信任域策略优化(Trust Region Policy Optimization, TRPO)。尽管这些方法在某些任务上表现良好,但它们各自存在一些局限性:
- 深度Q学习:在连续控制任务中表现不佳,且理论理解不够深入。
- 标准策略梯度方法:数据效率低,鲁棒性差。
- TRPO:虽然数据效率高且性能稳定,但实现复杂,且不兼容包含噪声(如dropout)或参数共享的架构。
为了克服这些局限性,作者提出了近端策略优化(Proximal Policy Optimization, PPO)算法。PPO 的主要目标是:
- 保持 TRPO 的数据效率和稳定性。
- 使用一阶优化(如随机梯度上升)简化实现。
- 适用于更广泛的架构和任务。
PPO 的核心思想是通过裁剪概率比来限制策略更新的幅度,从而避免过大的策略更新。实验表明,PPO 在连续控制任务和Atari游戏中表现优异,尤其在样本复杂度、简单性和训练时间之间取得了良好的平衡。
PPO 算法公式,主要是参考TRPO 做了优化和改进,因此论文中主要以TRPO为基线进行的介绍。
2.算法
2.1 策略梯度方法
策略梯度方法通过直接优化策略 来最大化期望回报。策略梯度定理表明,策略的梯度可以表示为:
其中:
• 是策略网络在状态下选择动作的概率。
• 是优势函数(Advantage Function),表示在状态下选择动作的相对优势。
策略梯度方法通过采样轨迹并使用上述梯度更新策略参数。
尽管策略梯度方法简单直观,但直接对同一轨迹进行多步优化会导致策略更新过大,从而破坏策略的性能。
2.2 信任域Trust Region Methods
信任域方法(如TRPO)通过在策略更新时引入约束来限制更新的幅度,从而确保策略更新的稳定性。以下是信任域方法的两种主要实现方式:
硬约束方法(Hard Constraint Method)
硬约束方法是信任域策略优化(TRPO)的核心思想。它通过引入一个硬约束来限制新旧策略之间的KL散度,从而确保策略更新的幅度在一个合理的范围内。
目标函数:
TRPO的目标是最大化以下替代目标函数:
约束条件:
同时,TRPO引入了一个硬约束,限制新旧策略之间的KL散度:
其中:
• 是一个小的正数,用于控制策略更新的幅度。
• 是旧策略和新策略之间的KL散度。
实现细节:
• TRPO使用共轭梯度法(Conjugate Gradient Method)来近似求解这个带约束的优化问题。
• 由于硬约束的存在,TRPO能够确保每次策略更新都在信任域内,从而保持策略优化的稳定性。
KL惩罚方法(KL Penalty Method)
KL惩罚方法不需要复杂的二阶优化(如共轭梯度法),只需使用一阶优化方法(如随机梯度上升)即可。
KL惩罚方法是信任域方法的另一种实现方式。与硬约束方法不同,KL惩罚方法通过在目标函数中引入KL散度惩罚项来限制策略更新的幅度,而不是使用硬约束。
KL惩罚方法的目标函数为:
其中:
• 是KL散度的惩罚系数,用于控制策略更新的幅度。
• 当较大时,KL散度惩罚项会限制策略更新的幅度;当较小时,策略更新的幅度可以更大。
2.3 PPO核心
PPO 的核心思想是通过限制策略更新的幅度来避免过大的策略更新,从而保持训练的稳定性。具体来说,PPO 通过以下两种方式实现这一目标:
- 裁剪概率比:限制策略更新的幅度,避免过大的策略变化。
- 自适应KL惩罚:通过动态调整KL散度的惩罚系数来控制策略更新的幅度。
DPO 中的KL 散度抑制,主要继承于这里。
裁剪概率比
PPO 使用了一个裁剪的替代目标函数,其形式如下:
其中:
• 是策略更新前后的概率比。
• 是优势函数的估计。
• 是一个超参数,通常设置为或,用于控制裁剪的范围。
裁剪概率比的作用:
• 当 超出范围 时,裁剪操作会限制策略更新的幅度。
• 通过取最小值 ,PPO 确保目标函数是原始目标函数的下界(即悲观估计),从而避免过大的策略更新。
下图是对clip 方法的直观解释

图里的横坐标 r 代表新策略动作概率除以旧策略动作概率的比值。图上的红色圆点是起点,也就是 r 等于 1 的地方,代表这时候新策略和旧策略一模一样,还没开始迈出更新的步伐。纵坐标可以理解为AI想要努力去最大化的那个“综合得分”。图里横轴上标注的希腊字母 epsilon 就是我们给AI设定的规矩界限,通常会设置成 0.2。
左边这半部分画的是 A大于0 的情况。A大于0意味着AI刚才做了一个好动作,比平均水平表现得更好。这时候,AI 显然想增加以后做这个动作的概率,也就是想让横坐标 r 往右边移动,变得大于1。顺着线看,在 r 到达 1 加 epsilon(也就是1.2)之前,线是一直往上走的,说明得分在增加,AI 受到了实打实的鼓励。但是关键点来了,一旦 r 超过了 1.2,这条线就突然变成平的了。这就是所谓的被截断了。
右边那半部分画的是 A小于0 的情况,意思是AI刚才做了一个比较差的动作。这时候,AI 想要减少以后做这个动作的概率,也就是想让横坐标 r 往左边移动,变得小于1。注意看图像的斜率,在这个图里,因为AI总是想要跑到纵坐标更高的地方去,所以当 r 在 1 减 epsilon(也就是0.8)到 1 之间的时候,AI 往左边走是可以爬得更高的。同样的关键点出现了,一旦 r 往左边降到了 0.8 以下,这条线也平了。把这个坏动作的概率降低到原来的百分之八十已经足够起到惩罚作用了,没必要为了这一个失误彻底颠覆整个大脑的认知。
自适应KL惩罚
除了裁剪概率比,PPO 还提出了另一种方法,即通过KL散度来限制策略更新的幅度。其目标函数为:
其中:
• 是新旧策略之间的KL散度。
• 是KL散度的惩罚系数。
下面介绍了如何修改系数
- 计算KL散度: 在每次策略更新后,计算新旧策略之间的KL散度: 2. 调整惩罚系数: 如果KL散度 小于目标值 的一定比例(如 ),则减小 : 如果KL散度 大于目标值 的一定倍数(如 ),则增大 : 3. 使用更新后的 : 更新后的 用于下一次策略更新。
2.4 PPO计算

PPO 的综合目标函数如下:
综合目标函数,主要包括3个部分:
- 裁剪目标函数,用于策略优化;
- 价值函数误差项,用于估计状态价值函数。【这里的价值函数用于估计计算优势函数】
- 熵正则化项,用于鼓励探索。
- 以及两个超参数,用于控制价值函数误差项以及熵正则的权重。
裁剪目标函数前边介绍了。 这里说一下价值函数误差项和熵正则化,帮助理解。
价值函数误差项用于估计状态价值函数 ,其形式为:
其中:
• 是策略网络对状态 的价值估计。
• 是目标价值,通常通过采样数据计算得到,例如使用TD目标或蒙特卡罗估计。
价值函数误差项的作用是优化价值函数网络,使其能够更准确地估计状态价值,从而帮助策略网络更好地理解环境。价值函数,一般实现是在基础模型的最后加一个 value head。
熵正则化项用于鼓励策略探索,其形式为:
其中:
• 是策略网络在状态 下选择动作 的概率。
熵正则化项的作用是增加策略的随机性,避免策略过早收敛到次优解。通过最大化熵,策略网络会更倾向于探索不同的动作,从而提高训练的鲁棒性。
优势函数的计算:
如公式10-12所示, 优势函数的基础计算在于公式12. 即 reward model 的评分 + 价值函数相邻token 的差。
基于此,代入公式11, 得到最终的优势函数输出。 这里叫做GAE, 广义优势计算。
下图是论文中PPO 的计算伪代码。

简要总结PPO 的计算步骤:
- 采样数据:使用当前策略与环境交互,采样轨迹数据。
- 计算优势函数:基于采样数据计算每个时间步的优势函数估计 。
- 优化目标函数:使用裁剪目标函数 或自适应KL惩罚目标函数 ,通过随机梯度上升(SGD)或 Adam 优化器对目标函数进行多轮优化。
- 更新策略:更新策略参数 和价值函数参数 。
结合PPO 的目标函数来讲, 其中的策略概率比,比较好计算,就是LLM 的 ref model 以及 policy model 的概率输出结果。 KL 散度也是可以通过概率输出计算的。
其中需要仔细理解的是优势函数是如何计算实现的。 我们先按照论文中的推导理解原理。后边会根据trl 包中的代码介绍具体的实现.
2.5 优势函数介绍
由于优势函数相对难以理解。解释的内容较多,这里单独放一个小结。
在强化学习中,优势函数(Advantage Function)是用于衡量在某个状态下采取某个动作的相对优势的指标。它表示在状态 下采取动作 的价值相对于该状态下平均动作价值的差异。优势函数的定义如下:
其中:
- 是动作价值函数,表示在状态 下采取动作 后,未来累积奖励的期望值。
- 是状态价值函数,表示在状态 下,未来累积奖励的期望值。
优势函数的核心思想是:
- 如果 ,说明动作 比平均动作更好。
- 如果 ,说明动作 比平均动作更差。
优势函数在策略梯度方法中起着关键作用,因为它能够帮助策略网络更好地理解哪些动作是好的,哪些动作是坏的。具体来说:
- 策略梯度更新:策略梯度方法通过优势函数来调整策略参数 θ,使得策略更倾向于选择优势较大的动作。
- 减少方差:优势函数能够减少策略梯度估计的方差,从而提高训练的稳定性。
优势函数的估计
在实际应用中,我们通常无法直接获得真实的 和 ,因此需要通过采样数据来估计优势函数。PPO算法使用广义优势估计(Generalized Advantage Estimation, GAE)来计算优势函数。
TD误差
TD误差是优势函数估计的基础,其定义为:
其中:
- 是在时间步 获得的即时奖励。
- 是折扣因子,用于衡量未来奖励的重要性。
- 是下一个状态的状态价值函数估计。
- 是当前状态的状态价值函数估计。
TD误差表示当前动作的即时奖励加上未来奖励的现值,减去当前状态的价值估计。
广义优势估计(GAE)
广义优势估计(GAE)是对TD误差的加权求和,其形式如下:
其中:
- 是GAE参数,用于控制偏差和方差之间的权衡。
- 是折扣因子。
- 是轨迹的长度。
GAE的核心思想是通过对多个时间步的TD误差进行加权求和,来估计优势函数。当 时,GAE退化为蒙特卡罗估计;当 时,GAE退化为单步TD误差。
优势函数的计算步骤
以下是 PPO 算法中计算优势函数的具体步骤:
- 采样轨迹:使用当前策略 与环境交互,采样固定长度的轨迹数据,包括状态 、动作 、奖励 和下一个状态 。
- 计算状态价值函数:使用价值函数网络 估计每个状态的状态价值 。
- 计算 TD 误差:对于每个时间步 ,计算 TD 误差 :
- 计算广义优势估计:对于每个时间步 ,计算广义优势估计 :
- 使用优势函数进行策略更新:将计算得到的优势函数 用于策略梯度更新,优化策略参数。
3.代码实践
所用代码是github中cleanrl项目https://github.com/vwxyzjn/cleanrl
action(动作): AI 决定做的动作(模式 A),或者是你硬塞给它的历史动作(模式 B)。这告诉环境接下来该怎么走。
probs.log_prob(action)(对数概率): 当前这个大脑,做出这个具体动作的概率是多少(取了对数)。 如果是模式 A,这就是收集数据时的旧概率(分母)。如果是模式 B,这就是网络更新后的新概率(分子)。 新旧概率一除,就是 PPO 截断公式里的主角:概率比 Ratio。
probs.entropy()(信息熵): 当前这个“概率轮盘”的混乱程度。如果大概率集中在一个动作上,熵就低;如果每个动作概率差不多,熵就高。PPO 拿着这个值去计算“熵奖励”,鼓励 AI 多尝试,别太死脑筋。
self.critic(x)(状态价值): 评论家网络出场了。它看着当前的局势x,给出一个预测总分(比如“我觉得当前这个局面未来还能拿 15 分”)。这个分数值就是用来算 TD 误差和 GAE(优势函数)的基石。
这段代码是 PPO 算法中最核心的数学计算部分:计算广义优势估计(GAE)和目标价值(Returns)。
- 通俗地说,这段代码的任务是 “秋后算总账”。
- 刚才 AI 跑了 128 步,收集了一堆数据。
- 现在,我们要给这 128 步里的每一步打个标签:这一步到底是走了一招妙棋,还是一步臭棋?
- 并且要为价值网络(评论家)算出它本应该预测出的“标准答案”。
- 我们逐行拆解这个精妙的 倒推(Backward) 过程:
1. 准备工作:预测“未来”与初始化
next_value:在这 128 步走完之后,AI 停在了第 129 步的状态(next_obs)。为了计算第 128 步的价值,我们需要让评论家对这“未卜的未来(第 129 步)”估个分。这在强化学习里叫自举(Bootstrapping)。
advantages:准备一个小本本,用来填入这 128 步里每一步的优势值(Advantage)。
lastgaelam:这是一个累加器,等会儿用来把未来的优势不断传递给现在。
2. 为什么要倒着算?(
reversed)这是整个 GAE 最聪明的工程实现。因为第 1 步的动作到底好不好,不仅看第 1 步的奖励,还要看第 2、3、4 步的奖励。如果正着算,每算一步都要把后面的数据重新遍历一遍,计算量爆炸()。
倒着算的话,第 128 步算出的结果,可以直接传递给第 127 步;127 步算完传给 126 步……这样只需要循环一次()就能全部算完!
3. 处理游戏结束的边界情况(Masking)
这里的
nextnonterminal 是一个非常关键的遮罩(Mask)机制:- 如果游戏在下一步结束了(死掉了),
done = 1,那么nextnonterminal就变成0。
- 如果游戏还没结束,
nextnonterminal就是1。
- 为什么要这么做? 因为如果游戏结束了,未来的奖励和预测价值就归零了,绝对不能把上一局死掉后的数值加到当前这一步来。
4. 计算单步 TD 误差(当前动作的即时惊喜度)
这就是你在前面的提问里发的那张图里的 TD 误差公式:
- :这是我们实际走了一步后,拿到的“真实奖励 + 对未来的最新预测”。
- :这是我们在走这一步之前,评论家“原本的预测”。
- 它们俩相减(
delta),就是“惊喜度”。如果大于 0,说明实际情况比预期的好;如果小于 0,说明比预期的差。
5. 计算 GAE 优势函数(核心公式)
这也是你之前截图中 GAE 公式的代码化:
在倒推循环中,这行代码通过累加器
lastgaelam,巧妙地把后面所有的 delta 都按衰减比例加到了当前的步骤上。- 算出的
advantages,就是接下来用来更新策略网络(演员)的极其重要的数据:它明确指出了这 128 步里,哪些动作该被鼓励(优势 > 0),哪些该被惩罚(优势 < 0)。
6. 拼凑价值网络的“标准答案”
在这段对话的一开始,你问过:
Vt_target(目标价值)怎么算?这就是答案!- 在数学上,优势 = 实际总价值 - 预期价值()。
- 稍微移个项:实际总价值 = 优势 + 预期价值()。
- 这里的
returns就是利用我们算出的真实优势和当时的预测值,拼凑出来的“更为准确的真实累计得分”。
- 在接下来的训练里,这个
returns就会作为标准答案(Target),用来计算均方误差,惩罚并更新价值网络(评论家),让它下次估分估得更准。
- 带截断的策略损失 (Clipped Policy Loss)
论文公式:
这是新手最容易懵圈的地方。论文的目标是“最大化预期收益”(梯度上升),所以公式外层套的是 ,体现一种“悲观的下界保证”。但是,PyTorch 的优化器天生只会做“最小化损失”(梯度下降)。为了让框架工作,我们给所有项都乘上了负号
- 价值网络双截断 (Value Loss Clipping)
论文建议价值网络的损失使用简单的均方误差(MSE),即代码里
else: 后面的部分。OpenAI 在其官方实现(baselines)中悄悄加入了这个 clip_vloss。为什么?因为策略网络(Actor)不能更新太快,价值网络(Critic)同样也不能!如果价值网络在一轮复习中预测值剧烈抖动,会导致下一步算出的优势函数完全失效。因此,这里对预测价值的变化量也做了截断限制,取截断前后误差较大的那个(torch.max),强迫价值网络稳步更新。- 联合损失与梯度裁剪
论文公式:
最终的
loss 是三项的加权求和:
1. pg_loss: 策略损失(推动 AI 做出高分动作)。
2. v_loss * args.vf_coef: 价值损失(论文中的 ,让 AI 对局势估分更准)。
3. - args.ent_coef * entropy_loss: 熵奖励(论文中的 )。注意前面是负号,因为优化器在最小化 loss,减去熵实际上是在最大化熵,目的是鼓励 AI 保持好奇心,多去探索未知的动作。nn.utils.clip_grad_norm_是全局梯度裁剪。无论前面算出的损失有多大,强制把梯度的模长限制在 args.max_grad_norm(通常为 0.5)以内。这是防止神经网络在遇到极端数据时瞬间崩溃的最后一道防线。- 作者:qetx
- 链接:http://qetx.top/article/33db233d-8731-80f5-b29c-dfaf2981bdff
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。





