一、前言
笔者在初次接触强化学习(Reinforcement Learning,RL)时,便对“让智能体自己学会决策”这个概念产生了浓厚的兴趣。随着近几年深度学习浪潮席卷整个 AI 领域,强化学习也开始和深度网络、生成式大模型等概念有机结合,衍生出诸如AlphaGo、深度Q网络(DQN)、策略梯度、PPO、RLHF(基于人类反馈的强化学习) 等一系列技术与应用。
其中,PPO(Proximal Policy Optimization, 近端策略优化算法) 算法又以其收敛稳定、实现简洁、适用面广泛等特性在业界和学术界获得了大量关注。OpenAI 的多项研究和实践成果都展示了 PPO 在连续动作控制、游戏对战(Atari)以及大语言模型微调等任务中的强大威力。
在大模型的浪潮下,我们也常常看到一些强化学习微调大模型的例子,如用 PPO 去让 ChatGPT 学会根据人类偏好产出更合适的回复,或者让大模型在写代码时更倾向于写出高效算法,这些背后都隐藏着 PPO 算法的身影。
本篇博客将从最基础的强化学习概念讲起,层层引入策略梯度、信任域策略优化(TRPO),最终剖析 PPO 的创新点与实现细节。然后再结合论文原文内容及一些示例代码,讨论 PPO 在大模型训练及实际应用(例如机器人控制、游戏、代码生成)的方式和优点。全文采用“先理论后实践”的结构,同时辅以必要的图示和代码,让读者能更清晰地把 PPO 的原理和实现对接起来。
二、强化学习入门:从马尔可夫决策过程到策略迭代
在探讨 PPO 之前,我们最好先温习一下强化学习的基本背景。毕竟,PPO 是策略梯度方法演化而来的一个变体,属于强化学习范畴;只有掌握了基础概念,才能理解 PPO 为何如此设计。
2.1 马尔可夫决策过程(MDP)
强化学习通常在一个 MDP(Markov Decision Process) 框架下进行。MDP 由如下元素构成:
- 状态空间(States):记作 S S S,智能体所在的环境状态。
- 动作空间(Actions):记作 A A A,在每个状态下能执行的可能动作。
- 转移概率(Transition Function):从状态 s s s 执行动作 a a a 后转移到新状态 s ′ s' s′ 的概率分布 P ( s ′ ∣ s , a ) P(s' \mid s,a) P(s′∣s,a)。
- 奖励函数(Reward Function):每次执行动作后,会得到一个即时奖励 r ( s , a ) r(s,a) r(s,a)。
- 折扣因子(Discount Factor):通常记作 γ ∈ [ 0 , 1 ) \gamma \in [0,1) γ∈[0,1),用来平衡短期奖励和长期奖励的重要性。
智能体的目标是找到一个最优策略 π ∗ \pi^* π∗,它能在与环境交互的过程中获得最大的期望累积奖励。如果要让大模型基于人类反馈去产出某种高质量文本,或者让机器人学会走路,都可以借助类似的 MDP 形式去表征交互过程和回报函数。
2.2 策略迭代(Policy Iteration)
强化学习的核心之一,就是如何搜索或优化策略 π ( a ∣ s ) \pi(a \mid s) π(a∣s)。有很多方法:基于值函数的、基于策略的、基于 actor-critic 混合的等等。其中,PPO 属于直接对策略参数进行梯度更新的流派,亦即策略梯度方法。因此,我们先要理解以下问题:政策梯度为什么成立? 又为什么需要 PPO 这样的特殊改进?
三、策略梯度:从 Vanilla Policy Gradient 到 TRPO
3.1 策略梯度方法简述
一般的策略梯度方法会定义一个可微的策略函数 π θ ( a ∣ s ) \pi_\theta(a \mid s) πθ(a∣s),其中 θ \theta θ 是神经网络参数。我们的目标是通过梯度上升,去最大化期望回报。
3.1.1 经典的梯度估计公式
让我们设想我们采集了一批经验 τ \tau τ(由若干状态-动作-奖励序列组成),然后根据那些数据来估计梯度。最常见的策略梯度估计器大致如下:
g ^ = E t [ ∇ θ log π θ ( a t ∣ s t ) A t ^ ] \hat{g} \;=\; \mathbb{E}_t \bigl[ \nabla_\theta \log \pi_\theta(a_t \mid s_t) \, \hat{A_t} \bigr] g^=Et[∇θlogπθ(at∣st)At^]
这里, A t ^ \hat{A_t} At^ 是优势函数(advantage function)的一个估计,描述了在当前状态下执行动作 a t a_t at 比平均水平好多少。实现时,往往会写成一个“可微目标函数”来让自动求导帮忙,比如:
L P G ( θ ) = E t [ log π θ ( a t ∣ s t ) A t ^ ] . L_{PG}(\theta) \;=\; \mathbb{E}_t \bigl[ \log \pi_\theta(a_t \mid s_t) \, \hat{A_t} \bigr]. LPG(θ)=Et[logπθ(at∣st)At^].
然后,我们就可以对 L P G L_{PG} LPG 做多次梯度上升更新参数,期望能够提升策略性能。但这里有个问题:多次对同一批数据做更新时,会可能导致策略发生很大的改变,从而让采样时的数据分布和后续优化不再匹配。这就是为什么在很多文献中我们看到传统的 policy gradient 通常只对单批数据更新一次,然后必须再收集新数据。
3.2 TRPO(Trust Region Policy Optimization):用 KL 约束大步更新
TRPO 提出了一个思路:直接在目标函数上加一个限制约束,让新旧策略别偏离太远,用 KL 散度来衡量这种差异。具体地,TRPO 要最大化一个近似的“替代”目标(Surrogate Objective):
max θ E [ π θ ( a t ∣ s t ) π θ old ( a t ∣ s t ) A t ^ ] , \max_\theta \;\; \mathbb{E}\Bigl[\frac{\pi_\theta(a_t \mid s_t)}{\pi_{\theta_{\text{old}}}(a_t \mid s_t)} \, \hat{A_t}\Bigr], maxθE[πθold(at∣st)πθ(at∣st)At^],
同时加上一个平均 KL 约束
E
[
K
L
(
π
θ
old
,
π
θ
)
]
≤
δ
\mathbb{E}[ KL(\pi_{\theta_{\text{old}}}, \pi_{\theta}) ] \le \delta
E[KL(πθold,πθ)]≤δ。
这样就避免了策略一口气更新得过猛,导致训练崩溃。TRPO 在实践上取得了很好的效果,但实现相对复杂,需要二阶优化或共轭梯度法等技巧,因而并非最为简洁易用。
四、PPO(Proximal Policy Optimization, 近端策略优化算法):核心思想与公式推导
PPO 算法是 John Schulman 等人在 2017 年论文 Proximal Policy Optimization Algorithms 中提出的。它可以被看作TRPO 的一种近似实现,用简单的一阶方法(SGD / Adam 等)就能实现与 TRPO 同级别的训练稳定性与性能,同时更加通用易落地。
论文原题:
Proximal Policy Optimization Algorithms
John Schulman, Filip Wolski, Prafulla Dhariwal, Alec Radford, Oleg Klimov
OpenAI
下文,我们先介绍最核心的公式和概念,然后再参考论文中各种实验对比、以及如何跟大模型训练结合等。
4.1 PPO 的两种常见实现思路
- Clipped Surrogate Objective:利用一个裁剪函数,对策略更新时的新旧概率比率 r t ( θ ) r_t(\theta) rt(θ) 做截断,保证更新不要超出一定范围。
- Adaptive KL Penalty:在目标函数上加上一个惩罚项 β ⋅ KL \beta \cdot \text{KL} β⋅KL,并动态地调整 β \beta β 以控制 KL 散度的大小。
根据论文以及后续社区实践,Clipped 版本更常用,被证明有更好的稳定性和简便性,也是大多数 PPO 代码库的默认实现。故下文将重点聚焦“clipped”版本。
4.2 Clipped Surrogate Objective:重点公式详解
先定义一个概率比率:
r t ( θ ) = π θ ( a t ∣ s t ) π θ old ( a t ∣ s t ) . r_t(\theta) = \frac{\pi_\theta(a_t \mid s_t)}{\pi_{\theta_\text{old}}(a_t \mid s_t)}. rt(θ)=πθold(at∣st)πθ(at∣st).
若新的策略让动作 a t a_t at 在状态 s t s_t st 下的概率变大,则 r t ( θ ) > 1 r_t(\theta) > 1 rt(θ)>1;如果变小,则 r t ( θ ) < 1 r_t(\theta) < 1 rt(θ)<1。
在 TRPO 里,我们希望别让 r t ( θ ) r_t(\theta) rt(θ) 跑得离 1 太远。PPO 的clipped版本直接在目标里嵌入一个截断操作:
L CLIP ( θ ) = E t [ min ( r t ( θ ) A t ^ , clip ( r t ( θ ) , 1 − ε , 1 + ε ) A t ^ ) ] . L_{\text{CLIP}}(\theta) = \mathbb{E}_t\bigl[\,\min\bigl(r_t(\theta)\hat{A_t},\; \text{clip}\bigl(r_t(\theta),1-\varepsilon,1+\varepsilon\bigr)\,\hat{A_t}\bigr)\bigr]. LCLIP(θ)=Et[min(rt(θ)At^,clip(rt(θ),1−ε,1+ε)At^)].
这里 ε \varepsilon ε 是个超参数,通常取 0.1 或 0.2。它控制了我们能容忍多大的“距离”更新。如果 r t ( θ ) r_t(\theta) rt(θ) 超过 [ 1 − ε , 1 + ε ] [1-\varepsilon,\;1+\varepsilon] [1−ε,1+ε],就被截到这个区间内,而取两者中的最小值的做法,可以理解为对“好处过大”的更新不再进一步奖励,但对那些变得更糟糕(劣势更明显)的更新却会实打实地惩罚。
下图(示意)可帮助理解截断过程:
(r 轴)
|
| unclipped objective: r_t(\theta) * A
|----1----(some boundary)----(some boundary)---
|
|
- 当 A > 0 A > 0 A>0(优势大),如果 r > 1 + ε r > 1+\varepsilon r>1+ε 就不再让其继续升高;
- 当 A < 0 A < 0 A<0(劣势),如果 r < 1 − ε r < 1-\varepsilon r<1−ε 也要进行惩罚。
如此一来,我们就能实现类似 TRPO 的“限制新旧策略距离”的效果,但却无需在优化时显式计算二阶梯度或做共轭梯度求解,只需用简单的 SGD / Adam 反复对这个 “ min ( ⋅ , ⋅ ) \min(\cdot,\cdot) min(⋅,⋅)” 目标做迭代即可。
4.3 整合价值函数与熵项
在策略梯度中,为了减少方差、提高收敛速度,往往会引入一个价值函数 V θ ( s ) V_\theta(s) Vθ(s),并基于它去计算优势函数 A ^ t \hat{A}_t A^t。另外还可能为鼓励探索,在目标中加上一项熵(Entropy)奖励。最终形成类似如下的完整 PPO 损失:
L ( θ ) = E t [ L CLIP , t ( θ ) − c 1 ⋅ ( V θ ( s t ) − V t target ) 2 + c 2 ⋅ S ( π θ ( s t ) ) ] , L(\theta) \;=\; \mathbb{E}_t\bigl[ L_{\text{CLIP},t}(\theta) - c_1 \cdot (V_\theta(s_t) - V_t^\text{target})^2 + c_2 \cdot S(\pi_\theta(s_t)) \bigr], L(θ)=Et[LCLIP,t(θ)−c1⋅(Vθ(st)−Vttarget)2+c2⋅S(πθ(st))],
- 第一项:PPO 的 clipped policy loss。
- 第二项:价值网络的均方误差损失。
- 第三项:熵奖励,系数 c 2 c_2 c2 一般较小。
其中 c 1 , c 2 c_1,c_2 c1,c2 也是超参,需要在实践中调节。有了这个目标函数,我们就能使用自动微分框架(如 PyTorch)一次性地反向传播更新策略和价值网络。
五、PPO 的训练流程与关键超参
结合上文,PPO 算法的典型实现一般是Actor-Critic 风格:Actor 负责输出策略分布,Critic 负责近似价值函数并提供优势估计。流程可简述如下:
- 采样:在当前策略 π θ old \pi_{\theta_\text{old}} πθold 下,运行若干并行环境,收集一批 trajectories(每条轨迹长度可定为 T T T),形成一个批次。
- 计算优势:基于 Critic(价值网络)来估计 A ^ t \hat{A}_t A^t,可以用 GAE(Generalized Advantage Estimation)等方式。
- 构建目标:利用 θ old \theta_\text{old} θold 固定的策略当做参考,定义 r t ( θ ) r_t(\theta) rt(θ) 并构造 L CLIP ( θ ) L_{\text{CLIP}}(\theta) LCLIP(θ) 等。
- 多轮小批更新:用这批数据反复进行 K K K 轮 minibatch SGD/Adam,对策略和价值网络的参数进行更新。
- 更新策略旧参数:将 θ old ← θ \theta_\text{old} \leftarrow \theta θold←θ,开始下一轮采样。
如此一来,每次我们都能“充分地”在同一批数据上做多次更新,却不会出现破坏性的大步偏移,因为 clip(或 KL 惩罚)在“守住”我们与旧策略的距离。
5.1 常见超参
- 步长 / 学习率 (learning rate):往往使用 Adam 优化器,需调参。
- 样本量 (batch size):常见如 2048、4096、10000 等,越大越平稳但也越慢。
- PPO 特有的 ε \varepsilon ε:通常设置 0.1 或 0.2。
- 价值函数系数 ( c 1 c_1 c1):如 0.5 或 1.0。
- 熵系数 ( c 2 c_2 c2):如 0.01 ~ 0.02,用于鼓励探索。
- GAE 的 λ \lambda λ:如 0.95。
- 折扣因子 γ \gamma γ:如 0.99。
这些超参往往需要针对具体任务和环境微调。论文也针对不同模拟控制任务(如 MuJoCo 机器人)和 Atari 游戏做了大量试验,给出了可参考的默认配置。
六、PPO 与大模型训练:为何如此重要?
在自然语言生成、对话模型、代码生成等任务中,近年非常流行对大语言模型做“基于人类反馈”的强化学习微调(RLHF),其核心流程是:先有一个预训练语言模型(或初步监督微调好的 SFT 模型),再结合人类偏好或自动奖励模型,对其进行策略优化。因为语言模型在输出 token 的过程中,也可以看作对“动作序列”做决策。此时,若仅使用传统的方式(如监督学习)去优化“likelihood”难以融入人类偏好;但引入 PPO,就能把“更符合人类期望”的输出得高分,进而在梯度更新时得到正向激励。
PPO 在这方面有以下优势:
- 稳定更新:语言模型规模庞大,若更新太猛易导致崩溃,PPO 的 clip 机制能很好控制更新幅度。
- 操作简便:只需要在框架里写出自定义的奖励函数 / 打分模型,然后把 PPO 的损失集成到网络中即可。
- 支持多次小批次迭代:同一批对话样本,可多次迭代,提升数据利用效率;对大模型来说,节省计算成本很重要。
因此,在 ChatGPT 等大模型的 RLHF 流程里,PPO 往往是主力方案;甚至做“写代码更高效”的大模型微调,也可通过 PPO 实现,让模型不断尝试输出不同写法,然后由一个“代码性能”打分器或人工标签器给出奖励。
七、论文主要实验对比:PPO vs. 其他方法
为了让读者更直观地感受 PPO 的强大与易用性,我们简要回顾论文中一些关键实验:
- 连续控制任务:如 MuJoCo 中的 Hopper、Walker2d、HalfCheetah 等。PPO 与 TRPO、A2C 等对比后,通常能收敛到更高的平均奖励,或更快收敛。
- Atari 游戏:PPO 相比 A2C、ACER 等,也展现了更出色的样本效率和最终得分。
- 3D Humanoid 复杂场景:如带障碍、带随机目标,PPO 能学出令人惊艳的动态行为。
论文还在附录中列举了大量超参表格(如 horizon、batch size、学习率等),这些都是社区在实践中可以直接参考的好起点。
八、PPO 的应用场景与实践心得
8.1 应用场景
- 机器人控制:通过 PPO,机器人能学会复杂的运动技巧,如倒立、跳跃、爬楼梯等。
- 游戏 AI:PPO 能让智能体在 Atari、Mujoco、Unity 3D 等环境中快速获得高分。
- 对话系统 / 大语言模型:通过 PPO 结合人类反馈,模型可在多轮对话或生成代码时更准确、更符合用户偏好。
- 其他泛化场景:任何需要稳定策略更新的序列决策任务,都可考虑 PPO。
8.2 实践心得
- Clip 系数 ε \varepsilon ε 选择:一般 0.1 ~ 0.2,若设置过大,约束不明显;过小则更新太保守。
- 优势估计:推荐用 GAE ( λ = 0.95 \lambda=0.95 λ=0.95 左右),稳定且易调。
- 多轮小批训练:对一批数据通常会做 K K K 轮(如 3~10 轮)的小批量更新,如果 K K K 过大,可能会“过拟合”那批数据。
- 观测训练曲线:重点留意 KL 散度、clipfrac(有多少比率被 clip)等指标,看是否更新过度或不足。
- 价值函数难度:若价值网络不准,会影响优势估计,从而影响策略更新效果。可视需要加大迭代次数或网络容量。
九、PPO 示例代码(简化版)
以下是一段 PyTorch 风格的伪代码示例,展示 PPO 训练的关键逻辑。这里我们用一个简化的“Actor-Critic”模型,其中 actor
用于输出策略分布,critic
输出状态价值
V
V
V。当然,读者也可用单一网络同时输出两者。
注意:此段代码仅为演示结构,去掉了很多工程细节(如并行采样、GAE、熵奖励等)。在实际项目中会更复杂一些。
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
class ActorCriticNet(nn.Module):
def __init__(self, state_dim, action_dim):
super().__init__()
self.shared = nn.Sequential(
nn.Linear(state_dim, 64),
nn.ReLU(),
nn.Linear(64, 64),
nn.ReLU()
)
# 输出策略参数
self.policy_mean = nn.Linear(64, action_dim)
self.policy_logstd = nn.Parameter(torch.zeros(1, action_dim))
# 输出价值函数
self.value_head = nn.Linear(64, 1)
def forward(self, x):
hidden = self.shared(x)
mean = self.policy_mean(hidden)
logstd = self.policy_logstd.expand_as(mean)
value = self.value_head(hidden)
return mean, logstd, value
def ppo_update(actor_critic, old_states, old_actions, old_log_probs, returns, advantages,
clip_param=0.2, vf_coef=1.0, max_grad_norm=0.5, lr=3e-4, epochs=10, batch_size=64):
"""
:param actor_critic: ActorCriticNet 模型
:param old_states, old_actions, old_log_probs, returns, advantages: 采样得到的训练数据
:param clip_param: PPO clipping 参数 epsilon
:param vf_coef: 价值函数损失系数
:param max_grad_norm: 梯度裁剪
:param lr: 学习率
:param epochs: 针对这批数据做多少轮
:param batch_size: 小批大小
"""
optimizer = optim.Adam(actor_critic.parameters(), lr=lr)
dataset_size = len(old_states)
for epoch in range(epochs):
# 打乱顺序,以小批方式训练
indices = np.arange(dataset_size)
np.random.shuffle(indices)
for start_idx in range(0, dataset_size, batch_size):
end_idx = start_idx + batch_size
mb_idx = indices[start_idx:end_idx]
states_b = old_states[mb_idx]
actions_b = old_actions[mb_idx]
old_log_b = old_log_probs[mb_idx]
returns_b = returns[mb_idx]
adv_b = advantages[mb_idx]
mean, logstd, value_b = actor_critic(states_b)
std = logstd.exp()
# 计算新策略的 log_probs
dist = torch.distributions.Normal(mean, std)
new_log_probs = dist.log_prob(actions_b).sum(dim=-1, keepdim=True)
# 计算 ratio
ratio = (new_log_probs - old_log_b).exp()
# 计算 PPO clipped objective
surr1 = ratio * adv_b
surr2 = torch.clamp(ratio, 1.0 - clip_param, 1.0 + clip_param) * adv_b
policy_loss = -torch.min(surr1, surr2).mean()
# 价值函数损失 (使用 MSE)
value_loss = nn.MSELoss()(value_b, returns_b)
# 总损失
loss = policy_loss + vf_coef * value_loss
optimizer.zero_grad()
loss.backward()
nn.utils.clip_grad_norm_(actor_critic.parameters(), max_grad_norm)
optimizer.step()
核心逻辑解析:
ratio = exp(new_log_probs - old_log_probs)
计算了新旧策略对同一动作的概率比。surr1 = ratio * advantage
和surr2 = clamp(ratio, 1-clip, 1+clip) * advantage
分别对应 unclipped 和 clipped 的策略损失。我们取二者之 min 以实现 PPO。value_loss
用 MSE 来让价值网络逼近目标returns
。- 总损失等于
policy_loss + vf_coef * value_loss
,然后对其做梯度下降/上升(视实现而定),并可以进行梯度裁剪以稳定训练。
在实际大语言模型或更复杂网络结构中,思路也类似,只不过输入输出变成了文本 token、生成概率分布等,还要结合注意力机制、RNN/Transformer 等设计。
十、PPO 与其他强化学习算法对比
10.1 PPO vs. TRPO
- 相似:都在“限制新旧策略差距”上做文章,目的都是让训练稳定。
- 不同:TRPO 使用二阶近似并且要解一个约束优化问题;PPO 用一阶的 clip 或 KL penalty 实现约束,代码更简洁高效。
- 实践结论:PPO 通常比 TRPO 更易调参、更通用,收敛效果也相当不错。
10.2 PPO vs. A2C / A3C
- A2C / A3C:更新幅度不受额外限制,可能收敛也快但不稳定,或需更多超参微调。
- PPO:更稳定,在许多连续控制和 Atari 游戏中表现优异。
- 论文和社区实验也显示,PPO 相比 A2C 等往往在训练速度、最终分数上都有不小优势。
10.3 PPO vs. SAC / TD3 等价值型方法
- SAC / TD3 属于值迭代范畴(离策略),对高维连续动作有不错表现。
- PPO 属于在策略范畴,策略分布直接建模,更易与大模型生成这种token-by-token的场景衔接。
- 在语言模型或需要“可微分采样”的场合,PPO 更加主流。
十一、论文中的更多细节回顾
若读者想深入阅读 Proximal Policy Optimization Algorithms 原文,可重点留意以下章节:
- Clipped Objective 的推导(Section 3):如何用截断概率比率来形成“保守估计”。
- Adaptive KL Penalty(Section 4):另一种做法,用动态调节的惩罚系数 β\beta 保持新旧策略 KL 不超标。
- 算法过程(Section 5):一步步的伪代码,以及多次小批次更新的思想。
- 实验对比(Section 6):从简单的 Mujoco 到 Atari,到 3D humanoid 全面展示 PPO 的优势。
整篇论文行文简洁,推荐有兴趣的同学阅读。PPO 的核心思路并不算复杂,主要看如何在实际中调参和稳定训练过程。
十二、在实际项目中“落地”PPO:几点建议
- 调试重点:
- 观察
policy_loss
、value_loss
曲线是否健康。 - 监控
KL
散度或clipfrac
(有多少 ratio 超过阈值被截断)。 - 监控奖励随时间是否持续上升。
- 观察
- 分布式并行:
- 对于大模型训练或高维控制任务,需用多线程 / 多GPU 并行收集样本,并行梯度更新。
- 混合 RL 与监督学习:
- 先进行一段时间的监督训练(如 SFT),得到一个可用策略,再用 PPO 做精调,往往效果更好。
- 日志与可视化:
- 建议结合 TensorBoard / Weights & Biases 等工具实时观察训练过程。
- 与其他激励相结合:
- 对话模型可加上“符合上下文连贯”或“避免有害内容”的惩罚项;写代码可加上“编译报错”惩罚;或加安全审计模块等。
十三、总结与展望
经过漫长的论述,我们从强化学习的基础概念,一路走到策略梯度、TRPO,再到 PPO 的核心思想与实验结果,最后讨论了 PPO 在大模型训练(如 RLHF)的落地方式与实操技巧。简而言之,PPO 提供了一种稳定、高效、易于实现的策略优化途径,既能对接深度神经网络,又能很好地克服“策略更新过猛”导致的崩溃问题。
在当前大模型爆炸的时代,PPO 仍然是许多工业界和学术界应用最广的强化学习优化器。无论是让机器人学跳舞,还是让 ChatGPT 学会编写高质量代码,都能见到 PPO 的身影。 其剪切式的创新思路在后续也影响了大量研究,一些变体或改进(如 DPPO、APPO、PPO2 等)不断被提出,但主要框架大体保持一致,可见其设计之优雅与通用。
当然,随着研究的不断深入,或许还会出现更多新方法,去解决 PPO 潜在的不足之处(如对超参依赖、对价值网络的敏感性等)。但就当前而言,若你打算在RL或RLHF场景中选择一个“一线成熟算法”,PPO 往往是首推。
希望这篇博文能让大家对 PPO 算法有一个相对完整、系统、深入的认识,并能在后续的应用中灵活运用。如果读者想进一步钻研,可参考以下资源:
- Schulman et al., Proximal Policy Optimization Algorithms (arXiv:1707.06347)
- OpenAI Spinning Up: PPO Tutorial
- Hugging Face Deep Reinforcement Learning Class: PPO 章节
- 各大 GitHub repo:
stable-baselines3
、CleanRL
、OpenAI Baselines
、RLlib
等均提供 PPO 的可用代码