1. 项目背景与核心挑战
登月器降落问题一直是强化学习领域的经典测试场景。这个看似简单的二维物理模拟环境,实际上包含了连续状态空间、稀疏奖励、延迟反馈等核心挑战。传统控制方法如PID在参数调优上耗时费力,而基于值函数的Q-learning又难以处理连续动作空间。这正是A2C(Advantage Actor-Critic)算法大显身手的场景。
去年我用DQN尝试解决这个问题时,遇到了两个致命瓶颈:一是离散化动作空间导致降落精度不足,二是稀疏奖励下学习效率低下。这次改用A2C方案,核心突破在于:
- 演员网络直接输出连续动作分布
- 评论家网络通过优势函数提供更精准的梯度信号
- 并行环境采样加速经验收集
2. A2C算法深度解析
2.1 算法架构设计
A2C的核心创新在于将策略评估与策略改进解耦为两个神经网络:
python复制class ActorCritic(nn.Layer):
def __init__(self, num_inputs, num_outputs, hidden_size):
super().__init__()
# 评论家网络估算状态价值
self.critic = nn.Sequential(
nn.Linear(num_inputs, hidden_size),
nn.ReLU(),
nn.Linear(hidden_size, 1))
# 演员网络输出动作概率
self.actor = nn.Sequential(
nn.Linear(num_inputs, hidden_size),
nn.ReLU(),
nn.Linear(hidden_size, num_outputs),
nn.Softmax(axis=1))
关键设计细节:
- 共享底层特征提取层(实验中单独设计反而降低效果)
- 演员网络使用Softmax保证概率归一化
- 评论家网络输出标量价值估计
2.2 优势函数计算
优势函数A(s,a) = Q(s,a) - V(s)是算法的灵魂所在。其计算过程如下:
python复制def compute_returns(next_value, rewards, masks, gamma=0.99):
R = next_value
returns = []
# 逆向计算n步TD目标
for step in reversed(range(len(rewards))):
R = rewards[step] + gamma * R * masks[step]
returns.insert(0, R)
return returns
# 训练过程中
returns = paddle.concat(returns).detach()
values = paddle.concat(values)
advantage = returns - values # 关键优势项
注意:gamma参数对稀疏奖励任务特别敏感,登月场景建议0.995-0.999
3. 登月器环境特调方案
3.1 状态空间改造
原始LunarLander-v2环境提供8维状态:
- 坐标(x,y)
- 速度(vx,vy)
- 角度(θ)
- 角速度(ω)
- 左右腿触地标志
我们新增三个关键特征:
python复制# 新增相对高度归一化
state[8] = (initial_altitude - current_y) / initial_altitude
# 新增速度方向标志
state[9] = 1 if vy < -0.5 else 0
# 新增紧急制动标志
state[10] = 1 if (y < 0.3 and abs(vy) > 1.5) else 0
3.2 奖励函数重塑
原始奖励函数存在局部最优陷阱,我们采用分阶段奖励设计:
| 阶段 | 奖励条件 | 计算公式 |
|---|---|---|
| 巡航 | 高度>0.5 | 0.1*(1 - abs(θ)/π) |
| 接近 | 0.3<高度≤0.5 | 2.0*(1 - vy) |
| 着陆 | 高度≤0.3 | 10.0 + 100*(leg_contact) - 50*(crashed) |
4. 关键实现细节
4.1 并行环境加速
使用SubprocVecEnv创建8个并行环境,显著提升样本效率:
python复制envs = [make_env('LunarLander-v2') for _ in range(8)]
envs = SubprocVecEnv(envs) # 关键加速点
# 训练时批量采集样本
states = envs.reset()
for _ in range(num_steps):
actions = model.sample_actions(states)
next_states, rewards, dones, _ = envs.step(actions)
# 存储轨迹数据...
4.2 策略熵正则化
为防止过早收敛到次优策略,在损失函数中加入熵项:
python复制dist = Categorical(probs)
entropy = dist.entropy().mean() # 关键探索项
loss = actor_loss + 0.5*critic_loss - 0.01*entropy # 系数需调优
5. 训练技巧与调参心得
5.1 学习率调度策略
采用余弦退火配合热重启:
python复制scheduler = optim.lr.CosineAnnealingDecay(
learning_rate=3e-4,
T_max=10000,
eta_min=1e-5)
optimizer = optim.Adam(
parameters=model.parameters(),
learning_rate=scheduler)
5.2 梯度裁剪技巧
演员和评论家网络需要不同的裁剪阈值:
python复制# 反向传播后
paddle.nn.utils.clip_grad_norm_(
model.actor.parameters(),
max_norm=0.5)
paddle.nn.utils.clip_grad_norm_(
model.critic.parameters(),
max_norm=1.0)
6. 典型问题排查指南
6.1 奖励不增长问题
可能原因及解决方案:
- 初始探索不足 → 增大熵系数到0.05
- 优势估计偏差 → 增加n_step到16
- 局部最优陷阱 → 添加定向探索奖励
6.2 训练不稳定问题
稳定性提升三板斧:
- 目标网络更新(τ=0.95):
python复制soft_update(target_net, model, tau=0.95)
- 观察标准化:
python复制running_mean = 0.99*running_mean + 0.01*state.mean()
state = (state - running_mean) / (running_std + 1e-8)
- 梯度归一化:
python复制grad_norm = paddle.norm([p.grad.norm() for p in model.parameters()])
if grad_norm > 1.0:
for p in model.parameters():
p.grad /= grad_norm
7. 性能优化记录
经过系统调优后,模型在NVIDIA RTX 3090上的表现:
| 优化阶段 | 平均奖励 | 训练步数 | 显存占用 |
|---|---|---|---|
| Baseline | -150 | 50k | 2.1GB |
| +状态改造 | 80 | 30k | 2.3GB |
| +奖励重塑 | 180 | 20k | 2.3GB |
| +并行环境 | 210 | 10k | 3.5GB |
| 最终方案 | 250+ | 5k | 3.8GB |
关键突破点出现在将n_step从8调整到12时,样本效率提升约40%。这验证了在稀疏奖励场景中,适当延长credit assignment距离的重要性。
8. 扩展应用方向
当前架构可轻松迁移到类似控制问题:
- 无人机定点降落 → 增加三维状态空间
- 机械臂抓取 → 替换为关节空间
- 自动驾驶泊车 → 修改观测输入
对于更复杂场景,可尝试以下改进:
python复制# 添加LSTM处理时序
self.lstm = nn.LSTM(input_size, hidden_size)
# 或使用Attention机制
self.attention = nn.MultiHeadAttention()
这个项目的完整实现让我深刻体会到:强化学习就像教小孩学自行车,既需要明确的目标指引(评论家),也要允许试错探索(演员),两者平衡才能稳健前行。
