# simple_ppo **Repository Path**: pengspace/simple_ppo ## Basic Information - **Project Name**: simple_ppo - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-11 - **Last Updated**: 2026-04-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## Simple PPO 一个简洁、模块化的 **近端策略优化(Proximal Policy Optimization, PPO)** 算法实现,基于 PyTorch。支持**离散动作**、**连续动作**以及**混合动作空间**,代码结构清晰,适合快速上手和二次开发。 ### 项目特点 - **混合动作空间支持**:同时支持离散动作(Categorical 分布)和连续动作(Normal 分布),可单独或组合使用 - **模块化设计**:Actor-Critic 网络与 PPO 训练逻辑分离,易于替换和扩展 - **三种网络规模**:提供 `Base`(单层)、`Simple`(256 维隐藏层)和 `Tiny`(32 维隐藏层)三种网络结构,适应不同复杂度任务 - **策略裁剪(Clipping)**:标准 PPO 裁剪机制,保证训练稳定性 - **优势归一化**:对 Advantage 进行标准化,提升训练稳定性 - **熵正则化**:内置熵损失项,促进策略探索 ### 环境要求 - Python 3.8+ - PyTorch >= 1.9 - NumPy ```bash pip install torch numpy ``` ### 项目结构 ``` simple_ppo/ ├── ActorCriticModule.py # Actor-Critic 网络定义(Base / Simple / Tiny) ├── PPOTrainer.py # PPO 训练器、经验回放缓冲区 └── README.md ``` ### 快速开始 ```python import torch from ActorCriticModule import ActorCriticSimple from PPOTrainer import PPOMemory, PPOTrainer # 1. 创建策略网络(支持纯离散、纯连续、混合动作) policy = ActorCriticSimple( state_dim=4, # 状态维度 discrete_action_dim=2, # 离散动作数(0 表示无) continuous_action_dim=0 # 连续动作维度(0 表示无) ) # 2. 初始化训练器 trainer = PPOTrainer( policy=policy, lr=3e-4, gamma=0.99, eps_clip=0.2, K_epochs=4 ) # 3. 交互与收集经验 memory = PPOMemory() state = env.reset() for t in range(2048): # 收集一个 episode 或固定步数 discrete_action, continuous_action, logprob = trainer.select_action(state) next_state, reward, done, _ = env.step(discrete_action) memory.push(state, discrete_action, continuous_action, logprob, reward, done) state = next_state if not done else env.reset() # 4. 更新策略 trainer.update(memory.get_memory()) memory = PPOMemory() # 清空缓冲区,开始下一轮收集 ``` ### 核心组件 #### 1. Actor-Critic 网络(`ActorCriticModule.py`) | 类名 | 隐藏层 | 适用场景 | |------|--------|----------| | `ActorCriticBase` | 无隐藏层(输入直连输出) | 简单线性任务、调试 | | `ActorCriticSimple` | 2×256 隐藏层 | 中等复杂度任务 | | `ActorCriticTiny` | 1×32 隐藏层 | 资源受限、轻量任务 | 所有网络均支持以下动作类型组合: - `discrete_action_dim > 0, continuous_action_dim = 0` → 纯离散动作 - `discrete_action_dim = 0, continuous_action_dim > 0` → 纯连续动作 - `discrete_action_dim > 0, continuous_action_dim > 0` → 混合动作 **网络输出:** - `discrete_probs`:Softmax 概率分布 - `continuous_mean`:Tanh 激活的均值 - `continuous_std`:Softplus 激活的标准差(裁剪在 [0.01, 0.5]) - `value`:状态价值估计 #### 2. PPO 训练器(`PPOTrainer.py`) **`PPOMemory`**:经验回放缓冲区,存储 `(state, action, logprob, reward, done)` 序列。 **`PPOTrainer`**:核心训练逻辑,包含: | 方法 | 说明 | |------|------| | `select_action(state)` | 根据旧策略采样动作,返回 `(离散动作, 连续动作, logprob)` | | `update(memory)` | 执行 PPO 更新,包括折扣回报计算、优势估计、K 轮 epoch 优化 | **PPO 目标函数:** $$\mathcal{L}^{clip}(\theta) = \hat{\mathbb{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]$$ 其中 $r_t(\theta) = \frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{old}}(a_t|s_t)}$,$\hat{A}_t$ 为优势函数。 **总损失:** $$\mathcal{L} = \mathcal{L}^{clip}_{policy} + 0.5 \cdot \mathcal{L}^{MSE}_{value} - 0.05 \cdot \mathcal{H}_{entropy}$$ ### 超参数 | 参数 | 默认值 | 说明 | |------|--------|------| | `lr` | 3e-4 | Adam 优化器学习率 | | `gamma` | 0.99 | 折扣因子 | | `eps_clip` | 0.2 | PPO 裁剪范围 | | `K_epochs` | 4 | 每次数据复用训练轮数 | | `entropy_coef` | 0.05 | 熵正则化系数(硬编码) | ### 动作采样示例 ```python # 纯离散动作(如 CartPole) policy = ActorCriticSimple(state_dim=4, discrete_action_dim=2, continuous_action_dim=0) d_action, c_action, logprob = trainer.select_action(state) # 返回: (1, None, -0.693) # 纯连续动作(如 Pendulum) policy = ActorCriticSimple(state_dim=3, discrete_action_dim=0, continuous_action_dim=1) d_action, c_action, logprob = trainer.select_action(state) # 返回: (None, array([0.42]), -1.234) # 混合动作(如同时选择方向和力度) policy = ActorCriticSimple(state_dim=8, discrete_action_dim=4, continuous_action_dim=2) d_action, c_action, logprob = trainer.select_action(state) # 返回: (2, array([0.1, -0.3]), -2.567) ``` ### 注意事项 1. **回报计算**:当前实现使用蒙特卡洛回报(完整 episode 折扣和),要求 `memory` 在一个完整的 episode 结束后调用 `update()`。若用于长 episode 或在线更新,建议改用 GAE(Generalized Advantage Estimation)。 2. **旧策略同步**:每次 `update()` 后会自动将当前策略参数复制到 `policy_old`,用于下一轮动作采样。 3. **动作类型**:`push()` 时若某类动作为 `None`,对应动作维度必须设为 0,否则会导致缓冲区异常。 ### 扩展建议 - **GAE 优势估计**:替换当前蒙特卡洛回报,支持在线更新 - **多步回放缓冲区**:支持多环境并行采样 - **学习率调度**:添加 `torch.optim.lr_scheduler` - **梯度裁剪**:`torch.nn.utils.clip_grad_norm_` - **TensorBoard 日志**:记录 reward、loss、entropy 等指标 ### 参考 - [Proximal Policy Optimization Algorithms](https://arxiv.org/abs/1707.06347) - Schulman et al., 2017 - [OpenAI Spinning Up - PPO](https://spinningup.openai.com/en/latest/algorithms/ppo.html) ### 许可证 本项目未声明开源许可证,使用前请关注具体项目描述及其代码上游依赖。