1. 课程内容概述
博磊老师的强化学习纲要第四课下主要围绕策略梯度方法展开深入讲解。这部分内容是整个强化学习课程体系中的关键转折点,标志着我们从基于值函数的方法转向直接优化策略的方法。在实际工业应用中,策略梯度方法因其灵活性和对连续动作空间的良好适应性而备受青睐。
这节课首先回顾了策略梯度定理的数学推导过程,这是理解后续各种算法变种的基础。随后详细分析了REINFORCE算法的实现细节和优缺点,并自然地引出带基线的策略梯度方法。课程最后探讨了现代深度强化学习中常用的Actor-Critic框架,为后续更复杂的算法学习奠定了基础。
2. 策略梯度定理详解
2.1 数学推导过程
策略梯度定理是理解所有策略优化方法的核心。它建立了策略参数θ与目标函数J(θ)之间的直接联系:
∇θJ(θ) = Eπ[∇θlogπ(a|s) Qπ(s,a)]
这个看似简单的公式背后蕴含着深刻的数学原理。推导过程需要用到对数导数技巧和期望的梯度交换,这是许多初学者容易困惑的地方。我建议从最简单的有限状态-动作空间开始理解,再推广到连续情况。
注意:在实际推导时,必须注意期望和梯度运算的交换条件。这在理论上是需要满足一定条件的,但在大多数实际应用中我们可以安全地进行这种交换。
2.2 直观理解
策略梯度定理的直观解释其实很直接:它告诉我们如何调整策略参数,使得高回报的动作被更频繁地选择。具体来说:
- Qπ(s,a)衡量了在状态s下采取动作a的质量
- ∇θlogπ(a|s)给出了增加动作a概率的参数更新方向
- 两者的乘积就是参数更新的合理方向
这种"奖励好的行为"的机制与人类学习过程非常相似,这也是策略梯度方法在复杂任务中表现优异的原因之一。
3. REINFORCE算法解析
3.1 算法实现细节
REINFORCE是最基础的策略梯度算法,其伪代码看似简单但实现时有诸多细节需要注意:
def REINFORCE(): # 初始化策略参数θ for episode in range(MAX_EPISODES): states, actions, rewards = run_episode() returns = compute_returns(rewards) for t in range(len(states)): # 计算梯度 grad = ∇θlogπ(at|st) * Gt # 参数更新 θ = θ + α * grad在实际编码时,以下几个细节至关重要:
- 回报Gt的计算需要考虑折扣因子γ
- 通常需要对回报进行归一化处理(减去均值,除以标准差)
- 策略网络输出层的激活函数选择(离散动作用softmax,连续动作用高斯分布)
3.2 优缺点分析
REINFORCE的优点在于:
- 概念简单,实现直接
- 适用于离散和连续动作空间
- 保证策略改进(在适当的学习率下)
但其缺点也很明显:
- 高方差:因为依赖完整轨迹的回报
- 样本效率低:每更新一次参数需要完成整个episode
- 收敛速度慢:特别是在稀疏奖励环境中
我在实际项目中曾尝试用原始REINFORCE算法训练机械臂控制任务,发现即使经过数千次episode,性能提升仍然有限。这促使我转向更先进的策略梯度方法。
4. 带基线的策略梯度
4.1 基线引入的动机
REINFORCE算法的高方差问题主要源于回报Gt的波动性。一个直观的改进思路是引入基线函数b(s),将梯度估计变为:
∇θJ(θ) = Eπ[∇θlogπ(a|s) (Qπ(s,a)-b(s))]
理论上,任何不依赖动作a的函数都可以作为基线,但最优选择是状态值函数Vπ(s)。这是因为:
- Vπ(s) = Ea~π[Qπ(s,a)],正好抵消掉Qπ(s,a)的平均水平
- 减少了梯度估计的方差而不引入偏差
- 保持了策略改进的方向性
4.2 实现技巧
在实践中,我们通常用另一个神经网络来近似Vπ(s)。这带来了一些实现上的考量:
- 值函数网络的结构设计:通常比策略网络简单
- 训练数据的获取:可以使用同一批轨迹数据
- 训练频率:可以与策略网络同步更新或交替更新
我个人的经验是,基线网络的训练步长应该小于策略网络,以避免基线变化过快导致策略训练不稳定。一个常用的比例是1:5(基线:策略)。
5. Actor-Critic框架
5.1 基本架构
Actor-Critic方法将策略梯度与值函数近似完美结合,形成了强化学习中最强大的框架之一:
- Actor(策略网络):负责选择动作
- Critic(值函数网络):评估动作质量
两者协同工作的流程如下:
- 环境交互阶段:Actor根据当前策略选择动作
- 评估阶段:Critic计算TD误差或优势函数
- 更新阶段:用Critic的评估指导Actor的更新
5.2 优势函数的使用
现代Actor-Critic算法通常使用优势函数A(s,a)=Q(s,a)-V(s)代替简单的Q值。这样做有几个好处:
- 进一步降低方差
- 提供更准确的相对评估
- 使不同状态间的更新幅度更具可比性
在实际实现中,GAE(Generalized Advantage Estimation)是一种非常有效的优势估计方法,它通过引入λ参数在偏差和方差之间取得平衡。
6. 实践中的挑战与解决方案
6.1 高方差问题
尽管带基线的策略梯度方法已经减少了方差,但在复杂环境中这仍然是一个主要挑战。以下是我在实践中总结的有效策略:
- 使用多步回报:平衡TD和MC方法的优缺点
- 实现经验回放:打破样本间的相关性
- 添加合适的正则化:如策略熵正则化
6.2 训练不稳定
策略梯度方法,特别是结合神经网络时,常常面临训练不稳定的问题。解决方法包括:
- 使用信任域方法:如TRPO或PPO
- 实现梯度裁剪:防止参数更新过大
- 自适应学习率:如Adam优化器
在机器人控制项目中,我发现PPO算法(下一课内容)特别有效,它通过限制策略更新的幅度来保证稳定性,同时保持了较好的样本效率。
7. 代码实现要点
7.1 策略网络设计
对于连续控制任务,策略网络通常输出高斯分布的均值和标准差:
class PolicyNetwork(nn.Module): def __init__(self, state_dim, action_dim): super().__init__() self.fc1 = nn.Linear(state_dim, 64) self.fc2 = nn.Linear(64, 64) self.mean = nn.Linear(64, action_dim) self.log_std = nn.Parameter(torch.zeros(action_dim)) def forward(self, state): x = F.relu(self.fc1(state)) x = F.relu(self.fc2(x)) mean = self.mean(x) std = torch.exp(self.log_std) return torch.distributions.Normal(mean, std)重要提示:在实践中,log_std通常作为可学习参数而非网络输出,这有助于训练稳定性。
7.2 训练循环结构
一个完整的训练循环应包含以下关键部分:
- 数据收集:与环境交互得到轨迹
- 优势计算:使用GAE或其他方法
- 策略更新:考虑多个epoch和minibatch
- 值函数更新:通常使用MSE损失
我发现将数据收集和训练过程分离(使用经验回放池)可以显著提高GPU利用率,特别是在仿真环境较慢的情况下。
8. 调参经验分享
经过多个项目的实践,我总结出以下调参心得:
学习率选择:
- 策略网络:通常在3e-4到1e-3之间
- 值函数网络:比策略网络小5-10倍
- 使用学习率衰减策略
折扣因子γ:
- 短期任务:0.9-0.95
- 长期任务:0.98-0.99
- 稀疏奖励任务:接近1.0
GAE参数λ:
- 低噪声环境:0.9-0.95
- 高噪声环境:0.8-0.9
- 可作为超参数优化
在最近的一个交易策略优化项目中,我发现γ=0.99和λ=0.92的组合效果最佳,这可能与金融数据的特定时间结构有关。