用最简单的python语法实现小网格环境下的迭代策略评估(Iterative Policy Evaluation in Small Gridworld)
一 、小网格环境下的迭代策略简介
哈哈,能看到这篇博客的应该都对这张两图再熟悉不过。
在阅读此篇博客之前,希望你已经对马尔可夫决策以及贝尔曼方程有初步的了解。
在此基础上,通过这篇博客,你可以学会以下几点。
- 那个-1.7究竟是怎么算的?(其实并不是-1.7)
- k取任意值时每个方格里面每个值是怎么算的?
- 如何用python计算任意次迭代次数(k取任意值)后这个网格中任意方格中的值?
- - 如何用python实现对于任意大小的网格,完成上步操作?
- 如何用python实现此游戏的的可视化?当然啦,网格的大小你可以自己调,同时除了马尔可夫决策外,我还准备了随机决策。通过可视化,你可以看到小方块在两种策略下具体是怎么移动的。
二、问题重述
已知(如上图):
- 状态空间 S:S_1 - S_14为非终止状态;S_0,S_15 终止状态,图中灰色方格所示两个位置;
- 行为空间 A:{n, e, s, w} 对于任何非终止状态可以有向北、东、南、西移动四个行为;
- 转移概率 P:任何试图离开方格世界的动作其位置将不会发生改变,其余条件下将100%地转移到动作指向的位置;
- 即时奖励 R:任何在非终止状态间的转移得到的即时奖励均为-1,进入终止状态即时奖励为0;
- 衰减系数 γ:1;
- 当前策略π:个体采用随机行动策略,在任何一个非终止状态下有均等的几率往任意可能的方向移动,即π(n|•) = π(e|•) = π(s|•) = π(w|•) = 1/4。
- 问题:评估在这个方格世界里给定的策略。
- 该问题等同于:求解该方格世界在给定策略下的(状态)价值函数,也就是求解在给定策略下,该方格世界里每一个状态的价值。
三、如何计算每个方块的状态的价值?
给出通俗易懂的解释:
这个格子在k=n时的价值等于(它到周围格子的策略价值总和再加上及时奖励的价值总和)/4。特别的,它如果撞墙了,则回到自身,同样也有-1的及时奖励,而回到自身所产生的策略价值就是k=n-1时的这个各自的价值。
给出通俗易懂的公式:
用Pn(i,j)表示坐标为(i,j)的格子在k=n时的策略价值,则
Pn(i,j)=Pn−1(i−1,j)+Pn−1(i+1,j)+Pn−1(i,j−1)+Pn−1(i,j+1)−44P_{n}(i, j)=\frac{P_{n-1}(i-1, j)+P_{n-1}(i+1, j)+P_{n-1}(i, j-1)+P_{n-1}(i, j+1)-4}{4}Pn(i,j)=4Pn−1(i−1,j)+Pn−1(i+1,j)+Pn−1(i,j−1)+Pn−1(i,j+1)−4
以下图红圈内的格子为例:
P=(0-1-1-1-4)/4=-1.75,所以这里的-1.7的确切值应该是-1.75
以下图红圈内的格子为例:
P=(0-1.75-2-2-4)/4=-2.4375,所以这里的-2.4的确切值应该是-2.4375
四、python求解任意棋盘大小任意k值任意网格的价值
定义一个评分函数,传入参数是棋盘的大小,题目中棋盘大小为4*4,所以chess_number为4。之后定义两个二维数组,用于存放每个格子的价值以及更新后的价值,均赋0备用。
def chess_score(chess_number):
global score
global newscore
for i in range(chess_number):
score.append([])
for j in range(chess_number):
score[i].append(0)
for i in range(chess_number):
newscore.append([])
for j in range(chess_number):
newscore[i].append(0)
设置迭代次数,因为有限过程的markov过程是收敛的,依据经验本约束条件下大约150次左右价值趋于稳定,所以这里我设置iteration为150.
之后遍历棋盘判断所有点的价值。
除了终点外,我将任意大小的棋盘分成九个区域,分别是右上角,中上,左上角,左中,右中,左下角,中下,右下角,以及通常。之后分类套公式,再将更新的价值存入newscore中。那么为什么不直接存入score中呢,因为如果立刻存入score,在一次迭代没有结束时,这个点的价值会影响后面未更新点的价值,导致结果出错。
for iteration in range(150):
print("第",iteration,"次迭代:")
for i in range(chess_number):
print(score[i])
for i in range(chess_number):
for j in range(chess_number):
if [i,j] in endpos1:#吸收态坐标
score[i][j]=0.0
else:
if(i==0 and j==0):#左上
newscore[i][j]=round((score[i][j]+score[i+1][j]+score[i][j+1]+score[i][j]-4)/4.0,5)
elif (i==0 and j!=0 and j!=chess_number-1):#中上
newscore[i][j]=