跳到主要内容

PPO 算法

PPO (Proximal Policy Optimization) 是由OpenAI于2017年提出的on-policy策略梯度算法。它通过限制策略更新幅度来保证训练稳定性,是目前最流行的深度强化学习算法之一。

算法原理

核心目标函数

PPO的核心思想是限制新旧策略的差异,避免策略更新过大导致性能崩塌:

LCLIP(θ)=E^t[min(rt(θ)A^t,clip(rt(θ),1ϵ,1+ϵ)A^t)]L^{CLIP}(\theta) = \hat{E}_t\left[\min\left(r_t(\theta)\hat{A}_t, \text{clip}(r_t(\theta), 1-\epsilon, 1+\epsilon)\hat{A}_t\right)\right]

其中:

  • rt(θ)=πθ(atst)πθold(atst)r_t(\theta) = \frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{old}}(a_t|s_t)}: 重要性采样比率
  • A^t\hat{A}_t: 优势函数估计
  • ϵ\epsilon: 裁剪参数,通常取0.1或0.2

策略梯度基础

PPO基于策略梯度定理: θJ(θ)=Eπθ[θlogπθ(as)Qπθ(s,a)]\nabla_\theta J(\theta) = \mathbb{E}_{\pi_\theta}\left[\nabla_\theta \log \pi_\theta(a|s) Q^{\pi_\theta}(s,a)\right]

重要性采样

为实现off-policy学习,使用重要性采样: Es,aπθold[πθ(as)πθold(as)θlogπθ(as)Aπθold(s,a)]\mathbb{E}_{s,a \sim \pi_{\theta_{old}}}\left[\frac{\pi_\theta(a|s)}{\pi_{\theta_{old}}(a|s)} \nabla_\theta \log \pi_\theta(a|s) A^{\pi_{\theta_{old}}}(s,a)\right]

算法流程

  1. 收集轨迹数据:使用当前策略πθold\pi_{\theta_{old}}收集(st,at,rt)(s_t, a_t, r_t)
  2. 计算优势估计:A^t=δt+(γλ)δt+1+\hat{A}_t = \delta_t + (\gamma\lambda)\delta_{t+1} + \cdots
  3. 更新策略:最大化LCLIP(θ)L^{CLIP}(\theta)
  4. 更新价值函数:最小化LVF(ϕ)=12(Vϕ(st)R^t)2L^{VF}(\phi) = \frac{1}{2}(V_\phi(s_t) - \hat{R}_t)^2
  5. 重复步骤1-4

PPO vs TRPO vs Vanilla PG

关键差异

特性Vanilla PGTRPOPPO
约束类型无约束KL散度硬约束裁剪软约束
计算复杂度高(二阶优化)中等
稳定性
实现难度简单复杂中等
超参数敏感性

数学比较

Vanilla PG目标LPG(θ)=E^t[logπθ(atst)A^t]L^{PG}(\theta) = \hat{E}_t\left[\log \pi_\theta(a_t|s_t) \hat{A}_t\right]

TRPO目标maxθE^t[πθ(atst)πθold(atst)A^t]\max_\theta \hat{E}_t\left[\frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{old}}(a_t|s_t)} \hat{A}_t\right] s.t. E^t[KL[πθold(st),πθ(st)]]δ\text{s.t. } \hat{E}_t[KL[\pi_{\theta_{old}}(\cdot|s_t), \pi_\theta(\cdot|s_t)]] \leq \delta

PPO目标LCLIP(θ)=E^t[min(rt(θ)A^t,clip(rt(θ),1ϵ,1+ϵ)A^t)]L^{CLIP}(\theta) = \hat{E}_t\left[\min\left(r_t(\theta)\hat{A}_t, \text{clip}(r_t(\theta), 1-\epsilon, 1+\epsilon)\hat{A}_t\right)\right]

裁剪机制分析

裁剪函数数学性质

1-\epsilon & \text{if } r < 1-\epsilon \\ r & \text{if } 1-\epsilon \leq r \leq 1+\epsilon \\ 1+\epsilon & \text{if } r > 1+\epsilon \end{cases}$$ ### 悲观下界 PPO取最小值实现悲观估计: **当$\hat{A}_t > 0$时**(好动作): - 如果$r_t > 1+\epsilon$,目标被限制为$(1+\epsilon)\hat{A}_t$ - 防止过度增加好动作概率 **当$\hat{A}_t < 0$时**(坏动作): - 如果$r_t < 1-\epsilon$,目标被限制为$(1-\epsilon)\hat{A}_t$ - 防止过度减少坏动作概率 ### 梯度分析 $$\nabla_\theta L^{CLIP} = \begin{cases} \nabla_\theta r_t(\theta) \hat{A}_t & \text{if 未被裁剪} \\ 0 & \text{if 被裁剪且会恶化目标} \end{cases}$$ ## 优势函数估计 ### GAE (Generalized Advantage Estimation) $$\hat{A}_t^{GAE(\gamma,\lambda)} = \sum_{l=0}^{\infty} (\gamma\lambda)^l \delta_{t+l}$$ 其中TD误差: $$\delta_t = r_t + \gamma V(s_{t+1}) - V(s_t)$$ ### λ权衡分析 - $\lambda = 0$: $\hat{A}_t = \delta_t$ (高偏差,低方差) - $\lambda = 1$: $\hat{A}_t = \sum_{t'=t}^{T-1} \gamma^{t'-t} r_{t'} - V(s_t)$ (低偏差,高方差) ### 数学推导 GAE的指数衰减权重来源于: $$\mathbb{E}[\hat{A}_t^{GAE}] = \mathbb{E}[A^{\pi,\gamma}(s_t, a_t)]$$ 在无限时域假设下。 ## 完整损失函数 ### 总体目标 $$L^{CLIP+VF+S}(\theta, \phi) = \hat{E}_t\left[L^{CLIP}_t(\theta) - c_1 L^{VF}_t(\phi) + c_2 S[\pi_\theta](s_t)\right]$$ 其中: - $L^{VF}_t(\phi) = \frac{1}{2}(V_\phi(s_t) - V_t^{targ})^2$: 价值函数损失 - $S[\pi_\theta](s_t) = H(\pi_\theta(\cdot|s_t))$: 熵正则化 - $c_1, c_2$: 损失权重系数 ### 价值函数裁剪 为保持价值函数更新稳定: $$L^{VF}_{CLIP} = \max\left((V_\phi(s_t) - V_t^{targ})^2, (\text{clip}(V_\phi(s_t), V_{old} - \epsilon_v, V_{old} + \epsilon_v) - V_t^{targ})^2\right)$$ ## 理论分析 ### 单调性改进下界 **定理**: 设$\eta(\pi)$为策略$\pi$的期望回报,则: $$\eta(\pi) \geq L_{\pi_{old}}(\pi) - \frac{4\epsilon\gamma}{(1-\gamma)^2} \alpha^2$$ 其中$\alpha = \max_s KL[\pi_{old}(\cdot|s), \pi(\cdot|s)]$ ### 收敛性保证 在适当条件下,PPO保证: 1. **单调改进**: 每次更新不会显著恶化性能 2. **渐近收敛**: 收敛到局部最优解 ### 样本复杂度 PPO的样本复杂度为$O(\epsilon^{-2})$,优于大多数策略梯度方法。 ## 实现要点 ### 神经网络架构 ```py class PPONetwork(nn.Module): def __init__(self, state_dim, action_dim, hidden_dim=64): super().__init__() self.shared = nn.Sequential( nn.Linear(state_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), nn.ReLU() ) self.policy_head = nn.Linear(hidden_dim, action_dim) self.value_head = nn.Linear(hidden_dim, 1) def forward(self, state): features = self.shared(state) policy_logits = self.policy_head(features) value = self.value_head(features) return policy_logits, value ``` ### 核心更新函数 ```py def ppo_update(self, states, actions, old_log_probs, returns, advantages): for _ in range(self.update_epochs): # 前向传播 logits, values = self.network(states) dist = Categorical(logits=logits) log_probs = dist.log_prob(actions) entropy = dist.entropy() # 计算比率 ratios = torch.exp(log_probs - old_log_probs) # PPO裁剪目标 surr1 = ratios * advantages surr2 = torch.clamp(ratios, 1-self.clip_param, 1+self.clip_param) * advantages policy_loss = -torch.min(surr1, surr2).mean() # 价值函数损失 value_loss = F.mse_loss(values.squeeze(), returns) # 熵正则化 entropy_loss = -entropy.mean() # 总损失 total_loss = policy_loss + self.vf_coef * value_loss + self.entropy_coef * entropy_loss ``` ## 扩展与变种 ### PPO2 (OpenAI Baselines) - 使用经验缓冲区 - 支持连续动作空间 - 改进的价值函数裁剪 ### APPO (Asynchronous PPO) 分布式训练版本: $$L^{APPO} = L^{CLIP} - \beta \cdot V\text{-trace correction}$$ ### PPG (Phasic Policy Gradient) 分离策略和价值学习: - 策略阶段:仅更新策略网络 - 辅助阶段:联合训练并加入辅助损失 ## 应用场景对比 ### 连续控制 vs 离散控制 **连续动作空间**: - 使用高斯策略:$\pi_\theta(a|s) = \mathcal{N}(a; \mu_\theta(s), \sigma_\theta(s))$ - 比率计算:$r_t = \frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{old}}(a_t|s_t)}$ **离散动作空间**: - 使用分类策略:$\pi_\theta(a|s) = \text{Softmax}(f_\theta(s))$ - 更稳定的训练过程 ### 环境复杂度适应性 - **简单环境**: PPO可能过度复杂,考虑DQN - **中等复杂度**: PPO表现优异 - **高复杂度**: 考虑SAC或TD3 ## 思考题 ### 为什么PPO比TRPO更实用? **计算复杂度分析**: TRPO需要计算海塞矩阵的逆: $$\theta_{k+1} = \theta_k + \sqrt{\frac{2\delta}{g^T H^{-1} g}} H^{-1} g$$ 而PPO仅需一阶梯度: $$\theta_{k+1} = \theta_k + \alpha \nabla_\theta L^{CLIP}(\theta_k)$$ **实现复杂度**:PPO的裁剪机制比TRPO的约束优化更容易实现和调试。 ### 裁剪如何实现单调改进? **数学证明思路**: 裁剪确保当优势为正时,比率不会过大增加策略概率;当优势为负时,比率不会过小减少策略概率。这种"悲观"估计保证了性能改进的下界。