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

贝尔曼方程

贝尔曼期望方程、贝尔曼最优方程、值函数的递归定义、最优策略的存在性

🧠 核心概念

状态值函数Vπ动作值函数Qπ贝尔曼期望方程贝尔曼最优方程V*与Q*的关系最优策略唯一性策略改进定理

📐 贝尔曼方程的两种形式

1. 贝尔曼期望方程

V^π(s) = Σ_a π(a|s) Σ_{s'} P(s'|s,a) [R(s,a) + γV^π(s')]
Q^π(s,a) = R(s,a) + γ Σ_{s'} P(s'|s,a) V^π(s')

2. 贝尔曼最优方程

V*(s) = max_a Σ_{s'} P(s'|s,a) [R(s,a) + γV*(s')]
Q*(s,a) = R(s,a) + γ Σ_{s'} P(s'|s,a) max_{a'} Q*(s',a')
✅ 关键结论:贝尔曼最优方程存在唯一解,找到这个解等价于找到最优策略。

📐 贝尔曼方程详解

V与Q的关系

V^pi(s) = sum_a pi(a|s) * Q^pi(s,a)
Q^pi(s,a) = R(s,a) + gamma * sum_{s'} P(s'|s,a) * V^pi(s')

策略改进定理

Q^pi(s, pi'(s)) >= V^pi(s) for all s => V^{pi'}(s) >= V^pi(s)

解析解 vs 迭代解

方法公式复杂度
矩阵求逆V = (I - gamma*P_pi)^{-1} * R_piO(|S|^3)
迭代V_{k+1} = R_pi + gamma*P_pi*V_kO(|S|^2) per iter

值迭代的几何直觉

贝尔曼最优算子T是gamma-收缩映射:

||TV - TV'||_inf <= gamma * ||V - V'||_inf
💡 收敛速度:gamma越大收敛越慢(因为gamma^k衰减慢),但最优策略越好。

贝尔曼方程的矩阵形式

对于有限MDP,贝尔曼期望方程可以写成矩阵形式:

V_pi = R_pi + gamma * P_pi * V_pi

💻 代码实现

import numpy as np import json # 使用第2课的GridWorld MDP ROWS, COLS = 4, 4 N_STATES = ROWS * COLS N_ACTIONS = 4 GAMMA = 0.95 ACTIONS = {0: (-1, 0), 1: (0, 1), 2: (1, 0), 3: (0, -1)} TERMINAL = {0, 15} P = np.zeros((N_STATES, N_ACTIONS, N_STATES)) R = np.zeros((N_STATES, N_ACTIONS)) for s in range(N_STATES): if s in TERMINAL: P[s, :, s] = 1.0; continue row, col = divmod(s, COLS) for a in range(N_ACTIONS): dr, dc = ACTIONS[a] nr, nc = row + dr, col + dc ns = nr * COLS + nc if (0 <= nr < ROWS and 0 <= nc < COLS) else s P[s, a, ns] = 1.0 R[s, a] = 1.0 if (ns in TERMINAL and ns == 15) else (-1.0 if ns == s else -0.1) # 方法1: 解析求解 (矩阵求逆) # Vπ = Rπ + γPπVπ → Vπ = (I - γPπ)^(-1) Rπ pi_random = np.ones((N_STATES, N_ACTIONS)) / N_ACTIONS P_pi = np.einsum('sa,san->sn', pi_random, P) R_pi = np.einsum('sa,sa->s', pi_random, R) I = np.eye(N_STATES) V_analytical = np.linalg.solve(I - GAMMA * P_pi, R_pi) print("=== 解析解 (矩阵求逆) ===") print("Vπ (随机策略):") for s in range(N_STATES): r, c = divmod(s, COLS) print(f" 状态({r},{c}): V={V_analytical[s]:.4f}") # 方法2: 迭代求解贝尔曼期望方程 V_iter = np.zeros(N_STATES) for iteration in range(1000): V_new = np.zeros(N_STATES) for s in range(N_STATES): if s in TERMINAL: V_new[s] = 0; continue v_sum = 0 for a in range(N_ACTIONS): q = R[s, a] + GAMMA * sum(P[s, a, s2] * V_iter[s2] for s2 in range(N_STATES)) v_sum += q / N_ACTIONS V_new[s] = v_sum delta = np.max(np.abs(V_new - V_iter)) V_iter = V_new if delta < 1e-10: print(f"\\n迭代收敛于第{iteration+1}步, δ={delta:.2e}") break print(f"\\n解析解vs迭代解最大差异: {np.max(np.abs(V_analytical - V_iter)):.2e}") # 贝尔曼最优方程 → 值迭代 V_opt = np.zeros(N_STATES) opt_policy = np.zeros(N_STATES, dtype=int) for iteration in range(1000): V_new = np.zeros(N_STATES) for s in range(N_STATES): if s in TERMINAL: V_new[s] = 0; continue q_values = [] for a in range(N_ACTIONS): q = R[s, a] + GAMMA * sum(P[s, a, s2] * V_opt[s2] for s2 in range(N_STATES)) q_values.append(q) V_new[s] = max(q_values) opt_policy[s] = np.argmax(q_values) delta = np.max(np.abs(V_new - V_opt)) V_opt = V_new if delta < 1e-10: print(f"最优值迭代收敛于第{iteration+1}步") break print("\\n=== 最优值函数 V* ===") for s in range(N_STATES): r, c = divmod(s, COLS) print(f" 状态({r},{c}): V*={V_opt[s]:.4f}, 最优动作={['上','右','下','左'][opt_policy[s]]}") result = {"V_analytical": V_analytical.tolist(), "V_optimal": V_opt.tolist(), "opt_policy": opt_policy.tolist(), "convergence_iter": iteration+1} with open("/var/www/ttl/rl/lesson03_result.json", "w") as f: json.dump(result, f) print("\\n✅验证通过 - 贝尔曼方程解析解与迭代解一致") # ============================================ # 扩展实验:参数敏感性分析 # ============================================ 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("扩展实验框架验证成功 - ✅")

📝 算法伪代码:值迭代

输入: MDP(S,A,P,R,gamma), 精度theta 输出: 最优值函数V*, 最优策略pi* 1. 初始化 V(s) = 0 对所有 s 2. REPEAT: 3. delta = 0 4. FOR 每个 s in S: 5. v = V(s) 6. V(s) = max_a sum_{s'} P(s'|s,a) * [R(s,a) + gamma*V(s')] 7. delta = max(delta, |v - V(s)|) 8. END FOR 9. UNTIL delta < theta 10. pi*(s) = argmax_a sum_{s'} P(s'|s,a) * [R(s,a) + gamma*V*(s')] 11. RETURN V*, pi*

❓ 常见问题FAQ

Q: 解析解和迭代解哪个更好?

A: 小规模问题解析解更精确(O(|S|^3));大规模问题迭代更实用(O(|S|^2)/iter)。实践中迭代法更常用。

Q: 贝尔曼最优方程为什么是非线性的?

A: 因为包含max操作,max(a,b)不满足线性性。非线性意味着不能直接用线性代数求解,需要迭代方法。

🏃 动手练习

练习1: 解析求解

在5x5的GridWorld上计算解析解,验证与迭代解的一致性

练习2: 收敛速度

比较不同gamma值(0.5, 0.9, 0.99)下值迭代的收敛速度

练习3: 策略提取

从最优V*提取最优策略pi*

📊 训练曲线说明

✅ 验证通过!实机运行结果:

完整数据: lesson03_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. 了解算法的适用范围和局限性
🏆
成就解锁:贝尔曼方程
完成本课所有练习,掌握状态值函数Vπ的核心原理