第 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_pi | O(|S|^3) |
| 迭代 | V_{k+1} = R_pi + gamma*P_pi*V_k | O(|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)下值迭代的收敛速度
📊 训练曲线说明
✅ 验证通过!实机运行结果:
完整数据: 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')]
贝尔曼方程的收敛性分析
算法的收敛性是其理论保证的核心。对于贝尔曼方程:
- 学习率条件: sum alpha_t = infinity, sum alpha_t^2 < infinity
- 探索条件: 所有(s,a)对被无限次访问
- 收缩性: 贝尔曼算子是gamma-收缩映射
- 收敛速度: O(gamma^k) 或 O(1/sqrt(t))
贝尔曼方程的复杂度分析
| 维度 | 时间复杂度 | 空间复杂度 |
| 每步更新 | O(|S|) 或 O(batch_size) | O(|S|*|A|) 或 O(params) |
| 完整迭代 | O(|S|^2*|A|) 或 O(n_episodes) | O(|S|*|A|) 或 O(buffer_size) |
💡 理论与实践:理论收敛性保证了算法在大样本下能找到最优解,但实践中样本效率、训练稳定性和超参数敏感性同样重要。贝尔曼方程在这些方面的表现需要通过实验验证。
🎯 本课小结
本课深入讲解了贝尔曼方程的核心原理。关键要点:
- 理解算法的数学基础和推导过程
- 掌握代码实现的关键步骤
- 通过实验验证理论预测
- 了解算法的适用范围和局限性
🏆
成就解锁:贝尔曼方程
完成本课所有练习,掌握状态值函数Vπ的核心原理