1. REINFORCE算法核心解析
在强化学习领域,REINFORCE算法代表了一种直接优化策略的经典方法。与常见的Q-learning、DQN等基于价值函数的方法不同,它直接对策略参数θ进行梯度上升优化。这种直接策略优化的特性使其在连续动作空间和随机策略场景中展现出独特优势。
关键区别:value-based方法通过估计状态-动作价值函数间接推导策略,而policy-based方法直接参数化并优化策略函数本身。
1.1 策略参数化实现
REINFORCE算法中策略π(a|s,θ)通常采用softmax形式实现:
code复制π(a|s, θ) = exp(h(s,a,θ)) / Σ_a' exp(h(s,a',θ))
其中h(s,a,θ)是状态-动作对的偏好分数,通常设计为特征向量的线性组合:
code复制h(s, a, θ) = θ^T · φ(s, a)
实际计算示例:
- 当θ=[0.5,1.8,-0.8,-1.5]时
- 对于状态s=(1,2),各动作的偏好分数:
- ↑ Up: h=0.5 → exp(0.5)=1.65 → 概率19.7%
- ↓ Down: h=1.8 → exp(1.8)=6.05 → 概率72.3%
- ← Left: h=-0.8 → exp(-0.8)=0.45 → 概率5.4%
- → Right: h=-1.5 → exp(-1.5)=0.22 → 概率2.6%
这种参数化方式天然支持:
- 连续动作空间处理
- 随机策略表达
- 无需ε-greedy的探索机制
1.2 算法执行流程
1.2.1 完整回合采样
必须完整执行整个episode获得轨迹:
code复制τ = {s₀,a₀,r₁,s₁,a₁,r₂,...,s_T}
这是Monte Carlo方法的特性要求。例如在网格世界中:
code复制t=0: s₀=(0,0), a₀=Right, r₁=-1
t=1: s₁=(0,1), a₁=Down, r₂=-1
t=2: s₂=(1,1), a₂=Right, r₃=+10 (终止)
注意事项:必须等到回合结束才能更新参数,这与TD方法有本质区别。长回合任务可能导致学习效率低下。
1.2.2 回报计算
采用折扣累计回报:
code复制q_t = Σ_{k=t+1}^T γ^{k-t-1}r_k
具体计算示例(设γ=0.9):
code复制t=0: q₀ = (-1) + 0.9*(-1) + 0.81*10 = 6.2
t=1: q₁ = (-1) + 0.9*10 = 8.0
t=2: q₂ = 10.0
1.2.3 参数更新
核心更新公式:
code复制θ ← θ + α · ∇_θ ln π(a_t|s_t, θ) · q_t
计算实例(设α=0.01):
code复制t=0时刻:
当前π(Right|s₀)=0.4
∇_θ ln π = [0.3, -0.1, 0.2]
更新量 = 0.01*6.2*[0.3,-0.1,0.2]
= [0.0186, -0.0062, 0.0124]
t=2时刻:
∇_θ ln π = [0.5, 0.1, -0.3]
更新量 = 0.01*10.0*[0.5,0.1,-0.3]
= [0.05, 0.01, -0.03]
更新方向分析:
- q_t > 0:增加该动作概率
- q_t < 0:减小该动作概率
- |q_t|大小决定更新幅度
2. 算法特性深度剖析
2.1 方差问题与解决方案
REINFORCE作为Monte Carlo方法存在高方差问题,主要源于:
- 完整轨迹采样带来的随机性
- 回报q_t的波动性
常用改进技术:
- 基线减法:使用状态值函数V(s)作为基线
code复制q_t ← q_t - V(s_t) - Advantage函数:A(s,a)=Q(s,a)-V(s)
- Actor-Critic架构:引入critic网络估计价值函数
2.2 探索机制分析
不同于ε-greedy的显式探索,REINFORCE通过:
- 策略本身的随机性
- 梯度更新对低概率动作的保留
实践技巧:
- 初始策略应保持较高熵值
- 可添加熵正则项防止过早收敛:
code复制L = -E[logπ(a|s)q_t] + βH(π(·|s))
2.3 与DQN的对比
| 特征 | DQN | REINFORCE |
|---|---|---|
| 学习目标 | Q值函数 | 策略函数 |
| 动作选择 | ε-greedy | 概率采样 |
| 更新时机 | 单步更新 | 回合更新 |
| 数据效率 | 经验回放 | 在线采样 |
| 方差特性 | 较低 | 较高 |
| 连续动作 | 困难 | 天然支持 |
| 收敛保证 | 无 | 局部最优 |
3. 实战实现要点
3.1 代码实现框架
python复制import torch
import torch.nn as nn
import torch.optim as optim
class PolicyNetwork(nn.Module):
def __init__(self, state_dim, action_dim):
super().__init__()
self.fc = nn.Sequential(
nn.Linear(state_dim, 64),
nn.ReLU(),
nn.Linear(64, action_dim)
)
def forward(self, state):
return torch.softmax(self.fc(state), dim=-1)
def compute_returns(rewards, gamma=0.99):
returns = []
R = 0
for r in reversed(rewards):
R = r + gamma * R
returns.insert(0, R)
return returns
def train(episodes):
policy = PolicyNetwork(state_dim, action_dim)
optimizer = optim.Adam(policy.parameters(), lr=1e-3)
for ep in range(episodes):
states, actions, rewards = run_episode(policy)
returns = compute_returns(rewards)
loss = 0
for s, a, R in zip(states, actions, returns):
prob = policy(s)[a]
loss += -torch.log(prob) * R
optimizer.zero_grad()
loss.backward()
optimizer.step()
3.2 超参数调优经验
-
学习率选择:
- 典型范围:1e-4到1e-2
- 建议采用自适应方法如Adam
-
折扣因子γ:
- 短期任务:0.9-0.99
- 长期任务:0.99-0.999
-
批次大小:
- 可累积多个episode后批量更新
- 典型值:4-32个完整回合
3.3 常见问题排查
-
训练不稳定:
- 检查梯度裁剪(gradient clipping)
- 添加基线函数减小方差
- 尝试减小学习率
-
策略过早收敛:
- 增加熵正则项系数
- 检查初始策略是否足够随机
-
回报不增长:
- 验证环境反馈是否正确
- 检查折扣回报计算实现
- 调整探索超参数
4. 进阶改进方向
4.1 基线方法对比
| 方法 | 优点 | 缺点 |
|---|---|---|
| 原始REINFORCE | 实现简单 | 高方差 |
| 均值基线 | 减小方差 | 需维护运行平均 |
| 线性基线 | 更准确的基准 | 需训练额外网络 |
| Advantage | 最优基线形式 | 实现复杂度高 |
4.2 自然策略梯度
将欧式空间梯度转换为KL散度约束下的自然梯度:
code复制θ ← θ + α F^{-1}∇_θ J(θ)
其中F是Fisher信息矩阵。实现方式:
- 共轭梯度法近似求逆
- TRPO/PPO等现代方法
4.3 分布式并行实现
利用多worker并行采样:
- 每个worker独立与环境交互
- 中央learner聚合梯度
- 同步或异步更新策略
典型配置:
- 16-256个worker
- 每10-100个episode同步一次
- 采用参数服务器架构
在实际应用中,我发现REINFORCE虽然理论优雅,但其高方差特性使得直接应用效果往往不如后期发展的PPO等算法。建议初学者先理解其核心思想,再转向更先进的策略梯度方法。一个实用的技巧是在简单环境中手动计算几个回合的更新过程,这能极大加深对算法机理的理解。
