强化学习的数学原理 | 赵世钰 | 西湖大学 | 笔记 | Lecture 2 | Part 4 | 贝尔曼公式(公式向量形式与求解)

目录

    • 前言
    • [1. Matrix-vector form of the Bellman equation](#1. Matrix-vector form of the Bellman equation)
    • [2. Solve state values](#2. Solve state values)
    • [3. Implementation of solving state values](#3. Implementation of solving state values)
      • [3.1 Closed-form solution](#3.1 Closed-form solution)
      • [3.2 Iterative solution](#3.2 Iterative solution)
    • 结语
    • 参考

前言

学习赵老师讲授的强化学习的数学原理视频,本篇文章记录第二讲 Part 4:贝尔曼公式(公式向量形式与求解),记录个人学习笔记,和大家一起分享交流😄

videohttps://www.bilibili.com/video/BV1sd4y167NS

1. Matrix-vector form of the Bellman equation

在上一部分我们介绍了 贝尔曼公式 的推导,下面我们来介绍 贝尔曼公式的矩阵和向量的形式

当我们有了一个 贝尔曼公式 之后,我们其实要考虑的就是怎么样 求解这个贝尔曼公式 ,大家可以看到下面是我们刚才得到的 贝尔曼公式的表达式

v π ( s ) = ∑ a π ( a ∣ s ) ∑ r p ( r ∣ s , a ) r + γ ∑ s ′ p ( s ′ ∣ s , a ) v π ( s ′ ) \textcolor{red}{v_\pi(s)} = \sum_{a} \pi(a \mid s) \left \\sum_{r} p(r \\mid s, a)r + \\gamma \\sum_{s'} p(s' \\mid s, a)\\textcolor{red}{v_\\pi(s')} \\right vπ(s)=a∑π(a∣s)r∑p(r∣s,a)r+γs′∑p(s′∣s,a)vπ(s′)

表达式左边有一个 state value v π ( s ) \textcolor{red}{v_{\pi}(s)} vπ(s) ,右边有另外一个 state value v π ( s ′ ) \textcolor{red}{v_{\pi}(s')} vπ(s′) ,单凭这一个公式,我们是无法求出 state value 的。

但是我们注意到这个 elementwise form ,也就是针对每一个 state value 的这样一个 equation,对所有的状态都是成立的,如果我有 n n n 个状态那么我就会有 n n n 个这样的 equation

如果我把所有的这些公式放在一起那我就得到了一组,那我进一步就可以整理成一个 matrix-vector form,这个形式对我们求解和理解问题其实非常有帮助。

下面我们就来看一下怎么得到它的 matrix-vector form

首先我们要对刚刚得到的 贝尔曼公式 做一个变形,我们把前面这一项和后面这一项这两项合并到一起,就得到:

v π ( s ) = r π ( s ) + γ ∑ s ′ p π ( s ′ ∣ s ) v π ( s ′ ) \begin{equation} v_\pi(s) = r_\pi(s) + \gamma \sum_{s'} p_\pi(s' \mid s) v_\pi(s') \tag{1} \end{equation} vπ(s)=rπ(s)+γs′∑pπ(s′∣s)vπ(s′)(1)

其中:

r π ( s ) ≜ ∑ a π ( a ∣ s ) ∑ r p ( r ∣ s , a ) r , p π ( s ′ ∣ s ) ≜ ∑ a π ( a ∣ s ) p ( s ′ ∣ s , a ) r_\pi(s) \triangleq \sum_{a} \pi(a \mid s) \sum_{r} p(r \mid s, a) r, \qquad p_\pi(s' \mid s) \triangleq \sum_{a} \pi(a \mid s) p(s' \mid s, a) rπ(s)≜a∑π(a∣s)r∑p(r∣s,a)r,pπ(s′∣s)≜a∑π(a∣s)p(s′∣s,a)

r π ( s ) r_{\pi}(s) rπ(s) 代表什么呢?代表我从当前状态出发,我所能得到的 immediate reward 的一个平均值 。然后我把前面这一项和后面这一项相结合,就得到了这个 p π ( s ′ ∣ s ) p_{\pi}(s'|s) pπ(s′∣s) 的一个概率,所以我们就通过这个得到了上面这样一个式子,这个式子就相比上一个会简化一些。

下面再继续看,为了要把它写成一个矩阵向量的形式,实际上我们要 把所有的状态都写到一起 ,那这时候不同的状态我们给它标上号,要不然的话我们只用 s s s 来表示的话,是分不清是哪个状态对应 s s s 的。

假如我们有 n n n 个状态,现在将它们标号: s 1 , s 2 , ... , s n s_1, s_2, \ldots, s_n s1,s2,...,sn ,所以刚才那个式子呢,就变成了下面这样一个式子:

v π ( s i ) = r π ( s i ) + γ ∑ s j p π ( s j ∣ s i ) v π ( s j ) v_\pi(s_i) = r_\pi(s_i) + \gamma \sum_{s_j} p_\pi(s_j \mid s_i) v_\pi(s_j) vπ(si)=rπ(si)+γsj∑pπ(sj∣si)vπ(sj)

s i s_i si 的 state value ,它就等于第一项是这个 immediate reward ,它的一个平均值,然后后边一项是对所有可能的 s j s_j sj 求和:从 s i s_i si 跳到 s j s_j sj 的概率乘以 s j s_j sj 处的 state value v π ( s j ) v_\pi(s_j) vπ(sj) 。

把这个式子写成 matrix-vector form 就很简单了: v π v_\pi vπ 是一个 n n n 维列向量,展开写为:

v π = r π + γ P π v π \textcolor{blue}{v_\pi = r_\pi + \gamma P_\pi v_\pi} vπ=rπ+γPπvπ

其中:

v π = v π ( s 1 ) , ... , v π ( s n ) T ∈ R n r π = r π ( s 1 ) , ... , r π ( s n ) T ∈ R n P π ∈ R n × n , w h e r e    P π i j = p π ( s j ∣ s i ) \begin{align*} & v_\pi = v_\\pi(s_1), \\dots, v_\\pi(s_n)^T \in \mathbb{R}^n \\6pt & r_\pi = r_\\pi(s_1), \\dots, r_\\pi(s_n)^T \in \mathbb{R}^n \\6pt & P_\pi \in \mathbb{R}^{n \times n}, \quad \mathrm{where} \,\, P_\\pi{ij} = p\pi(s_j \mid s_i) \end{align*} vπ=vπ(s1),...,vπ(sn)T∈Rnrπ=rπ(s1),...,rπ(sn)T∈RnPπ∈Rn×n,whereij=pπ(sj∣si)

v π v_\pi vπ 是由 v π ( s 1 ) v_\pi(s_1) vπ(s1) 到 v π ( s n ) v_\pi(s_n) vπ(sn) 组成的列向量 ,同样地 r π r_{\pi} rπ 也是一个向量写成这种形式,这里边的 P π P_{\pi} Pπ 可能会稍微复杂一点,待会我们通过例子可以更清晰地看到。

P π i j P_\\pi{ij} ij 这两边加上一个中括号然后有 i j ij ij 代表什么呢?代表 第 i i i 行第 j j j 列的元素是从 s i s_i si 跳到 s j s_j sj 的这样一个概率 , P π P{\pi} Pπ 这个矩阵也被称为 state transition matrix(状态转移矩阵),待会我们可以通过这个例子来看一下。

这个例子是什么呢?实际上就是当我有 n = 4 n=4 n=4 个状态的时候,我所得到的 matrix-vector form 是什么样子。

v π ( s 1 ) v π ( s 2 ) v π ( s 3 ) v π ( s 4 ) ⏟ v π = r π ( s 1 ) r π ( s 2 ) r π ( s 3 ) r π ( s 4 ) ⏟ r π + γ p π ( s 1 ∣ s 1 ) p π ( s 2 ∣ s 1 ) p π ( s 3 ∣ s 1 ) p π ( s 4 ∣ s 1 ) p π ( s 1 ∣ s 2 ) p π ( s 2 ∣ s 2 ) p π ( s 3 ∣ s 2 ) p π ( s 4 ∣ s 2 ) p π ( s 1 ∣ s 3 ) p π ( s 2 ∣ s 3 ) p π ( s 3 ∣ s 3 ) p π ( s 4 ∣ s 3 ) p π ( s 1 ∣ s 4 ) p π ( s 2 ∣ s 4 ) p π ( s 3 ∣ s 4 ) p π ( s 4 ∣ s 4 ) ⏟ P π v π ( s 1 ) v π ( s 2 ) v π ( s 3 ) v π ( s 4 ) ⏟ v π . \underbrace{\begin{bmatrix} v_\pi(s_1) \\ v_\pi(s_2) \\ v_\pi(s_3) \\ v_\pi(s_4) \end{bmatrix}}{v\pi} = \underbrace{\begin{bmatrix} r_\pi(s_1) \\ r_\pi(s_2) \\ r_\pi(s_3) \\ r_\pi(s_4) \end{bmatrix}}{r\pi} + \gamma \underbrace{\begin{bmatrix} p_\pi(s_1|s_1) & p_\pi(s_2|s_1) & p_\pi(s_3|s_1) & p_\pi(s_4|s_1) \\ p_\pi(s_1|s_2) & p_\pi(s_2|s_2) & p_\pi(s_3|s_2) & p_\pi(s_4|s_2) \\ p_\pi(s_1|s_3) & p_\pi(s_2|s_3) & p_\pi(s_3|s_3) & p_\pi(s_4|s_3) \\ p_\pi(s_1|s_4) & p_\pi(s_2|s_4) & p_\pi(s_3|s_4) & p_\pi(s_4|s_4) \end{bmatrix}}{P\pi} \underbrace{\begin{bmatrix} v_\pi(s_1) \\ v_\pi(s_2) \\ v_\pi(s_3) \\ v_\pi(s_4) \end{bmatrix}}{v\pi}. vπ vπ(s1)vπ(s2)vπ(s3)vπ(s4) =rπ rπ(s1)rπ(s2)rπ(s3)rπ(s4) +γPπ pπ(s1∣s1)pπ(s1∣s2)pπ(s1∣s3)pπ(s1∣s4)pπ(s2∣s1)pπ(s2∣s2)pπ(s2∣s3)pπ(s2∣s4)pπ(s3∣s1)pπ(s3∣s2)pπ(s3∣s3)pπ(s3∣s4)pπ(s4∣s1)pπ(s4∣s2)pπ(s4∣s3)pπ(s4∣s4) vπ vπ(s1)vπ(s2)vπ(s3)vπ(s4) .

v π v_\pi vπ 和 r π r_\pi rπ 这两项比较直观,而 P π P_\pi Pπ 这一项则能清楚地展示 state transition matrix 的结构。

我们可以看一下它的第一行,我们拿任何一行都可以,我们就拿第一行为例,第一行第一个元素是 从 s 1 s_1 s1 到 s 1 s_1 s1 的概率 ,第一行第二个元素是 从 s 1 s_1 s1 到 s 2 s_2 s2 的概率 ,第一行第三个元素是 从 s 1 s_1 s1 到 s 3 s_3 s3 的概率 ,第一行第四个元素是 从 s 1 s_1 s1 到 s 4 s_4 s4 的概率

下面我们再通过下面这个例子来进一步地展示。

考虑这样一个例子,这里边有一个策略 π \pi π ,上图用绿色的箭头已经标出来了,所以我们现在要把它的 Bellman equationmatrix-vector form 给写出来,如下所示:

v π ( s 1 ) v π ( s 2 ) v π ( s 3 ) v π ( s 4 ) = 0 1 1 1 + γ 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 1 v π ( s 1 ) v π ( s 2 ) v π ( s 3 ) v π ( s 4 ) \begin{bmatrix} v_\pi(s_1) \\ v_\pi(s_2) \\ v_\pi(s_3) \\ v_\pi(s_4) \end{bmatrix} = \begin{bmatrix} 0 \\ 1 \\ 1 \\ 1 \end{bmatrix} + \gamma \begin{bmatrix} 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} v_\pi(s_1) \\ v_\pi(s_2) \\ v_\pi(s_3) \\ v_\pi(s_4) \end{bmatrix} vπ(s1)vπ(s2)vπ(s3)vπ(s4) = 0111 +γ 0000000010000111 vπ(s1)vπ(s2)vπ(s3)vπ(s4)

等式左右两边都是向量形式的 state value ,中间是 r π r_{\pi} rπ 向量。 r π r_{\pi} rπ 的第一个元素是什么呢?这个元素代表的是我从 s 1 s_1 s1 出发,我所得到的 immediate reward 的 average

我从 s 1 s_1 s1 出发我得到的 immediate reward 是什么呢?这个是一个 确定性的 ,所以我会得到 0,所以 r π r_{\pi} rπ 的第一个元素就是 0,类似地从 s 2 , s 3 , s 4 s_2, s_3, s_4 s2,s3,s4 出发,所得到的 immediate reward 全都是 1。

上式中这个 4 × 4 4 \times 4 4×4 的矩阵就是 P π P_{\pi} Pπ ,那比如我们来看第一行,第一行第一个元素应该是从 s 1 s_1 s1 跳到 s 1 s_1 s1 的这样一个概率,从 s 1 s_1 s1 跳到 s 1 s_1 s1 这个概率是 0,对吧?然后第二个元素是从 s 1 s_1 s1 跳到 s 2 s_2 s2 的概率 这也是 0,第三个元素是从 s 1 s_1 s1 跳到 s 3 s_3 s3 的概率,显然这个概率是 1,第四个是从 s 1 s_1 s1 跳到 s 4 s_4 s4 的概率也是 0,其它的行以此类推都可以这样写出来。

我们下面再看另外一个例子。

v π ( s 1 ) v π ( s 2 ) v π ( s 3 ) v π ( s 4 ) = 0.5 ( 0 ) + 0.5 ( − 1 ) 1 1 1 + γ 0 0.5 0.5 0 0 0 0 1 0 0 0 1 0 0 0 1 v π ( s 1 ) v π ( s 2 ) v π ( s 3 ) v π ( s 4 ) . \begin{bmatrix} v_\pi(s_1) \\ v_\pi(s_2) \\ v_\pi(s_3) \\ v_\pi(s_4) \end{bmatrix} = \begin{bmatrix} 0.5(0) + 0.5(-1) \\ 1 \\ 1 \\ 1 \end{bmatrix} + \gamma \begin{bmatrix} 0 & 0.5 & 0.5 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} v_\pi(s_1) \\ v_\pi(s_2) \\ v_\pi(s_3) \\ v_\pi(s_4) \end{bmatrix}. vπ(s1)vπ(s2)vπ(s3)vπ(s4) = 0.5(0)+0.5(−1)111 +γ 00000.50000.50000111 vπ(s1)vπ(s2)vπ(s3)vπ(s4) .

这个例子稍微复杂一点:在 s 1 s_1 s1 处,agent 有 0.5 的概率向右走,0.5 的概率向下走。

这里重点看 r π r_\pi rπ 和 P π P_\pi Pπ 如何写出,然后 r π r_{\pi} rπ 的重点我们来看第一个元素,第一个元素呢,它从 s 1 s_1 s1 出发它的 immediate reward 是什么呢?

以 0.5 的概率向右走,得到 − 1 -1 −1 ;以 0.5 的概率向下走,得到 0。因此平均 immediate reward 为 0.5 ⋅ 0 + 0.5 ⋅ ( − 1 ) = − 0.5 0.5 \cdot 0 + 0.5 \cdot (-1) = -0.5 0.5⋅0+0.5⋅(−1)=−0.5 。

再看这个 P π P_{\pi} Pπ ,我们还是以第一行为例,第一个元素代表什么呢?是从 s 1 s_1 s1 到 s 1 s_1 s1 的概率,那大家看一下 s 1 s_1 s1 到 s 1 s_1 s1 的概率依旧是 0,第二个元素是从 s 1 s_1 s1 到 s 2 s_2 s2 的概率,那 s 1 s_1 s1 到 s 2 s_2 s2 和刚才不同,现在是有可能跳过去的,它概率是 0.5,第一行第三个元素是从 s 1 s_1 s1 到 s 3 s_3 s3 ,所以概率也是 0.5, s 1 s_1 s1 到 s 4 s_4 s4 是 0,其它的以此类推。

2. Solve state values

刚刚我们推导了 贝尔曼公式的 matrix-vector form ,下面我们用这样一个矩阵和向量的形式来求解 state value

首先我们回答一个非常关键的问题, 为什么要求解 state value?

实际上给定一个 policy ,然后我会列出来它的 贝尔曼公式 ,再进一步求解这个 贝尔曼公式 得到 state value ,这样一个过程实际上叫做 policy evaluation 。前面我们或多或少都提到过,这里我们正式地提一下,policy evaluation 是强化学习当中非常关键的一个问题,非常基础的一个工具。

因为我们只有能够去 评价一个策略到底好还是不好 ,我们才能够去进一步地去 改进它 ,最后再找到 最优的策略 ,所以求解 贝尔曼公式 进而得到 state value,是非常重要的一个问题。

v π = r π + γ P π v π v_{\pi} = r_{\pi} + \gamma P_{\pi} v_{\pi} vπ=rπ+γPπvπ

那么这个是我们刚刚推导得到的 贝尔曼公式的 matrix-vector form ,我们下面给出两种解决的方法。第一种是 closed-form solution ,也就是直接给出 state value 的解析表达式,就是下面这个;

v π = ( I − γ P π ) − 1 r π v_{\pi} = (I - \gamma P_{\pi})^{-1}r_{\pi} vπ=(I−γPπ)−1rπ

这个怎么得到呢?其实也很简单,大家可以自己回去详细推导一下,将 γ P π v π \gamma P_\pi v_\pi γPπvπ 移到等式左边,得到 ( I − γ P π ) v π = r π (I - \gamma P_\pi)v_\pi = r_\pi (I−γPπ)vπ=rπ ,再在两边左乘 ( I − γ P π ) (I - \gamma P_\pi) (I−γPπ) 的逆矩阵即可。

这个解析表达式非常地优美,但是在实际当中我们 并不会使用 ,因为这里要求一个 ,而当状态空间比较大的时候这个矩阵的维数也会比较大,求逆的计算量也会比较大,所以在实际当中我们可以用这样一个 迭代的方法

v k + 1 = r π + γ P π v k v_{k+1} = r_{\pi} + \gamma P_{\pi} v_k vk+1=rπ+γPπvk

iterative solution 这个迭代的算法就是上面这样一个式子,大家比较一下这个式子,和刚才的 贝尔曼公式 的这个式子其实非常像,中间这几项是一样的,只不过右边 v π v_{\pi} vπ 变换成了 v k v_k vk ,左边的这个 v π v_{\pi} vπ 也换成了 v k + 1 v_{k+1} vk+1 。

这个算法我怎么样使用呢?首先我右边是 v k v_k vk 左边是 v k + 1 v_{k+1} vk+1 ,从 k = 0 k=0 k=0 开始,初始值 v 0 v_0 v0 可以任意选取,例如取全零向量。然后我通过这个式子代入,把 v 0 v_0 v0 代到右边,左边我就可以计算出来 v 1 v_1 v1 ,因为 r π , γ , P π r_{\pi},\gamma, P_{\pi} rπ,γ,Pπ 这些都是事先知道的。

然后我把 v 1 v_1 v1 再代到右边,我就可以得到左边的 v 2 v_2 v2 ,我再把 v 2 v_2 v2 代到右边,我就可以得到左边的 v 3 v_3 v3 ,这样一直下去,我就会得到这样一个序列 { v 0 , v 1 , v 2 , ... } \{v_0,v_1,v_2,\ldots\} {v0,v1,v2,...} ,实际上我们可以证明当 k → ∞ k \rightarrow \infty k→∞ 的时候, v k v_k vk 就 收敛到了 v π v_{\pi} vπ

v k → v π = ( I − γ P π ) − 1 r π , k → ∞ v_k \to v_\pi = (I - \gamma P_\pi)^{-1}r_\pi, \quad k \to \infty vk→vπ=(I−γPπ)−1rπ,k→∞

这个 v π v_{\pi} vπ 就是真实的 state value ,为什么 v k v_k vk 会收敛到 v π v_{\pi} vπ 呢?

收敛性的证明如下:


证明。

定义误差为 δ k = v k − v π \delta_k = v_k - v_\pi δk=vk−vπ 。我们只需证明 δ k → 0 \delta_k \to 0 δk→0 。将 v k + 1 = δ k + 1 + v π v_{k+1} = \delta_{k+1} + v_\pi vk+1=δk+1+vπ 和 v k = δ k + v π v_k = \delta_k + v_\pi vk=δk+vπ 代入 v k + 1 = r π + γ P π v k v_{k+1} = r_\pi + \gamma P_\pi v_k vk+1=rπ+γPπvk 可得

δ k + 1 + v π = r π + γ P π ( δ k + v π ) , \delta_{k+1} + v_\pi = r_\pi + \gamma P_\pi (\delta_k + v_\pi), δk+1+vπ=rπ+γPπ(δk+vπ),

可以重写为

δ k + 1 = − v π + r π + γ P π δ k + γ P π v π = γ P π δ k . \delta_{k+1} = -v_\pi + r_\pi + \gamma P_\pi \delta_k + \gamma P_\pi v_\pi = \gamma P_\pi \delta_k. δk+1=−vπ+rπ+γPπδk+γPπvπ=γPπδk.

因此,

δ k + 1 = γ P π δ k = γ 2 P π 2 δ k − 1 = ⋯ = γ k + 1 P π k + 1 δ 0 . \delta_{k+1} = \gamma P_\pi \delta_k = \gamma^2 P_\pi^2 \delta_{k-1} = \cdots = \gamma^{k+1} P_\pi^{k+1} \delta_0. δk+1=γPπδk=γ2Pπ2δk−1=⋯=γk+1Pπk+1δ0.

注意到 0 ≤ P π k ≤ 1 0 \le P_\pi^k \le 1 0≤Pπk≤1,这意味着对于任意 k = 0 , 1 , 2 , ... k = 0, 1, 2, \dots k=0,1,2,... , P π k P_\pi^k Pπk 的每一项都不大于 1。这是因为 P π k 1 = 1 P_\pi^k \mathbf{1} = \mathbf{1} Pπk1=1,其中 1 = 1 , ... , 1 T \mathbf{1} = 1, \\dots, 1^T 1=1,...,1T 。另一方面,由于 γ < 1 \gamma < 1 γ<1 ,我们知道 γ k → 0 \gamma^k \to 0 γk→0 ,因此当 k → ∞ k \to \infty k→∞ 时, δ k + 1 = γ k + 1 P π k + 1 δ 0 → 0 \delta_{k+1} = \gamma^{k+1} P_\pi^{k+1} \delta_0 \to 0 δk+1=γk+1Pπk+1δ0→0 。


基本思路是定义 v k v_k vk 与 v π v_\pi vπ 之间的 误差 δ k \delta_k δk ,然后证明 δ k → 0 \delta_k \to 0 δk→0 。

下面我们通过几个例子来介绍一下。

:本节使用的 grid-world 比前面更复杂一些,是一个 5 × 5 5 \times 5 5×5 的网格,状态用坐标 ( i , j ) (i,j) (i,j) 表示,target 位于 ( 4 , 3 ) (4,3) (4,3) 。

首先在这个例子当中它的 reward 是:

r boundary = r forbidden = − 1 , r target = 1 r_{\text{boundary}} = r_{\text{forbidden}} = -1, \quad r_{\text{target}} = 1 rboundary=rforbidden=−1,rtarget=1

如果 agent 试图越过边界会得到 -1,进到 forbidden area 也会得到 -1,到 target area 会得到 +1,然后它的 γ \gamma γ 是 0.9。

首先我们来考虑两个比较好的策略,比如说上图第一个,这个策略为什么会比较好呢?直观上看它不会试图跳出边界不会撞墙,不会进到 forbidden area 。比如我从 ( 2 , 2 ) (2,2) (2,2) 这个点出发,沿着这个策略,会绕一圈最终进到这个 target area 里面去。

然后我计算出来的 state value ,我们可以用刚才的这个 解析表达式 或者是 迭代的算法 ,都可以得到它的 state value ,可以看到 state value 全部为正数 。还有一个很有意思的现象,之后其实我们也会分析,就是 靠近 target area 的状态,其 state value 都比较大;离 target area 越远,state value 越小

另外我们考虑第二个策略,这个策略与上面那个策略几乎一模一样,只不过这两个策略在 ( 1 , 4 ) (1,4) (1,4)、 ( 2 , 4 ) (2,4) (2,4) 处的动作不同:第一个策略向下走,第二个策略向右走,但是最后所得到的 state value 是完全相同的 ,也就是说在这两个格子我往下走往右走其实效果是一样的, 不同的策略是能够得到相同的 state value

刚才我们考虑了两个看起来比较好的策略,下面我们来看看起来比较差的两个策略。

首先上图第一个策略是:无论在哪一个格子,agent 都会向右走,这个显然是不合理的,然后计算出来的 state value 也全都是负数 ,所以很明显我通过 state value 就可以判断出来这个策略是不好的

第二个策略是随机生成的一个策略,在很多状态它会要撞墙或者要进到 forbidden area ,这个策略显然也是不好的,计算出的 state value 与我们的直觉一致。

通过这几个例子其实我们可以明显地看到, 我们可以计算 state value 来评价一个策略究竟好还是不好

3. Implementation of solving state values

前面我们介绍了两种求解 state value 的方法:

第一种是 closed-form solution

v π = ( I − γ P π ) − 1 r π v_{\pi} = (I - \gamma P_{\pi})^{-1} r_{\pi} vπ=(I−γPπ)−1rπ

第二种是 iterative solution

v k + 1 = r π + γ P π v k v_{k+1} = r_{\pi} + \gamma P_{\pi}v_k vk+1=rπ+γPπvk

下面我们进一步看一下这两种方法在实际问题中是如何具体实现的。

我们以上图第一个 policy 为例,来求解 ( 1 , 1 ) (1,1) (1,1) 的 state value

首先我们先确定从 ( 1 , 1 ) (1,1) (1,1) 出发会发生什么。

以图片上方的策略为例,从 ( 1 , 1 ) (1,1) (1,1) 出发:

( 1 , 1 ) → ( 1 , 2 ) → ( 1 , 3 ) → ( 1 , 4 ) → ( 2 , 4 ) → ( 3 , 4 ) → ( 3 , 5 ) → ( 4 , 5 ) → ( 5 , 5 ) → ( 5 , 4 ) → ( 5 , 3 ) → ( 4 , 3 ) . \begin{align*} (1, 1) &\rightarrow (1, 2) \rightarrow (1, 3) \rightarrow (1, 4) \\ &\rightarrow (2, 4) \rightarrow (3, 4) \rightarrow (3, 5) \\ &\rightarrow (4, 5) \rightarrow (5, 5) \rightarrow (5, 4) \\ &\rightarrow (5, 3) \rightarrow (4, 3). \end{align*} (1,1)→(1,2)→(1,3)→(1,4)→(2,4)→(3,4)→(3,5)→(4,5)→(5,5)→(5,4)→(5,3)→(4,3).

其中 ( 4 , 3 ) (4,3) (4,3) 就是蓝色的 target

为了方便,我们把这条路径上的状态重新编号为

s 1 = ( 1 , 1 ) , s 2 = ( 1 , 2 ) , ... , s 12 = ( 4 , 3 ) s_1 = (1,1), \quad s_2 = (1,2), \quad \ldots , \quad s_{12}=(4,3) s1=(1,1),s2=(1,2),...,s12=(4,3)

于是转移关系就是

s 1 → s 2 → ⋯ → s 11 → s 12 , s_1 \to s_2 \to \cdots \to s_{11} \to s_{12}, s1→s2→⋯→s11→s12,

而到达 target 后保持在 target

s 12 → s 12 . s_{12} \to s_{12}. s12→s12.

3.1 Closed-form solution

根据公式

v π = ( I − γ P π ) − 1 r π \boxed{ v_\pi=(I-\gamma P_\pi)^{-1}r_\pi } vπ=(I−γPπ)−1rπ

由于 policy 是确定的 ,因此对于从 ( 1 , 1 ) (1,1) (1,1) 可以访问到的这 12 个状态, transition matrix 具有非常简单的形式:

P π = 0 1 0 ⋯ 0 0 0 0 1 ⋯ 0 0 ⋮ ⋱ ⋱ ⋮ 0 0 ⋯ 0 1 0 0 0 ⋯ 0 0 1 0 0 ⋯ 0 0 1 . P_\pi= \begin{bmatrix} 0&1&0&\cdots&0&0\\ 0&0&1&\cdots&0&0\\ \vdots&&\ddots&\ddots&&\vdots\\ 0&0&\cdots&0&1&0\\ 0&0&\cdots&0&0&1\\ 0&0&\cdots&0&0&1 \end{bmatrix}. Pπ= 00⋮0001000001⋱⋯⋯⋯⋯⋯⋱0000010000⋮011 .

回忆一下, P i j = p ( s j ∣ s i ) P_{ij} = p(s_j | s_i) Pij=p(sj∣si) 表示 从 s i s_i si 跳到 s j s_j sj 的这样一个概率 ,以第一行第一个元素为例,它表示从 s 1 s_1 s1 到 s 1 s_1 s1 的概率,那大家看一下 policy 就知道这个概率为 0,因为 policy 的绿色箭头是向右的,只有从 s 1 s_1 s1 到 s 2 s_2 s2 的概率为 1。

reward vector

r π = 0 0 ⋮ 0 1 1 . r_\pi= \begin{bmatrix} 0\\ 0\\ \vdots\\ 0\\ 1\\ 1 \end{bmatrix}. rπ= 00⋮011 .

前 10 个状态 immediate reward 都为 0, s 11 s_{11} s11 进入 target 时得到 + 1 +1 +1 , target 自身每一步得到 + 1 +1 +1 。

现在 P π ,   r π P_{\pi}, \, r_{\pi} Pπ,rπ 都已经求出来了,并且我们知道 γ = 0.9 \gamma=0.9 γ=0.9 ,代入公式即可求得 v π ( s 1 ) v_{\pi}(s_1) vπ(s1) 即 v π ( 1 , 1 ) v_{\pi}(1,1) vπ(1,1) 。

我们可以编写一个简单的程序来完成这个公式的求解:

python 复制代码
import numpy as np


# ============================================================
# 1. 定义状态
# ============================================================

states = [
    (1, 1),
    (1, 2),
    (1, 3),
    (1, 4),
    (2, 4),
    (3, 4),
    (3, 5),
    (4, 5),
    (5, 5),
    (5, 4),
    (5, 3),
    (4, 3),   # target
]

n = len(states)

# 折扣因子
gamma = 0.9


# ============================================================
# 2. 构造状态转移矩阵 P_pi
# ============================================================

P_pi = np.zeros((n, n))

# 普通状态:
# s1 -> s2 -> s3 -> ... -> s12
for i in range(n - 1):
    P_pi[i, i + 1] = 1.0

# target 是吸收状态
# 到达 target 后仍然留在 target
P_pi[n - 1, n - 1] = 1.0


# ============================================================
# 3. 构造 reward vector r_pi
# ============================================================

r_pi = np.zeros(n)

# (5,3) -> target 时获得 +1
r_pi[n - 2] = 1.0

# 在 target 中每一步获得 +1
r_pi[n - 1] = 1.0


# ============================================================
# 4. 使用解析表达式求解
#
#       v_pi = (I - gamma * P_pi)^(-1) r_pi
#
# ============================================================

I = np.eye(n)

v_pi = np.linalg.inv(I - gamma * P_pi) @ r_pi


# ============================================================
# 5. 输出结果
# ============================================================

print("State values:")
print("-" * 30)

for state, value in zip(states, v_pi):
    print(f"{state}: {value:.10f}")

print("-" * 30)

print(f"v_pi(1,1) = {v_pi[0]:.10f}")
print(f"v_pi(1,1) ≈ {v_pi[0]:.1f}")

执行后输出如下:

shell 复制代码
State values:
------------------------------
(1, 1): 3.4867844010
(1, 2): 3.8742048900
(1, 3): 4.3046721000
(1, 4): 4.7829690000
(2, 4): 5.3144100000
(3, 4): 5.9049000000
(3, 5): 6.5610000000
(4, 5): 7.2900000000
(5, 5): 8.1000000000
(5, 4): 9.0000000000
(5, 3): 10.0000000000
(4, 3): 10.0000000000
------------------------------
v_pi(1,1) = 3.4867844010
v_pi(1,1) ≈ 3.5

因此, v π ( 1 , 1 ) = 3.5 v_{\pi}(1,1) = 3.5 vπ(1,1)=3.5 。

3.2 Iterative solution

根据公式

v k + 1 = r π + γ P π v k \boxed{v_{k+1}=r_\pi+\gamma P_\pi v_k} vk+1=rπ+γPπvk

假设初始化

v 0 = 0. v_0 = \mathbf{0}. v0=0.

第一次迭代:

v 1 = r π + 0.9 P π v 0 = r π v_1 = r_{\pi} + 0.9P_{\pi}v_0 = r_{\pi} v1=rπ+0.9Pπv0=rπ

因此

v 1 ( s 11 ) = 1 , v 1 ( s 12 ) = 1 v_1(s_{11})=1, \qquad v_1(s_{12})=1 v1(s11)=1,v1(s12)=1

其他状态仍然为 0。

第二次迭代:

v 2 = r π + 0.9 P π v 1 v_2=r_\pi+0.9P_\pi v_1 v2=rπ+0.9Pπv1

此时

v 2 ( s 10 ) = 0 + 0.9 v 1 ( s 11 ) = 0.9 v_2(s_{10}) =0+0.9v_1(s_{11}) =0.9 v2(s10)=0+0.9v1(s11)=0.9

于是价值信息开始继续向前传播。

因为 ( 1 , 1 ) (1,1) (1,1) 与第一次产生 reward 的 s 11 s_{11} s11 相隔 10 次状态转移,所以:

v 0 ( 1 , 1 ) = v 1 ( 1 , 1 ) = ⋯ = v 10 ( 1 , 1 ) = 0 v_0(1,1)=v_1(1,1)=\cdots=v_{10}(1,1)=0 v0(1,1)=v1(1,1)=⋯=v10(1,1)=0

直到第 11 次迭代:

v 11 ( 1 , 1 ) = 0.9 10 = 0.34867844 v_{11}(1,1) = 0.9^{10} = 0.34867844 v11(1,1)=0.910=0.34867844

第 12 次迭代:

v 12 ( 1 , 1 ) = 0.9 10 + 0.9 11 = 0.662489036 v_{12}(1,1) = 0.9^{10}+0.9^{11}=0.662489036 v12(1,1)=0.910+0.911=0.662489036

第 13 次:

v 13 ( 1 , 1 ) = 0.9 10 + 0.9 11 + 0.9 12 = 0.944918573 v_{13}(1,1) = 0.9^{10}+0.9^{11}+0.9^{12} = 0.944918573 v13(1,1)=0.910+0.911+0.912=0.944918573

一般地,当 k ≥ 11 k\ge11 k≥11 时:

v k ( 1 , 1 ) = ∑ t = 10 k − 1 0.9 t = 0.9 10 ( 1 − 0.9 k − 10 ) 1 − 0.9 \boxed{ v_k(1,1) = \sum_{t=10}^{k-1}0.9^t = \frac{0.9^{10}\left(1-0.9^{k-10}\right)}{1-0.9}} vk(1,1)=t=10∑k−10.9t=1−0.90.910(1−0.9k−10)

当 k → ∞ k \rightarrow \infty k→∞ 时 0.9 k − 10 → 0 0.9^{k-10} \rightarrow 0 0.9k−10→0 ,因此

lim ⁡ k → ∞ v k ( 1 , 1 ) = 0.9 10 1 − 0.9 = 3.486784401 \lim_{k\to\infty}v_k(1,1) = \frac{0.9^{10}}{1-0.9}= 3.486784401 k→∞limvk(1,1)=1−0.90.910=3.486784401

也就是说:

v k ( 1 , 1 ) ⟶ 3.486784401 ≈ 3.5 \boxed{ v_k(1,1) \longrightarrow 3.486784401 \approx3.5 } vk(1,1)⟶3.486784401≈3.5

closed-form solution 完全一致。

当然,我们也可以编写一个简单的程序来求解这个迭代过程:

python 复制代码
import numpy as np


# ============================================================
# 1. 定义状态
# ============================================================

states = [
    (1, 1),
    (1, 2),
    (1, 3),
    (1, 4),
    (2, 4),
    (3, 4),
    (3, 5),
    (4, 5),
    (5, 5),
    (5, 4),
    (5, 3),
    (4, 3),   # target
]

n = len(states)

gamma = 0.9


# ============================================================
# 2. 构造状态转移矩阵 P_pi
# ============================================================

P_pi = np.zeros((n, n))

for i in range(n - 1):
    P_pi[i, i + 1] = 1.0

# target 为吸收状态
P_pi[n - 1, n - 1] = 1.0


# ============================================================
# 3. 构造 reward vector r_pi
# ============================================================

r_pi = np.zeros(n)

# (5,3) -> target
r_pi[n - 2] = 1.0

# target -> target
r_pi[n - 1] = 1.0


# ============================================================
# 4. 初始化 v_0
# ============================================================

v = np.zeros(n)

# 收敛阈值
tolerance = 1e-10

# 最大迭代次数
max_iterations = 10000


# ============================================================
# 5. Bellman 迭代
#
#       v_{k+1} = r_pi + gamma * P_pi * v_k
#
# ============================================================

for k in range(max_iterations):

    v_new = r_pi + gamma * P_pi @ v

    # 计算两次迭代之间的最大误差
    error = np.max(np.abs(v_new - v))

    # 为了观察 (1,1) 的 value 如何变化,
    # 输出前几次以及部分关键迭代
    if k < 15 or (k + 1) % 10 == 0:
        print(
            f"Iteration {k + 1:3d}: "
            f"v(1,1) = {v_new[0]:.10f}, "
            f"error = {error:.10e}"
        )

    # 判断是否已经收敛
    if error < tolerance:
        v = v_new
        print(f"\nConverged after {k + 1} iterations.")
        break

    # v_k <- v_{k+1}
    v = v_new


# ============================================================
# 6. 输出最终 state value
# ============================================================

print("\nFinal state values:")
print("-" * 30)

for state, value in zip(states, v):
    print(f"{state}: {value:.10f}")

print("-" * 30)

print(f"v_pi(1,1) = {v[0]:.10f}")
print(f"v_pi(1,1) ≈ {v[0]:.1f}")

执行后输出如下:

shell 复制代码
Iteration   1: v(1,1) = 0.0000000000, error = 1.0000000000e+00
Iteration   2: v(1,1) = 0.0000000000, error = 9.0000000000e-01
Iteration   3: v(1,1) = 0.0000000000, error = 8.1000000000e-01
Iteration   4: v(1,1) = 0.0000000000, error = 7.2900000000e-01
Iteration   5: v(1,1) = 0.0000000000, error = 6.5610000000e-01
Iteration   6: v(1,1) = 0.0000000000, error = 5.9049000000e-01
Iteration   7: v(1,1) = 0.0000000000, error = 5.3144100000e-01
Iteration   8: v(1,1) = 0.0000000000, error = 4.7829690000e-01
Iteration   9: v(1,1) = 0.0000000000, error = 4.3046721000e-01
Iteration  10: v(1,1) = 0.0000000000, error = 3.8742048900e-01
Iteration  11: v(1,1) = 0.3486784401, error = 3.4867844010e-01
Iteration  12: v(1,1) = 0.6624890362, error = 3.1381059609e-01
Iteration  13: v(1,1) = 0.9449185727, error = 2.8242953648e-01
Iteration  14: v(1,1) = 1.1991051555, error = 2.5418658283e-01
Iteration  15: v(1,1) = 1.4278730801, error = 2.2876792455e-01
Iteration  20: v(1,1) = 2.2710178551, error = 1.3508517177e-01
Iteration  30: v(1,1) = 3.0628728182, error = 4.7101286972e-02
Iteration  40: v(1,1) = 3.3389755716, error = 1.6423203268e-02
Iteration  50: v(1,1) = 3.4352466489, error = 5.7264168970e-03
Iteration  60: v(1,1) = 3.4688142980, error = 1.9966781110e-03
Iteration  70: v(1,1) = 3.4805186135, error = 6.9619860913e-04
Iteration  80: v(1,1) = 3.4845996560, error = 2.4274944503e-04
Iteration  90: v(1,1) = 3.4860226275, error = 8.4641497831e-05
Iteration 100: v(1,1) = 3.4865187870, error = 2.9512665431e-05
Iteration 110: v(1,1) = 3.4866917871, error = 1.0290430146e-05
Iteration 120: v(1,1) = 3.4867521085, error = 3.5880511322e-06
Iteration 130: v(1,1) = 3.4867731413, error = 1.2510760721e-06
Iteration 140: v(1,1) = 3.4867804750, error = 4.3622325396e-07
Iteration 150: v(1,1) = 3.4867830321, error = 1.5210164417e-07
Iteration 160: v(1,1) = 3.4867839237, error = 5.3034565184e-08
Iteration 170: v(1,1) = 3.4867842346, error = 1.8492009701e-08
Iteration 180: v(1,1) = 3.4867843430, error = 6.4477658768e-09
Iteration 190: v(1,1) = 3.4867843808, error = 2.2481976281e-09
Iteration 200: v(1,1) = 3.4867843939, error = 7.8389872371e-10
Iteration 210: v(1,1) = 3.4867843985, error = 2.7332891506e-10
Iteration 220: v(1,1) = 3.4867844001, error = 9.5305097148e-11

Converged after 220 iterations.

Final state values:
------------------------------
(1, 1): 3.4867844001
(1, 2): 3.8742048891
(1, 3): 4.3046720991
(1, 4): 4.7829689991
(2, 4): 5.3144099991
(3, 4): 5.9048999991
(3, 5): 6.5609999991
(4, 5): 7.2899999991
(5, 5): 8.0999999991
(5, 4): 8.9999999991
(5, 3): 9.9999999991
(4, 3): 9.9999999991
------------------------------
v_pi(1,1) = 3.4867844001
v_pi(1,1) ≈ 3.5

在迭代过程中,我们会看到一个很有意思的现象,那就是前 10 次 v k ( 1 , 1 ) = 0 v_{k}(1,1)=0 vk(1,1)=0 ,这其实特别能体现 Bellman 迭代的本质

初始时 v 0 = 0 v_0=0 v0=0 ,第一次迭代,只有 target 附近的状态 才知道 "原来到达 target 可以获得 reward"。第二次迭代,这个信息向前传播一格,第三次又传播一格,于是 value 信息 会像下面这样:

Target → ( 5 , 3 ) → ( 5 , 4 ) → ( 5 , 5 ) → ⋯ → ( 1 , 1 ) \boxed{\text{Target}} \to (5,3) \to (5,4) \to (5,5) \to \cdots \to (1,1) Target→(5,3)→(5,4)→(5,5)→⋯→(1,1)

一轮 Bellman iteration,value 信息只能向前传播一个状态

因为 ( 1 , 1 ) (1,1) (1,1) 距离第一次 +1 reward 相隔 10 步,该 reward 需经过 10 次折扣( γ 10 \gamma^{10} γ10)才能传播到 ( 1 , 1 ) (1,1) (1,1) ,所以直到第 11 次迭代:

v 11 ( 1 , 1 ) = 0.9 10 = 0.34867844 v_{11}(1,1)=0.9^{10}=0.34867844 v11(1,1)=0.910=0.34867844

然后继续迭代:

v 12 ( 1 , 1 ) = 0.9 10 + 0.9 11 v 13 ( 1 , 1 ) = 0.9 10 + 0.9 11 + 0.9 12 \begin{align*} v_{12}(1,1) &= 0.9^{10}+0.9^{11} \\ v_{13}(1,1) &= 0.9^{10}+0.9^{11}+0.9^{12} \end{align*} v12(1,1)v13(1,1)=0.910+0.911=0.910+0.911+0.912

不断把 target 后续产生的 reward 传播回来。

最终:

v π ( 1 , 1 ) = 0.9 10 + 0.9 11 + 0.9 12 + ⋯ = 0.9 10 1 − 0.9 = 3.486784401 ≈ 3.5 \begin{aligned} v_\pi(1,1) &= 0.9^{10}+0.9^{11}+0.9^{12}+\cdots\\ &= \frac{0.9^{10}}{1-0.9}\\ &= 3.486784401 \\ & \approx 3.5 \end{aligned} vπ(1,1)=0.910+0.911+0.912+⋯=1−0.90.910=3.486784401≈3.5

结语

本讲第四部分将贝尔曼公式从 elementwise form 转化为简洁优美的矩阵-向量形式 v π = r π + γ P π v π v_{\pi} = r_{\pi} + \gamma P_{\pi} v_{\pi} vπ=rπ+γPπvπ ,并给出了两种求解 state value 的方法。第一种是解析解 v π = ( I − γ P π ) − 1 r π v_{\pi} = (I - \gamma P_{\pi})^{-1} r_{\pi} vπ=(I−γPπ)−1rπ ,形式优雅但求逆运算在大状态空间下代价高昂;第二种是迭代法 v k + 1 = r π + γ P π v k v_{k+1} = r_{\pi} + \gamma P_{\pi} v_k vk+1=rπ+γPπvk ,从任意初始值出发均可收敛到真实 state value,且收敛性可由误差 δ k = γ k P π k δ 0 → 0 \delta_k = \gamma^k P_\pi^k \delta_0 \to 0 δk=γkPπkδ0→0 严格证明,是实际应用中更常用的方法。

通过具体的 grid-world 例子与 Python 代码实现,我们不仅验证了两种方法结果的一致性,还观察到了一个极具启发性的现象:在 Bellman 迭代过程中,value 信息从 target 出发,每轮迭代只向前传播一个状态---这正是 bootstrapping 思想的生动体现。同时,通过对比好策略(state value 全为正)与坏策略(state value 全为负),我们再次确认了 state value 作为策略评估工具的威力,也正式确立了 policy evaluation 这一强化学习核心问题的地位。

下一讲我们将介绍 Action value,敬请期待🤗!

参考

相关推荐
海天一色y8 小时前
强化学习工具函数详解:从经验回放到优势函数计算
人工智能·python·强化学习
网络工程小王1 天前
【LLM开发实验】强化学习实现原理及实战
深度学习·强化学习·rlhf·ppo·dpo·grpo
白拾2 天前
【arXiv 2026】LoGos:把人类思考带回围棋——通用大模型的专业领域专家之路|从围棋AI与LLM推理交叉视角
强化学习·大模型推理·arxiv 2026·logos 论文分享·围棋ai·专家知识注入
Terrence Shen2 天前
【读论文系列】AGENTIC REINFORCEMENT LEARNING WITH IMPLICIT STEP REWARDS翻译+解读
大模型·agent·强化学习·rl
白拾2 天前
【COLM 2025】Search-R1:强化学习让大模型学会边推理边搜索|从LLM检索增强推理视角
强化学习·colm 2025·search-r1 论文分享·llm后训练·检索增强推理
海天一色y2 天前
深入解析 DeepSpeedPPOTrainer:基于 PPO 的大规模 RLHF 训练实现
人工智能·强化学习·deepspeed·后训练
皮卡丘不断更3 天前
从一段 RGB 视频到机器人开门:读懂 Video2DoorTraversal 的仿真闭环
机器人·强化学习·数字孪生·具身智能·机器人仿真
山顶夕景3 天前
【MLLM Agent】多模态理解Agent研究进展
agent·强化学习·多模态·rl·agentic
闲研随记4 天前
【文献阅读 ICLR 2026】RL算法:DECS
算法·llm·强化学习·iclr·rl