很多人学强化学习从动态规划入门看到状态价值回溯那一步觉得顺理成章结果一碰到真实项目比如机械臂抓取、游戏AI、机器人导航就撞上一堵墙环境的状态转移概率到底去哪找这个问题在强化学习里有个标准答案——对不起绝大多数真实环境根本不会把概率表递到你手上。这篇是强化学习简史系列的第4篇我打算把两个最经典的“不依赖模型”方法放在一起讲透MCMonte Carlo蒙特卡洛和TDTemporal Difference时序差分。单看名字它们像两把平行工具实际上它们代表的是两种人生一种等整段剧情落幕才结算另一种每走一步就重新校准导航。这篇文章会从原理出发给可运行的代码骨架再把它们放到现代深度强化学习的语境里看这些“老古董”是怎么影响DQN、PPO、AlphaGo的。1. 为什么强化学习需要“不依赖模型”1.1 动态规划的“上帝视角”为何失效动态规划Dynamic Programming在强化学习教材里总是第一个登场价值迭代和策略迭代也确实漂亮。但请注意它们都有一个前提你手里必须有完整的环境动力学模型也就是MDP里的转移概率 (P(s|s,a)) 和奖励函数 (R(s,a,s))。有了这些你才敢在用贝尔曼方程迭代的时候对下一时刻的状态做精确加权求和。生活里做个类比动态规划就像拿着机场航班总表做中转规划你知道每个航班准点率、转机时间可以算出最优路线。但如果你面前是一个没有航班表的机场所有航班信息只能靠现场问、现场改签那原封不动套用“总表算法”就行不通了。我自己的实操感受是很多入门者以为强化学习就是动态规划换皮是因为教材里那些GridWorld环境把概率分布写得明明白白。可一旦换成真实场景比如倒立摆的物理摩擦系数、游戏的隐藏机制、机器人关节的力矩延迟你根本拿不到精确的 (P) 和 (R)。这时候DP就从一个算法退化成一种“理想解法”工程上没几个人真的能拿到这么全的模型。1.2 建模成本与真实世界的差距有人会说“我可以用仿真器先拟合一个概率模型再套DP啊。”这个思路确实常见但坑也不少。仿真器本身是对真实环境的近似模型误差在DP里会被贝尔曼方程一步步放大——你今天低估了0.01的转移概率迭代几千轮后价值函数可能偏得离谱。这也是为什么强化学习社区一直有“sim-to-real gap”仿真到真机的落差这个老话题。无模型的MC和TD从根本上绕开了“显式建模”这一步。它们不向环境要公式只向环境要样本看到什么状态、执行什么动作、拿到什么奖励、跳到什么状态从这些交互记录里把价值函数学出来。这是一种很聪明的交易——用样本效率换建模普适性。代价也很明确你没法用一次迭代就得到精确解必须靠海量试错逐步逼近。所以“不依赖模型”这个说法里“模型”指的是MDP里的转移概率和奖励分布不是我们常说的“神经网络模型”。这是很多人第一次接触时容易绕晕的地方。MC和TD共同的起点就是这个问题既然环境动力学未知怎么估计某个状态到底“值多少钱”2. MC蒙特卡洛一种“不依赖模型”的原始直觉2.1 完整回合的价值估计蒙特卡洛方法的历史比强化学习这个概念早得多核心思想就一句话用大量采样的平均值逼近期望。放到强化学习里要估计状态 (s) 的价值 (V(s))就多次从 (s) 出发跑完完整回合记录每次的折扣回报 (G_t R_{t1} \gamma R_{t2} \gamma^2 R_{t3} \dots)然后取平均。为什么非要等到完整回合结束因为回报的定义包含了未来所有奖励只要回合没终止你就不知道后面会发生什么也就没法给前面这个状态“盖棺定论”。这一点如果用21点来类比特别清楚你想知道“手里点数14庄家明牌7”这个局面值多少钱只有等这一局发牌、叫牌、摊牌全部结束看清输赢是多少才能给这个牌局状态记上一笔。MC就像坚持“一局结束再复盘”的记分员每一条轨迹都是一个完整的故事。在一条具体轨迹里同一个状态可能多次出现。比如一个网格世界里智能体为了找宝藏反复经过同一个走廊。这时MC有两种结算方式只在这个状态第一次出现时记录回报叫 first-visit MC每次出现都记录叫 every-visit MC。理论分析里 first-visit 更干净因为它的估计是无偏的方差分析也简单。every-visit 因为同一条轨迹内的回报高度相关严格意义上会有一点偏差。实际工程中两者结果往往很接近但我个人更偏向 first-visit实现容易、复现稳定排查问题的时候也好解释。2.3 最小实现MC策略评估代码骨架直接给一段Python风格的伪代码骨架你可以把它套到任何一个有reset和step接口的环境上。def mc_policy_evaluation(env, policy, episodes10000, gamma0.99): returns_sum {} returns_count {} for _ in range(episodes): trajectory [] state, _ env.reset() done False while not done: action policy(state) next_state, reward, done, _ env.step(action) trajectory.append((state, reward)) state next_state seen set() G 0.0 for state, reward in reversed(trajectory): G reward gamma * G if state not in seen: seen.add(state) returns_sum[state] returns_sum.get(state, 0.0) G returns_count[state] returns_count.get(state, 0) 1 V {s: returns_sum[s] / returns_count[s] for s in returns_sum} return V注意几个细节第一从轨迹尾部倒推 (G)每一步都能直接拿到从该时刻到终点的累计回报复杂度是O(n)比从头往尾算每个状态要重新遍历一次高效得多。第二seen集合保证一个回合里同一个状态只计入一次实现的是first-visit语义。第三如果某个状态始终没有被访问到就不会出现在V里你在后续计算时要处理好缺失值的默认值。2.4 无偏与高方差的代价MC的优点是“无偏”——它用的是真实发生的累计回报而不是另一个估计值去修正当前估计不会因为出发点的偏差而系统性带歪。缺点也藏在同一个地方方差高。为什么高一条轨迹从开始到结束会叠加环境初始状态随机、策略动作随机、环境转移随机、奖励随机等大量噪声源。一局21点你可能爆牌输光下一局又可能21点通杀回到家立刻下结论说“这牌型价值高”肯定不靠谱。方差大带来的现实问题就是需要非常多回合才能把噪声平均掉。如果episode很长、奖励稀疏MC的训练曲线会像心电图一样剧烈抖动。所以在工程选型时MC并没有“过时”而是变少。它特别适合两类场景一是任务明确有终点的评估场景比如离线评估某个旧策略二是模拟成本很低、能快速滚出海量回合的游戏环境。但如果你要在真实机器人上边跑边学一个回合可能就要几分钟MC这种“等结局再算账”的方式就太慢了。3. TD时序差分边活边修正的学习方式3.1 TD(0)更新式如何被推导TDTemporal Difference名字听着抽象其实想法特别朴素既然MC要等完整回报才能更新那我可不可以走了一步之后用“当前这一步真实拿到奖励 对下一步状态的已有估计”来作为当前状态的目标这就是TD(0)更新式[ V(S_t) \leftarrow V(S_t) \alpha \left[ R_{t1} \gamma V(S_{t1}) - V(S_t) \right] ]括号里面那部分叫TD误差TD error。它表示“实际这一步带来的信息”和“我原本对当前状态的估计”之间的差值。如果差值为正说明实际走向比预期好就把价值往上抬为负就往下压。这种用估计值去更新另一个估计值的做法在强化学习里叫“自举”bootstrap。它是TD区别于MC最核心的地方也是一切优点和缺点的源头。生活类比你开车去一个陌生地方导航不会等你到了终点才告诉你路线错了而是在每个路口就根据“已经走过的路程 系统对剩余路程的预估”不断修正。TD就是这种“开着修正而不是到站再复盘”的方式。3.2 从Sarsa到Q-learning策略评估之外真正常用的是控制问题不仅要估计价值还要找到最优策略。TD发展到控制层面最出名的两兄弟就是Sarsa和Q-learning。Sarsa的更新公式是[ Q(S_t, A_t) \leftarrow Q(S_t, A_t) \alpha \left[ R_{t1} \gamma Q(S_{t1}, A_{t1}) - Q(S_t, A_t) \right] ]它更新时用的是实际执行的那个动作 (A_{t1})也就是说它的学习样本完全来自当前策略跑出来的轨迹这叫on-policy同策略。Q-learning则更激进[ Q(S_t, A_t) \leftarrow Q(S_t, A_t) \alpha \left[ R_{t1} \gamma \max_a Q(S_{t1}, a) - Q(S_t, A_t) \right] ]不管当前策略下一步实际选了哪个动作它都拿“下一步所有动作中最大的Q值”当目标这叫off-policy离策略。Q-learning就像一个人永远盯着前方最闪耀的十字路口哪怕自己从来没走过那条路也认为那里值得期待。这个特性让它更敢闯但也埋下了过估计的隐患——后面避坑部分细说。3.3 最小实现TD(0)策略评估TD(0)的代码比MC简单得多因为它不需要保存整条轨迹每走一步就能更新。def td0_prediction(env, policy, alpha0.1, episodes5000, gamma0.99): V {} for _ in range(episodes): state, _ env.reset() done False while not done: action policy(state) next_state, reward, done, _ env.step(action) if done: target reward else: target reward gamma * V.get(next_state, 0.0) V[state] V.get(state, 0.0) alpha * (target - V.get(state, 0.0)) state next_state return V关键点在于终止状态处理当doneTrue时下一时刻没有价值目标就是reward不能再加gamma * V(next_state)。这个小细节如果漏了价值估计会在回合末尾被莫名抬高或压低而且这种误差会通过TD的自举传播到前面所有状态排查起来很隐蔽。3.4 在线学习与自举的双刃剑TD最大的优势是能边走边学。一个step就能提供一次更新信号不用等整个回合结束数据利用率高方差也低——毕竟每一步只涉及当前这一步的随机性而不是一整条轨迹的随机性叠加。代价就是偏差。因为 (V(S_{t1})) 本身是估计用估计去更新另一个估计本质上是在拿可能不准的数修正同样不准的数。如果初始值设置不合理或者状态表示丢了关键信息TD的偏差会在自举过程中不断传播。这就是为什么TD学习快但有时候“快得出错”MC慢却慢得踏实。在很多工程场景里TD是首选状态空间大、任务无明确终止、实时交互成本高。但TD对“状态表示是否保留足够信息”非常敏感。如果观测不完整比如机器人只有局部传感器看不到身后的障碍物TD会把“局部观测下的错误价值”一路扩散最后学出一个看起来很自信、实际完全跑偏的策略。4. MC与TD的正面交锋两种人生怎么选4.1 一张表说清偏差、方差与场景先上一张大对照表后面详细解读维度MC蒙特卡洛TD时序差分更新时机一个完整回合结束后每走一步立即更新目标构造真实累计回报 (G_t)单步奖励 自举估计偏差无偏有偏依赖初始估计质量方差高受整个回合随机性影响低只受单步随机性和估计误差影响在线学习不可以可以马尔可夫性质依赖较低直接结算轨迹较高假设下一状态能代表未来适合任务有终点的episodic任务、离线评估在线交互、持续型任务、深度RL数据效率低要跑完一整集高每个step都能学奖励稀疏时的表现学习信号出现晚、方差爆炸需要长距离传播但传播有方向这张表里最容易让人误解的是“偏差”那一行。MC无偏不代表MC更“正确”只代表它给的是“真实样本的统计平均”。在样本量不足时无偏估计照样可能和真实值差很远因为方差太大。TD有偏但当训练足够久、状态空间覆盖得够全时偏差会被逐渐修正再加上方差低实际表现往往比MC稳定。4.2 马尔可夫假设的分水岭MC和TD真正最深刻的哲学差异在于对马尔可夫性质的依赖程度。马尔可夫性质说的是给定当前状态未来与过去独立。TD的自举更新天然利用了这一性质——它认为 (V(S_{t1})) 已经概括了从下一步开始的全部未来信息所以当前状态的价值可以借助它来构造。这在状态表示足够好的环境里非常高效。但如果环境是部分可观测的或者你的状态表示丢了信息TD就会出问题。举例你用一个智能体在迷宫里导航传感器只能看到前方3米这时状态表示并不能完整描述“全局位置”。TD会拿着当前的局部观测做自举把“我没看到障碍物”错误地当成“前方安全”的价值信号传播开来。MC虽然也在同一个不完整状态上做估计但它至少是拿完整轨迹的最终结果来结算不会把一个不靠谱的“下一步估计”接力传下去。这也是为什么有些资深工程师遇到“TD训练起来很顺但部署后崩了”这类问题时会回头怀疑状态表示是不是丢信息而不是盲目加深网络。MC的“笨办法”反而能帮他们定位问题。4.3 n-step与λ-return两种人生的中间态看到这里你可能会问非得二选一吗不能既保留MC的无偏感又保留TD的快速学习吗答案是可以而且这是TD(λ)和n-step TD做的事。核心思想是把“只看一步”和“看到终局”做一个折中。n-step回报的定义是[ G_t^{(n)} R_{t1} \gamma R_{t2} \dots \gamma^{n-1} R_{tn} \gamma^n V(S_{tn}) ]当 (n1) 时就是TD(0)当 (n\infty) 时就变成MC。n越大估计越接近真实回报偏差越小但方差越大n越小自举越强偏差越大但方差越小。如果把所有n的回报道按照几何权重组合起来就得到λ-return[ G_t^{\lambda} (1-\lambda) \sum_{n1}^{\infty} \lambda^{n-1} G_t^{(n)} ](\lambda0) 时退化为TD(\lambda \to 1) 时逼近MC。实际工程里几乎没人手写λ-return因为它需要看未来一整个horizon的轨迹计算不方便。更常用的等价变换是TD(λ)的后向视角以及现代强化学习里与actor-critic结合的GAEGeneralized Advantage Estimation其核心就是用一个介于0和1之间的λ来调节偏差和方差的平衡。PPO里默认GAE λ0.95这本质上就是“七分TD、三分MC”的混合体。5. 现代强化学习里MC与TD都留下了什么5.1 主流DRL算法为什么偏爱TD打开任何一个现代深度强化学习算法DQN、DDPG、SAC、TD3、PPO你会发现它们的内核都是TD思想。DQN本质上是Q-learning加神经网络、经验回放和目标网络PPO的actor-critic结构里critic学习价值函数用的也是TD误差SAC的软Q更新同样是自举。为什么一边倒地选TD原因有三个。第一深度神经网络需要密集的梯度信号。TD每走一步就有一个目标值可以算损失MC要等整场episode结束才能给一次梯度。对于动不动需要几十万步交互的深度RL来说MC的更新频率没法看。第二TD方差低配合经验回放时可以从历史transition里反复采样让训练稳定很多。DQN那套经验回放和TD天然契合因为TD目标只需要 ((s,a,r,s)) 四元组不依赖完整轨迹。第三target network的设计可以有效缓解TD自举不稳定的问题让“用估计更新估计”这件事变得可控。但这不代表MC消失了。恰恰相反MC思想在另一条技术线里活得很好。5.2 蒙特卡洛思想在MCTS与offline RL里回潮先说树搜索。AlphaGo和AlphaZero里最核心的搜索算法叫MCTSMonte Carlo Tree Search中文就是蒙特卡洛树搜索。它会在搜索过程中利用当前策略网络和价值网络进行引导但同样会做大量的随机模拟rollout用这些模拟结果的平均回报来评估局面。这个“采样、平均、结算”的底层逻辑就是MC的直系后代。再说离线强化学习offline RL。这几年业界越来越关注“只用已经采集好的数据不再和环境交互”的训练范式因为真实系统不允许你随便试探。离线数据里TD自举的最大隐患暴露得很明显如果一条轨迹中某个状态在训练数据里只出现一次TD会用当时的 (V(s)) 去更新它而 (V(s)) 本身可能是对某个分布外状态的不靠谱估计误差就这样一级级放大。很多离线算法论文讨论的“过估计”问题本质上就是TD在数据覆盖不足时“自嗨”出来的。相比之下MC目标用的完整回报来自真实轨迹没有自举至少不会凭空制造乐观幻觉。所以不少离线RL算法在构建目标时会刻意回归到“期望回报回归”这类偏MC的思路或者用裁剪、保守惩罚等手段限制TD的越界。IQL这类算法里也能看到“避免自举误差扩散”的设计意图。经典方法在现代语境里并没有退休而是换了个位子继续发光。6. 实操避坑手册从MC/TD视角排障6.1 怎么判断是MC方差大还是TD偏差大很多读者跑实验时遇到“价值估计不收敛”就直接调学习率、调网络结构但其实先分清楚问题是方差还是偏差效率会高很多。一个非常有效的检查方式拿同一个策略跑多个不同随机种子记录每个种子的累积回报曲线。如果多条曲线形状相差极大、互相纠缠那大概率是方差问题也就是轨迹本身的随机性太大MC或高n-step方法会尤其明显。如果曲线互相之间很接近但整体趋势和“真实期望回报”系统性偏离比如始终比理论值高出一截那就更可能是TD自举带来的偏差。另外我在调试时习惯把“每个episode的真实回报”和“critic的价值预测”画在同一张图上。MC方差大时真实回报曲线毛刺很多TD偏差大时两条曲线会出现方向一致但差距稳定的“剪刀差”。这两种情况的修法完全不同方差大考虑增大样本量、降低γ、用更多并行环境偏差大考虑改进状态表示、添加目标网络、用double DQN或者降低λ让它更接近MC。6.2 稀疏奖励下该调n-step还是λ奖励稀疏是强化学习里最磨人的问题之一。假设一个episode长度是100步奖励只在最后一步给1其他全部为0。纯TD要沿着轨迹一步步把奖励“倒灌”回去100步的距离意味着前面的状态至少需要几百上千次训练才能学到非零价值。纯MC则要等完整回合结束才能给一次信号回合又长方差非常高。这时候n-step或λ-return几乎是必然选择。我的建议是从小处试先试3-step或5-step观察训练曲线如果效果不明显再往上提到10甚至20。在GAE里如果奖励极稀疏λ可以往0.98、0.99推让估计更接近MC的真实回报如果奖励密集但环境噪声大λ往0.9推增强自举稳定性。记住这两个方向你调参时就不会全靠猜。6.3 容易忽略的实现细节第一个细节是折扣因子γ。γ越接近1MC的方差越大因为远方奖励对当前价值的贡献越来越大而远方的随机性也最大。很多项目默认γ0.99但如果episode特别长0.99会让回报计算对后期非常敏感。第二个细节是done处理。上一章TD代码里写的“终止状态不再加V(next_state)”不是随便说说的。我见过不少新人在实现DQN时漏掉这个条件导致terminal状态的价值也被自举了一手最终所有状态价值都被高估策略变得极其莽撞。第三个细节是回放缓冲区与TD的配合。离策略TD天然适合经验回放但目标网络是必需品。如果你看到训练早期Q值直线飙升先检查是不是target network没有冻结或更新频率太低——这不是数学问题而是工程上最容易出现的一个坎。6.4 我的几条经验守则这些是我这几年在多个项目里踩出来的总结不一定绝对但能少走很多弯路要做一个无偏的离线策略评估优先考虑MC或带重要性采样的MC别偷懒直接用TD目标要在线和环境交互、且数据量有限优先TD或GAE不要为了“无偏”硬等完整回合新任务不知道选什么时先从TD类baseline跑起用GAE λ0.95作为默认值有问题再把λ调高调试过估计问题先检查target network和double Q这两个工具就是为了治TD的“乐观倾向”如果训练途中价值曲线剧烈震荡先分方差和偏差再调学习率顺序反了会浪费大量时间。我自己折腾强化学习这几年最大的体会就是MC和TD根本不是新旧替代关系而是两种价值判断方式。做机器人项目时我一度迷信TD学得快结果在部分可观测的环境里被自举带偏调试了三天才发现问题不在网络规模而在“下一步状态的估计”本身就不可靠。后来我改为在离线阶段用MC目标做策略评估在线阶段再用TD做微调两边各取所长效果才稳定下来。如果你的项目也卡在价值估计上不妨退一步想想你是在等结局还是在修正路上的导航。两种人生各有风景选对才是关键。
阅读完成 · 觉得有帮助?