时序差分:不用等到游戏结束
Sutton 说时序差分是「强化学习里最核心、最新颖的一个想法」。它拆掉了上一章那个最硬的限制,办法却像在作弊:右边那个未来的价值我也不知道?那就用我现在的猜测顶上。
那个念头
蒙特卡洛的更新式是这样的:
V(s) ← V(s) + α [ G - V(s) ]
↑
这一局实际拿到的总分(要等到局末才知道)
那个 G 是唯一的障碍。有没有办法不等它?
回想贝尔曼方程说的那件事:G 可以拆成「这一步」加上「剩下的」:
G = r + γ G t t+1 t+1
而「剩下的」,我们手上正好有一个现成的估计——V(s')。
于是:
V(s) ← V(s) + α [ r + γV(s') - V(s) ]
└────┬────┘
TD 目标:走一步就能算出来
用一个估计去更新另一个估计。
那个 V(s') 不是真值——它就是我们正在学的那张表里的一个数,可能错得离谱。但我们照样拿它当「未来」的替身。
这听起来像用自己的鞋带把自己拎起来(bootstrap 这个词的字面意思正是如此)。它凭什么行得通?
因为终止状态是准的。走到终点那一步,V(s') 确定是 0,那一步的 TD 目标就是真值。于是终点旁边那一格被学准了,然后是它的邻居……准确性从锚点往外爬,和第 7 章那个水波是同一件事。
方括号里那个东西叫 TD 误差(δ):「我原以为这儿值 V(s),走了一步之后发现好像该是 r + γV(s'),差了这么多」。整门学科后半程几乎所有算法,核心都是这个 δ。
看它跑
下面把 MC 和 TD 放在同一个世界、同一个种子上跑,从 10 局到 5000 局。看谁前期准,谁后期准。
那个交叉点,是偏差和方差在换手
结果很清楚:
- 10 局的时候:MC 误差 0.0568,TD 误差 0.6802。TD 差了一个数量级。
- 1000 局的时候:MC 0.0178,TD 0.0053。TD 反超了三倍。
两段的原因完全不同:
前期 TD 惨,是因为偏差
开局那张 V 表全是 0。TD 用 r + γV(s') 当目标,而 V(s') 是 0——它在拿一个完全错误的数当「未来」。所以它一开始估出来的东西整体偏低,得等好几百局才把表「养」起来。
MC 没这个问题。它用的是真实回报,从第一局起就是无偏的。
后期 TD 赢,是因为方差
MC 每一次更新用的 G,是一整局所有随机性的累积——走了三十步,三十次滑动的运气全在里面。噪声大,得靠海量样本平掉。
TD 每次更新只用一步的实际结果,剩下的交给 V 表。而 V 表是几千次经验的平均,已经被平滑过了。所以 TD 的每次更新噪声小得多。
| 蒙特卡洛 | TD(0) | |
|---|---|---|
| 更新时机 | 局末 | 每一步 |
| 能处理不结束的任务 | 不能 | 能 |
| 偏差 | 无偏 | 有偏(自举) |
| 方差 | 大 | 小 |
| 要不要马尔可夫性 | 不要 | 要 |
| 收敛保证(表格) | 有 | 有 |
| 收敛保证(+ 神经网络) | 还有 | 没有(第 16 章) |
看最后两行。自举是一笔交易:拿「无偏」换「低方差 + 能在线学习」。在表格里这笔交易稳赚不赔;一旦换成神经网络,它会变成第 16 章那个把权重炸到 5.68×10⁶ 的东西。
中间地带:n 步与 TD(λ)
既然一端是「走一步就更新」,另一端是「走完整局才更新」,中间显然有一整条连续谱:
TD(0) 目标 = r + γV(s')
1
2 步 TD 目标 = r + γr + γ²V(s'')
1 2
n 步 TD 目标 = r + …… + γⁿV(s⁽ⁿ⁾)
1
MC 目标 = r + …… 一直到局末
1
n 越大,越像 MC(偏差小、方差大);n 越小,越像 TD(偏差大、方差小)。实践中最好的 n 通常在中间,既不是 1 也不是无穷。
TD(λ) 更聪明一点:不选某一个 n,而是把所有 n 的结果按 λ 的幂加权平均。λ=0 退化成 TD(0),λ=1 退化成 MC。
你今天在 PPO 里看到的那个 gae_lambda=0.95,就是这个 λ 的现代版本(叫 GAE,广义优势估计)。它是这条谱线上最常用的那个刻度。
Sutton & Barto 里有个很妙的例子,值得复述:
你每天开车回家,会预测「还要多久到家」。周一你出门时预测 30 分钟;开了 5 分钟上高速,发现路很通畅,于是把预测改成「还要 15 分钟」;结果最后真的 20 分钟就到了。
- 蒙特卡洛的做法:等你到家,才把「出门时那个 30 分钟的预测」往 20 修正。上高速那一刻发生的事,要等到家才被记账。
- TD 的做法:上高速那一刻就修正了——「我原以为还要 25 分钟,现在看只要 15,差了 10 分钟」,立刻把这 10 分钟记到「出门」这个状态头上。
TD 更符合直觉,因为信息在你获得它的那一刻就被用上了,不用等最终结果揭晓。
而且它有个 MC 做不到的能力:如果这一天你到家前突然堵车了,TD 只会怪「堵车」那一段,不会怪「上高速」那个正确的判断。MC 则会把整局的最终结果均摊给沿途每一步——这正是上一章末尾那个「信用分配」问题。
第 2 章提过 Gymnasium 为什么把 done 拆成两个。这里是它真正咬人的地方。
TD 目标是 r + γV(s') · (1 − done)。那个 (1 − done) 的意思是「结束了就没有未来了」。
但如果这一局是被步数上限掐断的(truncated),未来其实还在——只是你不看了。这时候如果你把 truncated 也当成 done,等于在告诉 agent:
「走到第 500 步的时候,世界会消失,价值归零。」
它会当真。你会看到 agent 学出一些莫名其妙的、在回合末尾特别保守(或者特别不要命)的行为。
正确做法:terminated 才把未来清零,truncated 要照常自举。SB3 已经处理好了,但你自己写循环的时候非常容易写错,而且不会报错。
def td_update(V, s, r, s2, terminated, alpha=0.1, gamma=0.99):
target = r + gamma * V[s2] * (not terminated) # ← 注意不是 truncated
V[s] += alpha * (target - V[s]) # ← TD 误差 δ 在这儿
就这两行。而这两行是 Q-learning、SARSA、DQN、以及 Actor-Critic 里 Critic 部分的共同内核。
那个 alpha(学习率)是新面孔,值得说一句:它是「新经验的权重」。α=1 表示完全相信这一次的观测(噪声大的环境里会剧烈震荡),α=0.01 表示几乎不动。表格法里常用 0.1~0.5;深度强化学习里学习率归神经网络的优化器管,通常是 1e-4 到 3e-4 那个量级。
回到那个学走路的小人。用 TD 之后,信用分配变得局部了:
第 213 帧它一个踉跄,价值估计当场从 0.8 掉到 0.3。这个 −0.5 的 TD 误差,直接记在第 212 帧那个动作头上——不需要等这局结束,也不会连累第 47 帧那次漂亮的抬腿。
这就是为什么现代算法几乎全部基于 TD:一局五百步,MC 给你一个数字,TD 给你五百个。
代价是那个偏差。而当 V 不再是一张表、而是一个神经网络的时候,那个偏差会变成一件真的能把训练炸掉的事。第 16 章会给你判例。
这一章的一句话
拿估计去更新估计,就不用等一局结束了。这笔交易在表格里稳赚——直到第 16 章你把表换成神经网络。
下一章:把这个 TD 更新式里加一个 max。加完之后,它就不再只是「评估当前策略」,而是直接学最优策略——而且不需要知道任何规则。那个算法叫 Q-learning,1989 年,它改变了一切。