Q − L e a r n i n g Q -\mathrm{Learning} Q−Learning 算法介绍
Q
−
L
e
a
r
n
i
n
g
Q- \mathrm{Learning}
Q−Learning是强化学习的算法之一,
Q
−
L
e
a
r
n
i
n
g
Q- \mathrm{Learning}
Q−Learning的主要目的就是学习状态动作价值函数的
Q
(
s
,
a
)
Q(s,a)
Q(s,a),其中
Q
(
s
,
a
)
Q(s,a)
Q(s,a)表示的是在给定当前状态s和采取动作a之后能够获得的收益期望。
Q
−
L
e
a
r
n
i
n
g
Q- \mathrm{Learning}
Q−Learning利用状态s和动作a张成一个Q表来储存Q值,然后根据Q值来选取能够获得最大收益的动作。
Q
−
L
e
a
r
n
i
n
g
Q- \mathrm{Learning}
Q−Learning采用是值迭代的方法进行求解,其核心的迭代公式为
Q
k
+
1
(
s
,
a
)
=
∑
s
^
∈
S
p
(
s
^
∣
s
,
a
)
[
R
(
s
,
a
)
+
γ
⋅
max
a
^
∈
A
{
Q
k
(
s
^
,
a
^
)
}
]
Q_{k+1}(s,a)=\sum\limits_{\hat{s}\in\mathcal{S}}p(\hat{s}|s,a)\left[R(s,a)+\gamma \cdot \max\limits_{\hat{a}\in \mathcal{A}}\{Q_k(\hat{s},\hat{a})\}\right]
Qk+1(s,a)=s^∈S∑p(s^∣s,a)[R(s,a)+γ⋅a^∈Amax{Qk(s^,a^)}]第
k
+
1
k+1
k+1次迭代函数,s和a分别表示的是当前的状态和执行的动作并且它们分别属于状态空间
S
\mathcal{S}
S和动作空间
A
\mathcal{A}
A,
R
(
s
,
a
)
R(s,a)
R(s,a)表示的是在状态s执行动作a后的即时奖励,
s
^
\hat{s}
s^和
a
^
\hat{a}
a^表示的是下一个的状态和行为,
p
(
s
^
∣
s
,
a
)
p(\hat{s}|s,a)
p(s^∣s,a)表示的是状态转移概率,
γ
\gamma
γ 表示的是折扣系数。
当动作空间
A
\mathcal{A}
A中的动作a划分的足够细时候,给定当前状态s和执行的动作a,就能够明确确定下一个状态
h
a
t
s
hat{s}
hats,进而则有
p
(
s
^
∣
s
,
a
)
=
1
p(\hat{s}|s,a)=1
p(s^∣s,a)=1,对上迭代公式进一步化简则有
Q
k
+
1
(
s
,
a
)
=
R
(
s
,
a
)
+
γ
⋅
max
a
^
∈
A
{
Q
k
(
s
^
,
a
^
)
}
Q_{k+1}(s,a)=R(s,a)+\gamma \cdot \max\limits_{\hat{a}\in \mathcal{A}}\{Q_k(\hat{s},\hat{a})\}
Qk+1(s,a)=R(s,a)+γ⋅a^∈Amax{Qk(s^,a^)}一般情况下
Q
−
L
e
a
r
n
i
n
g
Q- \mathrm{Learning}
Q−Learning算法用到的都是以上的迭代公式。
Q − L e a r n i n g Q -\mathrm{Learning} Q−Learning 具体实例
如下左半图显示,该图共有六个状态,五个房间分别是状态
0
,
1
,
2
,
3
0,1,2,3
0,1,2,3和
4
4
4,以及房间外状态
5
5
5,右半图为左半图的状态转移过程的抽象示意图。现在的问题是如果有一个人在任意的一个房间里,给他支个招让他走出房间外。我们就可以通过强化学习中的
Q
−
L
e
a
r
n
i
n
g
Q- \mathrm{Learning}
Q−Learning方法来解决这个问题。
在解决这个问题之前需要先确定奖励矩阵
R
R
R,其元素表示的是当一个给定一个状态s,当执行某个动作a后,它的即时奖励
R
(
s
,
a
)
R(s,a)
R(s,a)的取值。规定当走出房间外到达状态
5
5
5的动作奖励为
100
100
100,如果没有走出房间外但在房间内可以走通的是奖励为
0
0
0,如果房间内也不能走通的动作奖励为
−
1
-1
−1。奖励矩阵
R
R
R具体取值如下所示。
R
=
[
−
1
−
1
−
1
−
1
0
−
1
−
1
−
1
−
1
0
−
1
100
−
1
−
1
−
1
0
−
1
−
1
−
1
0
0
−
1
0
−
1
0
−
1
−
1
0
−
1
100
−
1
0
−
1
−
1
0
100
]
R=\left[\begin{array}{rrrrrr}-1&-1&-1&-1&0&-1\\-1&-1&-1&0&-1&100\\-1&-1&-1&0&-1&-1\\-1&0&0&-1&0&-1\\0&-1&-1&0&-1&100\\-1&0&-1&-1&0&100\end{array}\right]
R=⎣⎢⎢⎢⎢⎢⎢⎡−1−1−1−10−1−1−1−10−10−1−1−10−1−1−100−10−10−1−10−10−1100−1−1100100⎦⎥⎥⎥⎥⎥⎥⎤
- 首先确定折扣系数γ = 0.8 \gamma=0.8 γ=0 .8,并将Q初始化为一个零矩阵:
Q = [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] Q=\left[\begin{array}{cccccc}0&0&0&0&0&0\\0&0&0&0&0&0\\0&0&0&0&0&0\\0&0&0&0&0&0\\0&0&0&0&0&0\\0&0&0&0&0&0\end{array}\right] Q=⎣⎢⎢⎢⎢⎢⎢⎡000000000000000000000000000000000000⎦⎥⎥⎥⎥⎥⎥⎤ - 第一轮第一次迭代随机选择初始状态为房间
1
1
1,然后观察矩阵
R
R
R的第二行(对应房间
1
1
1或者状态
1
1
1),这一行中有两个非负值,即当前状态
1
1
1的下一步行为有两种可能:转至状态
3
3
3或
5
5
5,此时选择随机选择转至状态
5
5
5。观察矩阵
R
R
R的第六行(对应房间
5
5
5或者状态
5
5
5),这一行有三个非负值,即当前状态
5
5
5的下一步行为有三种可能:转至状态
1
1
1,
4
4
4或
5
5
5。根据
Q
−
L
e
a
r
n
i
n
g
Q- \mathrm{Learning}
Q−Learning值迭代公式则有
Q ( 1 , 5 ) = R ( 1 , 5 ) + 0.8 × max { Q ( 5 , 1 ) , Q ( 5 , 4 ) , Q ( 5 , 5 ) } = 100 + 0.8 × max { 0 , 0 , 0 } = 100 \begin{aligned}Q(1,5)&=R(1,5)+0.8 \times \max\left\{Q(5,1),Q(5,4),Q(5,5)\right\}\\&=100+0.8 \times \max \{0,0,0\}\\&=100\end{aligned} Q(1,5)=R(1,5)+0.8×max{Q(5,1),Q(5,4),Q(5,5)}=100+0.8×max{0,0,0}=100
则此时将矩阵
Q
(
1
,
5
)
Q(1,5)
Q(1,5)位置(即该矩阵的第二行第六列)用
100
100
100进行数值更新。
Q
=
[
0
0
0
0
0
0
0
0
0
0
0
100
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
]
Q=\left[\begin{array}{cccccc}0&0&0&0&0&0\\0&0&0&0&0&100\\0&0&0&0&0&0\\0&0&0&0&0&0\\0&0&0&0&0&0\\0&0&0&0&0&0\end{array}\right]
Q=⎣⎢⎢⎢⎢⎢⎢⎡00000000000000000000000000000001000000⎦⎥⎥⎥⎥⎥⎥⎤
- 第一轮第二次迭代随机选择状态为房间
3
3
3,然后观察矩阵
R
R
R的第四行(对应房间
3
3
3或者状态
3
3
3),这一行中有三个非负值,即当前状态
3
3
3的下一步行为有三种可能:转至状态
1
1
1,
2
2
2或
4
4
4,此时随机选择转至状态
1
1
1。观察矩阵
R
R
R的第二行(对应房间
1
1
1或者状态
1
1
1),这一行中有两个非负值,即当前状态
1
1
1的下一步行为有两种可能:转至状态
3
3
3或
5
5
5。根据
Q
−
L
e
a
r
n
i
n
g
Q- \mathrm{Learning}
Q−Learning值迭代公式则有
Q ( 3 , 1 ) = R ( 3 , 1 ) + 0.8 × max { Q ( 1 , 3 ) , Q ( 1 , 5 ) } = 0 + 0.8 × max { 0 , 100 } = 80 \begin{aligned}Q(3,1)&=R(3,1)+0.8 \times \max\left\{Q(1,3),Q(1,5)\right\}\\&=0+0.8 \times \max \{0,100\}\\&=80\end{aligned} Q(3,1)=R(3,1)+0.8×max{Q(1,3),Q(1,5)}=0+0.8×max{0,100}=80
则此时将矩阵 Q ( 3 , 1 ) Q(3,1) Q(3,1)位置(即该矩阵的第二行第六列)用 80 80 80进行数值更新。
Q = [ 0 0 0 0 0 0 0 0 0 0 0 100 0 0 0 0 0 0 0 80 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] Q=\left[\begin{array}{cccccc}0&0&0&0&0&0\\0&0&0&0&0&100\\0&0&0&0&0&0\\0&80&0&0&0&0\\0&0&0&0&0&0\\0&0&0&0&0&0\end{array}\right] Q=⎣⎢⎢⎢⎢⎢⎢⎡000000000800000000000000000000001000000⎦⎥⎥⎥⎥⎥⎥⎤ - 经过多轮迭代之后直至Q矩阵收敛,则此时的Q即为所求,最后对Q矩阵进行归一化。
Q = [ 0 0 0 0 400 0 0 0 0 320 0 500 0 0 0 320 0 0 0 400 256 0 400 0 320 0 0 320 0 500 0 400 0 0 400 500 ] ⟹ Q = [ 0 0 0 0 80 0 0 0 0 64 0 100 0 0 0 64 0 0 0 80 51 0 80 0 64 0 0 64 0 100 0 80 0 0 80 100 ] Q=\left[\begin{array}{cccccc}0&0&0&0&400&0\\0&0&0&320&0&500\\0&0&0&320&0&0\\0&400&256&0&400&0\\320&0&0&320&0&500\\0&400&0&0&400&500\end{array}\right]\Longrightarrow Q=\left[\begin{array}{cccccc}0&0&0&0&80&0\\0&0&0&64&0&100\\0&0&0&64&0&0\\0&80&51&0&80&0\\64&0&0&64&0&100\\0&80&0&0&80&100\end{array}\right] Q=⎣⎢⎢⎢⎢⎢⎢⎡00003200000400040000025600032032003200400004000400050000500500⎦⎥⎥⎥⎥⎥⎥⎤⟹Q=⎣⎢⎢⎢⎢⎢⎢⎡0000640000800800005100064640640800080080010000100100⎦⎥⎥⎥⎥⎥⎥⎤
下图表示的是经过
Q
−
L
e
a
r
n
i
n
g
Q- \mathrm{Learning}
Q−Learning算法学习之后得到的最终的状态转移示意图,其中每个带有箭头的线上标明这个动作对应的即时收益。所以不管在哪个状态下,只要利用贪心策略找即时收益最大的行为就可以走出房间。
以上实例中
Q
−
L
e
a
r
n
i
n
g
Q-\mathrm{Learning}
Q−Learning算法的完整代码如下所示
import numpy as np
import os
import random
def random_action(V):
index_list = []
for index, s in enumerate(list(V)):
if s >= 0:
index_list.append(index)
return random.choice(index_list)
def reward_setting(state_num, action_num):
R = -1 * np.ones((state_num , action_num))
R[0,4] = 0
R[1,3] = 0
R[1,5] = 100
R[2,3] = 0
R[3,1] = 0
R[3,2] = 0
R[3,4] = 0
R[4,0] = 0
R[4,3] = 0
R[4,5] = 100
R[5,1] = 0
R[5,4] = 0
R[5,5] = 100
return R
if __name__ == '__main__':
action_num = 6
state_num = 6
gamma = 0.8
epoch_number = 200
condition_stop = 5
Q = np.zeros((state_num , action_num))
R = reward_setting(state_num , action_num)
for epoch in range(epoch_number):
for s in range(state_num):
loop = True
while loop:
a = random_action(R[s,:])
q_max = np.max(Q[a,:])
Q[s,a] = R[s,a] + gamma * q_max
s = a
if s == condition_stop:
loop = False
Q = (Q / 5).astype(int)
print(Q)
实验结果如下所示,原作者这里人工设置了训练200轮,Q矩阵差不多可以收敛到理论值,提高轮数可以的
价值迭代法
价值迭代法有两种形式,一种是利用状态动作价值函数的贝尔曼最优方程迭代求解状态动作矩阵
Q
Q
Q,这也是俗称的
Q
−
L
e
a
r
n
i
n
g
Q- \mathrm{Learning}
Q−Learning算法;另一种利用状态价值函数的贝尔曼最优方程迭代求解状态向量
V
π
V_\pi
Vπ。本文主要介绍利用状态价值迭代法求解状态向量
V
V
V,状态向量
V
V
V的贝尔曼最优迭代公式表示为:
V
(
k
+
1
)
(
s
)
=
max
a
∈
A
∑
s
′
∈
S
p
(
s
′
∣
s
,
a
)
[
R
(
s
,
a
)
+
γ
V
(
k
)
(
s
′
)
]
V^{(k+1)}(s)=\max\limits_{a \in \mathcal{A}}\sum\limits_{s^{\prime}\in \mathcal{S}}p(s^{\prime}|s,a)[R(s,a)+\gamma V^{(k)}(s^{\prime})]
V(k+1)(s)=a∈Amaxs′∈S∑p(s′∣s,a)[R(s,a)+γV(k)(s′)]
其中
V
k
+
1
(
s
)
V^{k+1}(s)
Vk+1(s)第
k
+
1
k+1
k+1次迭代函数,
s
s
s和
a
a
a分别表示的是当前的状态和执行的动作并且它们分别属于状态空间
S
\mathcal{S}
S和动作空间
A
\mathcal{A}
A,
R
(
s
,
a
)
R(s,a)
R(s,a)表示的是在状态
s
s
s执行动作
a
a
a后的即时奖励,
s
′
s^{\prime}
s′表示的是下一个的状态,
p
(
s
′
∣
s
,
a
)
p(s^{\prime}|s,a)
p(s′∣s,a)表示的是状态转移概率,
γ
\gamma
γ表示的是折扣系数。
具体实例
如下左半图显示,该图共有九个状态分别是状态
0
0
0至
8
8
8,右半图为左半图的状态转移过程的抽象示意图。现在的问题是如果有一个人在任意的一个房间里,给他支个招让他走出房间外。我们就可以通过强化学习中的价值迭代法来求解这个问题。
假定状态空间
S
=
{
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
}
\mathcal{S}=\{0,1,2,3,4,5,6,7,8\}
S={0,1,2,3,4,5,6,7,8},动作空间为
A
=
{
0
,
1
,
2
,
3
}
\mathcal{A}=\{0,1,2,3\}
A={0,1,2,3}分别表示向上走,向右走,向下走,向左走。如上右半图所示,当状态为
0
0
0和
8
8
8时的动作的即时奖励取值
0
0
0,其它的行为奖励取值全为
−
1
-1
−1,即时奖励矩阵
R
R
R表示为
R
=
[
0
−
1
−
1
−
1
−
1
−
1
−
1
−
1
0
0
−
1
−
1
−
1
−
1
−
1
−
1
−
1
0
0
−
1
−
1
−
1
−
1
−
1
−
1
−
1
0
0
−
1
−
1
−
1
−
1
−
1
−
1
−
1
0
]
R=\left[\begin{array}{ccccccccc}0&-1&-1&-1&-1&-1&-1&-1&0\\0&-1&-1&-1&-1&-1&-1&-1&0\\0&-1&-1&-1&-1&-1&-1&-1&0\\0&-1&-1&-1&-1&-1&-1&-1&0\\ \end{array}\right]
R=⎣⎢⎢⎡0000−1−1−1−1−1−1−1−1−1−1−1−1−1−1−1−1−1−1−1−1−1−1−1−1−1−1−1−10000⎦⎥⎥⎤
其中矩阵的行表示的是状态
s
s
s,列表示的是动作
a
a
a。
- 首先令折扣系数 γ = 0.8 \gamma=0.8 γ=0.8,并将向量 V V V初始化为一个零向量: V = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] V=[0,0,0,0,0,0,0,0,0] V=[0,0,0,0,0,0,0,0,0]
- 第一轮第一次迭代随机选取初始状态为房间
1
1
1,利用矩阵
R
R
R的第二列(对应房间1或者状态1)和向量
V
V
V通过方程
V s a = ∑ s ′ ∈ S p ( s ′ ∣ s , a ) [ R ( s , a ) + γ V π ( k ) ( s ′ ) ] V_{sa}=\sum\limits_{s^{\prime}\in \mathcal{S}}p(s^{\prime}|s,a)[R(s,a)+\gamma V_\pi^{(k)}(s^{\prime})] Vsa=s′∈S∑p(s′∣s,a)[R(s,a)+γVπ(k)(s′)]
分别求出动作空间 a a a中所有四个动作下的收益
#这里比较奇怪,建议直接看代码,因为按照前面的设计,房间1去哪个方向,收益都是-1,所以R(1,3)不应该是-1吗?
{ ↑ : V 10 = p ( 1 ∣ 1 , 0 ) [ R ( 1 , 0 ) + 0.8 ⋅ V ( 1 ) ] = 1 × ( − 1 + 0.8 × 0 ) = − 1 → : V 11 = p ( 2 ∣ 1 , 1 ) [ R ( 1 , 1 ) + 0.8 ⋅ V ( 2 ) ] = 1 × ( − 1 + 0.8 × 0 ) = − 1 ↓ : V 12 = p ( 4 ∣ 1 , 2 ) [ R ( 1 , 1 ) + 0.8 ⋅ V ( 4 ) ] = 1 × ( − 1 + 0.8 × 0 ) = − 1 ← : V 13 = p ( 0 ∣ 1 , 3 ) [ R ( 1 , 3 ) + 0.8 ⋅ V ( 0 ) ] = 1 × ( − 1 + 0.8 × 0 ) = − 1 \left\{\begin{aligned}\mathrm{\uparrow:\quad} V_{10}&=p(1|1,0)[R(1,0)+0.8 \cdot V(1)]=1\times (-1 +0.8 \times 0)=-1\\ \mathrm{\rightarrow:\quad} V_{11}&=p(2|1,1)[R(1,1)+0.8 \cdot V(2)]=1\times (-1 +0.8 \times 0)=-1\\\mathrm{\downarrow:\quad} V_{12}&=p(4|1,2)[R(1,1)+0.8 \cdot V(4)]=1\times (-1 +0.8 \times 0)=-1\\ \mathrm{\leftarrow:\quad} V_{13}&=p(0|1,3)[R(1,3)+0.8 \cdot V(0)]=1\times (-1 +0.8 \times 0)=-1 \end{aligned}\right. ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧↑:V10→:V11↓:V12←:V13=p(1∣1,0)[R(1,0)+0.8⋅V(1)]=1×(−1+0.8×0)=−1=p(2∣1,1)[R(1,1)+0.8⋅V(2)]=1×(−1+0.8×0)=−1=p(4∣1,2)[R(1,1)+0.8⋅V(4)]=1×(−1+0.8×0)=−1=p(0∣1,3)[R(1,3)+0.8⋅V(0)]=1×(−1+0.8×0)=−1
然后找出在状态
s
s
s下,这四个动作的最大收益,并把此值赋给
V
[
1
]
V[1]
V[1],即有
V
[
1
]
=
max
a
∈
A
{
V
1
a
}
=
max
{
V
10
,
V
11
,
V
12
,
V
13
}
=
−
1
V[1]=\max\limits_{a\in \mathcal{A}}\{V_{1a}\}=\max\{ V_{10}, V_{11}, V_{12}, V_{13}\}=-1
V[1]=a∈Amax{V1a}=max{V10,V11,V12,V13}=−1
- 第一轮第二次迭代随机选取初始状态为房间
4
4
4,利用矩阵
R
R
R的第5列(对应房间4或者状态4)和向量
V
V
V分别求出动作空间
a
a
a中所有四个动作下的收益
{ ↑ : V 40 = p ( 1 ∣ 4 , 0 ) [ R ( 4 , 0 ) + 0.8 ⋅ V ( 1 ) ] = 1 × ( − 1 + 0.8 × 0 ) = − 1 → : V 41 = p ( 5 ∣ 4 , 1 ) [ R ( 4 , 1 ) + 0.8 ⋅ V ( 5 ) ] = 1 × ( − 1 + 0.8 × 0 ) = − 1 ↓ : V 42 = p ( 7 ∣ 4 , 2 ) [ R ( 4 , 2 ) + 0.8 ⋅ V ( 7 ) ] = 1 × ( − 1 + 0.8 × 0 ) = − 1 ← : V 43 = p ( 3 ∣ 4 , 3 ) [ R ( 4 , 3 ) + 0.8 ⋅ V ( 3 ) ] = 1 × ( − 1 + 0.8 × 0 ) = − 1 \left\{\begin{aligned}\mathrm{\uparrow:\quad} V_{40}&=p(1|4,0)[R(4,0)+0.8 \cdot V(1)]=1\times (-1 +0.8 \times 0)=-1\\ \mathrm{\rightarrow:\quad} V_{41}&=p(5|4,1)[R(4,1)+0.8 \cdot V(5)]=1\times (-1 +0.8 \times 0)=-1\\\mathrm{\downarrow:\quad} V_{42}&=p(7|4,2)[R(4,2)+0.8 \cdot V(7)]=1\times (-1 +0.8 \times 0)=-1\\ \mathrm{\leftarrow:\quad} V_{43}&=p(3|4,3)[R(4,3)+0.8 \cdot V(3)]=1\times (-1 +0.8 \times 0)=-1 \end{aligned}\right. ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧↑:V40→:V41↓:V42←:V43=p(1∣4,0)[R(4,0)+0.8⋅V(1)]=1×(−1+0.8×0)=−1=p(5∣4,1)[R(4,1)+0.8⋅V(5)]=1×(−1+0.8×0)=−1=p(7∣4,2)[R(4,2)+0.8⋅V(7)]=1×(−1+0.8×0)=−1=p(3∣4,3)[R(4,3)+0.8⋅V(3)]=1×(−1+0.8×0)=−1
然后找出在状态 s s s下,这四个动作的最大收益,并把此值赋给 V [ 7 ] V[7] V[7],即有
V [ 4 ] = max a ∈ A { V 4 a } = max { V 40 , V 41 , V 42 , V 43 } = − 1 V[4]=\max\limits_{a\in \mathcal{A}}\{V_{4a}\}=\max\{ V_{40}, V_{41}, V_{42}, V_{43}\}=-1 V[4]=a∈Amax{V4a}=max{V40,V41,V42,V43}=−1
此时的向量 V V V为
V = [ 0 , − 1 , 0 , 0 , − 1 , 0 , 0 , 0 , 0 ] V=[0,-1,0,0,-1,0,0,0,0] V=[0,−1,0,0,−1,0,0,0,0] - 每一轮中需要将向量
V
V
V每个状态进行都进行迭代更新,多轮之后直至向量
V
V
V收敛,收敛后的向量
V
∗
V^*
V∗为:
V
∗
=
[
0
,
−
1
,
−
1.8
,
−
1
,
−
1.8
,
−
1
,
−
1.8
,
−
1
,
0
]
V^*=[0,-1,-1.8,-1,-1.8,-1,-1.8,-1,0]
V∗=[0,−1,−1.8,−1,−1.8,−1,−1.8,−1,0]向量
V
∗
V^*
V∗并不能显式地告诉我们具体的行动策略是什么,但是可以利用向量
V
∗
V^{*}
V∗和矩阵
R
R
R通过方程
Π [ s ] = arg max a ∈ A ∑ s ′ ∈ S p ( s ′ ∣ s , a ) [ R ( s , a ) + γ V π ( k ) ( s ′ ) ] \Pi[s]=\arg\max\limits_{a\in \mathcal{A}}\sum\limits_{s^{\prime}\in \mathcal{S}}p(s^{\prime}|s,a)[R(s,a)+\gamma V_\pi^{(k)}(s^{\prime})] Π[s]=arga∈Amaxs′∈S∑p(s′∣s,a)[R(s,a)+γVπ(k)(s′)]
求解出具体的动作策略 Π \Pi Π为 Π = [ 0 , 3 , 2 , 0 , 0 , 0 , 0 , 1 , 0 ] \Pi=[0,3,2,0,0,0,0,1,0] Π=[0,3,2,0,0,0,0,1,0]其中 Π [ 2 ] = 2 \Pi[2]=2 Π[2]=2表示的是在状态 3 3 3时,最好的行动策略是往下走。
以上实例中值迭代算法的核心代码如下所示
#gridgame.py
from gym.envs.toy_text import discrete
import os
import sys
import numpy as np
UP = 0
RIGHT = 1
DOWN = 2
LEFT = 3
class GridgameEnv(discrete.DiscreteEnv):
def __init__(self, shape=[3,3]):
self.shape = shape
self.iter_cnt = 0
MAX_Y = shape[0]
MAX_X = shape[1]
nS = np.prod(shape)
#nS = 9
#print(nS)
nA = 4
grid = np.arange(nS).reshape(shape)
#print(np.arange(nS))
it = np.nditer(grid, flags=['multi_index'])
#print(it)
P = {}
while not it.finished:
s = it.iterindex
y, x = it.multi_index
P[s] = {a : [] for a in range(nA)}
is_done = lambda s: s == 0 or s == (nS - 1)
reward = 0.0 if is_done(s) else -1.0
# Get in a terminal state
if is_done(s):
P[s][UP] = [(1.0, s, reward, True)]
P[s][RIGHT] = [(1.0, s, reward, True)]
P[s][DOWN] = [(1.0, s, reward, True)]
P[s][LEFT] = [(1.0, s, reward, True)]
#print(P[s])
# Not a terminal state
else:
ns_up = s if y == 0 else s - MAX_X
ns_right = s if x == (MAX_X - 1) else s + 1
ns_down = s if y == (MAX_Y - 1) else s + MAX_X
ns_left = s if x == 0 else s - 1
P[s][UP] = [(1.0, ns_up, reward, is_done(ns_up))]
P[s][RIGHT] = [(1.0, ns_right, reward, is_done(ns_right))]
P[s][DOWN] = [(1.0, ns_down, reward, is_done(ns_down))]
P[s][LEFT] = [(1.0, ns_left, reward, is_done(ns_left))]
it.iternext()
isd = np.ones(nS) / nS
#print(isd)
self.P = P
super(GridgameEnv, self).__init__(nS, nA, P, isd)
#main.py
def state_value_iteration(env, theta=0.0001, discount_factor=0.8):
def one_step_action_choice(state, V):
A = np.zeros(env.nA)
for a in range(env.nA):
for prob, next_state, reward, done in env.P[state][a]:
A[a] += prob * (reward + discount_factor * V[next_state])
return A
V = np.zeros(env.nS)
while True:
delta = 0
for s in range(env.nS):
#if(s==0):
# continue
env.iter_cnt = env.iter_cnt + 1
# find the best action
A = one_step_action_choice(s, V)
best_action_value = np.max(A)
# Calculate terminate condition
delta = max(delta, np.abs(best_action_value - V[s]))
# Update the value function
V[s] = best_action_value
#print(A)
# if s==1:
# break;
# Check if we can stop
#if s==1:
# break
if delta < theta:
break
policy = np.zeros([env.nS, env.nA])
for s in range(env.nS):
A = one_step_action_choice(s, V)
#print(A)
best_action = np.argmax(A)
policy[s, best_action] = 1.0
return policy, V
if __name__ == '__main__':
env = GridgameEnv()
policy , V = state_value_iteration(env)
print("iter_num",env.iter_cnt)
print("V",V)
print("Grid Policy (0=up, 1=right, 2=down, 3=left):")
print(np.argmax(policy, axis=1))
print("")
训练27轮之后状态向量
V
∗
V^{*}
V∗就可以收敛到理论值,然后通过收敛后的状态向量
V
∗
V^{*}
V∗得到动作策略向量
Π
\Pi
Π。