2. PPO的广义优势估计(GAE)实现
任务目标
在连续控制任务中,实现PPO算法中的广义优势估计(GAE),并通过调整λ参数观察其对训练稳定性与收敛速度的影响。本案例聚焦GAE核心逻辑,不涉及完整PPO策略更新。
环境依赖
需要 numpy(数组计算)与 gymnasium(连续控制环境)。安装命令:
pip install numpy gymnasium
GAE核心实现
GAE通过指数加权平均多个TD残差来平衡偏差与方差。当λ=0时退化为一步TD误差,λ→1时接近蒙特卡洛回报。以下代码实现GAE计算,并在Pendulum-v1环境中模拟一次轨迹,展示不同λ下的优势估计差异。
import numpy as np
import gymnasium as gym
def compute_gae(rewards, values, dones, gamma=0.99, lam=0.95):
"""
计算广义优势估计(GAE)
rewards: 奖励序列, shape [T]
values: 价值函数预测, shape [T+1] (含最后一个状态的value)
dones: 终止标志, shape [T]
gamma: 折扣因子
lam: GAE平滑参数
返回: advantages shape [T], returns shape [T]
"""
T = len(rewards)
advantages = np.zeros(T)
gae = 0.0
for t in reversed(range(T)):
# 若t+1是终止状态,则下一个value为0
next_value = values[t+1] * (1 - dones[t])
delta = rewards[t] + gamma * next_value - values[t]
gae = delta + gamma * lam * (1 - dones[t]) * gae
advantages[t] = gae
returns = advantages + values[:T]
return advantages, returns
# 在Pendulum-v1中采样一条轨迹并计算GAE
env = gym.make("Pendulum-v1")
obs, _ = env.reset(seed=42)
gamma, lam = 0.99, 0.95
rewards, values, dones = [], [], []
value_net = lambda o: 0.0 # 简化:假设价值函数恒为0
for _ in range(200):
action = env.action_space.sample() # 随机策略采样
next_obs, reward, terminated, truncated, _ = env.step(action)
done = terminated or truncated
rewards.append(reward)
values.append(value_net(obs))
dones.append(done)
obs = next_obs
if done:
break
values.append(value_net(obs)) # 追加最后一个状态的value
adv_low, _ = compute_gae(np.array(rewards), np.array(values), np.array(dones), gamma, 0.0)
adv_high, _ = compute_gae(np.array(rewards), np.array(values), np.array(dones), gamma, 0.99)
print(f"轨迹长度: {len(rewards)}")
print(f"λ=0.0 优势均值: {adv_low.mean():.4f}, 标准差: {adv_low.std():.4f}")
print(f"λ=0.99 优势均值: {adv_high.mean():.4f}, 标准差: {adv_high.std():.4f}")
env.close()
运行与验证
直接执行上述脚本。预期输出显示:λ=0.99的优势估计标准差显著大于λ=0.0(因方差更高),但均值接近。若需观察训练稳定性差异,可将GAE接入PPO更新循环,对比不同λ下策略熵或奖励曲线的波动幅度——λ较小时训练更稳定但收敛慢,λ接近1时收敛快但波动大。
判定标准
- 代码能无错运行并输出两条轨迹的统计量
- λ=0.99的标准差大于λ=0.0的标准差(因高λ保留更多长期信息,方差增大)
- 修改λ值后重新运行,优势估计随之变化,说明GAE参数生效
常见问题
- dones处理:终止状态后的value应置0,否则优势估计会错误引入未来奖励
- values长度:需比rewards多一个元素(最后一个状态的value),否则索引越界
- λ调参:连续控制任务通常取0.9~0.99,λ过小导致偏差大,过大则方差高