第三章 动态规划与策略迭代:基于模型的强化学习方法
各位同学,今天我们来聊聊动态规划。说实话,这名字听起来挺吓人,但说白了,它就是一套「拆解问题」的数学工具。在强化学习里,动态规划是我们最早接触的、也是最有「确定性」的一类方法。
我个人习惯把这一章叫做「理想国里的算法」。为什么?因为动态规划要求我们完全知道环境的模型——也就是状态转移概率和奖励函数。这在真实世界里几乎不可能,但理解它,是后面所有算法的基石。
3.1 策略评估:算清楚当前策略到底有多好
先问一个问题:你手里有一个策略 π,它告诉你在每个状态该做什么动作。那这个策略到底好不好?
好,我们就需要量化它。策略评估做的就是这件事——计算每个状态的价值函数 Vπ(s)。
公式很简单,就是贝尔曼期望方程:
Vπ(s) = Σa π(a|s) Σs',r p(s',r|s,a) [r + γ Vπ(s')]
嗯,这里要注意:这个方程是自指的。Vπ(s) 依赖于 Vπ(s'),而 s' 又是下一个状态。怎么解?迭代!
我记得刚开始学的时候,总觉得这玩意儿要解到什么时候才算完。后来发现,只要迭代足够多次,V 会收敛到一个固定点。这就是「迭代策略评估」的核心思想。
3.2 策略改进:让策略变得更好一点
评估完了,然后呢?我们得改进策略啊。
策略改进的思路很直接:在当前状态 s,我们看看有没有比 π(s) 更好的动作。怎么判断?用动作价值函数 Qπ(s,a)。
如果存在某个动作 a',使得 Qπ(s,a') > Vπ(s),那就把策略改成 a'。这就是贪心策略改进。
我在项目中遇到过一个问题:贪心改进会不会导致策略震荡?答案是:不会。策略改进定理保证了,每次改进后,新策略一定比旧策略好,或者至少一样好。
3.3 策略迭代:评估 + 改进,循环往复
把策略评估和策略改进串起来,就是策略迭代算法。流程如下:
- 初始化一个随机策略 π
- 策略评估:计算 Vπ
- 策略改进:基于 Vπ 生成新策略 π'
- 如果 π' == π,停止;否则回到第2步
你想想看,这个过程像不像一个「自我进化」的循环?每次评估完,改进一下;改进了,再评估。直到策略稳定下来。
我建议初学者先手算一个小例子,比如4×4的网格世界。手动迭代两轮,你就能深刻理解「评估」和「改进」是怎么交替进行的。
3.4 值迭代:换个思路,直接算最优价值
策略迭代需要反复做策略评估,每次评估又要迭代很多次。有没有更高效的方法?有,值迭代。
值迭代的核心思想是:不显式维护策略,而是直接更新价值函数。更新公式是:
Vk+1(s) = maxa Σs',r p(s',r|s,a) [r + γ Vk(s')]
注意看,这里用了 max,而不是策略 π 的期望。也就是说,每次更新时,我们假设自己会选最好的动作。
说白了,值迭代就是把策略改进「揉进」了价值更新里。一步到位,直接逼近最优价值函数。
| 算法 | 核心操作 | 收敛速度 | 适用场景 |
|---|---|---|---|
| 策略迭代 | 评估 + 改进交替 | 迭代次数少,但每次评估耗时 | 状态空间较小 |
| 值迭代 | 直接更新价值 | 迭代次数多,但每次更新快 | 状态空间较大 |
3.5 核心逻辑图:动态规划家族
下面我用一张SVG图来展示本章的知识体系。这张图我画了好几次才满意,希望能帮你理清思路。
3.6 代码实现:手写一个策略迭代
光说不练假把式。下面是我写的一个简化版策略迭代,用于一个5×5的网格世界。代码不长,但包含了所有核心逻辑。
import numpy as np
# 环境参数
n_states = 25
n_actions = 4 # 上下左右
gamma = 0.9
theta = 1e-6 # 收敛阈值
# 初始化策略和价值
policy = np.zeros(n_states, dtype=int)
V = np.zeros(n_states)
# 策略评估
def policy_evaluation(policy, V, gamma, theta):
while True:
delta = 0
for s in range(n_states):
v = V[s]
# 根据策略选择动作
a = policy[s]
# 假设确定性转移,到下一个状态
s_next = get_next_state(s, a)
reward = get_reward(s, a)
V[s] = reward + gamma * V[s_next]
delta = max(delta, abs(v - V[s]))
if delta < theta:
break
return V
# 策略改进
def policy_improvement(policy, V, gamma):
policy_stable = True
for s in range(n_states):
old_action = policy[s]
# 贪心选择最优动作
action_values = []
for a in range(n_actions):
s_next = get_next_state(s, a)
reward = get_reward(s, a)
action_values.append(reward + gamma * V[s_next])
policy[s] = np.argmax(action_values)
if old_action != policy[s]:
policy_stable = False
return policy, policy_stable
# 主循环
while True:
V = policy_evaluation(policy, V, gamma, theta)
policy, stable = policy_improvement(policy, V, gamma)
if stable:
break
print("最优策略已找到!")
print(policy.reshape(5, 5))
3.7 策略迭代 vs 值迭代:怎么选?
这个问题我经常被问到。我的建议是:
- 状态空间小(比如小于1000):用策略迭代。它收敛需要的迭代次数少,虽然每次评估耗时,但总体更快。
- 状态空间大:用值迭代。每次更新只做一次扫描,内存占用也小。
- 如果你不确定:先试值迭代。它实现简单,不容易出错。
我记得有一次做机器人路径规划,状态空间有上万个。策略迭代跑了半天没出结果,换成值迭代后,几分钟就收敛了。嗯,选对工具很重要。
好了,这一章的内容就到这里。动态规划是强化学习的「第一性原理」,理解了它,后面的算法你就能触类旁通。代码多跑几遍,手算几个小例子,你会发现自己对「价值」和「策略」的理解会深很多。
可可精品资料库