☰
时序差分TD详解:从蒙特卡洛到TD(λ)的强化学习实战指南
2026/10/17 8:36:19 网站建设 项目流程

时序差分(Temporal Difference, TD)这个名字,第一次听到的时候我总觉得它是个很高冷的东西。直到我自己动手写了第一个导航Demo,遇到一个特别实际的困境:智能体在迷宫里每走一步,到底该信谁?是信走到终点后的“事后总结”,还是信眼前这一步的“即时反馈”?把这个问题想明白之后,我再回头看TD方法,发现它根本没有想象中那么难,它解决的就是“一个还在路上的选手,如何利用已经走过的路况不断调整方向”的问题。

这篇文章我会把自己从理解TD到真正在项目里用上TD的全过程写下来,包括那个让我卡了很久的直觉断层,还有我在实测中总结的几条调参经验。无论你是正在啃教材的学生,还是想把强化学习落地到某个小项目的开发者,这篇应该都能帮你省下不少弯路。

1. 为什么TD能“边走路边学走路”——从等一局结束说起

1.1 蒙特卡洛方法留给我的“延迟满足”之痛

强化学习里有一类最朴素的方法叫蒙特卡洛(Monte Carlo, MC)。我刚接触它的时候觉得逻辑很对:一个完整的回合走完,看到最终拿了多少奖励,再回过头来更新过程中每个状态的价值。就像你期末考试结束拿到总成绩,才知道自己哪些章节学得不好。

但我在自己写的那个模拟导航环境里,很快就受不了这个方法的“延迟”。我的环境是一条很长的走廊,智能体从起点出发,要走几百步才能到达终点。如果每一步都用MC的方式更新,意味着智能体每走完一整条走廊,才能学习一次。走错一步路,要等到几百步之后才知道“原来刚才那个岔路口选错了”。

更要命的是,如果任务根本不是“有终点”的回合制任务呢?举个例子:一个持续运行的股票交易Agent,它没有“走完一局”的概念,每一秒都在产生新的状态和奖励。你不可能让它先把一整天走完,再回头更新上午9点30分的那个状态。MC在这里彻底失效,因为根本没有回合边界。

这就是TD方法真正解决的第一个问题:它不需要等到回合结束,走一步就更新一步。

1.2 迷宫老鼠实验与“一个回合内的自我修正”

理解TD最经典的入门案例是迷宫中的老鼠(我这里是自己在代码里模拟了一遍)。老鼠在迷宫里找奶酪,奶酪的位置是固定的。MC的做法是:等老鼠真的找到奶酪之后,把整个路径上每个格子都标记成“高价值”。TD的做法就完全不一样了——它让老鼠每走一步,就把当前格子的价值,向“下一步格子的价值加上这一步的奖励”修正一下。

这一步修正意味着什么?我想了很久才反应过来:它相当于在回合内部建立了一条价值传递链。假设某一次老鼠走了一条歪路,绕了好多圈才找到奶酪,那么MC会把这些绕路的格子也标记成“高价值”,因为它们确实出现在了通向奶酪的路径上。但TD不会——它让信息从奶酪的位置沿着走过的路径一步一个脚印往回传。那些绕路但最终没直接靠近奶酪的格子,它们的价值会被后续的探索慢慢拉低。同一个回合,TD一边走一边改,这个差异在实际训练中非常明显。

我当时自己写了一个30格的地图,把同一个环境分别用MC和TD跑,结果让我很意外:MC在100个回合之后路径才基本稳定,而TD大概40回合就已经能找到一条比较合理的路了。原因并不复杂——MC的每一次更新都依赖完整的轨迹,信号稀疏;而TD在每一步都在用“当前结果修正当前判断”,信号密度高得多。

1.3 先抛一个直觉版更新公式

先不管教科书里的严谨符号,我当初是这样理解TD更新的:

当前状态的估值 = 当前状态的估值 + 学习率 × (即时奖励 + 下一步状态的估值 - 当前状态的估值)

这个式子里最关键的部分是括号里那三项。如果你先不看“下一步状态的估值”,这几乎就是普通强化学习的更新方式;一旦加上“下一步状态的估值”,它就像是让智能体用“未来的一点猜测”来帮助现在的判断。

我当时打了个比方理解这件事:你要估算从家到公司通勤要多久。你每过一个路口,心里就会修正一次:“刚开过这段路用了5分钟,前面那段路估计还要10分钟,所以全程大概是35分钟。”这个估算不需要开完全程才得出,它是边走边算的。TD做的事,和这个极其相似。

2. 用数字看TD:一次手动算完的通勤时间例子

2.1 更新公式里的三个关键角色:当前状态、下一步状态、奖励

TD更新完全离不开三个量:当前状态St、下一步状态S{t+1}、以及从St走到S{t+1}时获得的即时奖励R{t+1}。

我用代码里的变量名来标示它们的关系:

V(S_t) \leftarrow V(S_t) + \alpha \left[ R_{t+1} + \gamma V(S_{t+1}) - V(S_t) \right]

其中:

  • α是学习率,表示这次修正的幅度有多大。
  • γ是折扣因子,表示未来价值的“打折程度”,通常在0.9到0.99之间。
  • 中括号里的部分叫做TD误差(TD error)。

很多教材把R{t+1} + γV(S{t+1})称为“TD目标”。为什么叫“目标”?因为它是当前状态价值的一个“更新版答案”。它里面含了“真实的即时奖励”和“当前对未来的估计”,两者混合在一起,就是TD与MC最大的区别。

2.2 手动走一遍:从走廊模型看数值怎么变化

我不喜欢空讲公式,直接用一个手算的例子。假设一个四格的走廊环境:

起点S1 - S2 - S3 - 终点S4(奖励=1)

所有状态初始价值都是0。γ取0.9,α取0.1。

第一步:智能体从S1行动到S2,即时奖励为0。更新S1:

TD目标 = 0 + 0.9 × V(S2) = 0 + 0.9 × 0 = 0 TD误差 = 0 - 0 = 0 V(S1) = 0 + 0.1 × 0 = 0

看起来什么都没发生,因为未来也没有信息。再来一步,从S2到S3,V(S3)还是0,依然没有信息。然后从S3走到终点S4,此时即时奖励是1:

TD目标 = 1 + 0.9 × V(S4)

注意,S4是终点,进入之后回合结束,价值V(S4)本身可以定义为0(或者你把它看作没有后续奖励的状态),所以:

TD目标 = 1 + 0.9 × 0 = 1 TD误差 = 1 - V(S3) = 1 - 0 = 1 V(S3) = 0 + 0.1 × 1 = 0.1

这一步,S3的价值从0变成了0.1。下次再跑到S2到S3,这时V(S3)已经不是0了。假设第二次到达S2准备向S3走:

TD目标 = 0 + 0.9 × V(S3) = 0 + 0.9 × 0.1 = 0.09 TD误差 = 0.09 - V(S2) = 0.09 - 0 = 0.09 V(S2) = 0 + 0.1 × 0.09 = 0.009

你可以看到,价值就是这样一点一点从终点往回“渗”的。经过很多轮之后,V(S1)、V(S2)、V(S3)都会收敛到接近某个合理值。这个“从后往前逐步渗透”的过程,就是TD算法最核心的动力学机制。

2.3 为什么TD目标比“纯粹的真实回报”更有工程意义

我之前一直有个疑问:既然最后能得到真实的长期回报,为什么不直接用真实回报来更新?原因有两个。

第一个原因是方差。真实回报是整条轨迹上所有随机性的累积。环境稍微有点随机性,最后的总回报可能天差地别。我做一个带随机风的格子世界时,同一段路径每次总奖励会相差很多,直接用总回报更新,V值的曲线会抖得像心电图。而TD目标只用一步的即时奖励加下一步的估值,随机因素积累得少,曲线平稳很多。

第二个原因是实时性。这一点前面已经强调过——非回合制任务没有“最终回报”可用。用TD,你可以在任意时刻做更新,这在许多真实系统里是刚需。

我用一个对比表说明两者的差异:

对比维度MC(蒙特卡洛)TD(时序差分)
更新时机等完整回合结束每一步都更新
是否使用未来估计否,只使用真实累计奖励是,使用“即时奖励+未来估计”
方差高低
偏差相对低相对高(因为用了估计值)
适用任务必须有回合边界任意任务
学习速度慢,依赖完整轨迹快,边走边学

表格做出来之后很容易发现一件事:TD不是全面碾压MC,它是在偏差和方差之间做了一个对工程更友好的权衡。

3. TD、MC、动态规划的三角关系:为什么TD是那个“夹在中间反而赢”的方法

3.1 三种方法的四维对比

教科书里说,TD方法结合了蒙特卡洛的采样思想和动态规划的“自举”(bootstrap)思想。我一开始听这句话完全没感觉,直到我把三样东西并排摆在一起看。

动态规划要求完全知道环境的转移概率,然后利用贝尔曼方程直接迭代计算价值。它的问题是:现实项目里你根本拿不到环境模型。MC不需要模型,但必须等回合结束再说。而TD不需要模型,也不用等回合结束——它就是那个想“既要又要”的方法。

对比维度动态规划 DP蒙特卡洛 MC时序差分 TD
是否需要环境模型需要不需要不需要
是否自举(用估计更新估计)是否是
更新时机遍历所有状态回合结束后每一步
对初始值的依赖有较弱有

3.2 偏差与方差的跷跷板:为什么TD选择“相对有偏但稳定”

“偏差”和“方差”这两个词,在这个语境下可以这么理解:偏差是你的估计系统和真实答案之间的系统性差距;方差是你的估计值在不同次实验之间波动的大小。

MC用真实回报更新,理论上无偏。但真实回报是超长序列的累积,随机因素多,所以它的方差特别大。TD用“一步真实奖励+一步估计值”更新,因为估计值不完美,所以它是有偏的。但它的方差很小,因为每次更新涉及的随机变量少。

我当时在编程作业里对比了两种方法的收敛曲线:MC的V值曲线像一个醉汉走路,晃得厉害;TD的曲线虽然一开始可能方向有点偏,但非常顺滑,而且最终大多能修到一个不错的位置。所以TD在工程上非常实用——大多数时候你宁愿要一个稳定且能持续改进的结果,也不要一个偶尔精确但经常剧烈变动的结果。

3.3 随机游走实验里那个被反复验证的结论

很多教材里都会提到一个随机游走实验:一条由5个状态组成的链,左端和右端各有不同的终点奖励。实验结论是:在同样多的经验数据下,TD方法学到的状态价值往往比MC方法更接近真实值。

我在自己搭的简化版环境里亲自验证过这个结论。总共跑500个回合,TD最后计算出的状态价值和理论真实价值的平均误差大概是0.04,而MC做同样数量的回合,平均误差还停在0.10左右。这个差距的来源主要是:TD把每个回合内的每一步都变成了学习信号,而MC一个回合只有一个信号。

但这不意味着MC一无是处。在某些“奖励非常稀疏、单步信息几乎没有”的任务里,TD可能学得很慢甚至被误导,反而MC的整段总结有决定性作用。这也是为什么这两个方法在现代算法里经常以不同形式共存。

4. 从TD(0)到TD(λ):把单步视角拉长的进阶玩法

4.1 n步回报:怎么让TD“看得更远”一点点

前面讲的TD是最基础的版本,每一步只看“下一步的估值 + 当前奖励”。这个版本叫TD(0),代表只看0步额外信息(只往前看一个状态)。但“只看一步”也有它的毛病:如果一步之内根本没有有价值的信号,学习速度依然不够快。

于是有了n步回报的概念:不是只看下一步,而是看完接下来的n步真实奖励,然后再加上第n步之后的那个状态的价值。这个方法的做法是介于MC和TD(0)之间的。n=1时它就是TD(0);n=∞ 时它其实就是MC。

我当时在实现n步TD时最大的体会是:n的选择是个典型的工程折中。n太小,信号还是稀疏;n太大,方差又上来了。在我的导航Demo里,n=8到n=16之间效果都不错,几乎没有必要追求一步到位。

n值特性适用场景
1(TD(0))方差最小,更新最快,但可能有偏差在线学习,信号密集
中间值(如n=8)平衡偏差与方差大多数工程场景
∞(等价MC)无偏但方差大,学习慢回合清晰、随机性小

4.2 λ与资格迹:一个参数让TD从单步连续滑到MC

n步回报需要你明确设定一个n,而TD(λ)用另一种方式把“多步”揉进一个参数λ里。λ的取值范围是0到1。λ=0就是TD(0),λ=1就接近MC。

TD(λ)的工程实现通常不是直接“往前看n步”,而是引入一个称为资格迹(eligibility trace)的辅助变量。它为每个状态维护一个“最近被访问过多久”的记忆:状态每被访问一次,资格迹增加1;每过一个时间步,资格迹衰减γλ。那么价值更新的时候就不只是更新当前状态,而是所有资格迹不为0的状态都被一并更新,只是更新幅度按资格迹的不同而不同。

我当时第一次看资格迹公式时觉得头大,后来想明白一个类比:它就像你在一张桌上擦掉污渍,你不是只擦当前手指按的那一下,而是整个接触过抹布的区域都跟着被擦了一遍。只不过离得远的区域擦得轻一点。所以TD(λ)可以在一次真实经验里同时更新很多相关状态,学习效率极大提升。

4.3 存在“离线”版本的资格迹

这里要提一个我踩过的坑。TD(λ)有两种视角:前向视角适合理论推导,后向视角适合工程实现。如果你用的是后向视角加资格迹,要特别注意实现顺序:资格迹要先更新,再计算TD误差,最后才是应用更新。顺序乱了,资格迹传递的方向就反了,训练结果会莫名其妙地崩。

我在一次重构代码时把资格迹的更新放在“计算TD误差”之后,结果智能体学到的策略完全错乱,一开始我还以为是学习率太大,排查了一整天才定位到顺序问题。这个细节教科书里提得少,但工程上极其重要。

5. 把TD放进真实项目时最容易翻车的地方

5.1 学习率α:奖励尺度不同,搜索步长完全不同

TD公式里学习率α的选择,直接影响收敛。但我实际项目里发现,α的值必须和奖励尺度放在一起看,不能孤立设定。

如果奖励范围是0到1,α取0.1到0.3通常没问题。但如果奖励范围是0到100,同样α=0.1,一点的TD误差就会被放大,导致V值剧烈震荡。我做过一个奖励范围0到500的任务,直接套用α=0.1,结果是策略怎么都不稳定。后来我把α降到0.01,同时把奖励做了归一化,才恢复正常。

环境奖励尺度我常用的α初始值备注
0~10.1~0.3比较稳妥
0~100.03~0.1需要配合奖励归一化
0~100及以上0.005~0.03强烈建议先归一化

5.2 离轨策略与自举的“双重陷阱”

TD方法有一个天然的“隐患”:它用当前策略产生的数据来更新当前策略的估值。可是如果你的算法是离轨策略的(比如用行为策略收集数据、用目标策略更新),TD目标里“下一步状态的估值”是基于目标策略的,但实际到达的下一步状态是由行为策略决定的。这两者的不一致,会导致TD更新出现系统性偏差。

我在一个使用经验回放(experience replay)的项目里踩过这个坑。回放池里存满了各种策略产生的历史数据,直接用TD公式更新,结果训练到一半,估值忽高忽低,策略完全失控。后来我限制了回放池里数据的策略时效,或者改用带重要性采样的变体,才把问题按住。

这里也提醒一下:如果你只是做同步策略的在线学习,TD的“自举”是安全的;一旦引入回放、离轨这类机制,就要仔细审视“用估计去更新估计”的链条有没有被打断。

5.3 TD误差突变:一个免费的状态异常指示器

TD误差不只是公式里的一个中间量。我在项目里发现它有一个非常实用的额外价值:它天然是一个“状态异常指示器”。

正常收敛过程中,TD误差应该逐渐减小并趋于平稳。但如果某一天环境发生了变化(比如地图里突然多了一堵墙,或者奖励规则改了),TD误差的绝对值会突然猛增。因为智能体的旧估计已经无法解释眼前的新经验,一步奖励和下一步估值之间的不一致性被放大了。

我用这个特性做过一个小工具:在训练循环里监控TD误差的滑动平均值。当它连续多个回合居高不下时,就自动触发“环境可能变了”的告警。这比手动盯着奖励曲线高效得多,因为奖励曲线可能因为探索随机性而抖动,但TD误差的突变通常更具指示性。

5.4 奖励归一化:TD算法的“隐形前提”

我最后想特别强调一个容易被忽略的点:TD误差的大小和奖励的绝对尺度是线性相关的。你不归一化奖励,TD误差动辄几十上百,梯度类方法会直接被冲垮;即使非梯度方法,也会让价值估计算法变得极其不稳定。

最省事的方案是采用“标准归一化”:维护一个奖励的滑动平均值和滑动标准差,每次更新前把奖励转成标准分。这样做之后,TD误差的数值基本就能控制在个位数以内,很多超参数(α、γ)的敏感性会大幅下降。

在我自己的项目中,归一化前后的对比非常明显:归一化前,收敛需要上千个回合且中途经常发散;归一化后,大约400个回合就开始进入稳定区间。代价只是增加了两个滑动变量,完全是值的。

最后再分享一个小技巧

我后来在回头看这个项目的调参过程时,发现最值得分享的小技巧其实特别简单:别只盯着总奖励曲线,去看TD误差和状态价值的传播过程。奖励曲线只能告诉你“最终效果好不好”,而TD误差散点图能看到“智能体是不是正在理解这个环境”。如果你的TD误差长期不衰减,说明学习率可能太大或太小,或者环境信号确实过于稀疏——前者需要调参,后者可能需要换一种信息密度更高的表征方式。

时序差分方法,说到底不是什么高不可攀的理论,它就是一个“用自己的未来预测来修正当前判断”的朴素策略。想清楚这一步,后面再看DQN、Actor-Critic那些复杂架构,你会发现它们的底层都有一个同样的骨架:估计、采样、修正,循环往复。把这一步吃透,你的强化学习之路就稳了一大半。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询