[DQN自學筆記]一維離散迷宮(前篇)
建構最簡單的模型,熟悉數學公式以及程式主循環
- 設定參數與Q表
本實驗程式是參考莫煩老師的教學
https://mofanpy.com/tutorials/machine-learning/reinforcement-learning/general-rl/
用自己的方法重寫一次程式,做出一些改動以及延伸討論,我的模型一樣可以用字串X....T....O
表示,代理人(Agent)以字元T表示,可以在11個位置左右移動,但最左邊與最右邊都是終點,只是獲得的獎勵不同。
首先,設定幾個重要的貪婪度、學習率及遞減值等參數,狀態-行動 價值表簡稱Q表,是以numpy建立一個2x11的陣列,剛好對應Agent有2種行動action,以及11種狀態state。
import numpy as np
import random
import matplotlib.pyplot as plt# 設定參數
epslon = 0.9 # 貪婪度
alpha = 0.1 # 學習率
gamma = 0.9 # 递减值maxEpisodes = 30 # 總回合數
stepsRecord = [] # 紀錄每回合步數# 狀態-行動 價值表
qT=np.zeros((2,11))# 狀態 = 0~10
# [0,0,0,0,0,0,0,0,0,0,0] # 動作 0 向左
# [0,0,0,0,0,0,0,0,0,0,0] # 動作 1 向右
2.建立函式
在選擇行動的環節,有很大的機率直接挑選已知最有價值的行動,語法np.argmax(qT[:,state])
會回饋當前狀態下最有價值行動的index,設定貪婪度epslon為一個靠近1的數0.9,只有當隨機數超過貪婪度epslon時,才會隨機挑選其他行動進行嘗試。
又或者還處在訓練初期,Q表裡每個行動的價值都為0,也會直接從中隨機挑選行動,但這種狀況在使用神經網路代替Q表時可避免,pyTorch在模型建立之初就會隨機給定系數,使得計算出來的價值有微小的隨機數,並不會全部相同。
在執行行動的部分,可以看到我的模型在左右兩端(state=0 or 10)都是終點,只是當走到最左邊會得到-100的回饋,負的回饋表示逞罰,而走到最右邊會得到+100的回饋,正的回饋表示獎賞。
除了走到最末端的大回饋外,還可以調整在中間時選擇向左、向右的小回饋,並研究小回饋對學習過程的影響,通常遊戲內只會有大回饋,例如通關或死亡,小回饋是使用者自行加入的,用於輔助Agent更容易達成目標。
#選擇行動
def chooseAction(table,state):
# 隨機數超過貪婪度,或兩行動價值相等
if random.random() > epslon or qT[0,state] == qT[1,state] :
return random.randint(0,1)# 隨機選擇行動
else :
return np.argmax(qT[:,state]) # 否則,選擇最佳行動#執行行動
def executeAction(state,action):
reward=0
# 做出行動,改變狀態
if action == 0 : state-=1 ; reward = 0 # 向左一格
elif action == 1 : state+=1 ; reward = 0 # 向右一格
# 到達終點,取得回饋
if state == 0 : reward = -100
elif state == 10 : reward = 100
# 傳回獎勵與新狀態
return reward,state
3.強化學習
學習的階段簡而言之,就是使用前面兩個函式選擇並執行動作,再套公式更新Q表中的數值,重複執行直到到達終點結束一回合,其中qT.max(0).item(stateNew)
,會在某個State的眾多Action中找到對大的價值,結束一回合後記錄該回合使用的步數,如果終點走到了最左邊則將步數乘-1。
# 進行強化學習
for episode in range(maxEpisodes):
step=0
end=False
state=5 # 起始狀態
while not end :
action=chooseAction(qT,state) # 參考Q表作出選擇
# action=1 # 也可強迫做選擇
# 執行動作,並取得回饋與新狀態
reward,stateNew=executeAction(state,action) # 取得預測與目標值
qPredict=qT[action,state] # 從Q表查詢預測值
if stateNew!=0 and stateNew!=10 : # 還沒到終點
# 按照公式計算目標值
qTarget=reward + gamma * qT.max(0).item(stateNew)
else : # 到達終點
qTarget=reward
end = True # 更新Q表內容
qT[action,state] += alpha * (qTarget-qPredict)
state=stateNew # 更新狀態
step+=1
# 一回合結束,紀錄該回合步數
if state==0 : step*=-1 # 走到最左,步數設為負數
stepsRecord.append(step)
4.圖表繪製
關於畫圖的程式這裡就不多做解釋,畫出來的圖表左圖為訓練完30回合後,兩個動作在不同狀態下的價值分布圖,右圖是每個回合所用的步數,長條圖在0以下的長條圖,表示那些回合最終走到了最左邊。
而在圖片標題的部分,手動標註了每回合的起始狀態、每次訓練是參考最大的動作價值,以及每次做完向左或向右的動作之後,額外給的小回饋是多少,在下一篇會測試調整這些參數,並嘗試解讀圖表。
plt.figure(figsize=(20,6))
plt.suptitle("S0=5 ; maxQ(S',a') ; r(left)=0 ; r(right)=0")# 左圖
plt.subplot(1, 2, 1)
X=[0,1,2,3,4,5,6,7,8,9,10]
plt.xlabel('States')
plt.ylabel('Quality')
plt.plot(X,qT[0,:].tolist(),label='go left')
plt.plot(X,qT[1,:].tolist(),label='go right'
plt.legend(loc='upper left')# 右圖
plt.subplot(1, 2, 2)
X=np.arange(1,31)
plt.xlabel('Episodes')
plt.ylabel('Steps')
plt.bar(X,stepsRecord)
plt.show()