主题
贝尔曼方程
贝尔曼方程(Bellman equation)揭示了价值函数的递归结构:一个状态的价值,等于“走一步拿到的即时奖励”加上“下一个状态价值的折扣期望”。它分为描述给定策略价值的贝尔曼期望方程和描述最优价值的贝尔曼最优方程。几乎所有强化学习算法——动态规划、TD 学习、Q-learning、DQN、Actor-Critic——都可以看作在用不同方式近似求解这两个方程。
本节沿用 MDP 一节的记号:状态
动机:为什么需要递归形式
按定义,
关键观察是回报本身满足递归关系:
于是“对整条未来求期望”可以拆成“对一步求期望 + 对下一个状态的价值求期望”。这样价值函数就满足一组只涉及相邻两个时刻的方程,可以迭代求解,也可以从单步样本中学习。
贝尔曼期望方程
状态价值函数的递归形式
从定义出发,利用
这就是
动作价值函数的递归形式
同理可得:
把其中一条代入另一条,就得到上面两个方程。
矩阵形式与解析解
对有限 MDP,记
:策略 下的期望即时奖励; :策略 下的状态转移矩阵。
则贝尔曼期望方程可以写成线性方程组:
当
贝尔曼算子与压缩映射
定义贝尔曼期望算子
则
由巴拿赫不动点定理,从任意
贝尔曼最优方程
最优状态价值
最优价值函数
最优动作价值
一旦得到
相应的贝尔曼最优算子
为什么没有闭式解
期望方程是线性的,可以直接解线性方程组;最优方程中含有
回溯图(Backup Diagram)
回溯图用图形表示一次更新“从哪里取信息”。空心圆表示状态,实心圆表示状态—动作对:
flowchart TD
s((s)) -->|"π(a|s)"| a1((s,a₁))
s -->|"π(a|s)"| a2((s,a₂))
a1 -->|"p(s',r|s,a)"| s1((s'))
a1 -->|"p(s',r|s,a)"| s2((s''))
a2 -->|"p(s',r|s,a)"| s3((s'''))
的回溯:从 出发,对动作按 加权,再对后继状态按 加权,把后继状态的价值“回传”给 。 的回溯:结构相同,但在动作这一层取最大值而不是加权平均。
不同算法的区别可以概括为回溯的宽度(是否对所有可能的后继求期望)和深度(是只看一步还是一直看到回合结束):
| 方法 | 宽度 | 深度 |
|---|---|---|
| 动态规划 | 全宽(对所有后继求期望) | 一步 |
| 蒙特卡洛 | 采样(单条轨迹) | 整个回合 |
| TD(0) | 采样 | 一步 |
| 穷举搜索 | 全宽 | 整个回合 |
例题:FrozenLake 上的价值计算
下面在 Gymnasium 的 FrozenLake-v1(4×4,地面打滑)上,计算均匀随机策略的状态价值,分别用矩阵解析解和反复应用贝尔曼期望算子两种方法,验证两者一致。env.unwrapped.P 给出了完整的环境模型 P[s][a] = [(概率, 下一状态, 奖励, 是否终止), ...]。
py
"""贝尔曼期望方程:用矩阵形式求解 FrozenLake 上均匀随机策略的状态价值,并与迭代法对比。"""
import gymnasium as gym
import numpy as np
env = gym.make("FrozenLake-v1", is_slippery=True)
P = env.unwrapped.P # P[s][a] = [(prob, s_next, reward, terminated), ...]
nS, nA = env.observation_space.n, env.action_space.n
gamma = 0.9
pi = np.full((nS, nA), 1.0 / nA) # 均匀随机策略 π(a|s)
# 构造 P_π(nS×nS)和 r_π(nS)
P_pi = np.zeros((nS, nS))
r_pi = np.zeros(nS)
for s in range(nS):
for a in range(nA):
for prob, s2, r, done in P[s][a]:
P_pi[s, s2] += pi[s, a] * prob * (0.0 if done else 1.0) # 终止后不再有未来价值
r_pi[s] += pi[s, a] * prob * r
# 方法一:解析解 v = (I - γ P_π)^{-1} r_π
v_exact = np.linalg.solve(np.eye(nS) - gamma * P_pi, r_pi)
# 方法二:反复应用贝尔曼期望算子直到收敛
v = np.zeros(nS)
for it in range(1000):
v_new = r_pi + gamma * P_pi @ v
if np.max(np.abs(v_new - v)) < 1e-10:
break
v = v_new
print("解析解:\n", v_exact.reshape(4, 4).round(4))
print(f"迭代 {it} 次后与解析解的最大误差: {np.max(np.abs(v - v_exact)):.2e}")1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
在本站环境(Gymnasium 1.4.0)中实际运行的输出如下:
text
解析解:
[[0.0045 0.0042 0.0101 0.0041]
[0.0067 0. 0.0263 0. ]
[0.0187 0.0576 0.107 0. ]
[0. 0.1304 0.3915 0. ]]
迭代 63 次后与解析解的最大误差: 3.30e-101
2
3
4
5
6
2
3
4
5
6
可以看到:(1) 随机策略下起点价值只有约 0.0045,说明随机乱走几乎到不了终点;(2) 越靠近右下角终点,价值越高;(3) 冰洞和终点是终止状态,价值为 0;(4) 迭代法 63 次后与解析解的误差已在
常见误区
- 把终止状态的价值也算进去:到达终止状态后不再有未来奖励,计算目标时要乘以
。代码里(0.0 if done else 1.0)就是这个作用。 - 混淆期望方程和最优方程:前者评估“某个给定策略有多好”,后者刻画“最好能有多好”。
- 以为
唯一意味着最优策略唯一:最优价值函数唯一,但可能有多个动作并列最优,因此最优策略可以不唯一。
小结
- 回报的递归关系
导出了价值函数的贝尔曼方程。 - 贝尔曼期望方程是线性的,可直接求解;贝尔曼最优方程含
,需要迭代求解。 - 两个贝尔曼算子都是
-压缩映射,保证了迭代算法的收敛。 - 后续所有算法都可以看作用不同的“宽度 × 深度”回溯来近似求解贝尔曼方程。
练习题
- 从
的定义出发,完整推导 的贝尔曼期望方程。 - 证明贝尔曼期望算子
在无穷范数下是 -压缩映射。(提示: ,其中 。) - 在 MDP 一节的两状态例子中,写出贝尔曼最优方程并手算
、 。 - 修改例题代码,把
改为 0.99,起点价值如何变化?为什么? - 修改例题代码,计算“永远向右”的确定性策略的价值,并与随机策略比较。
延伸阅读
交互工具:网格世界:价值迭代 / 策略迭代可视化
参考文献
- Bellman, R. (1957). Dynamic Programming. Princeton University Press.
- Sutton, R. S., & Barto, A. G. (2018). Reinforcement Learning: An Introduction (2nd ed.), 第 3 章. MIT Press.
下一步
继续阅读:动态规划——用迭代的方式求解贝尔曼方程,并找到最优策略。