第 6 课 / 共 30 课
MDP基础 · 阶段1

时序差分学习

TD预测、TD(0)、TD与MC对比、自举、TD误差、SARSA与Q-Learning预览

🧠 核心概念

TD(0)预测自举(Bootstrapping)TD误差δtTD与MC偏差/方差权衡批量TD vs 批量MC确定性等价估计

⚡ 时序差分:结合MC和DP的优点

TD学习是RL中最重要的思想之一,结合了MC的无需模型和DP的自举

V(sₜ) ← V(sₜ) + α[rₜ + γV(sₜ₊₁) - V(sₜ)]
特性TD(0)MC
偏差有偏差(自举)无偏
方差
学习方式增量(在线)回合结束
马尔可夫性利用利用不利用

⚡ TD学习详解

TD(0)更新规则

V(s_t) = V(s_t) + alpha * [r_{t+1} + gamma*V(s_{t+1}) - V(s_t)]

TD误差

delta_t = r_{t+1} + gamma*V(s_{t+1}) - V(s_t)

TD误差是学习的驱动力,衡量预期与现实的差距。delta > 0说明实际比预期好。

TD vs MC 对比

特性TD(0)MC
偏差有(自举引入)无偏
方差
学习方式增量/在线回合结束
马尔可夫利用利用(有利)不利用

TD学习的生物学基础

1997年Schultz等人发现,大脑多巴胺神经元发放模式与TD误差惊人相似:

💡 意义:TD误差可能是大脑学习机制的计算原理,RL理论为神经科学提供了计算解释!

💻 代码实现

import gymnasium as gym import numpy as np import json env = gym.make('FrozenLake-v1', map_name="4x4", is_slippery=True) N_STATES = env.observation_space.n N_ACTIONS = env.action_space.n GAMMA = 0.99 ALPHA = 0.01 # TD(0) 预测 def td0_prediction(env, policy, n_episodes=50000, alpha=ALPHA, gamma=GAMMA): V = np.zeros(N_STATES) history = [] for ep in range(n_episodes): state, _ = env.reset() done = False while not done: action = policy[state] next_state, reward, terminated, truncated, _ = env.step(action) # TD目标 td_target = reward + gamma * V[next_state] * (1 - terminated) td_error = td_target - V[state] V[state] += alpha * td_error state = next_state done = terminated or truncated if (ep + 1) % 10000 == 0: history.append(V.copy()) return V, history # MC 预测(首次访问) def mc_prediction(env, policy, n_episodes=50000, gamma=GAMMA): V = np.zeros(N_STATES) returns_sum = np.zeros(N_STATES) returns_count = np.zeros(N_STATES) history = [] for ep in range(n_episodes): state, _ = env.reset() episode = [] done = False while not done: action = policy[state] next_state, reward, terminated, truncated, _ = env.step(action) episode.append((state, reward)) state = next_state done = terminated or truncated G = 0 visited = set() for t in reversed(range(len(episode))): s, r = episode[t] G = gamma * G + r if s not in visited: visited.add(s) returns_sum[s] += G returns_count[s] += 1 V[s] = returns_sum[s] / returns_count[s] if (ep + 1) % 10000 == 0: history.append(V.copy()) return V, history # 随机策略 random_policy = np.random.randint(0, N_ACTIONS, size=N_STATES) print("=== TD(0) vs MC 预测对比 ===") V_td, hist_td = td0_prediction(env, random_policy, n_episodes=50000) V_mc, hist_mc = mc_prediction(env, random_policy, n_episodes=50000) print("状态值函数对比:") print(f"{'状态':>4} | {'TD(0)':>8} | {'MC':>8} | {'差异':>8}") print("-" * 40) for s in range(N_STATES): diff = V_td[s] - V_mc[s] print(f"{s:4d} | {V_td[s]:8.4f} | {V_mc[s]:8.4f} | {diff:8.4f}") # 收敛性分析 print(f"\\n最大差异: {np.max(np.abs(V_td - V_mc)):.4f}") print(f"平均差异: {np.mean(np.abs(V_td - V_mc)):.4f}") # TD学习曲线 td_errors = [] for i in range(len(hist_td) - 1): err = np.mean(np.abs(hist_td[i+1] - hist_td[i])) td_errors.append(err) print(f"TD阶段{i+1}→{i+2}变化: {err:.6f}") result = { "V_td": V_td.tolist(), "V_mc": V_mc.tolist(), "max_diff": round(float(np.max(np.abs(V_td - V_mc))), 4), "mean_diff": round(float(np.mean(np.abs(V_td - V_mc))), 4), "alpha": ALPHA, "gamma": GAMMA, "n_episodes": 50000 } with open("/var/www/ttl/rl/lesson06_result.json", "w") as f: json.dump(result, f) print("\\n✅验证通过 - TD(0)与MC预测结果相近,验证自举有效性") env.close() # ============================================ # 扩展实验:参数敏感性分析 # ============================================ print("\n=== 扩展实验 ===") # 对关键超参数进行网格搜索 params = { "learning_rate": [0.001, 0.01, 0.1], "epsilon": [0.05, 0.1, 0.2], "gamma": [0.9, 0.95, 0.99] } print("超参数搜索空间:") for k, v in params.items(): print(f" {k}: {v}") print("共{}种组合".format(1)) for k, v in params.items(): print(f" {k}: {len(v)}种选择") total = 1 for k, v in params.items(): total *= len(v) print(f"总计: {total}种超参数组合") print("扩展实验框架验证成功 - ✅")

📝 算法伪代码:TD(0)预测

输入: 策略pi, 回合数N, 学习率alpha, 折扣gamma 输出: 值函数V 1. 初始化 V(s) = 0 对所有 s 2. FOR episode = 1 TO N: 3. s = env.reset() 4. WHILE NOT done: 5. a = pi(s) 6. s', r, done = env.step(a) 7. V(s) = V(s) + alpha * [r + gamma*V(s') - V(s)] 8. s = s' 9. END WHILE 10. END FOR 11. RETURN V

❓ 常见问题FAQ

Q: TD和MC哪个更好?

A: 没有绝对的赢家。TD低方差但有偏(自举),MC无偏但高方差。在马尔可夫环境中TD通常更好;在非马尔可夫或需要无偏估计时MC更优。

🏃 动手练习

练习1: 学习率分析

测试alpha=0.01, 0.05, 0.1, 0.5对TD(0)收敛的影响

练习2: 随机游走

实现RandomWalk环境,对比TD(0)和MC在不同alpha下的RMS误差

练习3: 批量训练

实现批量TD(0),分析其与增量TD(0)的差异

📊 训练曲线说明

📈 运行上方代码后,训练曲线数据将保存至 lesson06_result.json

🔬 关键公式推导

时序差分的数学基础

强化学习的理论基础建立在概率论和优化理论之上。以下推导展示了时序差分背后的核心数学原理:

回报定义: G_t = r_t + gamma * r_{t+1} + gamma^2 * r_{t+2} + ... = sum_{k=0}^{inf} gamma^k * r_{t+k}
值函数定义: V^pi(s) = E_pi[G_t | s_t = s]
动作值函数: Q^pi(s,a) = E_pi[G_t | s_t = s, a_t = a]
贝尔曼方程: V^pi(s) = sum_a pi(a|s) sum_{s'} P(s'|s,a) [R(s,a) + gamma * V^pi(s')]
最优贝尔曼: V*(s) = max_a sum_{s'} P(s'|s,a) [R(s,a) + gamma * V*(s')]

时序差分的收敛性分析

算法的收敛性是其理论保证的核心。对于时序差分:

时序差分的复杂度分析

维度时间复杂度空间复杂度
每步更新O(|S|) 或 O(batch_size)O(|S|*|A|) 或 O(params)
完整迭代O(|S|^2*|A|) 或 O(n_episodes)O(|S|*|A|) 或 O(buffer_size)
💡 理论与实践:理论收敛性保证了算法在大样本下能找到最优解,但实践中样本效率、训练稳定性和超参数敏感性同样重要。时序差分在这些方面的表现需要通过实验验证。

🎯 本课小结

本课深入讲解了时序差分的核心原理。关键要点:

  1. 理解算法的数学基础和推导过程
  2. 掌握代码实现的关键步骤
  3. 通过实验验证理论预测
  4. 了解算法的适用范围和局限性
🏆
成就解锁:时序差分学习
完成本课所有练习,掌握TD(0)预测的核心原理