(8-1)OpenAI的PPO和DeepSeek的GRPO:PPO算法的核心知识和应用

PPO(Proximal Policy Optimization,近端策略优化)是一种经典的强化学习算法,通过截断概率比来限制策略更新的幅度,从而保证更新的稳定性,广泛应用于连续动作空间任务。GRPO(Group Relative Policy Optimization,群组相对策略优化)是由DeepSeek提出的一种强化学习算法,它通过引入更灵活的策略更新方式和目标函数,能够适应多种强化学习问题,尤其在复杂环境和多目标优化场景中表现出色。两者都致力于提高策略学习的效率和效果,但PPO更注重稳定性,GRPO更强调灵活性和通用性。

8.1  PPO算法的核心知识和应用

PPO由OpenAI于2017年提出,是一种强化学习算法,用于训练能够执行连续动作的智能体,以最大化累积奖励。

8.1.1  PPO的推出背景

PPO的推出背景是为了解决传统策略梯度方法和TRPO的局限性,通过简化算法实现、提高数据效率和保持训练稳定性,为强化学习的广泛应用奠定了坚实的基础。

1. 传统策略梯度方法的局限性

早期的强化学习算法在实际应用中面临诸多挑战,例如训练不稳定、样本效率低、难以扩展到复杂环境等,具体说明如下所示。

  1. 训练不稳定:传统的策略梯度方法(如REINFORCE算法)直接优化策略的参数,但更新过程中容易导致策略的剧烈变化,从而使得训练过程不稳定。
  2. 样本效率低:这些方法通常需要大量的样本才能收敛,因为每次策略更新后,旧的样本数据可能不再适用,导致数据利用率低。
  3. 更新步长难以控制:策略梯度方法中,学习率的选择非常关键。如果学习率过大,可能导致策略更新过度,训练发散;如果学习率过小,则收敛速度过慢。

2. TRPO的局限性

TRPO(Trust Region Policy Optimization,信任区域策略优化)是为了解决传统策略梯度方法的不稳定性而提出的。TRPO通过限制策略更新的幅度,确保每次更新都在“信任区域”内,从而保证策略更新的稳定性。然而,TRPO也存在一些问题:

  1. 实现复杂:TRPO的实现需要计算复杂的二阶导数(如共轭梯度法),这使得算法的实现和调试变得非常困难。
  2. 计算成本高:TRPO的每次更新都需要进行复杂的优化计算,导致计算成本较高,难以在大规模问题中应用。

3. PPO的提出动机

PPO(Proximal Policy Optimization,近端策略优化)正是为了解决上述问题而提出的。PPO的主要目标是:

  1. 简化TRPO的复杂性:通过引入一种更简单的方式来限制策略更新的幅度,避免使用复杂的二阶导数计算。
  2. 提高数据效率:允许使用相同的数据进行多次更新,从而提高样本的利用效率。
  3. 保持训练稳定性:通过限制策略更新的幅度,避免过大的策略变化,从而保证训练过程的稳定性。

4. PPO的核心思想

PPO的核心思想是通过裁剪的概率比来限制策略更新的幅度。具体来说,PPO定义了一个目标函数,其中引入了一个“裁剪项”(clipping term),确保策略更新不会偏离当前策略太远。这种裁剪机制既保证了策略更新的稳定性,又避免了复杂的二阶导数计算。

5. PPO的优势

  1. 简单易实现:PPO的实现相对简单,不需要复杂的二阶导数计算,因此更容易实现和调试。
  2. 高效稳定:PPO在保持训练稳定性的同时,提高了数据的利用效率,能够更快地收敛。
  3. 适用性强:PPO适用于多种强化学习任务,包括连续动作空间和离散动作空间的问题。

6. PPO的广泛影响

PPO的提出极大地推动了强化学习的发展,它不仅在学术界得到了广泛的应用和研究,还在工业界得到了大量的实践。例如,在机器人控制、游戏AI、自动驾驶等领域,PPO都被证明是一种非常有效的强化学习算法。

总之,PPO的推出背景是为了解决传统策略梯度方法和TRPO的局限性,通过简化算法实现、提高数据效率和保持训练稳定性,为强化学习的广泛应用奠定了坚实的基础。

8.1.2  PPO算法的基本思想

PPO(Proximal Policy Optimization,近端策略优化)的核心思想是通过限制策略更新的幅度,确保更新过程的稳定性,同时简化算法实现并提高样本效率。

1. 策略更新的稳定性

PPO的核心目标是确保策略更新的稳定性。在传统策略梯度方法中,策略更新可能会导致策略的剧烈变化,从而使得训练过程不稳定。PPO通过引入裁剪的概率比(clipping)来限制策略更新的幅度。具体来说,PPO定义了一个目标函数,其中引入了一个“裁剪项”,确保策略更新不会偏离当前策略太远。

2. 裁剪的概率比(Clipping

PPO的目标函数基于策略梯度方法的期望奖励目标,但引入了一个裁剪机制。假设当前策略为πθ​,更新后的策略为 πθ′​,则概率比 r(θ) 定义为:

PPO的目标函数为:

其中:

  1. At是优势函数(Advantage Function),表示在状态st下采取行动at的期望奖励;
  2. ϵ 是裁剪参数,通常取值为0.1或0.2。裁剪机制能够确保概率比 r(θ) 在 1−ϵ 和 1+ϵ 之间,从而限制策略更新的幅度。

3. 计算策略梯度

通过下面公式计算策略梯度:

在这里,是策略的梯度,表示策略在当前状态下采取动作a的对数概率的梯度。

4. 优化策略

在计算出策略梯度后,PPO通过梯度上升方法更新策略参数θ

其中,α是学习率,控制更新的步长。

5. 目标函数的改进

除了裁剪的概率比,PPO还引入了一个额外的目标函数,称为“目标函数的截断版本”(Clipped Surrogate Objective Function)。这个目标函数结合了裁剪的概率比和原始的概率比,进一步提高了算法的稳定性。具体来说,PPO的目标函数可以表示为:

其中:

  1. 是值函数(Value Function)的损失,用于优化状态价值函数;
  2. S(θ) 是策略的熵,用于增加策略的探索性;
  3. 是超参数,用于平衡不同部分的权重。

6. 数据的多次利用

PPO允许使用相同的数据进行多次更新,从而提高样本的利用效率。在每次策略更新时,PPO会从经验回放缓存(Experience Replay Buffer)中采样一批数据,并使用这些数据进行多次策略更新。这种机制类似于深度学习中的小批量梯度下降(Mini-batch Gradient Descent),能够有效提高样本的利用效率,减少样本浪费。

7. 简化实现

PPO的另一个重要特点是简化了TRPO的复杂性。TRPO需要计算复杂的二阶导数(如共轭梯度法),这使得算法的实现和调试变得非常困难。而PPO通过裁剪的概率比和目标函数的改进,避免了复杂的二阶导数计算,使得算法的实现更加简单高效。

总之,PPO算法的基本思想是通过裁剪的概率比限制策略更新的幅度,确保训练过程的稳定性;同时,通过允许数据的多次利用,提高样本效率;并通过简化目标函数和实现过程,降低算法的复杂性。这些改进使得PPO在实际应用中表现出色,成为强化学习领域中一种广泛使用的算法。

8.1.3  综合实战:使用PPO算法解决CartPole平衡问题

例如在下面的实例中实现了一个基于PPO(近端策略优化)算法的强化学习训练程序,用于解决Gym环境中的CartPole平衡问题。在实例中定义了策略网络和价值网络,通过采样动作、计算折扣回报和优势估计,利用裁剪的概率比来优化策略,同时更新价值网络以更准确地估计状态价值。训练过程中,智能体与环境交互,收集数据并周期性地更新策略,最终通过可视化展示训练好的策略在环境中的表现。

实例8-1:使用PPO算法解决CartPole平衡问题(源码路径:codes\8\ppo_cartpole.py

实例文件ppo_cartpole.py的具体实现代码如下所示。

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.distributions import Categorical
import gym
import matplotlib.pyplot as plt
from collections import deque

# 设置随机种子以保证结果可复现
torch.manual_seed(0)
np.random.seed(0)

class PolicyNetwork(nn.Module):
    def __init__(self, state_dim, action_dim, hidden_dim=128):
        super(PolicyNetwork, self).__init__()
        self.fc1 = nn.Linear(state_dim, hidden_dim)
        self.fc2 = nn.Linear(hidden_dim, hidden_dim)
        self.fc3 = nn.Linear(hidden_dim, action_dim)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return F.softmax(x, dim=-1)

class ValueNetwork(nn.Module):
    def __init__(self, state_dim, hidden_dim=128):
        super(ValueNetwork, self).__init__()
        self.fc1 = nn.Linear(state_dim, hidden_dim)
        self.fc2 = nn.Linear(hidden_dim, hidden_dim)
        self.fc3 = nn.Linear(hidden_dim, 1)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        return self.fc3(x)

def select_action(policy, state):
    # 确保状态是有效的 numpy 数组
    if isinstance(state, tuple):
        state = state[0]  # 处理可能包含额外信息的元组
    if isinstance(state, list):
        state = np.array(state)
    
    # 处理可能的空状态或异常状态
    if state.size == 0:
        print("Warning: Empty state received. Using zeros as fallback.")
        state = np.zeros(4)  # CartPole 环境状态维度为 4
    elif state.shape != (4,):
        print(f"Warning: State shape {state.shape} is not (4,). Attempting to reshape.")
        state = state.reshape(4)
    
    state = torch.FloatTensor(state)
    
    # 确保状态维度正确(添加批次维度)
    if state.dim() == 1:
        state = state.unsqueeze(0)
    
    with torch.no_grad():
        probs = policy(state)
    dist = Categorical(probs)
    action = dist.sample()
    log_prob = dist.log_prob(action)
    return action.item(), log_prob

def update(ppo_optimizer, policy, value, states, actions, log_probs_old, rewards, dones, gamma=0.99, eps_clip=0.2):
    # 计算折扣回报
    returns = []
    R = 0
    for r, done in zip(reversed(rewards), reversed(dones)):
        if done:
            R = 0
        R = r + gamma * R
        returns.insert(0, R)
    returns = torch.FloatTensor(returns)
    
    # 标准化回报
    returns = (returns - returns.mean()) / (returns.std() + 1e-8)
    
    # 转换数据为张量
    states = torch.FloatTensor(states)
    actions = torch.LongTensor(actions)
    log_probs_old = torch.FloatTensor(log_probs_old)
    
    # 获取当前策略下的动作概率和状态价值
    probs = policy(states)
    dist = Categorical(probs)
    log_probs = dist.log_prob(actions)
    values = value(states).squeeze()
    
    # 计算优势估计
    advantages = returns - values.detach()
    
    # 计算策略损失
    ratio = torch.exp(log_probs - log_probs_old)
    surr1 = ratio * advantages
    surr2 = torch.clamp(ratio, 1 - eps_clip, 1 + eps_clip) * advantages
    policy_loss = -torch.min(surr1, surr2).mean()
    
    # 计算价值损失
    value_loss = F.mse_loss(values, returns)
    
    # 总损失
    loss = policy_loss + 0.5 * value_loss
    
    # 优化
    ppo_optimizer.zero_grad()
    loss.backward()
    ppo_optimizer.step()
    
    return loss.item()

def train():
    # 创建环境
    env = gym.make('CartPole-v1')
    state_dim = env.observation_space.shape[0]
    action_dim = env.action_space.n
    
    # 初始化网络
    policy = PolicyNetwork(state_dim, action_dim)
    value = ValueNetwork(state_dim)
    
    # 优化器
    optimizer = optim.Adam(list(policy.parameters()) + list(value.parameters()), lr=3e-4)
    
    # 训练参数
    max_episodes = 300
    max_steps = 500
    update_interval = 20
    
    # 记录奖励
    episode_rewards = []
    avg_rewards = []
    
    for episode in range(max_episodes):
        # 获取初始状态 - 处理可能的 Gym API 变化
        state_info = env.reset()
        state = state_info[0] if isinstance(state_info, tuple) else state_info
        
        episode_reward = 0
        states, actions, log_probs, rewards, dones = [], [], [], [], []
        
        for step in range(max_steps):
            # 选择动作
            action, log_prob = select_action(policy, state)
            
            # 执行动作 - 处理可能的 Gym API 变化
            step_info = env.step(action)
            next_state, reward, terminated, truncated, _ = step_info if len(step_info) == 5 else (*step_info[:3], False, {})
            done = terminated or truncated
            
            # 修改奖励以加速训练
            reward = reward if not done else -10
            
            # 存储转换
            states.append(state)
            actions.append(action)
            log_probs.append(log_prob)
            rewards.append(reward)
            dones.append(done)
            
            state = next_state
            episode_reward += reward
            
            if done:
                break
        
        # 记录奖励
        episode_rewards.append(episode_reward)
        avg_reward = np.mean(episode_rewards[-100:])
        avg_rewards.append(avg_reward)
        
        # 打印进度
        print(f"Episode {episode+1}/{max_episodes}, Reward: {episode_reward}, Avg Reward: {avg_reward:.2f}")
        
        # 更新策略
        if (episode + 1) % update_interval == 0:
            loss = update(optimizer, policy, value, states, actions, log_probs, rewards, dones)
            print(f"Update at episode {episode+1}, Loss: {loss:.4f}")
        
        # 检查是否解决
        if avg_reward > 490:
            print(f"Environment solved in {episode+1} episodes!")
            break
    
    env.close()
    
    # 可视化训练结果
    plt.figure(figsize=(10, 5))
    plt.plot(episode_rewards, label='Episode Rewards')
    plt.plot(avg_rewards, label='Average Rewards', linewidth=2)
    plt.xlabel('Episode')
    plt.ylabel('Reward')
    plt.title('PPO Training Performance on CartPole')
    plt.legend()
    plt.grid(True)
    plt.show()
    
    return policy, env

def visualize_policy(policy, env, episodes=5):
    for episode in range(episodes):
        # 获取初始状态 - 处理可能的 Gym API 变化
        state_info = env.reset()
        state = state_info[0] if isinstance(state_info, tuple) else state_info
        
        done = False
        total_reward = 0
        
        while not done:
            env.render()
            action, _ = select_action(policy, state)
            
            # 执行动作 - 处理可能的 Gym API 变化
            step_info = env.step(action)
            next_state, reward, terminated, truncated, _ = step_info if len(step_info) == 5 else (*step_info[:3], False, {})
            done = terminated or truncated
            
            state = next_state
            total_reward += reward
        
        print(f"Visualization Episode {episode+1}, Total Reward: {total_reward}")
    
    env.close()

if __name__ == "__main__":
    trained_policy, env = train()
    visualize_policy(trained_policy, env)

上述代码的实现流程如下所示。

(1)初始化环境和网络

创建Gym环境(CartPole-v1),初始化策略网络(PolicyNetwork)和价值网络(ValueNetwork),分别用于输出动作的概率分布和估计状态的价值。

设置优化器,用于更新策略网络和价值网络的参数。

(2)训练过程

与环境交互:在每个episode中,智能体从初始状态开始,根据当前策略网络选择动作并与环境交互,收集状态、动作、奖励、对数概率等信息。

奖励修改:为了加速训练,对奖励进行调整,例如在智能体失败时给予较大的负奖励。

数据存储:将每个时间步的状态、动作、对数概率、奖励和终止标志存储到缓冲区中。

(3)策略更新:每隔一定间隔(update_interval),使用收集到的数据进行策略更新,具体流程如下所示。

  1. 计算折扣回报:从后向前计算每个时间步的折扣回报。
  2. 标准化回报:对回报进行标准化处理,以提高训练稳定性。
  3. 计算优势估计:通过回报减去状态价值来估计优势函数。
  4. 计算策略损失和价值损失:利用裁剪的概率比计算策略损失,同时计算价值网络的均方误差损失。
  5. 优化网络:通过反向传播更新策略网络和价值网络的参数。

(4)记录和可视化:在每个episode中记录奖励,并计算最近100个episode的平均奖励。使用Matplotlib绘制奖励曲线,展示训练过程中的性能变化。

(5)策略可视化:在训练完成后,使用训练好的策略在环境中运行多个episode,可视化展示智能体的行为表现,观察其是否能够成功完成任务。如图8-1所示。

图8-1  训练过程中的奖励曲线图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

感谢鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值