强化学习PPO算法逻辑剖析,基于PyTorch实现PPO算法

以下是关于 PPO(Proximal Policy Optimization)算法的底层逻辑解析,结合数学推导和代码实现进行双重剖析。

一、PPO的核心思想

PPO 是一种基于策略优化的强化学习算法,旨在解决传统策略梯度方法(如TRPO)的复杂性问题。其核心目标是在策略更新时,**确保新策略与旧策略的差异不会过大**,从而保持训练稳定性。

关键设计:
1. Clipped Surrogate Objective
   通过限制策略更新的幅度,避免破坏性的策略变化。
2. Importance Sampling
   重用旧策略采集的经验,提高样本利用率。
3. Advantage Estimation
   使用优势函数(Advantage)替代纯奖励值,更精准评估动作价值。

二、数学底层逻辑解析

1. 策略梯度基础
策略梯度方法的目标是最大化期望回报:
\[
J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta} \left[ \sum_{t=0}^T \gamma^t r_t \right]
\]
梯度计算公式为:
\[
\nabla J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta} \left[ \sum_{t=0}^T \nabla_\theta \log \pi_\theta(a_t|s_t) A^{\pi}(s_t, a_t) \right]
\]
其中 \( A^{\pi}(s_t, a_t) = Q(s_t, a_t) - V(s_t) \) 为优势函数。

2. 重要性采样
为了利用旧策略 \( \pi_{\theta_{\text{old}}} \) 的数据,引入重要性权重:
\[
\mathbb{E}_{\tau \sim \pi_{\theta_{\text{old}}}} \left[ \frac{\pi_\theta(a|s)}{\pi_{\theta_{\text{old}}}(a|s)} A^{\pi_{\text{old}}}(s, a) \right]
\]
此时目标函数变为:
\[
J(\theta) = \mathbb{E} \left[ \frac{\pi_\theta(a|s)}{\pi_{\theta_{\text{old}}}(a|s)} A(s, a) \right]
\]

3. Clipped Surrogate Objective
为防止重要性权重过大导致更新不稳定,对目标函数进行截断:
\[
J^{\text{CLIP}}(\theta) = \mathbb{E} \left[ \min \left( \frac{\pi_\theta(a|s)}{\pi_{\theta_{\text{old}}}(a|s)} A, \text{clip} \left( \frac{\pi_\theta}{\pi_{\theta_{\text{old}}}}, 1-\epsilon, 1+\epsilon \right) A \right) \right]
\]
其中 \( \epsilon \) 是超参数(通常取0.1~0.3),限制策略更新的幅度。

4. 完整目标函数
结合值函数误差和熵正则化:
\[
L(\theta) = \mathbb{E} \left[ L^{\text{CLIP}} - c_1 L^{\text{VF}} + c_2 H(\pi_\theta(\cdot|s)) \right]
\]
其中:
- \( L^{\text{VF}} = (V_\theta(s) - V_{\text{target}})^2 \) 是值函数损失
- \( H \) 是策略熵,用于鼓励探索
- \( c_1, c_2 \) 是超参数

三、代码实现解析

以下是一个简化的PPO实现(基于PyTorch):

import torch
import torch.nn as nn
import torch.optim as optim
from torch.distributions import Categorical

class ActorCritic(nn.Module):
    def __init__(self, state_dim, action_dim):
        super().__init__()
        self.actor = nn.Sequential(
            nn.Linear(state_dim, 64),
            nn.Tanh(),
            nn.Linear(64, action_dim)
        )
        self.critic = nn.Sequential(
            nn.Linear(state_dim, 64),
            nn.Tanh(),
            nn.Linear(64, 1)
        )
    
    def forward(self, x):
        return self.actor(x), self.critic(x)

class PPO:
    def __init__(self, state_dim, action_dim, lr=3e-4, gamma=0.99, epsilon=0.2, entropy_coef=0.01):
        self.gamma = gamma
        self.epsilon = epsilon
        self.entropy_coef = entropy_coef
        
        self.model = ActorCritic(state_dim, action_dim)
        self.optimizer = optim.Adam(self.model.parameters(), lr=lr)
        self.MseLoss = nn.MSELoss()

    def update(self, states, actions, old_log_probs, advantages, returns):
        # 转换为Tensor
        states = torch.FloatTensor(states)
        actions = torch.LongTensor(actions)
        old_log_probs = torch.FloatTensor(old_log_probs)
        advantages = torch.FloatTensor(advantages)
        returns = torch.FloatTensor(returns)

        # 计算新策略的概率和熵
        logits, values = self.model(states)
        dist = Categorical(logits=logits)
        new_log_probs = dist.log_prob(actions)
        entropy = dist.entropy().mean()

        # 重要性权重
        ratios = (new_log_probs - old_log_probs).exp()

        # Clipped Surrogate Loss
        surr1 = ratios * advantages
        surr2 = torch.clamp(ratios, 1 - self.epsilon, 1 + self.epsilon) * advantages
        actor_loss = -torch.min(surr1, surr2).mean()

        # Critic Loss
        critic_loss = self.MseLoss(values.squeeze(), returns)

        # 总损失
        loss = actor_loss + 0.5 * critic_loss - self.entropy_coef * entropy

        # 反向传播
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()

    def compute_advantages(self, rewards, dones, values, next_value, gamma=0.99, gae_lambda=0.95):
        # 广义优势估计 (GAE)
        advantages = []
        gae = 0
        next_value = next_value
        for t in reversed(range(len(rewards))):
            delta = rewards[t] + gamma * (1 - dones[t]) * next_value - values[t]
            gae = delta + gamma * gae_lambda * (1 - dones[t]) * gae
            advantages.insert(0, gae)
            next_value = values[t]
        return advantages

四、代码关键逻辑解析

1. 策略更新流程

def update(self, states, actions, old_log_probs, advantages, returns):
    # 计算新策略的概率分布
    logits, values = self.model(states)
    dist = Categorical(logits=logits)
    new_log_probs = dist.log_prob(actions)
    
    # 重要性采样比率
    ratios = (new_log_probs - old_log_probs).exp()
    
    # Clipped Surrogate Objective
    surr1 = ratios * advantages
    surr2 = torch.clamp(ratios, 1-self.epsilon, 1+self.epsilon) * advantages
    actor_loss = -torch.min(surr1, surr2).mean()

- 重要性权重:通过新旧策略的概率比计算
- Clipping操作:限制更新幅度,防止策略突变

2. 优势函数计算

def compute_advantages(self, rewards, dones, values, next_value, gamma=0.99, gae_lambda=0.95):
    advantages = []
    gae = 0
    next_value = next_value
    for t in reversed(range(len(rewards))):
        delta = rewards[t] + gamma * (1 - dones[t]) * next_value - values[t]
        gae = delta + gamma * gae_lambda * (1 - dones[t]) * gae
        advantages.insert(0, gae)
        next_value = values[t]
    return advantages

- GAE(Generalized Advantage Estimation):结合多步TD误差,平衡偏差与方差
- 数学形式:  
  \( \delta_t = r_t + \gamma V(s_{t+1}) - V(s_t) \)  
  \( \text{GAE} = \sum_{l=0}^{T-t} (\gamma \lambda)^l \delta_{t+l} \)

五、PPO算法流程总结

1. 数据收集:使用当前策略与环境交互,收集轨迹数据  
2. 优势估计:计算每个状态动作对的GAE优势值  
3. 策略评估:计算旧策略的动作概率 \( \pi_{\theta_{\text{old}}}(a|s) \)  
4. 多轮更新:对采样的数据执行多次小批量更新(通常4-10次)  
5. 策略改进:通过Clipped目标函数优化策略和值函数  

六、PPO与TRPO的对比

特性PPOTRPO
优化目标Clipped Surrogate ObjectiveKL散度约束
实现复杂度简单(一阶优化)复杂(二阶优化需计算Hessian)
样本效率高(支持多轮更新)中(单次更新)
超参数敏感性对 \(\epsilon\) 敏感对KL阈值敏感
适用场景通用强化学习任务需要严格策略约束的场景

七、工程实践建议

1. 超参数调优:
   - \( \epsilon \):初始值0.2,根据任务调整(复杂任务可能需要更小的值)
   - 批量大小:通常取64~4096,取决于环境复杂度
   - 学习率:3e-4 ~ 1e-5,使用学习率衰减策略

2. 训练技巧:

# 动态调整Clip范围
if kl_divergence > 0.02:
    self.epsilon *= 0.5
elif kl_divergence < 0.005:
    self.epsilon *= 1.5

3. 并行化:

# 使用多进程收集数据
from multiprocessing import Pool
with Pool(4) as p:
    trajectories = p.map(collect_rollout, [policy]*4)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值