强化学习-PPO

Posted by 云起 on 2025-03-11
Estimated Reading Time 4 Minutes
Words 1.1k In Total
Viewed Times

[toc]

PPO(Proximal Policy Optimization,近端策略优化) 是OpenAI于2017年提出的一种强化学习算法,属于策略梯度(Policy Gradient)方法的改进版本。它以高稳定性和样本高效性著称,广泛应用于机器人控制、游戏AI等领域(如《Dota 2》AI和《星际争霸II》AI)。

策略梯度(Policy Gradient)的局限性

  • 问题:传统策略梯度(如REINFORCE)直接通过梯度上升更新策略参数,但存在两大问题:
    1. 更新步长敏感:步长过大可能导致策略崩溃(性能骤降);
    2. 样本效率低:需要大量与环境交互的数据。
  • 改进方向:如何安全地更新策略,避免性能剧烈波动?

PPO的核心思想

PPO通过限制策略更新的幅度,确保新策略(更新后的策略)与旧策略(更新前的策略)的差异在可控范围内,从而提升稳定性。
其核心是Clipped Surrogate Objective(裁剪替代目标函数),替代传统的策略梯度目标。

关键公式与机制

重要性采样(Importance Sampling)

  • 目的:利用旧策略收集的数据估计新策略的期望奖励,提升数据复用效率。

  • 重要性权重
    $$
    r_t(θ)=\frac{π_θ(a_t∣s_t)}{π_{θold}(a_t∣s_t)}
    $$
    其中,$$π_θ$$是新策略,$$π_{θold}$$是旧策略。

替代目标函数(Surrogate Objective)

  • 原始目标:最大化新策略的期望优势函数 A^tA^t(如通过蒙特卡洛或TD误差估计):
    $$
    L^{CPI}(θ)=E_t[r_t(θ)\hat{A}_t]
    $$
    (CPI表示“保守策略迭代”)

  • 问题:若$$ r_t(θ)$$ 过大(策略变化剧烈),会导致更新不稳定。

裁剪机制(Clipping)

PPO通过裁剪重要性权重,限制策略更新的幅度:
$$
L^{CLIP}(θ)=E_t[min⁡(r_t(θ)\hat{A}_t,clip(r_t(θ),1−ϵ,1+ϵ)\hat{A}t)]
$$

  • 参数 ϵ:通常设为0.1~0.3,控制裁剪范围。
  • 逻辑解释
    • 如果优势 $$\hat{A}t>0$$(动作优于平均),限制$$ r_t(θ)≤1+ϵ$$;
    • 如果优势 $$\hat{A}t<0$$(动作劣于平均),限制 $$r_t(θ)≥1−ϵ$$。

通过这种方式,PPO在鼓励策略改进的同时,防止更新步长过大。

步骤

  1. 收集数据:使用当前策略 $$π_{θold}$$与环境交互,生成轨迹数据。
  2. 计算优势估计:通过广义优势估计(GAE, Generalized Advantage Estimation)或其他方法计算 $$\hat{A}t$$。
  3. 优化替代目标函数:在多个epoch中,用小批量数据重复更新策略参数,最大化 $$L^{CLIP}(θ)$$。
  4. 更新旧策略:将当前策略参数 θ复制给 θold,进入下一轮数据收集。

关键参数调优

  • **裁剪阈值 ϵ*ϵ***:通常设为0.1~0.3,控制策略更新幅度。
  • **GAE参数 λ*λ***:平衡偏差与方差,一般取0.9~0.99。
  • 学习率:建议从3e-4开始调整。
  • 并行环境数量:增加环境数可提升数据收集速度。

伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import torch
import torch.optim as optim

# 定义策略网络(Actor)和价值网络(Critic)
class PolicyNetwork(torch.nn.Module):
def __init__(self, state_dim, action_dim):
super().__init__()
self.fc = torch.nn.Linear(state_dim, 64)
self.action_head = torch.nn.Linear(64, action_dim)
self.value_head = torch.nn.Linear(64, 1)

def forward(self, x):
x = torch.relu(self.fc(x))
return torch.softmax(self.action_head(x), dim=-1), self.value_head(x)

# PPO算法核心
def ppo_update(policy, optimizer, states, actions, advantages, old_log_probs, epsilon=0.2):
new_probs, new_values = policy(states)
new_log_probs = torch.log(new_probs.gather(1, actions))
ratio = torch.exp(new_log_probs - old_log_probs)
clipped_ratio = torch.clamp(ratio, 1-epsilon, 1+epsilon)
loss = -torch.min(ratio * advantages, clipped_ratio * advantages).mean()

optimizer.zero_grad()
loss.backward()
optimizer.step()

# 训练循环
policy = PolicyNetwork(state_dim, action_dim)
optimizer = optim.Adam(policy.parameters(), lr=3e-4)
for episode in range(1000):
states, actions, rewards, old_log_probs = collect_data(policy)
advantages = compute_advantages(rewards, policy.values)
ppo_update(policy, optimizer, states, actions, advantages, old_log_probs)

PPO vs. TRPO(Trust Region Policy Optimization)

  • 共同目标:限制策略更新幅度,保证稳定性。
  • TRPO:通过KL散度约束实现,需计算二阶导数(复杂度高)。
  • PPO:通过目标函数裁剪实现,仅需一阶优化(更简单高效)。
  • 结论:PPO以更简单的实现达到了与TRPO相近的性能,成为主流算法。

PPO的优势

  1. 稳定性强:通过裁剪避免策略突变。
  2. 样本效率高:支持多轮策略更新(复用旧数据)。
  3. 适应性强:适用于连续和离散动作空间。
  4. 易于实现:无需复杂约束(如TRPO的KL散度优化)。

If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !