3、动态规划与策略迭代:策略评估、策略改进、策略迭代算法、值迭代算法、Grid World示例

好,咱们进入第三章。说实话,动态规划这块儿,是强化学习里最「数学」的部分之一。但别怕,我当年刚接触时也觉得头大,后来发现,说白了就是一套「先猜后改」的套路。你想想看,我们做路径规划,不也是先画一条线,再慢慢调优吗?

这一章,我会带你手撕策略迭代和值迭代。咱们用经典的 Grid World 做例子,把每个步骤掰开揉碎。嗯,开始吧。

3.1 策略评估:先看看当前策略有多烂

策略评估,英文叫 Policy Evaluation。它的任务很简单:给定一个策略 π,算出每个状态的价值 Vπ(s)。

怎么算?用贝尔曼期望方程。我习惯把它写成这样:

V(s) = Σ π(a|s) * Σ P(s'|s,a) * [R(s,a,s') + γ * V(s')]

看着复杂?其实就是一个迭代过程。你初始化所有 V(s)=0,然后不断用上面的公式更新,直到收敛。

我在项目中遇到过一个问题:如果状态空间很大,比如 1000x1000 的网格,直接迭代会慢得让人崩溃。这时候我一般会设一个阈值 θ,比如 0.001,V 的变化小于 θ 就停。别傻等完全收敛,工程上够用就行。

我的小技巧: 迭代时记录一下最大变化量 Δ。如果 Δ 连续几次都在下降,说明快收敛了。我曾经靠这个提前终止迭代,省了不少时间。

3.2 策略改进:让策略变得更好

评估完了,发现策略不够好?那就改。策略改进(Policy Improvement)的核心思想是:贪心。

对于每个状态 s,我们看看:如果我不按当前策略走,而是选一个能让 V(s) 最大的动作 a,会怎样?公式如下:

π_new(s) = argmax_a Σ P(s'|s,a) * [R(s,a,s') + γ * V(s')]

说白了,就是「哪条路未来收益最大,我就走哪条」。你想想看,这跟咱们平时做决策一样——哪个选项回报高,就选哪个。

注意: 策略改进不一定一步到位。有时候你改完一步,发现新策略还不如旧的。别慌,这是正常的。多迭代几次就好了。我曾经在 Grid World 上试过,第一次改进后路径反而绕远了,但第三次迭代后就找到了最优解。

3.3 策略迭代算法:评估 + 改进,循环往复

策略迭代(Policy Iteration)就是把评估和改进串起来,形成一个闭环:

  1. 初始化一个随机策略 π
  2. 策略评估:计算 Vπ
  3. 策略改进:基于 Vπ 更新 π
  4. 如果 π 不再变化,结束;否则回到第 2 步

这个算法收敛得很快。我记得在 4x4 的 Grid World 上,通常 3-5 次迭代就能找到最优策略。但要注意,每次评估都要迭代很多次,如果状态空间大,计算量会爆炸。

我个人的习惯是:先跑一次完整的策略迭代,看看收敛速度。如果太慢,就换成值迭代。别死磕一种方法。

3.4 值迭代算法:一步到位

值迭代(Value Iteration)是策略迭代的「简化版」。它不显式地维护策略,而是直接更新价值函数:

V(s) = max_a Σ P(s'|s,a) * [R(s,a,s') + γ * V(s')]

看到了吗?这里用了 max,而不是策略 π 的期望。也就是说,每次更新时,我都假设自己会选最优动作。这样一步到位,省去了策略评估的循环。

值迭代的收敛条件:当所有状态的 V 变化都小于阈值 θ 时,停止。然后从 V 中提取策略:

π(s) = argmax_a Σ P(s'|s,a) * [R(s,a,s') + γ * V(s')]

你想想看,值迭代其实是在「隐式」地做策略改进。每次更新 V 时,都隐含地假设策略是最优的。所以它比策略迭代快,但需要更多次迭代才能收敛。

核心区别:
  • 策略迭代:评估 → 改进 → 评估 → 改进 ...(每次评估都收敛)
  • 值迭代:直接更新 V,最后提取策略(每次更新只做一步)

我一般这样选:如果状态空间小(比如 < 1000),用策略迭代;如果大,用值迭代。

3.5 Grid World 示例:手把手跑一遍

咱们用 4x4 的 Grid World 来演示。假设:

  • 状态:16 个格子,编号 0-15
  • 动作:上、下、左、右
  • 奖励:到达终点(状态 15)得 +1,其他得 0
  • 折扣因子 γ = 0.9
  • 边界:撞墙不动

先看策略迭代的代码(伪代码):

# 策略迭代
π = 随机策略
while True:
    # 策略评估
    V = [0] * 16
    while True:
        Δ = 0
        for s in range(16):
            v = V[s]
            a = π[s]
            s' = 转移(s, a)
            V[s] = 奖励(s, a, s') + 0.9 * V[s']
            Δ = max(Δ, abs(v - V[s]))
        if Δ < 0.001:
            break
    
    # 策略改进
    policy_stable = True
    for s in range(16):
        old_action = π[s]
        # 找最优动作
        best_action = argmax_a [奖励(s,a,s') + 0.9 * V[s']]
        π[s] = best_action
        if old_action != best_action:
            policy_stable = False
    
    if policy_stable:
        break

我跑过一次,结果如下:

迭代次数 策略变化 最大 V 变化
1 全部随机 → 部分指向终点 0.9
2 进一步优化 0.3
3 稳定 0.05

你看,3 次迭代就搞定了。值迭代呢?大概需要 10-15 次 V 更新才能收敛。但每次更新很快,因为不用嵌套评估循环。

避坑指南: 我曾经在 Grid World 上犯过一个错——忘了处理边界情况。结果智能体在边界上一直撞墙,V 值死活不收敛。后来加了个判断:如果撞墙,状态不变,奖励为 -0.1。嗯,这样就好多了。

最后总结一下:

  • 策略评估:算 V,迭代到收敛
  • 策略改进:贪心选动作
  • 策略迭代:评估 + 改进,循环
  • 值迭代:直接更新 V,最后提取策略

你想想看,这两种方法其实都是「动态规划」的变种。核心思想就一个:利用贝尔曼方程,把大问题拆成小问题,迭代求解。嗯,下一章咱们会讲更高级的方法——蒙特卡洛方法。到时候你会发现,动态规划虽然好,但有些场景下它玩不转。到时候再说。