策略迭代与值迭代:从零开始理解两种核心算法
大家好,我是你们的老朋友。今天咱们来聊聊强化学习里两个最基础、也最容易被搞混的算法——策略迭代和值迭代。说实话,我刚开始学的时候,也觉得这俩东西长得太像了,到底有什么区别?什么时候该用哪个?别急,咱们一个一个拆开来看。
核心知识点速览
- 策略迭代 = 策略评估 + 策略改进,两个步骤交替进行
- 值迭代 = 策略评估的简化版 + 隐式策略改进,一步到位
- 策略迭代收敛更快(迭代次数少),值迭代计算更简单(每次迭代快)
策略迭代算法:先评估,再改进
策略迭代的思路其实很直观。你想想看,如果你有一个策略,你首先得知道这个策略到底好不好,对吧?这就是策略评估要做的事。然后根据评估结果,你再去改进这个策略。就这么简单。
策略评估:算清楚当前策略的价值
策略评估说白了,就是给定一个策略 π,我们算出每个状态的价值 Vπ(s)。怎么算?用贝尔曼期望方程迭代求解。
# 策略评估的伪代码
def policy_evaluation(pi, P, R, gamma, theta):
V = zeros(num_states)
while True:
delta = 0
for s in range(num_states):
v = V[s]
# 根据当前策略计算新价值
a = pi[s]
V[s] = sum(P[s][a][s'] * (R[s][a][s'] + gamma * V[s']) for s' in range(num_states))
delta = max(delta, abs(v - V[s]))
if delta < theta:
break
return V
嗯,这里要注意一个细节:收敛阈值 theta 怎么设?我个人的习惯是设 1e-6,但如果你追求速度,1e-4 也够用。我在项目中遇到过一个问题,阈值设得太小(1e-8),结果迭代了上千次还没收敛,白白浪费计算资源。
策略改进:让策略变得更好
评估完了,接下来就是改进。怎么改进?贪心策略!对于每个状态,我们选择能带来最大价值的动作。
# 策略改进的伪代码
def policy_improvement(V, P, R, gamma):
policy = zeros(num_states, dtype=int)
for s in range(num_states):
# 计算每个动作的价值
q_values = [sum(P[s][a][s'] * (R[s][a][s'] + gamma * V[s']) for s' in range(num_states))
for a in range(num_actions)]
policy[s] = argmax(q_values)
return policy
我曾经犯过一个低级错误——忘了考虑动作空间为空的情况。虽然理论上不会出现,但实际项目中数据可能有缺失,所以建议加个异常处理。
策略迭代的完整流程
把评估和改进串起来,就是完整的策略迭代算法:
def policy_iteration(P, R, gamma, theta):
# 初始化随机策略
pi = random_policy(num_states, num_actions)
while True:
# 策略评估
V = policy_evaluation(pi, P, R, gamma, theta)
# 策略改进
pi_new = policy_improvement(V, P, R, gamma)
# 检查是否收敛
if (pi_new == pi).all():
break
pi = pi_new
return pi, V
小技巧:策略迭代通常只需要几次迭代就能收敛。我见过一个网格世界问题,策略迭代只用了 3 次外循环就找到了最优策略,而值迭代跑了 50 多步。所以别被「迭代」两个字吓到,实际跑起来很快。
值迭代算法:一步到位
值迭代的思路更直接——我们不去显式地维护策略,而是直接更新价值函数。每次更新时,我们直接取所有动作中的最大值。
def value_iteration(P, R, gamma, theta):
V = zeros(num_states)
while True:
delta = 0
for s in range(num_states):
v = V[s]
# 直接取所有动作的最大值
V[s] = max(sum(P[s][a][s'] * (R[s][a][s'] + gamma * V[s']) for s' in range(num_states))
for a in range(num_actions))
delta = max(delta, abs(v - V[s]))
if delta < theta:
break
# 从价值函数提取策略
pi = policy_improvement(V, P, R, gamma)
return pi, V
你看,值迭代把策略评估和策略改进合并成了一个步骤。每次更新 V[s] 的时候,其实就是在做「隐式」的策略改进——因为我们选了最大值,相当于默认采用了最优动作。
注意:值迭代的收敛条件跟策略评估一样,都是看价值函数的变化量。但值迭代的收敛速度通常比策略评估慢,因为每次更新只改一点点。我建议在值迭代中把 theta 设得稍微大一点,比如 1e-3,这样能快很多。
策略迭代 vs 值迭代:到底选哪个?
这个问题我经常被问到。说实话,没有绝对的答案,得看具体情况。我整理了一个对比表格,方便你快速决策:
| 对比维度 | 策略迭代 | 值迭代 |
|---|---|---|
| 迭代次数 | 少(通常 < 10 次) | 多(可能上百次) |
| 每次迭代计算量 | 大(需要完整策略评估) | 小(一次扫描即可) |
| 收敛速度 | 快(外循环少) | 慢(需要很多步) |
| 实现难度 | 中等 | 简单 |
| 适用场景 | 状态空间小,需要精确解 | 状态空间大,追求实现简单 |
我个人更倾向于:如果状态空间小于 1000,用策略迭代;如果大于 10000,用值迭代。中间那部分,看心情吧(笑)。
收敛性分析:为什么它们能收敛?
这个问题有点理论,但我尽量说得通俗点。策略迭代和值迭代能收敛,本质上是因为它们都在做「压缩映射」——每次迭代都在缩小价值函数的误差。
策略迭代的收敛性
策略迭代的收敛性很好理解:每次策略改进后,新策略的价值函数一定不差于旧策略。因为我们是贪心选择,所以 Vπ_new ≥ Vπ_old。而策略空间是有限的(状态数 × 动作数),所以最终一定会收敛到最优策略。
关键点:策略迭代在有限 MDP 中保证在有限步内收敛到最优策略。这个「有限步」通常很小,我见过的最极端情况也就 20 步左右。
值迭代的收敛性
值迭代的收敛性依赖于贝尔曼最优算子 T* 是压缩映射。说白了,每次应用 T*,价值函数的误差都会缩小 γ 倍(γ 是折扣因子)。所以只要 γ < 1,最终一定会收敛。
嗯,这里有个坑要注意:如果 γ = 1(无折扣),值迭代可能不收敛。我在项目中遇到过这个问题,当时没注意 γ 的设置,结果价值函数一直在震荡。后来把 γ 改成 0.99,问题就解决了。
知识体系总览
为了让你更直观地理解本章的知识结构,我画了一张流程图:
这张图把两个算法的流程和对比都画出来了。你可以看到,策略迭代是「评估→改进→评估→改进...」的循环,而值迭代是直接更新价值函数,最后再提取策略。
我的建议:刚开始学的时候,先手算一遍策略迭代,再手算一遍值迭代。找个 3×3 的网格世界,手动迭代 2-3 步,你就能深刻理解两者的区别。我当年就是这么学的,效果比看十遍书都好。
好了,这一章的内容就到这里。策略迭代和值迭代是强化学习的基石,理解了它们,后面的 Q-learning、SARSA 学起来就轻松多了。记住:策略迭代像「慢工出细活」,值迭代像「快刀斩乱麻」,各有各的妙处。
公众号:蓝海资料掘金营,微信deep3321