PPOProximal Policy Optimization
第 9 章的 AC 每步更新,但更新幅度完全不受控——一步过头就可能毁掉整个策略。本章的 PPO 用「裁剪目标」把每次更新锁在信任区域内:简单、稳定、可大规模并行,是 OpenAI 训练 ChatGPT 的 RLHF 底座。
裁剪目标 · 机制可视化
实线 = 有效目标 min(r·A, clip(r)·A)。虚线 = 未裁剪的 r·A。信任区域之外目标变平 → 梯度为 0 → 策略不会被推得太远。
PPO vs A2C vs DQN · CartPole 同场对比
当前观看:PPO 的 CartPole
三个算法(PPO / A2C / DQN)独立训练。PPO 按批收集后统一更新,A2C 每步 TD 更新,DQN 经验回放更新——比谁的曲线爬得快、站得稳。
为什么学这步?
策略梯度方法普遍脆弱:更新步长稍大,策略一步崩溃;稍小,训练慢如蜗牛。PPO 用「裁剪」代替二阶信任区域优化(TRPO),在几乎零调参成本下获得稳定的更新——因此成为 OpenAI 训练 ChatGPT 与 Claude 等大模型 RLHF 阶段的事实标准。它是现代 RL 的「工业底座」。
下一步预告:PPO 能对齐"奖励"本身。下一章 RLHF 把人类偏好变成奖励模型,用 PPO 教会大模型"说人类爱听的话"。
📌 发生了什么
- 重要性采样比率 r = π_new/π_old,让一批旧数据可被多次更新
- 裁剪目标把单次更新限制在 [1−ε, 1+ε] 的信任区域内
- GAE(γ, λ) 在偏差与方差之间滑动权衡优势估计
- CartPole 上 PPO 的曲线比无约束的 A2C 更稳
⚠️ 常见陷阱
- 误以为 ε 越大越好——ε 太大信任区域名存实亡,退化为无约束策略梯度
- 多轮 epoch 里更新 ratio 的分母——π_old 必须冻结为收集数据时的策略
- 忽略 λ 的作用——λ 控制 GAE 的偏差-方差权衡,不是可以随便设的常数
✅ 本章小结
- PPO = 收集轨迹 + GAE 优势 + 裁剪目标多轮更新
- 裁剪让每次更新的「步长」被限制,稳定性远超无约束方法
- 简单、稳健、可并行 → 大模型 RLHF 的事实标准
📐 PPO 推导:从策略梯度到裁剪目标
策略梯度 J(θ) = E[∇logπ_θ(a|s)·A]。若想用旧策略 π_old 收集的数据训练新策略 π_θ,需要重要性采样修正:每一项乘上比率 r(θ)。
直接最大化 r·A 有风险:若 r 变得很大(新策略远偏离旧策略),一次更新就可能摧毁策略。TRPO 用约束保证「安全距离」,但实现复杂;PPO 换了个思路——把目标本身钳制住。
min 的妙处:当 r 越过信任区域边界时,取到的是常数 clip(r)·A,梯度为 0——策略「不前进也不后退」,在原地等待数据更新。A>0 时只剪 r 的上界(防止过度推崇好动作),A<0 时只剪下界。
GAE(γ, λ) 把多步 TD 误差按 (γλ)^l 加权求和:λ=0 是一步 TD(低方差高偏差),λ=1 是 MC 回报(无偏差高方差),0<λ<1 在两者间插值——PPO 通常取 λ≈0.95。
🎛 PPO 超参对比
PPO 以「几乎不用调参」著称,但少数几个旋钮仍直接影响稳定性。
| 超参 | 表现 | 结果 |
|---|---|---|
| ε 过大(> 0.5) | 信任区域几乎不设限 | 退化为 A2C |
| ε ≈ 0.1 ~ 0.3 | 更新受限但仍能快速学习 | 推荐 |
| epochs 过多(> 10) | 同一批数据反复拟合 | 过拟合旧批 |
| λ ≈ 0.95 | 偏差-方差平衡良好 | 默认推荐 |
💡 经验法则:ε=0.2、λ=0.95、epochs=3 是几乎处处可用的起点;若 clipFrac 长期接近 100%,先调小学习率而不是调大 ε。
💻 PPO 核心循环
「收集 → 算优势 → 裁剪更新」三步循环,伪代码即实现。
for iteration in range(T):
# 1) 用当前策略收集一批轨迹,记录旧 log 概率
for (s, a, r, done) in rollout():
old_logp.append(log_prob(policy, s, a))
# 2) GAE 计算优势与回报
A = gae(rewards, values, gamma, lam)
G = discounted_returns(rewards, gamma)
# 3) 多轮 epoch:裁剪目标更新策略,MSE 更新价值
for epoch in range(K):
for (s, a, adv, g, old) in batch():
ratio = exp(log_prob(policy, s, a) - old) # π_new/π_old
clipped = clamp(ratio, 1-eps, 1+eps)
loss = -min(ratio*adv, clipped*adv) # 裁剪目标
policy_step(loss)
value_step(mse(V(s), g))
📚 参考文献与延伸阅读
- Schulman, J. et al. (2017), Proximal Policy Optimization Algorithms, arXiv:1707.06347 — PPO 原始论文,裁剪目标的定义与对比实验
- Schulman, J. et al. (2016), High-Dimensional Continuous Control Using Generalized Advantage Estimation, ICLR — GAE 原始论文
- Schulman, J. et al. (2015), Trust Region Policy Optimization, ICML — TRPO,PPO 的信任区域思想来源
- OpenAI Spinning Up: PPO — 最小可读实现与直觉讲解
📝 课后练习
检验你的理解——答对为止