共计 1570 个字符,预计需要花费 4 分钟才能阅读完成。
在强化学习实践中,策略梯度方法(如 REINFORCE)虽然直观易懂,但在实际应用中常常因为高方差导致训练不稳定。本文将深入分析这一问题的根源,并给出基于 Actor-Critic 框架的工程实现方案。

1. 问题背景与分析
策略梯度方法的核心思想是通过梯度上升来优化策略参数 θ,其梯度估计可表示为:
$$\nabla_\theta J(\theta) = \mathbb{E}{\tau \sim \pi\theta} \left[\sum_{t=0}^T \nabla_\theta \log \pi_\theta(a_t|s_t) G_t \right]$$
其中 $G_t$ 是从时刻 t 开始的累积回报。这个估计的主要问题是方差过高,原因在于:
- $G_t$ 包含了从当前状态到 episode 结束的所有随机性
- 对于长序列任务,$G_t$ 的波动可能非常大
数学上可以证明,这个估计的方差与时间步数 T 的平方成正比,这在实际任务中会导致训练极其不稳定。
2. Actor-Critic 技术方案
Actor-Critic 框架通过引入价值函数作为基线 (baseline) 来降低方差。我们对比两种 Critic 实现方式:
- Monte Carlo Critic:使用完整 episode 回报作为目标,无偏但高方差
- TD Critic:使用自举 (bootstrapping) 估计,有偏但低方差
实践中我们采用 GAE(Generalized Advantage Estimation)来平衡偏差和方差:
$$\hat{A}t^{GAE} = \sum$$}^{\infty} (\gamma\lambda)^l \delta_{t+l
其中 $\delta_t = r_t + \gamma V(s_{t+1}) – V(s_t)$ 是 TD 误差。
3. 关键实现细节
网络架构设计
class ActorCritic(nn.Module):
def __init__(self, obs_dim, act_dim):
super().__init__()
# 共享基网络
self.base = nn.Sequential(nn.Linear(obs_dim, 64),
nn.ReLU())
self.actor = nn.Linear(64, act_dim)
self.critic = nn.Linear(64, 1)
def forward(self, x):
x = self.base(x)
return torch.distributions.Normal(self.actor(x), 1.0), self.critic(x)
并行环境采样
使用 torch.multiprocessing 实现并行采样,关键点:
1. 每个 worker 维护自己的环境实例
2. 通过共享内存实现经验收集
3. 主进程定期同步模型参数
训练循环
# 关键训练步骤
1. 收集 n 步经验
2. 计算 GAE 优势
3. 更新 Critic 最小化 MSE 损失
4. 更新 Actor 最大化策略梯度
5. 应用梯度裁剪(阈值 0.5)
4. 生产环境考量
- Batch Size 选择:建议从 256 开始,根据 GPU 内存调整
- 分布式训练:采用异步更新策略,每 10 个 episode 同步一次参数
- 监控指标:
- 平均 episode 长度
- Critic 的 MSE 损失
- 策略熵(避免过早收敛)
5. 常见问题与解决方案
- 数据穿越问题:
- 确保计算优势函数时使用正确的时序关系
-
实现经验回放时添加 episode 边界标记
-
连续动作梯度消失:
- 在 tanh 激活后添加少量高斯噪声
-
使用 layer normalization 稳定输入分布
-
调试技巧:
- 先在 Pendulum-v1 等简单环境验证
- 可视化策略在状态空间的探索范围
开放性问题
PPO 通过信任域机制限制了策略更新的幅度,如何将其与当前方案结合?一个可能的思路是:
- 在 Actor 更新时添加 KL 散度约束
- 自适应调整学习率以维持合理的更新步长
- 使用二阶优化方法近似信任域
期待大家在实践中探索更多可能性,也欢迎分享你们的改进经验!
