小網格環境下的迭代策略評估的價值計算以及python實現(可視化)

用最簡單的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)=Pn1(i1,j)+Pn1(i+1,j)+Pn1(i,j1)+Pn1(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}

以下圖紅圈內的格子爲例:
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]=round((score[i][j]+score[i+1][j]+score[i][j+1]+score[i][j-1]-4)/4.0,5)
					elif (i==0 and j==chess_number-1 ):#右上
						newscore[i][j]=round((score[i][j]+score[i+1][j]+score[i][j]+score[i][j-1]-4)/4.0,5)
					elif (i!=0 and i!=chess_number-1 and j==0 ):#左中
						newscore[i][j]=round((score[i-1][j]+score[i+1][j]+score[i][j+1]+score[i][j]-4)/4.0,5)
					elif (i!=0 and i!=chess_number-1 and j!=0 and j!=chess_number-1):#normal
						newscore[i][j]=round((score[i-1][j]+score[i+1][j]+score[i][j+1]+score[i][j-1]-4)/4.0,5)
					elif (i!=0 and i!=chess_number-1 and j==chess_number-1):#右中
						newscore[i][j]=round((score[i-1][j]+score[i+1][j]+score[i][j]+score[i][j-1]-4)/4.0,5)
					elif (i==chess_number-1 and j==0):#左下
						newscore[i][j]=round((score[i-1][j]+score[i][j]+score[i][j+1]+score[i][j]-4)/4.0,5)
					elif (i==chess_number-1 and j!=0 and j!=chess_number-1):#中下
						newscore[i][j]=round((score[i-1][j]+score[i][j]+score[i][j+1]+score[i][j-1]-4)/4.0,5)
					elif (i==chess_number-1 and j==chess_number-1):#右下
						newscore[i][j]=round((score[i-1][j]+score[i][j]+score[i][j]+score[i][j-1]-4)/4.0,5)

更新score的值,沒啥好說的。

	for i in range(chess_number):
			for j in range(chess_number):
				if newscore[i][j]!=0:
					score[i][j]=newscore[i][j]
					newscore[i][j]=0

五、python實現該遊戲的可視化

首先說說可以實現哪些內容吧。

  • 可以自己設置網格的大小。
  • 實現隨機決策下隨機格子走到終點的動畫
  • 實現馬爾可夫決策下隨機格子走到終點的動畫

準備工作

這裏我是用pygame做的,所以要導入pygame哦,沒裝的同學要記得先裝一下,網上教程很多,這裏就不再贅述。

import pygame
import sys 
import math 
import random
 
# pygame 初始化
pygame.init()
# 設置棋盤大小
chess_number=6
# 設置是否使用馬爾可夫決策
usemarkov=1#等於1使用,等於0不使用

BG=(144,136,145)#背景色
LINECOLOR=(112,73,46)#網格色
STEPCOLOR=(79,167,47)#隨機格子的顏色
STARTCOLOR=(119,207,87)#你想實現格子軌跡的時候用介個顏色好看
ENDCOLOR=(34,60,36)#吸收態格子的顏色
WINCOLOR=(253,176,36)#隨機格子落入吸收態的顏色
WALLCOLOR=(112,73,46)#牆壁的顏色,本來還想實現障礙物的,介個就交給你們啦
TEXTCOLOR=(200,98,96)#文本的顏色
#設置起始位置(左上角)
START_POS=(50,50)
START_POSX=50
START_POSY=50
CELL_LENGTH=100#每個格子的像素大小
LINE_WIDTH=4#線的寬度
# 設置背景框大小
size = width, height = 2*START_POSX+chess_number*CELL_LENGTH,2*START_POSY+chess_number*CELL_LENGTH
 
# 設置幀率,返回clock 類
clock = pygame.time.Clock()
 
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Accelerator made")
# 設置起始位置
start_posx=random.randint(1,chess_number)
start_posy=random.randint(1,chess_number)
#設置位置
pos=[start_posx,start_posy]
endpos=[[1,1],[chess_number,chess_number]]#可視化用
endpos1=[[0,0],[chess_number-1,chess_number-1]]#價值計算用
#設置分數
score=[]
newscore=[]
#初始化步數
step=0

畫圖函數

畫網格線啦,畫各種格子啦,顯示完成後的文字“COMPLETE!”啦
在一開始的時候step爲0,畫起點,之後通過判斷usemarkov的值來確定決策種類。更新方塊兒位置。

def draw():
	global pos
	global step
	for i in range(chess_number+1):
		pygame.draw.line(screen, LINECOLOR, (START_POSX,START_POSY+i*CELL_LENGTH), (START_POSX+chess_number*CELL_LENGTH,START_POSY+i*CELL_LENGTH), LINE_WIDTH)#橫線
		pygame.draw.line(screen, LINECOLOR, (START_POSX+i*CELL_LENGTH,START_POSY),(START_POSX+i*CELL_LENGTH,START_POSY+chess_number*CELL_LENGTH), LINE_WIDTH)#豎線#
	drawcell(chess_number, chess_number, ENDCOLOR) #終點
	drawcell(1, 1, ENDCOLOR)#終點
	if step==0:
		drawcell(pos[0],pos[1], STEPCOLOR)#起點
	#drawcell(start_posx, start_posy, STARTCOLOR)#起點
	else:
		if (pos!=endpos[0] and pos!=endpos[1]):
			print(pos)
			if usemarkov==0:
				pos=nologic(pos)#隨機決策
			else:
				pos=markov(pos)#馬爾可夫決策
		else:
			drawcell(pos[0], pos[1], WINCOLOR)#終點
			my_font=pygame.font.Font('mufont.ttf',20*chess_number)
			text=my_font.render("COMPLETE!",True,TEXTCOLOR)
			screen.blit(text,(100,height/2-100))
	step+=1

具體畫格子的方法

在pygame中很簡單,就是畫一個矩形就行

def drawcell(i,j,cellkind):#行,列,方塊種類
	pygame.draw.rect(screen,cellkind,[START_POSX+CELL_LENGTH*(j-1)+(LINE_WIDTH-1),START_POSY+CELL_LENGTH*(i-1)+(LINE_WIDTH-1),CELL_LENGTH-LINE_WIDTH,CELL_LENGTH-LINE_WIDTH],0)#終點. 

實現隨機決策的方法

很簡單,思想前面已經說過了,將棋盤分成九個區域,對於每個區域的格子判斷可能的行走方向,再隨機取一個就OK。

def nologic(pos):
	i=pos[0]
	j=pos[1]
	#drawcell(i,j, STARTCOLOR)#下
	if   (i==1 and j==1):#左上
		print("左上")
		godnum=random.randint(1,2)
		if godnum==1:
			drawcell(i,j+1, STEPCOLOR)#下
			pos=[i,j+1]
		elif godnum==2:
			drawcell(i,j+1, STEPCOLOR)#右
			pos=[i,j+1]
	elif (i==1 and j!=1 and j!=chess_number):#中上
		print("中上")
		godnum=random.randint(1,3)
		if godnum==1:
			drawcell(i,j+1, STEPCOLOR)#下
			pos=[i,j+1]
		elif godnum==2:
			drawcell(i,j+1, STEPCOLOR)#右
			pos=[i,j+1]
		elif godnum==3:
			drawcell(i,j-1, STEPCOLOR)#左
			pos=[i,j-1]
	elif (i==1 and j==chess_number ):#右上
		print("右上")
		godnum=random.randint(1,2)
		if godnum==1:
			drawcell(i+1,j, STEPCOLOR)#下
			pos=[i+1,j]
		elif godnum==2:
			drawcell(i,j-1, STEPCOLOR)#左
			pos=[i,j-1]
	elif (i!=1 and i!=chess_number and j==1 ):#左中
		print("左中")
		godnum=random.randint(1,3)
		if godnum==1:
			drawcell(i+1,j, STEPCOLOR)#下
			pos=[i+1,j]
		elif godnum==2:
			drawcell(i,j+1, STEPCOLOR)#右
			pos=[i,j+1]
		elif godnum==3:
			drawcell(i-1,j, STEPCOLOR)#上
			pos=[i-1,j]
	elif (i!=1 and i!=chess_number and j!=1 and j!=chess_number):#normal
		print("normal")
		godnum=random.randint(1,4)
		if godnum==1:
			drawcell(i+1,j, STEPCOLOR)#下
			pos=[i+1,j]
		elif godnum==2:
			drawcell(i,j+1, STEPCOLOR)#右
			pos=[i,j+1]
		elif godnum==3:
			drawcell(i,j-1, STEPCOLOR)#左
			pos=[i,j-1]
		elif godnum==4:
			drawcell(i-1,j, STEPCOLOR)#上
			pos=[i-1,j]
	elif (i!=1 and i!=chess_number and j==chess_number):#右中
		print("右中")
		godnum=random.randint(1,3)
		if godnum==1:
			drawcell(i+1,j, STEPCOLOR)#下
			pos=[i+1,j]
		elif godnum==2:
			drawcell(i,j-1, STEPCOLOR)#左
			pos=[i,j-1]
		elif godnum==3:
			drawcell(i-1,j, STEPCOLOR)#上
			pos=[i-1,j]
	elif (i==chess_number and j==1):#左下
		print("左下")
		godnum=random.randint(1,2)
		if godnum==1:
			drawcell(i,j+1, STEPCOLOR)#右
			pos=[i,j+1]
			print("往右邊走")
		elif godnum==2:
			drawcell(i-1,j, STEPCOLOR)#上
			pos=[i-1,j]
			print("往上邊走")
	elif (i==chess_number and j!=1 and j!=chess_number):#中下
		print("中下")
		godnum=random.randint(1,3)
		if godnum==1:
			drawcell(i,j+1, STEPCOLOR)#右
			pos=[i,j+1]
			print("往右邊走")
		elif godnum==2:
			drawcell(i,j-1, STEPCOLOR)#左
			pos=[i,j-1]
			print("往左邊走")	
		elif godnum==3:
			drawcell(i-1,j, STEPCOLOR)#上
			pos=[i-1,j]
			print("往上邊走")	
	elif (i==chess_number and j==chess_number):#右下
		print("右下")
		godnum=random.randint(1,2)
		if godnum==1:
			drawcell(i,j-1, STEPCOLOR)#左
			pos=[i,j-1]
			print("往左邊走")
		elif godnum==2:
			drawcell(i-1,j, STEPCOLOR)#上
			pos=[i-1,j]
			print("往上邊走")	
	return pos

實現馬爾可夫決策的方法

有了上面價值表作爲基礎,實現馬爾可夫決策就更簡單啦,只需要判斷方塊兒上下左右的價值是否比自己價值大,然後往價值大的地方走就OK啦。

def markov(pos):
	i=pos[0]-1
	j=pos[1]-1
	print(pos)
	print(score[i][j-1],score[i][j])
	if score[i-1][j]>score[i][j] and i-1>=0:
		drawcell(i,j+1, STEPCOLOR)
		print("往上走")
		pos=[i,j+1]
		return pos
	if i+1<chess_number and score[i+1][j]>score[i][j]:
		drawcell(i+2,j+1, STEPCOLOR)
		print("往下走")
		pos=[i+2,j+1]
		return pos
	if score[i][j-1]>score[i][j]:
		drawcell(i+1,j, STEPCOLOR)
		print("往左走")
		pos=[i+1,j]
		return pos
	if j+1<chess_number and score[i][j+1]>score[i][j]:
		drawcell(i+1,j+2, STEPCOLOR)
		print("往右走")
		pos=[i+1,j+2]
		return pos

好啦,到此爲止,小網格環境下的迭代策略評估的價值計算以及python可視化的實現就算全部完成啦。如果有什麼疏漏之處或者好的建議,也歡迎指正哦。

配套源碼已經上傳CSDN啦,直接下載就可以,謝謝大家支持。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章