Actor–Critic:用价值估计缩短信号路径¶
REINFORCE 等到整条轨迹结束,再用 Monte Carlo 回报评价每个动作;它无须学习环境模型,却把大量未来随机性都带进梯度。Actor–Critic 增加一个 critic,用当前状态的价值预测构造低方差 advantage,让 actor 不必只依赖终局回报。
这是一种统计分工,而不是两个模型名称的组合:actor 表示要优化的策略,critic 估计该策略下的回报。policy-gradient 的无偏起点见 Policy Gradient;critic 提供的 advantage 如何进入受控更新,见 Trust Region 与 PPO。
从 Monte Carlo 到 bootstrap¶
对固定策略 \(\pi\),状态价值为
若完整 episode 已结束,可用 Monte Carlo target
它不依赖当前 value 预测,但同一状态后的所有环境与动作随机性都会进入 target。一步 TD 改用
对应 TD residual
其中 \(d_t=1\) 只表示真正终态。TD 用 bootstrap 降低方差,也引入来自 \(V_\phi\) 的近似偏差。
Actor 以
更新:
critic 则最小化 value regression:
两个目标可以共享网络 trunk,但 target 的梯度边界必须清楚:bootstrap target 通常停止梯度,否则 critic 会通过目标分支追逐自身。完整双边界推导见 Advantage 估计与 GAE。
\(n\)-step return 与 GAE¶
一步 TD 信号短但偏差更依赖 critic;Monte Carlo 偏差小但方差高。\(n\)-step return 位于两者之间:
Generalized Advantage Estimation 用 TD residual 的指数加权和:
反向递推形式更适合实现:
其中 \(d_t\) 只控制当前 transition 是否 bootstrap,\(b_t\) 则表示 trace 是否必须在这里停止。普通 transition 有 \(d_t=b_t=0\),真正 terminal 有 \(d_t=b_t=1\);具备真实 final observation 的 truncation 则是 \(d_t=0,b_t=1\)。因此一个 done 不能同时承担两个角色。
- \(\lambda=0\) 接近一步 TD,方差低、critic 偏差影响大;
- \(\lambda=1\) 在有限轨迹中接近 reward-to-go 减 value baseline;
- 中间值在 bias–variance 之间折中,但没有脱离 critic 质量。
常用 value target 为
这里右侧的旧 value 和 advantage 都应视作冻结 target。
Terminal、truncation 与边界价值¶
结束标记至少分三类:
| 状态 | 是否环境终态 | 通常是否 bootstrap |
|---|---|---|
terminated |
是 | 否,边界值为零 |
truncated |
否,只是预算或时间耗尽 | 是,若能估计边界状态 |
infrastructure_error |
未形成有效策略结果 | 不应直接作为普通终止训练 |
若把所有 timeout 都设成 \(d_t=1\),critic 会把“尚未完成但仍有希望”的尾部状态估成零;长任务越常被预算截断,偏差越强。反过来,在真正失败终态上继续 bootstrap 也会虚构未来价值。
语言模型中的 critic 放在哪里¶
语言策略可以在多种粒度上定义 value:
- response-level:只在 prompt 末端预测整条回答的回报;
- token-level:每个生成前缀都有一个 value;
- turn-level:每条 assistant message 或工具 action 结束时预测;
- environment-state level:工具执行后,根据新 observation 预测。
token-level critic 易与 causal LM hidden state 对齐,却不意味着每个 token 都是独立环境决策。若 reward 只在工具执行后出现,把同一 transition 任意摊给工具名、JSON 参数和解释文本会改变信用分配。更完整的粒度选择见信用分配。
对包含 observation 的轨迹,critic 可以读取 observation,因为它估计条件状态价值;actor loss 仍只能覆盖 policy action。两套 mask 因此可能不同:
attention mask: 可作为上下文读取的 token
action mask: policy 实际选择的 token
value mask: 需要训练或评估 value 的位置
bootstrap mask: 终态边界是否保留下一状态价值
把四者压成一个 attention_mask 是常见但危险的捷径。
一个最小 GAE 实现¶
import torch
@torch.no_grad()
def generalized_advantage(reward, value, bootstrap_mask, trace_mask, gamma=.99, lam=.95):
if (reward.ndim != 2 or value.shape != (*reward.shape[:-1], reward.shape[-1] + 1)
or bootstrap_mask.shape != reward.shape or trace_mask.shape != reward.shape):
raise ValueError("reward, masks and bootstrap value must align")
if bootstrap_mask.dtype != torch.bool or trace_mask.dtype != torch.bool:
raise ValueError("bootstrap and trace masks must be boolean")
if torch.any(trace_mask & ~bootstrap_mask):
raise ValueError("trace continuation requires a valid bootstrap transition")
adv = torch.zeros_like(reward)
carry = torch.zeros_like(reward[:, 0])
for t in range(reward.shape[1] - 1, -1, -1):
boot, trace = bootstrap_mask[:, t], trace_mask[:, t]
next_value = torch.where(boot, value[:, t + 1], 0.)
delta = reward[:, t] + gamma * next_value - value[:, t]
carry = delta + gamma * lam * torch.where(trace, carry, 0.)
adv[:, t] = carry
target = adv + value[:, :-1]
return adv, target
r = torch.tensor([[1.0, 2.0]])
v = torch.tensor([[0.3, 0.5, float("nan")]], requires_grad=True)
bootstrap = torch.tensor([[True, False]])
trace = torch.tensor([[True, False]])
a, target = generalized_advantage(
r, v, bootstrap, trace, gamma=1.0, lam=1.0
)
assert torch.allclose(a, torch.tensor([[2.7, 1.5]]))
assert torch.allclose(target, torch.tensor([[3.0, 2.0]]))
assert torch.isfinite(a).all() and not a.requires_grad and not target.requires_grad
try: generalized_advantage(r, v, bootstrap, torch.tensor([[True, True]]))
except ValueError: pass
else: raise AssertionError("terminal transitions cannot continue the trace")
正常 transition 的两个 mask 都为真,真实 terminal 都为假;有真实 final observation 的 truncation 则 bootstrap=True, trace=False。这个实现假设 batch 中每条轨迹已经按时间对齐。padding 位置必须在外层用有效步 mask 排除,不能仅靠把 reward 置零;否则 padding 上的 value、loss 分母和递推仍可能污染结果。完整推导与边界测试见 Advantage 估计与 GAE。
packed trajectory、bootstrap 与 valid-step mask 的组合实现见手撕:LLM 策略优化 · GAE。
Critic 的训练节奏¶
critic 面对的目标分布随 actor 变化。常见稳定手段包括:
- 在 actor 更新前用同批或更广轨迹预热 critic;
- 让 critic 每轮比 actor 多做若干受控更新;
- 限制 actor KL,使 value target 不至于瞬间漂移;
- 按任务难度、轨迹长度和终止类型检查 explained variance;
- 对旧 policy 的数据记录 staleness,而非混进同一回归集;
- 在共享 trunk 时分别监控 actor 与 critic 梯度范数。
训练得更久不一定更好。critic 对一批 Monte Carlo return 过拟合,会在同批轨迹上给出漂亮 loss,却对更新后的 actor 和新状态产生系统偏差。长时异步场景中的 critic、policy lag 和 trajectory freshness 见训练系统。
实现契约¶
可审计的 actor–critic batch 至少包含:
ordered state/action transitions
reward components before weighting
terminated and truncated separately
behavior policy revision and action log-probability
value revision used to build targets
gamma, lambda, horizon and bootstrap convention
attention, action, value and valid-step masks
advantage normalization scope
actor/critic update counts and optimizer revisions
最小测试应覆盖:
- 一步终态的 target 等于即时奖励;
- truncation 保留给定的边界 value;
- padding 不进入递推、value loss 或分母;
- 给所有 advantage 加零均值 baseline 不改变符号预期;
- critic target 分支没有梯度;
- 保存再恢复后,value revision 与 rollout revision 仍可辨认。
失败边界¶
- critic 被当成真值:它只是当前策略分布上的近似,分布外状态可能任意错误。
- 终态和截断合并:bootstrap 语义错误。
- actor loss 回传进 advantage:策略可通过修改 critic 来“改善”自身目标。
- value target 未停止梯度:网络同时移动预测与靶点。
- 只看 value MSE:回报尺度大时 MSE 难解释;还需 explained variance、分层校准和策略结果。
- advantage 在全局随意 whitening:跨任务难度与长度的相对权重被改变。
- 共享 trunk 互相拖拽:critic 梯度可能破坏语言表示,actor 梯度也可能让 value 退化。
- 旧轨迹无限复用:critic 和 actor 都离开声明的 on-policy 分布;校正见 Off-policy 校正。
历史位置¶
早期 actor–critic 把 policy-gradient actor 与 TD critic 组合起来;A3C 展示了并行 actor 产生多样经验、异步更新共享模型的深度 RL 实现;GAE 则把多步 TD residual 组织成可调的 advantage estimator。现代语言模型 RL 的模型更大、动作更长、rollout 更昂贵,但核心矛盾没有改变:critic 用偏差换方差,actor 的更新速度又决定 critic 的目标漂移速度。