PPO-Ant: 用 PPO 教 MuJoCo 机械蚂蚁走路
仓库地址https://github.com/ctfxffy/PPO
效果展示
10 万步冒烟训练曲线(早期学习阶段,蚂蚁学会“站立不倒”,回报约 850):

渲染评估(确定性策略,实时窗口支持鼠标旋转/缩放视角):
python evaluate.py --checkpoint checkpoints/best.pt --render --episodes 3
特性
- 正确的 PPO 实现:Clipped Surrogate + GAE(λ=0.95)+ 优势归一化 + 价值损失 + 梯度裁剪,所有组件均有单元测试(含 GAE 手算对照)。
- 现代技术栈:Gymnasium 1.x + MuJoCo 3.x 纯 pip 安装,Windows 免编译,告别
mujoco-py。 - 断点续训:checkpoint 完整保存网络/优化器/归一化器/步数/RNG 状态,
--resume一键恢复,可边续训边改超参(配合分阶段调参)。 - 训练监控:TensorBoard 全指标(回报/损失/KL/clip_frac/lr)+ CSV 日志 + tqdm 实时进度条 + matplotlib 出图。
- 评估工具:确定性策略评估、
--render实时渲染、离屏视频录制(mp4)。 - 工程细节:观测 RunningMeanStd 归一化(Welford 算法)、正交初始化、terminated/truncated 分别处理、NaN 保护、原子化 checkpoint 保存。
- 兼容性修复:内置 gymnasium 1.x + mujoco 3.x 渲染鼠标回调不兼容的 shim(
ppo/render_fix.py)。
任务与奖励机制
Ant-v5 是 MuJoCo 经典连续控制环境:一只躯干 + 四腿(8 关节)的蚂蚁机器人,目标是在不摔倒的前提下沿 x 轴方向尽快移动。
| 要素 | 内容 |
|---|---|
| 观测空间 | 105 维连续向量(躯干姿态、关节角度/角速度、78 维足底接触力) |
| 动作空间 | 8 维连续向量,[-1, 1],各关节电机力矩 |
| 回合长度 | 上限 1000 步(每步 0.05s 仿真时间,共 50s) |
| 终止条件 | terminated:躯干高度掉出 [0.2, 1.0](摔倒);truncated:超时(仍可 bootstrap) |
奖励函数(环境内置,本项目未做自定义 shaping):
r_t = v_x(前进速度 × 1.0)+ 1.0(存活奖励)− 0.5 × Σ a_i²(控制代价)− 5×10⁻⁴ × Σ F_contact²(接触代价,裁剪后)
环境与依赖
开发与验证环境(Windows 11 + conda):
| 包 | 版本 | 说明 |
|---|---|---|
| Python | 3.10 | 3.9–3.12 均可 |
| PyTorch | 2.13 (cu126) | >=2.0 即可,CPU 也能训 |
| numpy | 2.2.6 | 2.x 是关键约束 |
| gymnasium[mujoco] | 1.3.0 | 必须 >=1.0(numpy 2 兼容从 1.0 起) |
| mujoco | 3.11 | 随 gymnasium 自动安装,纯 wheel |
| tensorboard | >=2.17 | 2.17 起支持 numpy 2 |
| matplotlib | >=3.9 | 3.9 起支持 numpy 2 |
| tqdm | >=4.66 | 进度条 |
| moviepy | 任意 | 可选,仅录视频需要(注意会降级 pillow 到 11.x) |
安装:
pip install -r requirements.txt
验证环境可用:
python -c "import gymnasium; env = gymnasium.make('Ant-v5'); print(env.observation_space.shape, env.action_space.shape); env.close()"
# 期望输出: (105,) (8,)
快速开始
训练
python train.py --total-steps 3000000
推荐:带学习率退火
python train.py --total-steps 3000000 --lr-anneal
断点续训
# 从上次 checkpoint 继续,一切状态(网络/优化器/归一化器/RNG/步数)原样恢复
python train.py --total-steps 6000000 --resume checkpoints/latest.pt
续训同时调整超参(分阶段调参,见下文)
python train.py --total-steps 6000000 --resume checkpoints/latest.pt --lr 1e-4 --lr-anneal
监控
tensorboard --logdir runs # 浏览器打开 http://localhost:6006
python plot.py runs/<run-dir>/metrics.csv # 生成 reward_curve.png
评估与渲染
# 无头评估 10 回合,输出均值/方差
python evaluate.py --checkpoint checkpoints/best.pt --episodes 10
实时渲染(窗口里可鼠标拖拽旋转、滚轮缩放)
python evaluate.py --checkpoint checkpoints/best.pt --render --episodes 3
录制视频
import gymnasium as gym
env = gym.make("Ant-v5", render_mode="rgb_array")
env = gym.wrappers.RecordVideo(env, video_folder="videos",
episode_trigger=lambda e: True, disable_logger=True)
# ... 之后按 evaluate.py 的方式加载模型跑回合即可,视频自动保存到 videos/
项目结构
PPO/
├── ppo/ # 核心算法包(建议按此顺序阅读)
│ ├── utils.py # 种子固定、设备检测、环境工厂(v5/classic 观测模式)
│ ├── config.py # argparse 全部超参数(先看它混个脸熟)
│ ├── normalizer.py # RunningMeanStd 观测归一化(Welford 并行更新)
│ ├── models.py # ActorCritic:高斯策略 + 价值网络,正交初始化
│ ├── buffer.py # RolloutBuffer:数据存储 + GAE 计算 + minibatch 迭代
│ ├── agent.py # PPOAgent:clipped surrogate 更新逻辑(算法核心)
│ └── render_fix.py # gymnasium+mujoco3 渲染鼠标回调兼容 shim
├── train.py # 训练入口:采样→GAE→更新循环,日志/checkpoint/续训
├── evaluate.py # 评估入口:确定性策略,支持 --render
├── plot.py # 从 metrics.csv 画回报曲线
├── requirements.txt
├── assets/ # README 配图(训练曲线)
├── runs/ # TensorBoard 事件 + metrics.csv(.gitignore)
├── checkpoints/ # latest.pt / best.pt(.gitignore)
└── videos/ # 评估录像
PPO 算法要点与代码对照
1. 策略:高斯分布(ppo/models.py)
连续动作空间的策略输出分布参数而非动作值:Actor 头输出均值 μ(s),log_std 为独立可学习参数(不随状态变),打包成 torch.distributions.Normal:
dist.sample()→ 训练时采样(探索)dist.mean→ 评估时确定性输出dist.log_prob(a).sum(-1)→ 动作的对数概率(8 维独立求和),PPO ratio 的原料
2. GAE 优势估计(ppo/buffer.py)
δ_t = r_t + γV(s_{t+1})·m_t − V(s_t),A_t = Σ_l (γλ)^l δ_{t+l}
critic 的训练目标是 returns = advantages + values(GAE 修正后的回报估计),用 MSE 拟合。
3. Clipped Surrogate(ppo/agent.py)
L^CLIP = E[min(r_t·A_t, clip(r_t, 1±ε)·A_t)],r_t = π_new(a_t|s_t) / π_old(a_t|s_t)
ratio = (new_log_probs - old_log_probs).exp() # log 域做除法
surr1 = ratio * adv
surr2 = torch.clamp(ratio, 1.0 - clip_eps, 1.0 + clip_eps) * adv
policy_loss = -torch.min(surr1, surr2).mean()
4. 完整损失与更新
loss = policy_loss + 0.5 * value_loss - entropy_coef * entropy
每批 2048 步数据复用 10 个 epoch,每 epoch 切成 8 个 256 的 minibatch 随机打乱;每个 minibatch 内做优势归一化;反向传播后梯度裁剪到 0.5。
超参数说明
python train.py -h 查看全部,常用项:
| 参数 | 默认值 | 说明 |
|---|---|---|
--total-steps |
3,000,000 | 总环境步数 |
--rollout-steps |
2048 | 每次 PPO 更新前采样步数 |
--minibatch-size |
256 | minibatch 大小(建议为 rollout 的 1/8) |
--n-epochs |
10 | 每批数据复用轮数 |
--lr |
3e-4 | Adam 学习率 |
--lr-anneal |
关 | 线性退火到 0,长训练强烈建议开 |
--gamma |
0.99 | 折扣因子 |
--lam |
0.95 | GAE λ(偏差-方差权衡) |
--clip-eps |
0.2 | PPO 剪切系数 ε |
--value-coef |
0.5 | 价值损失权重 |
--entropy-coef |
0.0 | 熵奖励(Ant 通常为 0) |
--max-grad-norm |
0.5 | 梯度裁剪 |
--seed |
0 | 随机种子 |
--resume |
无 | 续训 checkpoint 路径 |
--obs-mode |
v5 | v5=105 维;classic=107 维(补回全局坐标) |
--save-interval |
10 | 每 N 次更新存一次 checkpoint |
分阶段训练建议
| 阶段 | 步数 | lr | clip-ε | rollout | GAE λ |
|---|---|---|---|---|---|
| 探索 | 0–1M | 3e-4 | 0.3 | 2048 | 0.95 |
| 提升 | 1M–3M | 1e-4 | 0.2 | 4096 | 0.90 |
| 微调 | >3M | 5e-5 | 0.1 | 8192 | 0.80 |
阶段间通过 --resume + 覆盖超参切换:
python train.py --total-steps 1000000
python train.py --total-steps 3000000 --resume checkpoints/latest.pt \
--lr 1e-4 --clip-eps 0.2 --rollout-steps 4096 --lam 0.9
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)