在第四单元中,学习了第一个基于策略的算法——Reinforce。
在基于策略的方法中,目标是通过不使用价值函数来直接优化策略。更具体地说,Reinforce 是策略梯度方法的一个子类的一部分。这个子类通过使用梯度上升来估计最优策略的权重来直接优化策略。
由于使用蒙特卡洛采样来估计回报(使用整个回合来计算回报),策略梯度估计中存在显著的方差。
<aside> 💡
蒙特卡洛回报估计
用整回合去感受一次策略的“全部后果”:不向未来做假设,不用引导(无自举),用多次完整经历来换取无偏估计。
定义与基本公式
基于回合的价值估计
控制:基于 Q 的 on-policy MC
策略梯度:REINFORCE(整回合回报)
实用要点
代码示例(Python/NumPy)
import numpy as np
def mc_returns(rewards, gamma):
# 输入一条回合的奖励序列 [R1, R2, ..., RT]
T = len(rewards)
G = np.zeros(T, dtype=float)
g = 0.0
for t in reversed(range(T)):
g = rewards[t] + gamma * g
G[t] = g
return G # [G0, G1, ..., G_{T-1}]
# 首次访问 MC 估计 V(s)
from collections import defaultdict
def first_visit_mc_value(episodes, gamma=0.99):
# episodes: 列表,每个元素为 [(s0,a0,r1), (s1,a1,r2), ..., (s_{T-1}, a_{T-1}, r_T)]
returns_sum = defaultdict(float)
returns_count = defaultdict(int)
V = defaultdict(float)
for ep in episodes:
states = [s for (s, a, r) in ep]
rewards = [r for (s, a, r) in ep]
G = mc_returns(rewards, gamma)
visited = set()
for t, s in enumerate(states):
if s in visited:
continue # 首次访问
visited.add(s)
returns_sum[s] += G[t]
returns_count[s] += 1
V[s] = returns_sum[s] / max(1, returns_count[s])
return V
# REINFORCE(带基线)
import numpy as np
def reinforce_update(log_probs, values, rewards, gamma=0.99, lr=1e-3):
# log_probs: [log πθ(a_t|s_t)] 的列表(Tensor/ndarray)
# values: 基线 b(s_t) ≈ V(s_t) 的列表(同框架张量)
# rewards: [R1, R2, ..., RT]
G = mc_returns(rewards, gamma)
# 优势
advantages = G - np.array(values)
# 目标:最大化 sum_t logπ * A_t 等价于最小化其负值
loss = -(np.array(log_probs) * advantages).sum()
# 伪代码:反向传播与参数更新(具体取决于你用的框架)
# loss.backward(); optimizer.step()
return float(loss)
</aside>
研究 Actor-Critic 方法,结合基于值和基于策略的混合架构,通过以下方式帮助稳定训练并减少方差:
在Reinforce中,希望在轨迹中增加动作的概率,使其与回报成正比。

这个回报$R(τ)$ 是通过蒙特卡洛采样计算的, 收集一个轨迹并计算折扣回报,然后使用分数来增加或减少该轨迹中每个动作的概率。如果回报好,所有动作都会通过提高它们被采取的可能性来“强化”。
$鉴于环境的随机性以及策略的随机性,轨迹可能导致不同的回报,从而导致高方差$
→相同的起始状态可能导致不同的回报→从相同状态开始的回报在不同回合中可能会有显著差异

解决方法是:使用大量轨迹来降低方差,单个轨迹引入的方差在总体上会减少,并提供“真实”的回报估计。
然而, $增加批次大小会显著降低样本效率$