第 4 课:GAE 与优势估计

参考答案版:包含完整代码实现与问答题深度参考解析。建议先独立完成练习题后再展开核对。

本课目标与完成标准

学完后你应能:实现带终止 mask 的 GAE 反向递推,并解释 λ 如何连接 TD 与 MC。

通过必须同时满足:

  • 独立补齐本课唯一的代码填空题,并通过给定检查;
  • 三个问答题均说明因果链,而不是只报术语;
  • 能指出至少一个正确性边界和一个性能取舍;
  • 总分不低于 8/10,且没有一票否决级概念错误。

前置关系

  • 课程前置:Python、概率期望、基本深度学习
  • 本课在路线中的作用:GAE 把多个 n-step TD error 以 (γλ)^k 加权,控制优势估计的偏差—方差。

核心心智模型

1. 它是什么,解决什么问题

广义优势估计(Generalized Advantage Estimation, GAE)由 John Schulman 等人于 2015 年提出,是现代 Actor-Critic、PPO 与大模型后训练算法中计算策略优势函数 A(s,a)A(s, a) 的事实工业标准。 在策略梯度更新 ∇θ𝒥=𝔼[∇θlog⁡πθ(a∣s)⋅A(s,a)]\nabla_\theta \mathcal{J} = \mathbb{E}[\nabla_\theta \log \pi_\theta(a \mid s) \cdot A(s, a)] 中,优势函数刻画了“在状态 ss 下采取动作 aa 相比于当前策略的平均水平好多少”: Aπ(s,a)=Qπ(s,a)−Vπ(s) A^\pi(s, a) = Q^\pi(s, a) - V^\pi(s) 我们在工程上面临的核心困境是方差与偏差的剧烈冲突:

  • 若用单步 TD 误差估计优势 Ât(1)=rt+γV(st+1)−V(st)\hat{A}_t^{(1)} = r_t + \gamma V(s_{t+1}) - V(s_t),由于高度依赖价值网络自身的不准确预估,具有高偏差、低方差;
  • 若用蒙特卡洛全轨迹回报估计优势 Ât(∞)=∑k=0∞γkrt+k−V(st)\hat{A}_t^{(\infty)} = \sum_{k=0}^\infty \gamma^k r_{t+k} - V(s_t),虽然数学期望严格无偏,但由于动作随机性在长时序中累乘发散,具有零偏差、极高方差。

GAE 解决的核心问题是:如何通过超参数 λ∈[0,1]\lambda \in [0, 1] 构筑连续可控的滑动折中,在单步 TD(0) 与无限步 MC 之间无缝插值,实现方差与偏差在 Pareto 前沿上的最优平衡。如图 4-1 所示,真实环境中总存在一个使全局均方误差(MSE = Bias2+Variance\text{Bias}^2 + \text{Variance})达到极小值的黄金参数区间(通常 λ∈[0.90,0.98]\lambda \in [0.90, 0.98])。

2. 它如何工作

GAE 的数学推导、状态权衡与逆序执行流水线如图 4-1 与图 4-2 所示:

图 4-1:广义优势估计 GAE(λ) 偏差-方差权衡与最优点曲线

  1. 时序差分残差(TD Residual)与多步优势的指数折叠: 定义单步 TD 残差 δtV=rt+γ(1−dt)V(st+1)−V(st)\delta_t^V = r_t + \gamma (1 - d_t) V(s_{t+1}) - V(s_t)。 将多步优势展开:
    • 1 步优势:Ât(1)=δtV\hat{A}_t^{(1)} = \delta_t^V
    • 2 步优势:Ât(2)=δtV+γδt+1V=rt+γrt+1+γ2V(st+2)−V(st)\hat{A}_t^{(2)} = \delta_t^V + \gamma \delta_{t+1}^V = r_t + \gamma r_{t+1} + \gamma^2 V(s_{t+2}) - V(s_t)
    • kk 步优势:Ât(k)=∑l=0k−1γlδt+lV=∑l=0k−1γlrt+l+γkV(st+k)−V(st)\hat{A}_t^{(k)} = \sum_{l=0}^{k-1} \gamma^l \delta_{t+l}^V = \sum_{l=0}^{k-1} \gamma^l r_{t+l} + \gamma^k V(s_{t+k}) - V(s_t) GAE(γ,λ\gamma, \lambda) 定义为对所有 kk-step 优势估计的几何加权指数衰减平均: ÂtGAE(γ,λ)=(1−λ)∑k=1∞λk−1Ât(k)=∑l=0∞(γλ)lδt+lV \hat{A}_t^{\text{GAE}(\gamma, \lambda)} = (1 - \lambda) \sum_{k=1}^\infty \lambda^{k-1} \hat{A}_t^{(k)} = \sum_{l=0}^\infty (\gamma \lambda)^l \delta_{t+l}^V
  2. 反向递推(Backward Telescoping Recurrence,图 4-2):

flowchart LR
    Last["最后一步: A_T^{GAE} = δ_T"] --> Step["递归计算: A_t = δ_t + γ λ (1 - done_t) A_{t+1}"]
    Step --> Norm["全批次标准化: A_t = (A_t - mean) / (std + 1e-8)"]
    Norm --> Out["输出高质量优势信号注入策略损失更新"]

图 4-2:GAE 逆序递归高效计算与批量标准化流水线

利用几何级数的可递归性,无需展开无限求和,只需自轨迹终点向起点单遍扫描: ÂtGAE=δtV+γλ(1−donet)Ât+1GAE \hat{A}_t^{\text{GAE}} = \delta_t^V + \gamma \lambda (1 - \text{done}_t) \hat{A}_{t+1}^{\text{GAE}} - 当 λ=0\lambda = 0 时:Ât=δtV\hat{A}_t = \delta_t^V,退化为纯单步 TD 优势估计(方差最小,完全依赖 Critic); - 当 λ=1\lambda = 1 时:若轨迹自然完结,中间 V(st+l)V(s_{t+l}) 项发生望远镜级数抵消(Telescoping Sum): ∑l=0T−t−1γl[rt+l+γV(st+l+1)−V(st+l)]=∑l=0T−t−1γlrt+l−V(st)=Gt−V(st) \sum_{l=0}^{T-t-1} \gamma^l [r_{t+l} + \gamma V(s_{t+l+1}) - V(s_{t+l})] = \sum_{l=0}^{T-t-1} \gamma^l r_{t+l} - V(s_t) = G_t - V(s_t) 退化为标准的 REINFORCE 蒙特卡洛经验优势估计。

  1. 批量归一化(Batch Advantage Normalization): 如图 4-2 所示,在将 GAE 优势输入策略损失前,工程上通常在整个 mini-batch 上计算均值 μA\mu_A 与标准差 σA\sigma_A,并执行归一化: Ãt=At−μAσA+10−8 \tilde{A}_t = \frac{A_t - \mu_A}{\sigma_A + 10^{-8}} 这保证了一半动作具有正优势、一半具有负优势,且梯度尺度在不同训练阶段恒定,极大稳定了网络优化。

3. 正确性条件与常见误区

  • 终止掩码双通道阻断(Bootstrap Mask vs Carry Mask): 在反向递归式中,not_done = 1.0 - float(dones[t]) 必须同时施加在两处物理关键点:

    1. 自举阻断通道:δt=rt+γ⋅not_donet⋅V(st+1)−V(st)\delta_t = r_t + \gamma \cdot \text{not\_done}_t \cdot V(s_{t+1}) - V(s_t)。防止物理终局状态继承虚假的未来价值;
    2. 累积传递通道(Carry Mask):carry=δt+γλ⋅not_donet⋅carry\text{carry} = \delta_t + \gamma \lambda \cdot \text{not\_done}_t \cdot \text{carry}。在密集打包(Packed Sequences)的多轨迹样本中,如果遗漏了累积掩码,下一个 Episode 的优势值将会沿着递归链直接逆向倒灌进上一个已经完结的 Episode 末尾,造成致命的跨轨迹数据污染。
  • 截断(Truncation)与终止(Termination)的掩码解耦: 若因超时或步数截断结束,必须保留末状态价值自举(V(struncated)V(s_{\text{truncated}}) 乘入 δT\delta_T),但反向扫描到截断边界时,后续累积项必须归零(carry=0\text{carry} = 0)。将二者混淆会导致截断状态附近的优势严重畸变。

  • 长度对齐不变量: 给定长度为 TT 的奖励序列 rewards,values 数组的长度必须为 T+1T + 1(包含末状态价值 V(sT)V(s_T))。若直接用长度为 TT 的 values 错位计算,会导致最后一步无法正确自举,甚至触发数组越界。

4. 性能与工程取舍

  • λ\lambda 的环境依赖敏感度:
    • 在环境转移动力学随机性极高(如风向扰动、复杂博弈)且轨迹极长时,选择较小的 λ\lambda(如 0.90)有助于隔绝后续大量不可控的随机噪声,保持训练稳定;
    • 在物理模拟确定性极高或奖励高度稀疏的推理场景(如数学证明、围棋)中,Critic 在训练初期预测极不准确,选择较大的 λ\lambda(如 0.98 或 1.0)能够更多依赖真实终端判题反馈,避免被错误的 Critic 引导带偏。
  • 内存局部性与矢量化扫描: GAE 逆序扫描在 Python 纯循环中存在一定的解释器开销。在工业实现中(如 CleanRL / Ray RLlib),通常利用 PyTorch 的 C++ 底层或 Triton/CUDA 自定义算子执行反向融合扫描(Fused Backward Scan),将张量反向遍历时间压缩至微秒级。

具体演示:两步轨迹的 GAE 逆序手工推导

设环境折现因子 γ=0.9\gamma = 0.9,衰减参数 λ=0.95\lambda = 0.95。有一条两步轨迹:

  • 奖励序列:rewards = [1.0, 1.0]
  • 价值序列:values = [0.5, 0.6, 0.0](第 2 步为物理终止状态,真实后继价值为 0)
  • 终止标志:dones = [False, True]

手工推导步骤:

  1. 时刻 t=1t=1(倒数第一步):
    • 终止掩码:not_done1=1.0−1.0=0.0\text{not\_done}_1 = 1.0 - 1.0 = 0.0;
    • 单步残差:δ1=r1+γ⋅not_done1⋅V2−V1=1.0+0.9×0.0×0.0−0.6=0.4\delta_1 = r_1 + \gamma \cdot \text{not\_done}_1 \cdot V_2 - V_1 = 1.0 + 0.9 \times 0.0 \times 0.0 - 0.6 = 0.4;
    • 累加优势:A1=δ1+γλ⋅not_done1⋅carry=0.4+0=0.4A_1 = \delta_1 + \gamma \lambda \cdot \text{not\_done}_1 \cdot \text{carry} = 0.4 + 0 = 0.4。
  2. 时刻 t=0t=0(倒数第二步):
    • 终止掩码:not_done0=1.0−0.0=1.0\text{not\_done}_0 = 1.0 - 0.0 = 1.0;
    • 单步残差:δ0=r0+γ⋅not_done0⋅V1−V0=1.0+0.9×1.0×0.6−0.5=1.04\delta_0 = r_0 + \gamma \cdot \text{not\_done}_0 \cdot V_1 - V_0 = 1.0 + 0.9 \times 1.0 \times 0.6 - 0.5 = 1.04;
    • 累加优势:A0=δ0+γλ⋅not_done0⋅A1=1.04+(0.9×0.95)×1.0×0.4=1.04+0.342=1.382A_0 = \delta_0 + \gamma \lambda \cdot \text{not\_done}_0 \cdot A_1 = 1.04 + (0.9 \times 0.95) \times 1.0 \times 0.4 = 1.04 + 0.342 = 1.382。

最终输出优势序列为 [1.382,0.4][1.382, 0.4],与代码计算结果完全一致。第二步的残差通过 γλ\gamma \lambda 衰减通道平滑传递回了第一步。

实践任务:唯一代码填空题

补齐 GAE 中两个 mask 位置。

规则:只能修改 TODO/______ 所在位置;不要删除断言或放宽误差。代码注释说明了每个边界条件。

Code
def gae(rewards, values, dones, gamma, lam):
    assert len(values) == len(rewards) + 1
    assert len(dones) == len(rewards)
    adv = [0.0] * len(rewards)
    carry = 0.0
    for t in range(len(rewards) - 1, -1, -1):
        not_done = 1.0 - float(dones[t])
        delta = rewards[t] + gamma * ______ * values[t + 1] - values[t]
        carry = delta + gamma * lam * ______ * carry
        adv[t] = carry
    return adv

got = gae([1., 1.], [0.5, 0.6, 0.0], [False, True], .9, .95)
assert all(abs(a-b) < 1e-9 for a,b in zip(got, [1.382, 0.4]))

# 真正终止不读末状态价值;采样窗口结束仍保留 bootstrap。
assert gae([1.], [0., 5.], [True], .9, .95) == [1.]
assert gae([1.], [0., 5.], [False], .9, .95) == [5.5]
# 两个独立的单步 episode,后一个分数不可泄漏到前一个。
assert gae([1., 100.], [0., 0., 0.], [True, True], 1., 1.) == [1., 100.]
assert gae([0., 1.], [0., 0., 0.], [False, True], 1., 1.) == [1., 1.]
assert gae([], [0.], [], .9, .95) == []

检查方法

运行断言,并解释最后一步为何不读取 values[2] 的数值贡献。

提交时请给出:补齐后的代码、实际运行输出(环境不可用时注明“仅静态审查”)以及对失败用例的解释。

Q1

不要背定义:请从输入、状态变化和输出三个阶段解释“GAE 与优势估计”的工作机制。

你的答案:

Q2

只在 δ 上乘 done mask、递推 carry 不乘,会跨 episode 泄漏什么?

你的答案:

Q3

LLM token 级奖励只有末尾一个分数时,GAE 的信用会如何向前传播?

你的答案:

评分与通过规则

  • 代码 4 分:正常输入 2 分,边界输入 1 分,解释实现 1 分;
  • Q1~Q3 各 2 分;
  • 一票否决:结果碰巧正确但核心因果链错误、删除边界检查、把未运行结果说成实测。

需要提示时按四级机制请求:概念区域 → 具体方向 → 关键局部 → 完整答案。

参考答案(仅 answer 分支)

先完成题目再核对。即使代码一致,也要能解释关键步骤,并尝试更换一个输入规模。

Code
def gae(rewards, values, dones, gamma, lam):
    assert len(values) == len(rewards) + 1
    assert len(dones) == len(rewards)
    adv = [0.0] * len(rewards)
    carry = 0.0
    for t in range(len(rewards) - 1, -1, -1):
        not_done = 1.0 - float(dones[t])
        delta = rewards[t] + gamma * not_done * values[t + 1] - values[t]
        carry = delta + gamma * lam * not_done * carry
        adv[t] = carry
    return adv

got = gae([1., 1.], [0.5, 0.6, 0.0], [False, True], .9, .95)
assert all(abs(a-b) < 1e-9 for a,b in zip(got, [1.382, 0.4]))

# 真正终止不读末状态价值;采样窗口结束仍保留 bootstrap。
assert gae([1.], [0., 5.], [True], .9, .95) == [1.]
assert gae([1.], [0., 5.], [False], .9, .95) == [5.5]
# 两个独立的单步 episode,后一个分数不可泄漏到前一个。
assert gae([1., 100.], [0., 0., 0.], [True, True], 1., 1.) == [1., 100.]
assert gae([0., 1.], [0., 0., 0.], [False, True], 1., 1.) == [1., 1.]
assert gae([], [0.], [], .9, .95) == []

Q1 参考答案

  1. 输入阶段(时序转移、基线预测与超参数配置):算法输入沿时间维度对齐的即时奖励序列 r0,…,rT−1r_0, \dots, r_{T-1}、由 Critic 价值网络前向推导出的状态价值序列 V0,…,VTV_0, \dots, V_T(长度为 T+1T+1,末项为终态自举值)、物理终局标志位布尔数组 dones\text{dones}、以及衰减超参数折扣因子 γ∈[0,1]\gamma \in [0, 1] 与 GAE 平滑因子 λ∈[0,1]\lambda \in [0, 1]。

  2. 状态变化阶段(残差展开与指数加权逆向折叠):

    • 单步残差解构(TD Residual):计算每步局部的预测落差 δt=rt+γ(1−dt)Vt+1−Vt\delta_t = r_t + \gamma (1 - d_t) V_{t+1} - V_t,衡量该步转移超出 Critic 预期的即时意外增量;
    • 逆向指数级联累加(Backward Recursion):按照图 4-2 拓扑,维护累加标量 carry\text{carry},自轨迹终点 T−1T-1 逆序扫描回起点 0:At=δt+γλ(1−dt)At+1A_t = \delta_t + \gamma \lambda (1 - d_t) A_{t+1}。数学上该式等价于对所有多步优势估计实施几何指数衰减求和 ∑l=0∞(γλ)lδt+l\sum_{l=0}^\infty (\gamma \lambda)^l \delta_{t+l}。
  3. 输出阶段(基线校准与方差-偏差自适应输出):输出整条轨迹的高精度优势估计张量 [A0,…,AT−1][A_0, \dots, A_{T-1}] 及对齐的价值回归目标 ytvalue=At+Vty_t^{\text{value}} = A_t + V_t。若经过批量标准化,该输出为 Actor 策略梯度反传提供了方差最低且偏差受控的最佳驱动信号,平稳连接了 TD 局部快速更新与 MC 全局真实反馈。

Q2 参考答案

若仅在单步残差 δt\delta_t 上乘以掩码、而在递推更新 carry 时漏掉了 not_done 掩码(即写成 carry = delta + gamma * lam * carry),会引发跨 Episode 优势逆向串扰泄漏(Cross-Episode Advantage Leakage):

  1. 递归通道的幽灵传递:虽然在终局步 donet=True\text{done}_t = \text{True} 时,δt=rt+γ×0×Vt+1−Vt\delta_t = r_t + \gamma \times 0 \times V_{t+1} - V_t 成功阻断了对下一状态价值的自举;但是,下一条紧邻 Episode(t+1t+1 步以后)所累积的未来所有优势残差已经暂存在 carry 变量中!

  2. 逆向因果律崩塌:若不乘 not_done,下一条 Episode 的巨大正优势或惩罚负优势,会直接乘以 γλ\gamma \lambda 被无条件叠加进当前刚刚死亡/通关的 Episode 倒数各步中。

  3. 破坏性后果:在多进程环境打包拼接(Packed Batch)训练中,上一条轨迹末尾的决策会被完全无关的下一条轨迹的表现所赏罚(例如上一局玩得极好但刚结束,下一局出生立刻暴毙,暴毙的负优势通过 carry 反向传导污染上一局通关末端),导致策略梯度产生荒谬的因果错乱和剧烈振荡。

Q3 参考答案

在 LLM 强化学习(如 RLHF / 过程或结果奖励推理)中,当只有回答序列最后一个有效 Token 获得标量判题结果奖励 RR(中间各 Token 即时奖励全为 0)时,GAE 的信用分配机制如下:

  1. 末端残差吸收全局反馈:在回答结束的最后一个 Token T−1T-1 处,即时奖励为 RR,其残差为 δT−1=R+0−VT−1=R−VT−1\delta_{T-1} = R + 0 - V_{T-1} = R - V_{T-1}。该值直接反映了生成结果与 Critic 模型对该回答最终质量的预估差值;

  2. 指数衰减与中间步 Critic 预期差的叠加:在向左逆序回溯过程中,中间任一 Token tt(rt=0r_t = 0)的残差为 δt=γVt+1−Vt\delta_t = \gamma V_{t+1} - V_t。通过递推展开,第 tt 步的 GAE 优势为: At=δt+γλδt+1+…+(γλ)T−1−tδT−1 A_t = \delta_t + \gamma \lambda \delta_{t+1} + \dots + (\gamma \lambda)^{T-1-t} \delta_{T-1} 展开后可见:终局的超额惊喜 (R−VT−1)(R - V_{T-1}) 以 (γλ)T−1−t(\gamma \lambda)^{T-1-t} 的几何速率衰减反传给前面的 Token;与此同时,中间每一个 Token 若引起了 Critic 预期价值的剧烈跃迁(即 γVt+1−Vt≫0\gamma V_{t+1} - V_t \gg 0,例如写出了关键解题突破步骤 Token),该局部跃迁会作为额外的非零正残差叠加进该位置的优势中;

  3. 消除统一赋值弊端:这完全不同于简单地将终局标量奖励 RR 粗暴广播复制给所有 Token。GAE 使得越靠近关键决策点的 Token、以及显著推高了后续成功概率的“转折点 Token”,获得越大的正信用,实现了高分辨率的 Token 级信用分配。

参考资料

资料用于建立事实基线;面试回答仍需用自己的语言组织。