的强化学习核心算法)
学完蒙特卡洛那一章时我隐约觉得哪里不对劲。MC的方法很直白等一场游戏打完用真实的累计回报去修正状态价值估计。这个逻辑没问题可问题在于等一场游戏打完——在连续任务里根本没有打完这回事在真实机器人实验里你也等不起那么久。当时我的直觉是能不能走一步就修正一步答案就是这第7章要讲的东西——时序差分Temporal Difference简称TD。如果你正处在读懂了贝尔曼方程但不知道它怎么落地成算法的阶段这篇笔记应该能帮上忙。我会把每个更新式拆开把为什么这样写的逻辑也说清楚。1. 为什么边走边学能替代跑完再改TD思想的由来1.1 蒙特卡洛方法的两处硬伤先说清楚我们想解决什么问题。第4章里蒙特卡洛方法用完整回合的累计回报 $G_t r_{t1}\gamma r_{t2}\gamma^2 r_{t3}\dots$ 作为状态价值 $v_\pi(s)$ 的估计目标。给定一个策略 $\pi$我们不断采样轨迹对每个访问过的状态求这些回报的平均值就能逼近真值 $v_\pi(s)$。这个思路有两点让人不舒服必须等到幕结束才能更新。如果任务没有终止状态比如机器人持续搬运物品或者一局要跑几小时MC就非常尴尬——你只能干等。方差大。$G_t$ 是一长串随机奖励的累加和中间任何一次随机抖动都会被放大。尤其当环境有较强的随机性时MC的估计曲线会剧烈震荡收敛速度肉眼可见地慢。当时我自己的体会是MC像期末考试后才知道自己考砸了但是考试已经结束想改也来不及了。我们真正想要的是一个能随堂测验、立刻反馈的方法。1.2 动态规划留下的钥匙贝尔曼方程而第3章动态规划其实给过一把钥匙——贝尔曼方程$$v_\pi(s) \mathbb{E}\pi\left[ r_t \gamma v\pi(s_{t1}) \mid s_t s \right]$$它告诉我们一个状态的价值可以由即时奖励 折扣后的后继状态价值计算出来。动态规划的做法是用当前估计值 $v_k(s)$ 去算 $v_{k1}(s)$一遍遍迭代这叫自举bootstrapping。DP的问题是它需要一个完美模型你得知道状态转移概率 $p(s|s,a)$还得能枚举所有后继状态。真实场景里环境模型要么没有要么不准。既然MC说我可以采样DP说我可以用后继状态的价值那为什么不把两者捏到一起1.3 TD的做法走一步就更新第7章给出的答案就是利用贝尔曼方程做一步采样从状态 $s_t$ 按策略走一步得到奖励 $r_t$ 和新状态 $s_{t1}$。我们手头虽然没有真实后继价值但有一份当前估计值 $V(s_{t1})$。那就把$$r_t \gamma V(s_{t1})$$当成一个伪目标TD target然后让 $V(s_t)$ 向它靠近$$V(s_t) \leftarrow V(s_t) \alpha \left[ r_t \gamma V(s_{t1}) - V(s_t) \right]$$你看这个操作既没有等到回合结束这是MC的特征也没有计算期望这是DP的特征它走一步、采样一步、就地更新——所以叫时序差分。我当时为了记住这件事画过一张 三选一 的对比表也放这里方法是否需要环境模型是否自举是否采样动态规划 DP是是否蒙特卡洛 MC否否是时序差分 TD否是是一句话总结TD同时继承了DP的自我预测和MC的经验采样而且是增量式更新不需要等结局。这个思想之后会反复出现是整个强化学习算法家族最核心的骨架之一。2. 拆开TD误差公式一个数字案例与有偏但方差小的权衡2.1 TD(0)的更新式从贝尔曼期望到一步采样自举教材里一般把最简单的单步更新叫 TD(0)下标0表示只看未来一步。它的完整形式是$$ V_t(s_t) V_{t-1}(s_t) \alpha_t \left[ r_t \gamma V_{t-1}(s_{t1}) - V_{t-1}(s_t) \right] $$其中 $V_{t-1}$ 表示更新前的价值估计。方括号里的东西就是一个误差信号专门给它一个名字叫TD误差$$ \delta_t r_t \gamma V_{t-1}(s_{t1}) - V_{t-1}(s_t) $$注意一个细节这里的 $r_t$ 是真实采样到的即时奖励而 $\gamma V(s_{t1})$ 用的是当前还不准确的估计值。所以 $\delta_t$ 不是真实误差它只是当前估计与自举目标之差。整个过程等于把状态价值往某个近似方向上拉了一小步。如果要写成旧值 增量的形式就是$$ V_t(s_t) (1-\alpha_t)V_{t-1}(s_t) \alpha_t (r_t \gamma V_{t-1}(s_{t1})) $$我当初第一次看到这个式子容易犯的迷糊是它为什么只改 $s_t$ 的价值而不改 $s_{t1}$原因很简单我们手里关于状态 $s_{t1}$ 的信息还不够它只是被路过了一下它的下一跳还没发生。TD的哲学是谁的经验谁先改走到哪、改到哪。2.2 一个三次轨迹的数字推演光看公式还是不够我建议你跟着我手推一个极简例子。假设三个非终止状态 $A \to B \to C \to T$$T$ 是终止状态$\gamma1$所有初始价值为0学习率 $\alpha0.1$。轨迹1$A \to B$ 得 $r0$$B \to C$ 得 $r0$$C \to T$ 得 $r1$。更新 $V(A)$$\delta 0 1\times 0 - 0 0$不变。更新 $V(B)$$\delta 0 1\times 0 - 0 0$不变。更新 $V(C)$$\delta 1 1\times 0 - 0 1$$V(C)00.1\times10.1$。一次轨迹下来只有 $V(C)$ 变了是不是很抠门继续。轨迹2走同样的路。更新 $V(A)$$\delta 0 1\times 0 - 0 0$还是不变。更新 $V(B)$$\delta 0 1\times 0.1 - 0 0.1$$V(B)00.1\times0.10.01$。更新 $V(C)$$\delta 1 1\times 0 - 0.1 0.9$$V(C)0.10.1\times0.90.19$。看到了吗$C$ 的经验开始往 $B$ 传递了。轨迹3更新 $V(A)$$\delta 0 1\times 0.01 - 0 0.01$$V(A)0.001$。更新 $V(B)$$\delta 0 1\times 0.19 - 0.01 0.18$$V(B)0.010.1\times0.180.028$。更新 $V(C)$$\delta 1 0 - 0.19 0.81$$V(C)0.190.1\times0.810.271$。三幕下来奖励信号像水波一样从终点往起点一层层反向扩散。TD更新的关键在这里每个状态只需要等到下一跳发生就能收到后继状态传来的涟漪。这正是时序差分名字里时序二字的含义——按时间顺序把差异一步一步往回传。2.3 为什么说TD有偏但方差小蒙特卡洛的回报 $G_t$ 是真实奖励的累计它不依赖任何估计值所以是无偏的。代价是因为要累加很多随机量方差大。TD的target $r_t\gamma V(s_{t1})$ 里面 $V(s_{t1})$ 是估计值一开始它根本不准所以TD估计是有偏的。但它的好处是只依赖一次随机奖励和一次后继状态随机性的来源少方差明显低。用一个不太严谨但很好记的比喻MC是期末考完看总分一次考试可能因为题目难易起伏很大TD是边学边做单元测小测验波动小但测验卷子本身可能出得不够准。这两种方法在数学上一个对应无偏高方差一个对应有偏低方差没有绝对谁更好只有你所在任务更在意哪一头。3. 从估计状态到学会动作SARSA、Q-learning与它们的分岔口3.1 为什么必须转向行为值函数到目前为止TD都是在对状态价值 $V(s)$ 做估计。可做控制的时候我们需要知道在状态 $s$ 下哪个动作好光知道状态的价值不够。比如两个状态价值相同一个能到达高奖励区域一个只能走来走去策略改进会比较动作而不是状态。所以从这一节开始TD系列的主角换成了行为值函数 $Q(s,a)$。定义还是一样的贝尔曼期望形式只是把条件从状态换成状态-动作对$$q_\pi(s,a) \mathbb{E}\pi\left[ r_t \gamma q\pi(s_{t1}, a_{t1}) \mid s_ts, a_ta \right]$$TD的单步更新变成了对 $Q$ 的更新。接下来麻烦的事来了$a_{t1}$ 怎么选不同的选择方式直接分裂出了两个著名的算法。3.2 SARSA用实际采取的下一步动作做目标SARSA这个名字就是五个字母拼起来的State-Action-Reward-State-Action。更新公式$$ Q(s_t,a_t) \leftarrow Q(s_t,a_t) \alpha \left[ r_t \gamma Q(s_{t1}, a_{t1}) - Q(s_t,a_t) \right] $$注意$a_{t1}$ 是什么它必须是当前策略 $\pi$ 实际下一步会采的那个动作。比如你用 $\epsilon$-greedy 探索那 $a_{t1}$ 就是真的用 $\epsilon$-greedy 选出来的动作而不是回头想想最贪心的动作。因为这个原因SARSA属于**on-policy在线策略**算法它评价和优化的是同一个正在执行的策略。我记得教材里曾用悬崖行走Cliff Walking这个任务做演示起点在左下终点在右下中间是一排悬崖。用SARSA训练出来智能体通常绕着悬崖上边走非常保守。原因很直观SARSA把当前策略可能的失足也学到了Q值里$\epsilon$ 探索阶段一旦掉下去过它就知道那条路危险下次宁可绕远。3.3 Q-learning用所有动作里的最大值做目标Q-learning的思路更贪婪$$ Q(s_t,a_t) \leftarrow Q(s_t,a_t) \alpha \left[ r_t \gamma \max_{a} Q(s_{t1}, a) - Q(s_t,a_t) \right] $$它和SARSA唯一的差别就是 $Q(s_{t1},a_{t1})$ 变成了 $\max_{a} Q(s_{t1}, a)$。这个 $\max$ 意味着不管行为策略下一步实际选了哪个动作更新时都假设下一步会采取最优动作。所以Q-learning可以一边用探索策略收集数据一边学习最优策略对应的Q函数属于**off-policy离线策略**算法。这也是Q-learning在理论上的漂亮之处——它直接逼近最优值函数 $q_*$而不依赖当前策略。回到悬崖行走Q-learning学出的路径往往是贴着悬崖边缘的最短路径。因为它更新时假设以后会走最贪心的动作而最贪心的动作看起来风险低、路径短于是它敢于冒险。现实中的对比我后面还会细讲。但必须先提醒一句SARSA学到的是带探索动作的策略的最优价值Q-learning学到的是纯贪心策略的最优价值所以两者最后的Q值不能直接拿来互相比较它们根本不是同一个对象。3.4 Expected SARSA用期望来代替最大或单样本SARSA的缺点是目标里包含随机采样的 $a_{t1}$方差偏大Q-learning的缺点是 $\max$ 会带来过估计会把噪声的最大值当成真实最大值。Expected SARSA夹在中间用行为策略 $\pi$ 下的期望值来做目标$$ Q(s_t,a_t) \leftarrow Q(s_t,a_t) \alpha \left[ r_t \gamma \sum_{a} \pi(a \mid s_{t1}) Q(s_{t1}, a) - Q(s_t,a_t) \right] $$这样既保留了 off-policy 的思路你可以用任意策略采集数据再用行为策略的期望做自举又比单样本SARSA的方差小。如果 $\pi$ 是确定性贪心策略那期望就退化成 $\max$Expected SARSA就变成了Q-learning如果 $\pi$ 是正在使用的探索策略那它也等价于一个低方差的SARSA变体。这个式子看上去只是习惯性把期望写出来但在实际工程调参中非常有用后面我做表格型实验时经常拿它当低方差baseline。4. 收敛性不是凭感觉TD的随机逼近视角与条件4.1 把TD(0)看成Robins-Monro采样迭代讲完算法本身很多初学者会卡在TD到底为什么能收敛上。我建议你把它放回上一章学的随机逼近框架里看。策略评估的目标是求解贝尔曼方程 $v_\pi(s)\mathbb{E}\pi[r\gamma v\pi(s)]$移项一下$$v_\pi(s) - \mathbb{E}\pi\left[r\gamma v\pi(s)\right] 0$$这里未知数是函数 $v$右边是0。我们想要找一个让这个方程成立的价值函数。但问题是我们不知道期望 $\mathbb{E}\pi$只能采样到 $r_t$ 和 $s{t1}$。那就可以用随机逼近的方式来解把真实但不满足的目标 $r_t\gamma V_{t-1}(s_{t1})$ 当成带噪声的观测用增量式学习率 $\alpha_t$ 去更新。所以TD(0)的更新$$ V_t(s_t) V_{t-1}(s_t) \alpha_t \delta_t $$本质上就是Robins-Monro迭代更新方向是TD误差 $\delta_t$而TD误差的期望恰好是当前值与贝尔曼目标之差。当 $\delta_t$ 的期望为0时我们就到达了贝尔曼不动点。4.2 表格型TD收敛需要什么条件既然是随机逼近自然要满足随机逼近的条件。几条我记忆很深的学习率要满足 $\sum_t \alpha_t \infty$ 且 $\sum_t \alpha_t^2 \infty$。前者保证任何初始离得远都能被拉到后者保证后期的随机抖动不会累积成发散。实践中常用 $\alpha_t \frac{1}{n1}$ 或固定小学习率。每个状态或状态-动作对要被无限次访问。也就是说你的探索策略必须保证状态空间能被遍历否则没被访问到的状态永远学不到。对于SARSA和Q-learning收敛性还要求探索策略满足每个动作在每个状态下都有非零概率被执行比如 $\epsilon$-greedy 配合 $\epsilon \to 0$ 但不完全到0。这里有个很容易踩的坑TD的那一步更新只改了当前访问的那个状态其他状态的价值完全不动。这意味着访问到本身是硬前提而表格法下所有状态的访问频率不可能均匀。所以工程上通常要加足够大的 $\epsilon$ 或使用乐观初始化否则某些冷门状态会被长期放弃导致智能体永远不知道自己错过了什么好的转移。4.3 一个反直觉点有偏为什么还能收敛前面刚说过TD是有偏的可它又能收敛到真值这看起来矛盾。我当时的理解是这样TD的偏差不是随机噪声导致的系统漂移而是用估计值代替真值带来的自举偏差。每做一次更新我们实际上是在贝尔曼方程的方向上前进一小步就像在解一个自洽的方程组。只要迭代是压缩映射并且采样噪声被学习率平均掉序列就会收敛到方程组的解 $v_\pi$。换句话说偏差只是当前估值不够好的偏差不是方向错了的偏差。用望远镜来比喻MC的望远镜看到了清晰但遥远的真实山体不过手抖得厉害TD的望远镜有一定模糊但你每走一步都重新对焦最终也能对到同一座山上。5. 资格迹与TD(λ)在多步与一步之间找甜点5.1 n步回报从单步到多步的折中方案TD(0)只往前走一步蒙特卡洛走到终点。那能不能取中间走两步、走三步这就是n步TD的核心。定义n步回报$$G_t^{(n)} r_t \gamma r_{t1} \gamma^2 r_{t2} \dots \gamma^{n-1} r_{tn-1} \gamma^n V_{t}(s_{tn})$$前 $n-1$ 步用真实采样奖励第 $n$ 步后用自举估计值。当 $n1$它就是TD(0)当 $n\infty$它就是MC。n越大偏差越小、方差越大n越小偏差越大、方差越小。这给了我们一个旋钮实际场景里可以在偏差和方差之间拨动n。5.2 λ-return把所有n步回报加权平均更进一步的想法是不要只取某一个n而是把 $n1,2,3,\dots$ 的所有n步回报都综合起来按权重组合。这就是 λ-return$$ G_t^\lambda (1-\lambda) \sum_{n1}^{\infty} \lambda^{n-1} G_t^{(n)} $$权重 $ (1-\lambda)\lambda^{n-1}$ 共同组成一个和为1的分布当 $\lambda0$ 时权重全部落在 $G_t^{(1)}$ 上退化成TD(0)当 $\lambda \to 1$ 时权重几乎全落在很远的n步回报上接近MC。这个公式看起来很美但是有个问题它需要往未来看足够多远才能计算 $G_t^{(n)}$还是要等回合结束。这又回到想在线更新的困境了。5.3 资格迹前视转后视的工程魔法为了解决在线问题书里引入了资格迹eligibility trace把前视公式变成后视增量更新。维护一个和V同样维度的迹 $z_t(s)$每次碰到状态就点亮一下然后随时间逐步衰减$$ z_t(s) \gamma \lambda z_{t-1}(s) \mathbf{1}{s_t s} $$更新所有状态的价值时不只看当前状态的TD误差而是让当前得到的TD误差 $\delta_t$ 按迹的强度去更新所有历史访问过的状态$$ V_{t1}(s) V_t(s) \alpha_t \delta_t z_t(s) $$直觉是这个样子的你在连续走动的过程中某个状态最近被访问过、或者经常被访问它的痕迹就浓如果中途走远了之前状态的痕迹按 $\gamma\lambda$ 衰减。所以每一步虽然只计算当前这步的TD误差但通过资格迹这个误差被分发给之前所有相关状态相当于在线的多步TD。前视公式算的是目标后视递推算的是如何高效分配两者在离线更新下等价这正是 TD(λ) 的理论核心。我在实现时有一个小建议可以用替换迹replacing trace代替累积迹accumulating trace也就是每次访问到某状态时直接把迹置为1而不是加1否则高频状态迹会无界增长数值上容易爆掉。表格法里这个小改动不明显但在线性函数近似里能明显提升稳定性。实践上 $\lambda$ 我一般先取0.5到0.9之间做粗调$\lambda$ 太靠近1在非平稳环境中容易把噪声也累积进来太靠近0又浪费了多步信息。现代深度强化学习算法里有的直接做固定n步截断如n-step DQN取n3左右有的用GAE——广义优势估计本质就是把λ-return的思路平移到了优势函数上。你现在再看那些术语会觉得熟悉很多。6. 从表格法到函数近似学完这一章后我的几条实战体会6.1 为什么后续所有大名字都绕不开TD书看到这里应该警惕一个误区不要以为TD只是老旧的表格法。后面几章一旦引入函数近似TD的基本结构依旧成立只是 $V(s)$ 换成了参数化的 $V_w(s)$更新目标变成了沿TD误差方向做梯度下降$$ w \leftarrow w \alpha \left[ r_t \gamma V_w(s_{t1}) - V_w(s_t) \right] \nabla_w V_w(s_t) $$之后你会碰到的 DQN、DDPG、PPO、SAC价值估计部分无一例外都在用类似TD的结构。我在实验室跑机械臂抓取这类连续控制任务时最常用的组合就是Actor-CriticCritic用TD误差评估当前策略Actor再用Critic给出的信号改进策略。TD是整个深度强化学习的货币你不在这一章把它想清楚后面看代码会处处卡壳。还要提一个三大要素危局当自举TD、函数近似、离策略三者同时出现时价值估计有可能发散这在表格法里不会发生。这就是为什么Q-learning配神经网络时需要目标网络、经验回放这些额外手段。不过这是后面章节的事了在这一章先把表格法的扎实底座打好。6.2 跑实验时踩过的几个坑第一α过大是真会发散的。表格法里我还试过 $\alpha0.5$看上去每个状态都有修正但状态之间存在依赖更新起来互相拉扯曲线直接发散到无穷。稳妥的做法是先取0.05~0.1量级跑一条曲线看震荡幅度再说。第二探索率ε不能衰减太快。TD更新只触碰实际走过的状态-动作ε太小意味着很多转移根本不会被探索你学到的是一个残缺的Q值。我比较习惯让ε先保持0.1左右跑几千步再慢慢降到0.01。第三画评估曲线别只跑一条轨迹。TD的更新本身方差小但单次运行仍然有随机性要对比算法时最好至少固定10个随机种子每个种子跑完取累计奖励曲线再算均值和置信区间。之前看有人用Origin画强化学习置信区间曲线其实就是把多条seed的结果做统计别用单条曲线下结论。这个东西在真实机器人环境里尤其重要——机器人摩擦、关节响应这些都会给奖励带来额外方差单次实验的曲线完全没有说服力。第四奖励尺度的敏感性。TD误差直接等于即时奖励 后继价值估计 - 当前价值估计如果奖励动不动就到几百几千而价值估计还在个位数那一开始学习时会非常颠簸。我习惯把奖励做一下缩放或裁剪比如限制到 $[-1,1]$让TD误差稳定在同一量级收敛会顺很多。6.3 我建议的学习路径如果你和我一样是从公式入手这章之后一定要做三件事手推一遍本章的数字例子让误差传播的方向变成肌肉记忆在自写的网格环境里分别实现SARSA、Q-learning和Expected SARSA跑通后对比它们的行为差异用悬崖行走这种任务体会保守和激进的区别再写一个带资格迹的TD(λ)小demo把 $\lambda$ 调成0、0.5、0.9观察收敛速度的变化。做完这三步你再回头看深度强化学习的那些论文会发现它们的核心思想其实和第7章的TD相差并不远——只不过把表换成了网络把手工规则换成了自动梯度。带着TD误差到底在哪一行这个问题去读代码比背公式有用得多。