强化学习:动态规划、Monte Carlo 与 TD
本章回答什么
已经有了 Bellman 方程,怎样真正算出 value?本章用同一个 2×3 GridWorld 比较三条路径:Dynamic Programming(DP)枚举已知模型,Monte Carlo(MC)等待完整 episode,Temporal-Difference(TD)从单步样本 bootstrap。
三类方法解决的是同一个预测问题,却依赖不同数据、产生不同偏差与方差。读完后,你应能说明 policy evaluation、policy improvement、policy iteration、value iteration、first-visit Monte Carlo、TD(0) 和 n-step return 之间的依赖关系,并正确处理 terminal mask。
先修知识
先读 MDP、价值函数与 Bellman。本章直接使用 、、Bellman expectation、Bellman optimality、return 和 discount,不重新定义它们。
代码实现与运行前提见 强化学习示例 README。示例只依赖 Python 与 NumPy;完整源码是 gridworld.py。
最小任务
GridWorld 是确定性的 2×3 地图,状态按行编号:
1 | 0 1 2 |
状态 0 是起点,5 是 terminal。动作 0/1/2/3 是上、右、下、左;撞边界时留在原状态。每个非终止转移 reward 为 -1,进入或从终点转移的 reward 为 0 且 terminated=True。因此 0 -> 1 -> 2 -> 5 的 reward 序列是 -1, -1, 0,而不是每步都 -1。
从仓库根目录运行:
1 | python files/assets/examples/reinforcement-learning/gridworld.py --seed 7 |
当前示例输出:
1 | policy_value_mean=-4.464 |
前两行分别来自均匀随机 policy evaluation 与 value iteration。greedy_policy 中动作 1 是右、2 是下;terminal 的 -1 是“无动作”的 sentinel。第三行是脚本附带的 Q-learning smoke test,不是本章用来证明收敛的实验。
核心机制
1. Policy evaluation:已知模型下求
若能查询每个 的 transition 与 reward,可反复应用 Bellman expectation backup:
这行式子在第 轮旧数组 上计算整张新数组 。policy_evaluation 正是这种同步更新:先创建 updated = np.zeros_like(values),所有 state 都读旧 values,一轮结束后才替换。若改成 in-place 更新,仍可能收敛到同一不动点,但每轮数值与收敛速度会不同,不能把两种实验逐轮硬对齐。
对均匀随机 policy,。边界动作会原地不动,也必须计入四个动作的平均;漏掉它会改变被评估的 policy。
2. Policy improvement 与 policy iteration
有了 ,可用一次前瞻计算每个动作的分数:
其中 表示当前先做 、之后遵循 的价值。policy improvement 令新策略在每个状态选择 。交替执行“policy evaluation 评估当前策略”和“policy improvement 变成 greedy”,直到策略稳定,就是 policy iteration。
这里先完整评估再改进,概念边界最清楚。实际实现可以提前停止评估或交错更新,但必须明确自己使用的是哪种近似,不能把尚未收敛的 当成精确 。
3. Value iteration:直接应用 Bellman optimality
Value iteration 把 evaluation 与 improvement 压进一次 backup:
这行式子使用 Bellman optimality 的 ,所以目标是 ,不是某个固定 。示例的 value_iteration 也做同步更新,并在最大绝对变化小于 tolerance 时停止;若达到 max_iterations 仍不满足容差,则抛出 RuntimeError,不会返回伪装成收敛的数组。
在本任务中,从 0 到 5 最少三次转移,reward 是 -1,-1,0。取 ,最优起点 value 为 ,与 CLI 的 optimal_value_start=-1.900 一致。
4. First-visit Monte Carlo:等 episode 结束
若不知道完整 ,可以按 policy 采样 episode,再从末尾反算每个时刻的 return。first-visit Monte Carlo 只用一个 episode 中某 state 第一次出现处的 更新该 state;下一个 episode 再计一次。对上述最短 episode, 时:
1 | states: 0 1 2 5 |
示例的增量样本均值更新为:
1 | def monte_carlo_update(values, counts, state, return_): |
真实函数还会验证数组、索引、有限 return 与计数溢出。MC target 不含当前 value 估计,因此没有 bootstrap bias;但必须等到 episode 结束,长轨迹中的随机 reward 会带来较高方差。
5. TD(0):一步样本加 bootstrap
TD(0) 每次 transition 都更新 predecessor state 。非终止 target 为 ,terminal target 为 ;两类转移都执行:
其中 是步长,方括号内是 TD error。非终止 target 用当前估计 作为学习目标的一部分,这就是 bootstrap;terminal transition 仍更新 ,只是没有终点之后的 bootstrap。目标因此可能有估计偏差,但通常比完整 return 的方差低,也能在线更新。
6. n-step return 与 bias-variance
MC 和 TD(0) 之间可以用 n-step return 连起来:
这行式子先使用 个真实 reward,再从 bootstrap。 就是 TD(0) target;若 步内遇到真正 terminal,则求和在该转移结束且不添加 bootstrap 项。当 延伸到 episode 末尾且不再 bootstrap 时,就得到 Monte Carlo return。较小 通常方差低但更依赖当前 value,bias 可能较大;较大 减少 bootstrap 依赖,却累积更多采样噪声。这就是 n-step target 的 bias-variance 权衡,不是“ 越大越准确”的单调关系。
7. Terminal mask 与 truncation 边界
把结束边界写进 TD error:
其中 只表示真正 terminal:任务语义上已结束,后面没有可计入当前 return 的价值。此时 bootstrap 乘零。源码中的实现完全对应这个边界:
1 | def td_target(reward, gamma, next_value, terminated): |
truncated=True 常表示时间上限、采样片段长度或外部中断,而非 MDP 到达 terminal。时间上限处是否 bootstrap,要看是否仍有有效 successor state 及其 value:若环境返回的是可继续任务的有效下一状态,通常保留 bootstrap;若截断同时销毁了状态语义或任务本身确实以时限定义失败,则需按该任务定义处理。不要把 terminated or truncated 无条件塞给 。
训练数据流
三类估计的输入边界可以压缩为:
1 | 已知模型 DP: P,R + policy/value -> 枚举全部转移 -> Bellman backup -> 新 value |
DP 的“训练数据”是可枚举模型,不需要 rollout;MC 与 TD 都需要 policy 产生样本,因此它们估计的是采样 policy 所覆盖的数据分布。仅用 on-policy trajectory 做 prediction,不会因为把 target 写成 TD 就自动成为 optimal control。
一次样本记录至少保留 state, action, reward, next_state, terminated, truncated。先依据结束语义构造 bootstrap mask,再计算 MC/TD target,最后更新 value;若先丢掉两个结束标志的区别,后面无法可靠恢复。
常见失败
| 失败 | 表现 | 修正 |
|---|---|---|
| 混淆 in-place 与 synchronous DP | 每轮数组和讲义不同就判错 | 先确认读取旧数组还是立即写回;比较最终不动点与停止条件 |
| MC 未等 episode 结束 | 用不完整后缀冒充完整 return | 等真正结束,或明确改用 n-step / bootstrapped target |
| terminal target leakage | 终点 value 被加到前一状态 target | 对真正 terminal 令 |
| tolerance / limit 错误 | 容差非正、上限耗尽仍返回结果 | 用正有限容差;未收敛达到上限时显式失败 |
| prediction / control 混淆 | 用 on-policy 样本评估 ,却声称得到最优策略 | prediction 固定 policy;control 还需要 improvement 或最优性更新 |
| 所有 truncation 都置零 | 时间片段末端系统性低估 value | 判断是否有有效 successor state/value,再决定 bootstrap |
自检与练习
- 手算 Bellman update:令初始 、。对状态
2的四个动作分别算一次 target,再写出 value iteration 的 。注意向下进入5的 reward 是0。 - 比较目标:对 transition
(0, right, -1, 1, False),设当前 ,算 TD(0) target;再解释为什么只看这条 transition 不能得到 MC return。 - 代码实验:运行
gridworld.py,把gamma从0.9改为0.5传给value_iteration,预测并验证optimal_value_start;不要修改环境 reward 语义。 - 边界题:分别为“到达目标”和“采样器每 32 步切片但保留下一状态”写出 ,解释两者为何不同。
- Title: 强化学习:动态规划、Monte Carlo 与 TD
- Author: Charles
- Created at : 2026-06-27 09:00:00
- Updated at : 2026-06-27 09:00:00
- Link: https://charles2530.github.io/2026/06/27/ai-files-reinforcement-learning-dynamic-programming-monte-carlo-td/
- License: This work is licensed under CC BY-NC-SA 4.0.